diff options
author | Werner Koch <[email protected]> | 2001-11-13 12:50:14 +0000 |
---|---|---|
committer | Werner Koch <[email protected]> | 2001-11-13 12:50:14 +0000 |
commit | 90d060c1997c6c0b9f26c9088020d62f91d450da (patch) | |
tree | b2e7720d625699a49729b36286fb66a774c5faed /kbx/keybox-search.c | |
parent | A Makefile is a pretty useful thing (diff) | |
download | gnupg-90d060c1997c6c0b9f26c9088020d62f91d450da.tar.gz gnupg-90d060c1997c6c0b9f26c9088020d62f91d450da.zip |
We have reached a state where we are able to import certs and
check the certification path.
Diffstat (limited to '')
-rw-r--r-- | kbx/keybox-search.c | 511 |
1 files changed, 397 insertions, 114 deletions
diff --git a/kbx/keybox-search.c b/kbx/keybox-search.c index d2c61ff21..3468a8ecf 100644 --- a/kbx/keybox-search.c +++ b/kbx/keybox-search.c @@ -25,134 +25,417 @@ #include "keybox-defs.h" +static ulong +get32 (const byte *buffer) +{ + ulong a; + a = *buffer << 24; + a |= buffer[1] << 16; + a |= buffer[2] << 8; + a |= buffer[3]; + return a; +} -/**************** - * Check whether the given fingerprint (20 bytes) is in the - * given keyblob. fpr is always 20 bytes. - * Return: 0 = found - * -1 = not found - other = error (fixme: do not always reurn gpgerr_general) - */ -int -keybox_blob_has_fpr ( KEYBOXBLOB blob, const byte *fpr ) +static ulong +get16 (const byte *buffer) +{ + ulong a; + a = *buffer << 8; + a |= buffer[1]; + return a; +} + + + +static int +blob_get_type (KEYBOXBLOB blob) +{ + const unsigned char *buffer; + size_t length; + + buffer = _keybox_get_blob_image (blob, &length); + if (length < 40) + return -1; /* blob too short */ + + return buffer[4]; +} + + +static int +blob_cmp_sn (KEYBOXBLOB blob, const unsigned char *sn) +{ + size_t snlen; + const unsigned char *buffer; + size_t length; + size_t pos, off; + size_t nkeys, keyinfolen; + size_t nserial; + + snlen = (sn[0] << 24) | (sn[1] << 16) | (sn[2] << 8) | sn[3]; + sn += 4; + + 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 */ + + /*serial*/ + nserial = get16 (buffer+pos); + off = pos + 2; + if (off+nserial > length) + return 0; /* out of bounds */ + + return nserial == snlen && !memcmp (buffer+off, sn, snlen); +} + +static int +blob_cmp_name (KEYBOXBLOB blob, int idx, const char *name, size_t namelen) { - ulong n, nkeys, keyinfolen; - const byte *p, *pend; - byte *buffer = blob->blob; - size_t buflen = blob->bloblen; - - if ( buflen < 40 ) - return GPGERR_GENERAL; /* blob too short */ - n = get32( buffer ); - if ( n > buflen ) - return GPGERR_GENERAL; /* blob larger than announced length */ - buflen = n; /* ignore trailing stuff */ - pend = buffer + n - 1; - - if ( buffer[4] != 2 ) - return GPGERR_GENERAL; /* invalid blob type */ - if ( buffer[5] != 1 ) - return GPGERR_GENERAL; /* invalid blob format version */ - - nkeys = get16( buffer + 16 ); - keyinfolen = get16( buffer + 18 ); - p = buffer + 20; - for(n=0; n < nkeys; n++, p += keyinfolen ) { - if ( p+20 > pend ) - return GPGERR_GENERAL; /* blob shorter than required */ - if (!memcmp ( p, fpr, 20 ) ) - return 0; /* found */ + const unsigned char *buffer; + size_t length; + size_t pos, off, len; + size_t nkeys, keyinfolen; + size_t nuids, uidinfolen; + size_t nserial; + + 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 */ + + /*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 */ + + 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); +} + + + + +/* + The has_foo functions are used as helpers for search +*/ +#if 0 +static int +has_short_kid (KEYBOXBLOB blob, u32 kid) +{ + return 0; +} + +static int +has_long_kid (KEYBOXBLOB blob, u32 *kid) +{ + return 0; +} +#endif + +static int +has_fingerprint (KEYBOXBLOB blob, const unsigned char *fpr) +{ + return 0; +} + + +static int +has_issuer (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, 0 /* issuer */, name, namelen); +} + +static int +has_issuer_sn (KEYBOXBLOB blob, const char *name, const unsigned char *sn) +{ + size_t namelen; + + return_val_if_fail (name, 0); + return_val_if_fail (sn, 0); + + if (blob_get_type (blob) != BLOBTYPE_X509) + return 0; + + namelen = strlen (name); + + return (blob_cmp_sn (blob, sn) + && blob_cmp_name (blob, 0 /* issuer */, name, namelen)); +} + + + +/* + + The search API + +*/ + +int +keybox_search_reset (KEYBOX_HANDLE hd) +{ + if (!hd) + return KEYBOX_Invalid_Value; + + if (hd->found.blob) + { + _keybox_release_blob (hd->found.blob); + hd->found.blob = NULL; + } + + if (hd->fp) + { + fclose (hd->fp); + hd->fp = NULL; } - return -1; + hd->error = 0; + hd->eof = 0; + return 0; } -/**************** - * Check whether the given keyID (20 bytes) is in the - * given keyblob. - * Return: 0 = found - * -1 = not found - other = error (fixme: do not always return gpgerr_general) - */ -int -keybox_blob_has_kid ( KEYBOXBLOB blob, const byte *keyidbuf, size_t keyidlen ) +int +keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc) { - ulong n, nkeys, keyinfolen, off; - const byte *p, *pend; - byte *buffer = blob->blob; - size_t buflen = blob->bloblen; - - if ( buflen < 40 ) - return GPGERR_GENERAL; /* blob too short */ - n = get32( buffer ); - if ( n > buflen ) - return GPGERR_GENERAL; /* blob larger than announced length */ - buflen = n; /* ignore trailing stuff */ - pend = buffer + n - 1; - - if ( buffer[4] != 2 ) - return GPGERR_GENERAL; /* invalid blob type */ - if ( buffer[5] != 1 ) - return GPGERR_GENERAL; /* invalid blob format version */ - - nkeys = get16( buffer + 16 ); - keyinfolen = get16( buffer + 18 ); - p = buffer + 20; - for(n=0; n < nkeys; n++, p += keyinfolen ) { - if ( p+24 > pend ) - return GPGERR_GENERAL; /* blob shorter than required */ - off = get32 ( p + 20 ); - if (keyidlen < 8 ) /* actually keyidlen may either be 4 or 8 */ - off +=4; - if ( off+keyidlen > buflen ) - return GPGERR_GENERAL; /* offset out of bounds */ - if ( !memcmp ( buffer+off, keyidbuf, keyidlen ) ) - return 0; /* found */ + int rc; + size_t n; + int need_words, any_skip; + KEYBOXBLOB blob = NULL; + + if (!hd) + return KEYBOX_Invalid_Value; + + /* clear last found result */ + if (hd->found.blob) + { + _keybox_release_blob (hd->found.blob); + hd->found.blob = NULL; + } + + if (hd->error) + return hd->error; /* still in error state */ + if (hd->eof) + return -1; /* still EOF */ + + /* figure out what information we need */ + need_words = any_skip = 0; + for (n=0; n < ndesc; n++) + { + switch (desc[n].mode) + { + case KEYDB_SEARCH_MODE_WORDS: + need_words = 1; + break; + case KEYDB_SEARCH_MODE_FIRST: + /* always restart the search in this mode */ + keybox_search_reset (hd); + break; + default: + break; + } + if (desc[n].skipfnc) + any_skip = 1; + } + + if (!hd->fp) + { + hd->fp = fopen (hd->kb->fname, "rb"); + if (!hd->fp) + return (hd->error = KEYBOX_File_Open_Error); + } + + + for (;;) + { + _keybox_release_blob (blob); blob = NULL; + rc = _keybox_read_blob (&blob, hd->fp); + if (rc) + break; + + for (n=0; n < ndesc; n++) + { + switch (desc[n].mode) + { + case KEYDB_SEARCH_MODE_NONE: + never_reached (); + break; + case KEYDB_SEARCH_MODE_EXACT: + case KEYDB_SEARCH_MODE_SUBSTR: + case KEYDB_SEARCH_MODE_MAIL: + case KEYDB_SEARCH_MODE_MAILSUB: + case KEYDB_SEARCH_MODE_MAILEND: + case KEYDB_SEARCH_MODE_WORDS: + never_reached (); /* not yet implemented */ + break; + case KEYDB_SEARCH_MODE_ISSUER: + if (has_issuer (blob, desc[n].u.name)) + goto found; + break; + case KEYDB_SEARCH_MODE_ISSUER_SN: + if (has_issuer_sn (blob, desc[n].u.name, desc[n].sn)) + goto found; + break; + case KEYDB_SEARCH_MODE_SHORT_KID: +/* if (has_short_kid (blob, desc[n].u.kid[1])) */ +/* goto found; */ + break; + case KEYDB_SEARCH_MODE_LONG_KID: +/* if (has_long_kid (blob, desc[n].u.kid)) */ +/* goto found; */ + break; + case KEYDB_SEARCH_MODE_FPR: + if (has_fingerprint (blob, desc[n].u.fpr)) + goto found; + break; + case KEYDB_SEARCH_MODE_FIRST: + goto found; + break; + case KEYDB_SEARCH_MODE_NEXT: + goto found; + break; + default: + rc = KEYBOX_Invalid_Value; + goto found; + } + } + continue; + found: + for (n=any_skip?0:ndesc; n < ndesc; n++) + { +/* if (desc[n].skipfnc */ +/* && desc[n].skipfnc (desc[n].skipfncvalue, aki)) */ +/* break; */ + } + if (n == ndesc) + break; /* got it */ + } + + if (!rc) + { + hd->found.blob = blob; + } + else if (rc == -1) + { + _keybox_release_blob (blob); + hd->eof = 1; + } + else + { + _keybox_release_blob (blob); + hd->error = rc; } - return -1; + + return rc; } + +/* + Functions to return a certificate or a keyblock. To be used after + a successful search operation. +*/ +#ifdef KEYBOX_WITH_X509 +/* + Return the last found cert. Caller must free it. + */ int -keybox_blob_has_uid ( KEYBOXBLOB blob, - int (*cmp)(const byte *, size_t, void *), void *opaque ) +keybox_get_cert (KEYBOX_HANDLE hd, KsbaCert *r_cert) { - ulong n, nuids, uidinfolen, off, len; - const byte *p, *pend; - byte *buffer = blob->blob; - size_t buflen = blob->bloblen; - - if ( buflen < 40 ) - return GPGERR_GENERAL; /* blob too short */ - n = get32( buffer ); - if ( n > buflen ) - return GPGERR_GENERAL; /* blob larger than announced length */ - buflen = n; /* ignore trailing stuff */ - pend = buffer + n - 1; - - if ( buffer[4] != 2 ) - return GPGERR_GENERAL; /* invalid blob type */ - if ( buffer[5] != 1 ) - return GPGERR_GENERAL; /* invalid blob format version */ - - p = buffer + 20 + get16( buffer + 16 ) * get16( buffer + 18 ); - if ( p+4 > pend ) - return GPGERR_GENERAL; /* blob shorter than required */ - - nuids = get16( p ); p+= 2; - uidinfolen = get16( p ); p+=2; - for(n=0; n < nuids; n++, p += uidinfolen ) { - if ( p+8 > pend ) - return GPGERR_GENERAL; /* blob shorter than required */ - off = get32 ( p ); - len = get32 ( p + 4 ); - if ( off+len > buflen ) - return GPGERR_GENERAL; /* offset out of bounds */ - if ( (*cmp) ( buffer+off, len, opaque ) ) - return 0; /* found */ + const unsigned char *buffer; + size_t length; + size_t cert_off, cert_len; + KsbaReader reader = NULL; + KsbaCert cert = NULL; + int rc; + + if (!hd) + return KEYBOX_Invalid_Value; + if (!hd->found.blob) + return KEYBOX_Nothing_Found; + + if (blob_get_type (hd->found.blob) != BLOBTYPE_X509) + return KEYBOX_Wrong_Blob_Type; + + buffer = _keybox_get_blob_image (hd->found.blob, &length); + if (length < 40) + return KEYBOX_Blob_Too_Short; + cert_off = get32 (buffer+8); + cert_len = get32 (buffer+12); + if (cert_off+cert_len > length) + return KEYBOX_Blob_Too_Short; + + reader = ksba_reader_new (); + if (!reader) + return KEYBOX_Out_Of_Core; + rc = ksba_reader_set_mem (reader, buffer+cert_off, cert_len); + if (rc) + { + ksba_reader_release (reader); + /* fixme: need to map the error codes */ + return KEYBOX_General_Error; } - return -1; -} + cert = ksba_cert_new (); + if (!cert) + { + ksba_reader_release (reader); + return KEYBOX_Out_Of_Core; + } + rc = ksba_cert_read_der (cert, reader); + if (rc) + { + ksba_cert_release (cert); + ksba_reader_release (reader); + /* fixme: need to map the error codes */ + return KEYBOX_General_Error; + } + + *r_cert = cert; + ksba_reader_release (reader); + return 0; +} +#endif /*KEYBOX_WITH_X509*/ |