aboutsummaryrefslogtreecommitdiffstats
path: root/kbx/keybox-search.c
diff options
context:
space:
mode:
Diffstat (limited to 'kbx/keybox-search.c')
-rw-r--r--kbx/keybox-search.c171
1 files changed, 135 insertions, 36 deletions
diff --git a/kbx/keybox-search.c b/kbx/keybox-search.c
index ef5cd953e..5e6432fa6 100644
--- a/kbx/keybox-search.c
+++ b/kbx/keybox-search.c
@@ -1,5 +1,6 @@
/* keybox-search.c - Search operations
- * Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2002, 2003, 2004, 2012,
+ * 2013 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -102,7 +103,7 @@ _keybox_get_flag_location (const unsigned char *buffer, size_t length,
size_t nkeys, keyinfolen;
size_t nuids, uidinfolen;
size_t nserial;
- size_t nsigs, siginfolen;
+ size_t nsigs, siginfolen, siginfooff;
switch (what)
{
@@ -116,6 +117,7 @@ _keybox_get_flag_location (const unsigned char *buffer, size_t length,
case KEYBOX_FLAG_OWNERTRUST:
case KEYBOX_FLAG_VALIDITY:
case KEYBOX_FLAG_CREATED_AT:
+ case KEYBOX_FLAG_SIG_INFO:
if (length < 20)
return GPG_ERR_INV_OBJ;
/* Key info. */
@@ -140,6 +142,7 @@ _keybox_get_flag_location (const unsigned char *buffer, size_t length,
if (pos+4 > length)
return GPG_ERR_INV_OBJ ; /* Out of bounds. */
/* Signature info. */
+ siginfooff = pos;
nsigs = get16 (buffer + pos); pos += 2;
siginfolen = get16 (buffer + pos); pos += 2;
if (siginfolen < 4 )
@@ -158,6 +161,10 @@ _keybox_get_flag_location (const unsigned char *buffer, size_t length,
*flag_size = 4;
*flag_off += 1+2+4+4+4;
break;
+ case KEYBOX_FLAG_SIG_INFO:
+ *flag_size = siginfolen * nsigs;
+ *flag_off = siginfooff;
+ break;
default:
break;
}
@@ -227,6 +234,9 @@ blob_cmp_sn (KEYBOXBLOB blob, const unsigned char *sn, int snlen)
}
+/* Returns 0 if not found or the number of the key which was found.
+ For X.509 this is always 1, for OpenPGP this is 1 for the primary
+ key and 2 and more for the subkeys. */
static int
blob_cmp_fpr (KEYBOXBLOB blob, const unsigned char *fpr)
{
@@ -253,7 +263,7 @@ blob_cmp_fpr (KEYBOXBLOB blob, const unsigned char *fpr)
{
off = pos + idx*keyinfolen;
if (!memcmp (buffer + off, fpr, 20))
- return 1; /* found */
+ return idx+1; /* found */
}
return 0; /* not found */
}
@@ -285,7 +295,7 @@ blob_cmp_fpr_part (KEYBOXBLOB blob, const unsigned char *fpr,
{
off = pos + idx*keyinfolen;
if (!memcmp (buffer + off + fproff, fpr, fprlen))
- return 1; /* found */
+ return idx+1; /* found */
}
return 0; /* not found */
}
@@ -293,7 +303,7 @@ blob_cmp_fpr_part (KEYBOXBLOB blob, const unsigned char *fpr,
static int
blob_cmp_name (KEYBOXBLOB blob, int idx,
- const char *name, size_t namelen, int substr)
+ const char *name, size_t namelen, int substr, int x509)
{
const unsigned char *buffer;
size_t length;
@@ -330,10 +340,9 @@ blob_cmp_name (KEYBOXBLOB blob, int idx,
return 0; /* out of bounds */
if (idx < 0)
- { /* compare all names starting with that (negated) index */
- idx = -idx;
-
- for ( ;idx < nuids; idx++)
+ { /* Compare all names. Note that for X.509 we start with index 1
+ so to skip the issuer at index 0. */
+ for (idx = !!x509; idx < nuids; idx++)
{
size_t mypos = pos;
@@ -347,15 +356,14 @@ blob_cmp_name (KEYBOXBLOB blob, int idx,
if (substr)
{
if (ascii_memcasemem (buffer+off, len, name, namelen))
- return 1; /* found */
+ return idx+1; /* found */
}
else
{
if (len == namelen && !memcmp (buffer+off, name, len))
- return 1; /* found */
+ return idx+1; /* found */
}
}
- return 0; /* not found */
}
else
{
@@ -371,20 +379,25 @@ blob_cmp_name (KEYBOXBLOB blob, int idx,
if (substr)
{
- return !!ascii_memcasemem (buffer+off, len, name, namelen);
+ if (ascii_memcasemem (buffer+off, len, name, namelen))
+ return idx+1; /* found */
}
else
{
- return len == namelen && !memcmp (buffer+off, name, len);
+ if (len == namelen && !memcmp (buffer+off, name, len))
+ return idx+1; /* found */
}
}
+ return 0; /* not found */
}
-/* compare all email addresses of the subject. With SUBSTR given as
- True a substring search is done in the mail address */
+/* Compare all email addresses of the subject. With SUBSTR given as
+ True a substring search is done in the mail address. If X509
+ states whether thr search is done on an X.509 blob. */
static int
-blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen, int substr)
+blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen, int substr,
+ int x509)
{
const unsigned char *buffer;
size_t length;
@@ -425,7 +438,9 @@ blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen, int substr)
if (namelen < 1)
return 0;
- for (idx=1 ;idx < nuids; idx++)
+ /* Note that for X.509 we start at index 1 becuase index 0 is used
+ for the issuer name. */
+ for (idx=!!x509 ;idx < nuids; idx++)
{
size_t mypos = pos;
@@ -434,6 +449,12 @@ blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen, int substr)
len = get32 (buffer+mypos+4);
if (off+len > length)
return 0; /* error: better stop here out of bounds */
+ if (!x509)
+ {
+ /* For OpenPGP we need to forward to the mailbox part. */
+ for ( ;len && buffer[off] != '<'; len--, off++)
+ ;
+ }
if (len < 2 || buffer[off] != '<')
continue; /* empty name or trailing 0 not stored */
len--; /* one back */
@@ -443,12 +464,12 @@ blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen, int substr)
if (substr)
{
if (ascii_memcasemem (buffer+off+1, len, name, namelen))
- return 1; /* found */
+ return idx+1; /* found */
}
else
{
if (len == namelen && !ascii_memcasecmp (buffer+off+1, name, len))
- return 1; /* found */
+ return idx+1; /* found */
}
}
return 0; /* not found */
@@ -583,7 +604,7 @@ has_issuer (KEYBOXBLOB blob, const char *name)
return 0;
namelen = strlen (name);
- return blob_cmp_name (blob, 0 /* issuer */, name, namelen, 0);
+ return blob_cmp_name (blob, 0 /* issuer */, name, namelen, 0, 1);
}
static inline int
@@ -601,7 +622,7 @@ has_issuer_sn (KEYBOXBLOB blob, const char *name,
namelen = strlen (name);
return (blob_cmp_sn (blob, sn, snlen)
- && blob_cmp_name (blob, 0 /* issuer */, name, namelen, 0));
+ && blob_cmp_name (blob, 0 /* issuer */, name, namelen, 0, 1));
}
static inline int
@@ -625,22 +646,25 @@ has_subject (KEYBOXBLOB blob, const char *name)
return 0;
namelen = strlen (name);
- return blob_cmp_name (blob, 1 /* subject */, name, namelen, 0);
+ return blob_cmp_name (blob, 1 /* subject */, name, namelen, 0, 1);
}
+
static inline int
-has_subject_or_alt (KEYBOXBLOB blob, const char *name, int substr)
+has_username (KEYBOXBLOB blob, const char *name, int substr)
{
size_t namelen;
+ int btype;
return_val_if_fail (name, 0);
- if (blob_get_type (blob) != BLOBTYPE_X509)
+ btype = blob_get_type (blob);
+ if (btype != BLOBTYPE_PGP && btype != BLOBTYPE_X509)
return 0;
namelen = strlen (name);
- return blob_cmp_name (blob, -1 /* all subject names*/, name,
- namelen, substr);
+ return blob_cmp_name (blob, -1 /* all subject/user names */, name,
+ namelen, substr, (btype == BLOBTYPE_X509));
}
@@ -648,16 +672,21 @@ static inline int
has_mail (KEYBOXBLOB blob, const char *name, int substr)
{
size_t namelen;
+ int btype;
return_val_if_fail (name, 0);
- if (blob_get_type (blob) != BLOBTYPE_X509)
+ btype = blob_get_type (blob);
+ if (btype != BLOBTYPE_PGP && btype != BLOBTYPE_X509)
return 0;
+ if (btype == BLOBTYPE_PGP && *name == '<')
+ name++; /* Hack to remove the leading '<' for gpg. */
+
namelen = strlen (name);
if (namelen && name[namelen-1] == '>')
namelen--;
- return blob_cmp_mail (blob, name, namelen, substr);
+ return blob_cmp_mail (blob, name, namelen, substr, (btype == BLOBTYPE_X509));
}
@@ -711,6 +740,7 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
int need_words, any_skip;
KEYBOXBLOB blob = NULL;
struct sn_array_s *sn_array = NULL;
+ int pk_no, uid_no;
if (!hd)
return gpg_error (GPG_ERR_INV_VALUE);
@@ -827,6 +857,7 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
}
+ pk_no = uid_no = 0;
for (;;)
{
unsigned int blobflags;
@@ -852,19 +883,23 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
never_reached ();
break;
case KEYDB_SEARCH_MODE_EXACT:
- if (has_subject_or_alt (blob, desc[n].u.name, 0))
+ uid_no = has_username (blob, desc[n].u.name, 0);
+ if (uid_no)
goto found;
break;
case KEYDB_SEARCH_MODE_MAIL:
- if (has_mail (blob, desc[n].u.name, 0))
+ uid_no = has_mail (blob, desc[n].u.name, 0);
+ if (uid_no)
goto found;
break;
case KEYDB_SEARCH_MODE_MAILSUB:
- if (has_mail (blob, desc[n].u.name, 1))
+ uid_no = has_mail (blob, desc[n].u.name, 1);
+ if (uid_no)
goto found;
break;
case KEYDB_SEARCH_MODE_SUBSTR:
- if (has_subject_or_alt (blob, desc[n].u.name, 1))
+ uid_no = has_username (blob, desc[n].u.name, 1);
+ if (uid_no)
goto found;
break;
case KEYDB_SEARCH_MODE_MAILEND:
@@ -891,16 +926,19 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
goto found;
break;
case KEYDB_SEARCH_MODE_SHORT_KID:
- if (has_short_kid (blob, desc[n].u.kid[1]))
+ pk_no = has_short_kid (blob, desc[n].u.kid[1]);
+ if (pk_no)
goto found;
break;
case KEYDB_SEARCH_MODE_LONG_KID:
- if (has_long_kid (blob, desc[n].u.kid[0], desc[n].u.kid[1]))
+ pk_no = has_long_kid (blob, desc[n].u.kid[0], desc[n].u.kid[1]);
+ if (pk_no)
goto found;
break;
case KEYDB_SEARCH_MODE_FPR:
case KEYDB_SEARCH_MODE_FPR20:
- if (has_fingerprint (blob, desc[n].u.fpr))
+ pk_no = has_fingerprint (blob, desc[n].u.fpr);
+ if (pk_no)
goto found;
break;
case KEYDB_SEARCH_MODE_KEYGRIP:
@@ -933,6 +971,8 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
if (!rc)
{
hd->found.blob = blob;
+ hd->found.pk_no = pk_no;
+ hd->found.uid_no = uid_no;
}
else if (rc == -1)
{
@@ -958,6 +998,65 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
Functions to return a certificate or a keyblock. To be used after
a successful search operation.
*/
+
+
+/* Return the last found keyblock. Returns 0 on success and stores a
+ new iobuf at R_IOBUF and a signature status vector at R_SIGSTATUS
+ in that case. R_UID_NO and R_PK_NO are used to retun the number of
+ the key or user id which was matched the search criteria; if not
+ known they are set to 0. */
+gpg_error_t
+keybox_get_keyblock (KEYBOX_HANDLE hd, iobuf_t *r_iobuf,
+ int *r_pk_no, int *r_uid_no, u32 **r_sigstatus)
+{
+ gpg_error_t err;
+ const unsigned char *buffer, *p;
+ size_t length;
+ size_t image_off, image_len;
+ size_t siginfo_off, siginfo_len;
+ u32 *sigstatus, n, n_sigs, sigilen;
+
+ *r_iobuf = NULL;
+ *r_sigstatus = NULL;
+
+ if (!hd)
+ return gpg_error (GPG_ERR_INV_VALUE);
+ if (!hd->found.blob)
+ return gpg_error (GPG_ERR_NOTHING_FOUND);
+
+ if (blob_get_type (hd->found.blob) != BLOBTYPE_PGP)
+ return gpg_error (GPG_ERR_WRONG_BLOB_TYPE);
+
+ buffer = _keybox_get_blob_image (hd->found.blob, &length);
+ if (length < 40)
+ return gpg_error (GPG_ERR_TOO_SHORT);
+ image_off = get32 (buffer+8);
+ image_len = get32 (buffer+12);
+ if (image_off+image_len > length)
+ return gpg_error (GPG_ERR_TOO_SHORT);
+
+ err = _keybox_get_flag_location (buffer, length, KEYBOX_FLAG_SIG_INFO,
+ &siginfo_off, &siginfo_len);
+ if (err)
+ return err;
+ n_sigs = get16 (buffer + siginfo_off);
+ sigilen = get16 (buffer + siginfo_off + 2);
+ p = buffer + siginfo_off + 4;
+ sigstatus = xtrymalloc ((1+n_sigs) * sizeof *sigstatus);
+ if (!sigstatus)
+ return gpg_error_from_syserror ();
+ sigstatus[0] = n_sigs;
+ for (n=1; n <= n_sigs; n++, p += sigilen)
+ sigstatus[n] = get32 (p);
+
+ *r_pk_no = hd->found.pk_no;
+ *r_uid_no = hd->found.uid_no;
+ *r_sigstatus = sigstatus;
+ *r_iobuf = iobuf_temp_with_content (buffer+image_off, image_len);
+ return 0;
+}
+
+
#ifdef KEYBOX_WITH_X509
/*
Return the last found cert. Caller must free it.