diff --git a/kbx/ChangeLog b/kbx/ChangeLog new file mode 100644 index 000000000..8451dd250 --- /dev/null +++ b/kbx/ChangeLog @@ -0,0 +1,23 @@ +2001-12-13 Werner Koch + + * keybox-search.c (blob_cmp_name): Kludge to allow searching for + more than one name. + (has_subject_or_alt): New. + (blob_cmp_mail): New. + (has_mail): New. + (keybox_search): Implemented exact search and exact mail search. + + * kbx/keybox-blob.c (_keybox_create_x509_blob): Insert alternate + names. + + + Copyright 2001 g10 Code GmbH + + This file is free software; as a special exception the author gives + unlimited permission to copy and/or distribute it, with or without + modifications, as long as this notice is preserved. + + This file is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, to the extent permitted by law; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + \ No newline at end of file diff --git a/kbx/keybox-blob.c b/kbx/keybox-blob.c index 84ebc904c..18503a576 100644 --- a/kbx/keybox-blob.c +++ b/kbx/keybox-blob.c @@ -774,9 +774,11 @@ int _keybox_create_x509_blob (KEYBOXBLOB *r_blob, KsbaCert cert, unsigned char *sha1_digest) { - int rc = 0; + int i, rc = 0; KEYBOXBLOB blob; unsigned char *p; + unsigned char **names = NULL; + size_t max_names; *r_blob = NULL; blob = xtrycalloc (1, sizeof *blob); @@ -790,10 +792,43 @@ _keybox_create_x509_blob (KEYBOXBLOB *r_blob, KsbaCert cert, blob->seriallen = n; blob->serial = p; } - blob->nkeys = 1; - blob->nuids = 2; /* issuer and subject - fixme: count alternate names */ + + /* create list of names */ + blob->nuids = 0; + max_names = 100; + names = xtrymalloc (max_names * sizeof *names); + if (!names) + { + rc = KEYBOX_Out_Of_Core; + goto leave; + } + p = ksba_cert_get_issuer (cert, 0); + if (!p) + { + rc = KEYBOX_Missing_Value; + goto leave; + } + names[blob->nuids++] = p; + for (i=0; (p = ksba_cert_get_subject (cert, i)); i++) + { + if (blob->nuids >= max_names) + { + unsigned char **tmp; + + max_names += 100; + tmp = xtryrealloc (names, max_names * sizeof *names); + if (!tmp) + { + rc = KEYBOX_Out_Of_Core; + goto leave; + } + } + names[blob->nuids++] = p; + } + + /* space for signature information */ blob->nsigs = 1; blob->keys = xtrycalloc (blob->nkeys, sizeof *blob->keys ); @@ -809,21 +844,17 @@ _keybox_create_x509_blob (KEYBOXBLOB *r_blob, KsbaCert cert, blob->keys[0].off_kid = 0; /* We don't have keyids */ blob->keys[0].flags = 0; - /* issuer */ - p = ksba_cert_get_issuer (cert); - blob->uids[0].name = p; - blob->uids[0].len = p? (strlen(p)+1):0; - blob->uids[0].flags = 0; - blob->uids[0].validity = 0; - - /* subject */ - p = ksba_cert_get_subject (cert); - blob->uids[1].name = p; - blob->uids[1].len = p? (strlen(p)+1):0; - blob->uids[1].flags = 0; - blob->uids[1].validity = 0; - - /* fixme: add alternate names */ + /* issuer and subject names */ + for (i=0; i < blob->nuids; i++) + { + blob->uids[i].name = names[i]; + blob->uids[i].len = strlen(names[i]); + names[i] = NULL; + blob->uids[i].flags = 0; + blob->uids[i].validity = 0; + } + xfree (names); + names = NULL; /* signatures */ blob->sigs[0] = 0; /* not yet checked */ @@ -849,6 +880,12 @@ _keybox_create_x509_blob (KEYBOXBLOB *r_blob, KsbaCert cert, leave: release_kid_list (blob->temp_kids); blob->temp_kids = NULL; + if (blob && names) + { + for (i=0; i < blob->nuids; i++) + xfree (names[i]); + } + xfree (names); if (rc) { _keybox_release_blob (blob); diff --git a/kbx/keybox-errors.c b/kbx/keybox-errors.c index e75373c0b..e11efc10b 100644 --- a/kbx/keybox-errors.c +++ b/kbx/keybox-errors.c @@ -38,6 +38,7 @@ keybox_strerror (KeyboxError err) case KEYBOX_File_Close_Error: s="file close error"; break; case KEYBOX_Nothing_Found: s="nothing found"; break; case KEYBOX_Wrong_Blob_Type: s="wrong blob type"; break; + case KEYBOX_Missing_Value: s="missing value"; break; default: sprintf (buf, "ec=%d", err ); s=buf; break; } diff --git a/kbx/keybox-search.c b/kbx/keybox-search.c index 23543ec66..e168d2b97 100644 --- a/kbx/keybox-search.c +++ b/kbx/keybox-search.c @@ -102,6 +102,7 @@ blob_cmp_sn (KEYBOXBLOB blob, const unsigned char *sn) return nserial == snlen && !memcmp (buffer+off, sn, snlen); } + static int blob_cmp_name (KEYBOXBLOB blob, int idx, const char *name, size_t namelen) { @@ -139,18 +140,105 @@ blob_cmp_name (KEYBOXBLOB blob, int idx, const char *name, size_t namelen) if (pos + uidinfolen*nuids > length) return 0; /* out of bounds */ - if (idx > nuids) - return 0; /* no user ID with that idx */ - pos += idx*uidinfolen; - off = get32 (buffer+pos); - len = get32 (buffer+pos+4); - if (off+len > length) + if (idx < 0) + { /* compare all names starting with that (negated) index */ + idx = -idx; + + for ( ;idx < nuids; idx++) + { + size_t mypos = pos; + + mypos += idx*uidinfolen; + off = get32 (buffer+mypos); + len = get32 (buffer+mypos+4); + if (off+len > length) + return 0; /* error: better stop here out of bounds */ + if (len < 2) + continue; /* empty name or 0 not stored */ + len--; + if (len == namelen && !memcmp (buffer+off, name, len)) + return 1; /* found */ + } + return 0; /* not found */ + } + else + { + if (idx > nuids) + return 0; /* no user ID with that idx */ + pos += idx*uidinfolen; + off = get32 (buffer+pos); + len = get32 (buffer+pos+4); + if (off+len > length) + return 0; /* out of bounds */ + if (len < 2) + return 0; /* empty name or 0 not stored */ + len--; + + return len == namelen && !memcmp (buffer+off, name, len); + } +} + + +/* compare all email addresses of the subject */ +static int +blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen) +{ + const unsigned char *buffer; + size_t length; + size_t pos, off, len; + size_t nkeys, keyinfolen; + size_t nuids, uidinfolen; + size_t nserial; + int idx; + + /* fixme: this code is common to blob_cmp_mail */ + buffer = _keybox_get_blob_image (blob, &length); + if (length < 40) + return 0; /* blob too short */ + + /*keys*/ + nkeys = get16 (buffer + 16); + keyinfolen = get16 (buffer + 18 ); + if (keyinfolen < 28) + return 0; /* invalid blob */ + pos = 20 + keyinfolen*nkeys; + if (pos+2 > length) return 0; /* out of bounds */ - if (len < 2) - return 0; /* empty name or 0 not stored */ - len--; - - return len == namelen && !memcmp (buffer+off, name, len); + + /*serial*/ + nserial = get16 (buffer+pos); + pos += 2 + nserial; + if (pos+4 > length) + return 0; /* out of bounds */ + + /* user ids*/ + nuids = get16 (buffer + pos); pos += 2; + uidinfolen = get16 (buffer + pos); pos += 2; + if (uidinfolen < 12 /* should add a: || nuidinfolen > MAX_UIDINFOLEN */) + return 0; /* invalid blob */ + if (pos + uidinfolen*nuids > length) + return 0; /* out of bounds */ + + for (idx=1 ;idx < nuids; idx++) + { + size_t mypos = pos; + + mypos += idx*uidinfolen; + off = get32 (buffer+mypos); + len = get32 (buffer+mypos+4); + if (off+len > length) + return 0; /* error: better stop here out of bounds */ + if (len < 2 || buffer[off] != '<') + continue; /* empty name or trailing 0 not stored */ + len--; /* remove the null */ + if ( len < 3 || buffer[off+len-1] != '>') + continue; /* not a prober email address */ + off++; len--; /* skip the leading angle bracket */ + len--; /* don't compare the trailing one */ + if (len == namelen && !memcmp (buffer+off, name, len)) + return 1; /* found */ + } + return 0; /* not found */ } @@ -235,6 +323,35 @@ has_subject (KEYBOXBLOB blob, const char *name) return blob_cmp_name (blob, 1 /* subject */, name, namelen); } +static int +has_subject_or_alt (KEYBOXBLOB blob, const char *name) +{ + size_t namelen; + + return_val_if_fail (name, 0); + + if (blob_get_type (blob) != BLOBTYPE_X509) + return 0; + + namelen = strlen (name); + return blob_cmp_name (blob, -1 /* all subject names*/, name, namelen); +} + + +static int +has_mail (KEYBOXBLOB blob, const char *name) +{ + size_t namelen; + + return_val_if_fail (name, 0); + + if (blob_get_type (blob) != BLOBTYPE_X509) + return 0; + + namelen = strlen (name); + return blob_cmp_mail (blob, name, namelen); +} + static void release_sn_array (unsigned char **array, size_t size) @@ -413,8 +530,14 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc) never_reached (); break; case KEYDB_SEARCH_MODE_EXACT: - case KEYDB_SEARCH_MODE_SUBSTR: + if (has_subject_or_alt (blob, desc[n].u.name)) + goto found; + break; case KEYDB_SEARCH_MODE_MAIL: + if (has_mail (blob, desc[n].u.name)) + goto found; + break; + case KEYDB_SEARCH_MODE_SUBSTR: case KEYDB_SEARCH_MODE_MAILSUB: case KEYDB_SEARCH_MODE_MAILEND: case KEYDB_SEARCH_MODE_WORDS: diff --git a/kbx/keybox.h b/kbx/keybox.h index 645f1e715..fcacc49d3 100644 --- a/kbx/keybox.h +++ b/kbx/keybox.h @@ -60,6 +60,7 @@ typedef enum { KEYBOX_File_Close_Error = 13, KEYBOX_Nothing_Found = 14, KEYBOX_Wrong_Blob_Type = 15, + KEYBOX_Missing_Value = 16, } KeyboxError;