diff options
Diffstat (limited to 'kbx/keybox-search.c')
-rw-r--r-- | kbx/keybox-search.c | 171 |
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. |