diff options
-rw-r--r-- | doc/gcryptref-digest.sgml | 17 | ||||
-rw-r--r-- | g10/ChangeLog | 7 | ||||
-rw-r--r-- | g10/Makefile.am | 8 | ||||
-rw-r--r-- | g10/build-packet.c | 3 | ||||
-rw-r--r-- | g10/gpg.c | 4 | ||||
-rw-r--r-- | g10/gpgd.c | 2 | ||||
-rw-r--r-- | g10/kbx.h | 21 | ||||
-rw-r--r-- | g10/kbxblob.c | 399 | ||||
-rw-r--r-- | g10/kbxfile.c | 291 | ||||
-rw-r--r-- | g10/kbxio.c | 75 | ||||
-rw-r--r-- | g10/kbxutil.c | 442 |
11 files changed, 1208 insertions, 61 deletions
diff --git a/doc/gcryptref-digest.sgml b/doc/gcryptref-digest.sgml index f0d5efff4..a123c9b25 100644 --- a/doc/gcryptref-digest.sgml +++ b/doc/gcryptref-digest.sgml @@ -65,7 +65,10 @@ </indexterm> <function>gcry_md_open</function> creates the context required for the message digest functions. The hash algorithm may optionally be - specified. + specified. It is possible to use these functions as MAC functons; therefore + the flag <literal/GCRY_MD_FLAG_HMAC/ must be given along with the + hash functions. Other MAC algorithms than HMAC are currently not + supported. The key for the MAC must be set using the gcry_md_setkey macro. <function>gcry_md_close</function> releases all resources associated with the context. <function>gcry_md_enable</function> may be used to enable hash @@ -149,6 +152,7 @@ <refnamediv> <refname>gcry_md_ctl</refname> <refname>gcry_md_final</refname> + <refname>gcry_md_setkey</refname> <refpurpose>perform special operations on a digest context</refpurpose> </refnamediv> @@ -179,9 +183,18 @@ </para> <para> Currently defined values for <parameter>cmd</> are: - <literal>GCRYCTL_FINALIZE</> and the conevnience macro + </para> + <para> + <literal>GCRYCTL_FINALIZE</> and the convenience macro <function>gcry_md_final(a)</> </para> + <para> + <literal>GCRYCTL_SET_KEY</> and the convenience macro + <function>gcry_md_setkey(a)</>. This is used to turn these + hash functions into MAC functions. The key may be any string + of the speicified length. The type of the MAC is determined + by special flags set with the open function. + </para> </refentry> <!--********************************************** diff --git a/g10/ChangeLog b/g10/ChangeLog index d20c26aec..64056be69 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,10 @@ +Thu May 25 18:39:11 CEST 2000 Werner Koch <wk@openit.de> + + * kbxio.c: New. + + * kbxfile.c (print_kbxfile): Add a loop + (do_print_kbxfile): Fixed passing to kbx_dump_blob. + Fri Mar 24 11:25:45 CET 2000 Werner Koch <wk@openit.de> * gpg.c (print_mds): Add arg keys as a kludge to print hmacs diff --git a/g10/Makefile.am b/g10/Makefile.am index 9018c1450..55d0ed222 100644 --- a/g10/Makefile.am +++ b/g10/Makefile.am @@ -9,7 +9,7 @@ LDFLAGS = -static @LDFLAGS@ @DYNLINK_LDFLAGS@ needed_libs = ../util/libutil.la ../gcrypt/libgcrypt.la ../jnlib/libjnlib.la ../util/libutil.la #noinst_PROGRAMS = gpgd -bin_PROGRAMS = gpg +bin_PROGRAMS = gpg kbxutil common_source = \ build-packet.c \ @@ -26,6 +26,7 @@ common_source = \ kbnode.c \ kbx.h \ kbxblob.c \ + kbxio.c \ kbxfile.c \ main.h \ mainproc.c \ @@ -73,6 +74,11 @@ gpg_SOURCES = gpg.c \ dearmor.c \ keygen.c +# fixme: remove unused sources from kbxutil +kbxutil_SOURCES = kbxutil.c \ + $(common_source) + + #gpgd_SOURCES = gpgd.c \ # ks-proto.h \ # ks-proto.c \ diff --git a/g10/build-packet.c b/g10/build-packet.c index 5772b13be..84912ac05 100644 --- a/g10/build-packet.c +++ b/g10/build-packet.c @@ -196,7 +196,8 @@ static int do_user_id( IOBUF out, int ctb, PKT_user_id *uid ) { write_header(out, ctb, uid->len); - uid->stored_at = iobuf_tell( out ); /* what a hack */ + uid->stored_at = iobuf_get_temp_length ( out ); /* what a hack ... */ + /* ... and it does only work when used with a temp iobuf */ if( iobuf_write( out, uid->name, uid->len ) ) return GPGERR_WRITE_FILE; return 0; @@ -1461,9 +1461,11 @@ main( int argc, char **argv ) break; case aFixTrustDB: - log_error("this command ist not yet implemented.\"\n"); + log_error("this command is not yet implemented.\"\n"); log_error("A workaround is to use \"--export-ownertrust\", remove\n"); log_error("the trustdb file and do an \"--import-ownertrust\".\n" ); + #warning removed the next line + export_as_kbxfile(); break; case aListTrustPath: diff --git a/g10/gpgd.c b/g10/gpgd.c index 54a105978..99c91f6fc 100644 --- a/g10/gpgd.c +++ b/g10/gpgd.c @@ -1,4 +1,4 @@ -/* ggpd.c - The GnuPG daemon (keyserver) +/* gpg.c - The GnuPG daemon (keyserver) * Copyright (C) 1998 Free Software Foundation, Inc. * * This file is part of GnuPG. @@ -23,10 +23,29 @@ #include "keydb.h" +/*-- kbxblob.c */ +struct kbxblob; typedef struct kbxblob *KBXBLOB; -int kbx_create_blob ( KBXBLOB *retkbx, KBNODE keyblock ); +int kbx_new_blob ( KBXBLOB *r_blob, char *image, size_t imagelen ); +int kbx_create_blob ( KBXBLOB *r_blob, KBNODE keyblock ); void kbx_release_blob ( KBXBLOB blob ); +const char *kbx_get_blob_image ( KBXBLOB blob, size_t *n ); + +int kbx_dump_blob ( FILE *fp, KBXBLOB blob ); +int kbx_blob_has_fpr ( KBXBLOB blob, const byte *fpr ); +int kbx_blob_has_kid ( KBXBLOB blob, const byte *keyidbuf, size_t keyidlen ); +int kbx_blob_has_uid ( KBXBLOB blob, + int (*cmp)(const byte *, size_t, void *), void *opaque ); + +/*-- kbxio.c --*/ +int kbx_read_blob ( KBXBLOB *r_blob, FILE *a ); + +/*-- kbxfile.c --*/ +int kbxfile_search_by_fpr( const char *filename, const byte *fpr ); +int kbxfile_search_by_kid ( const char *filename, u32 *kid, int mode ); +int kbxfile_search_by_uid ( const char *filename, const char *name ); +void print_kbxfile( const char *filename ); #endif /*GPG_KBX_H*/ diff --git a/g10/kbxblob.c b/g10/kbxblob.c index 301671fbe..c298d587f 100644 --- a/g10/kbxblob.c +++ b/g10/kbxblob.c @@ -88,7 +88,7 @@ The standard KBX Blob looks like this: Here comes the keyblock - maybe we put a sigture here later. + maybe we put a signature here later. b16 MD5 checksum (useful for KS syncronisation) * @@ -136,20 +136,31 @@ struct keyid_list { byte kid[8]; }; +struct fixup_list { + struct fixup_list *next; + u32 off; + u32 val; +}; + + struct kbxblob { + byte *blob; + size_t bloblen; + + /* stuff used only by kbx_create_blob */ int nkeys; struct kbxblob_key *keys; int nuids; struct kbxblob_uid *uids; int nsigs; u32 *sigs; + struct fixup_list *fixups; struct keyid_list *temp_kids; - IOBUF buf; /* the KBX is stored here */ + IOBUF buf; /* the KBX is temporarly stored here */ }; - - +void kbx_release_blob ( KBXBLOB blob ); /* Note: this functions are only used for temportay iobufs and therefore * they can't fail */ @@ -183,28 +194,9 @@ putn ( IOBUF out, const byte *p, size_t n ) } } -/**************** - * special version of put 32, which is used to fixup a value at file offset OFF - */ -static void -put32at ( IOBUF out, u32 a, size_t pos ) -{ - size_t n; - byte *p; - - iobuf_flush_temp ( out ); - p = iobuf_get_temp_buffer( out ); - n = iobuf_get_temp_length( out ); - assert( n >= pos+4 ); - p[0] = a >> 24 ; - p[1] = a >> 16 ; - p[2] = a >> 8 ; - p[3] = a ; -} - /**************** - * We must store the keyid at some place becuase we can't calculate the + * We must store the keyid at some place because we can't calculate the * offset yet. This is only used for v3 keyIDs. Function returns an index * value for later fixupd; this must be a non-zero value */ @@ -269,8 +261,10 @@ create_key_part( KBXBLOB blob, KBNODE keyblock ) if ( node->pkt->pkttype == PKT_PUBLIC_KEY || node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { PKT_public_key *pk = node->pkt->pkt.public_key; + char tmp[20]; - fingerprint_from_pk( pk, blob->keys[n].fpr, &fprlen ); + fingerprint_from_pk( pk, tmp , &fprlen ); + memcpy(blob->keys[n].fpr,tmp,20); if ( fprlen != 20 ) { /*v3 fpr - shift right and fill with zeroes*/ assert( fprlen == 16 ); memmove( blob->keys[n].fpr+4, blob->keys[n].fpr, 16); @@ -346,10 +340,10 @@ create_blob_header( KBXBLOB blob ) put32 ( a, 0 ); /* length of the keyblock, needs fixup */ put16 ( a, blob->nkeys ); - put16 ( a, 20 + 8 + 2 + 2 ); /* size of key info */ + put16 ( a, 20 + 4 + 2 + 2 ); /* size of key info */ for ( i=0; i < blob->nkeys; i++ ) { putn ( a, blob->keys[i].fpr, 20 ); - blob->keys[i].off_kid_addr = iobuf_tell ( a ); + blob->keys[i].off_kid_addr = iobuf_get_temp_length (a); put32 ( a, 0 ); /* offset to keyid, fixed up later */ put16 ( a, blob->keys[i].flags ); put16 ( a, 0 ); /* reserved */ @@ -358,7 +352,7 @@ create_blob_header( KBXBLOB blob ) put16 ( a, blob->nuids ); put16 ( a, 4 + 4 + 2 + 1 + 1 ); /* size of uid info */ for ( i=0; i < blob->nuids; i++ ) { - blob->uids[i].off_addr = iobuf_tell ( a ); + blob->uids[i].off_addr = iobuf_get_temp_length ( a ); put32 ( a, 0 ); /* offset to userid, fixed up later */ put32 ( a, blob->uids[i].len ); put16 ( a, blob->uids[i].flags ); @@ -385,13 +379,17 @@ create_blob_header( KBXBLOB blob ) * not part of the fingerprint. While we are doing that, we fixup all * the keyID offsets */ for ( i=0; i < blob->nkeys; i++ ) { + struct fixup_list *fl = gcry_xcalloc(1, sizeof *fl ); + fl->off = blob->keys[i].off_kid_addr; + fl->next = blob->fixups; + blob->fixups = fl; + if ( blob->keys[i].off_kid ) { /* this is a v3 one */ - put32at ( a, iobuf_tell(a), blob->keys[i].off_kid_addr ); + fl->val = iobuf_get_temp_length (a); put_stored_kid ( blob, blob->keys[i].off_kid ); } else { /* the better v4 key IDs - just store an offset 8 bytes back */ - put32at ( a, blob->keys[i].off_kid_addr-8, - blob->keys[i].off_kid_addr ); + fl->val = blob->keys[i].off_kid_addr-8; } } @@ -405,9 +403,17 @@ create_blob_keyblock( KBXBLOB blob, KBNODE keyblock ) IOBUF a = blob->buf; KBNODE node; int rc; - int nsig; - - for ( nsig = 0, node = keyblock; node; node = node->next ) { + int n; + u32 kbstart = iobuf_get_temp_length ( a ); + + { + struct fixup_list *fl = gcry_xcalloc(1, sizeof *fl ); + fl->off = 8; + fl->val = kbstart; + fl->next = blob->fixups; + blob->fixups = fl; + } + for ( n = 0, node = keyblock; node; node = node->next ) { rc = build_packet ( a, node->pkt ); if ( rc ) { gpg_log_error("build_packet(%d) for kbxblob failed: %s\n", @@ -418,11 +424,22 @@ create_blob_keyblock( KBXBLOB blob, KBNODE keyblock ) PKT_user_id *u = node->pkt->pkt.user_id; /* build_packet has set the offset of the name into u ; * now we can do the fixup */ - put32at ( a, u->stored_at, blob->uids[nsig].off_addr ); - nsig++; + struct fixup_list *fl = gcry_xcalloc(1, sizeof *fl ); + fl->off = blob->uids[n].off_addr; + fl->val = u->stored_at; + fl->next = blob->fixups; + blob->fixups = fl; + n++; } } - assert( nsig == blob->nsigs ); + assert( n == blob->nuids ); + { + struct fixup_list *fl = gcry_xcalloc(1, sizeof *fl ); + fl->off = 12; + fl->val = iobuf_get_temp_length (a) - kbstart; + fl->next = blob->fixups; + blob->fixups = fl; + } return 0; } @@ -438,10 +455,13 @@ create_blob_finish( KBXBLOB blob ) { IOBUF a = blob->buf; byte *p; + char *pp; + int i; size_t n; /* write a placeholder for the checksum */ - put32( a, 0 ); put32( a, 0 ); put32( a, 0 ); put32( a, 0 ); + for ( i = 0; i < 16; i++ ) + put32( a, 0 ); /* get the memory area */ iobuf_flush_temp ( a ); p = iobuf_get_temp_buffer ( a ); @@ -449,23 +469,48 @@ create_blob_finish( KBXBLOB blob ) assert( n >= 20 ); /* fixup the length */ - put32at ( a, 0, n ); + { + struct fixup_list *fl = gcry_xcalloc(1, sizeof *fl ); + fl->off = 0; + fl->val = n; + fl->next = blob->fixups; + blob->fixups = fl; + } + /* do the fixups */ + { + struct fixup_list *fl; + for ( fl = blob->fixups; fl; fl = fl->next ) { + assert( fl->off+4 <= n ); + p[fl->off+0] = fl->val >> 24 ; + p[fl->off+1] = fl->val >> 16 ; + p[fl->off+2] = fl->val >> 8 ; + p[fl->off+3] = fl->val ; + } + + } /* calculate and store the MD5 checksum */ gcry_md_hash_buffer( GCRY_MD_MD5, p + n - 16, p, n - 16 ); + pp = gcry_malloc ( n ); + if ( !pp ) + return GCRYERR_NO_MEM; + memcpy ( pp , p, n ); + blob->blob = pp; + blob->bloblen = n; + return 0; } int -kbx_create_blob ( KBXBLOB *retkbx, KBNODE keyblock ) +kbx_create_blob ( KBXBLOB *r_blob, KBNODE keyblock ) { int rc = 0; KBNODE node; KBXBLOB blob; - *retkbx = NULL; + *r_blob = NULL; blob = gcry_calloc (1, sizeof *blob ); if( !blob ) return GCRYERR_NO_MEM; @@ -484,9 +529,9 @@ kbx_create_blob ( KBXBLOB *retkbx, KBNODE keyblock ) default: break; } } - blob->keys = gcry_calloc ( blob->nkeys, sizeof ( blob->keys ) ); - blob->uids = gcry_calloc ( blob->nuids, sizeof ( blob->uids ) ); - blob->sigs = gcry_calloc ( blob->nsigs, sizeof ( blob->sigs ) ); + blob->keys = gcry_calloc ( blob->nkeys, sizeof ( *blob->keys ) ); + blob->uids = gcry_calloc ( blob->nuids, sizeof ( *blob->uids ) ); + blob->sigs = gcry_calloc ( blob->nsigs, sizeof ( *blob->sigs ) ); if ( !blob->keys || !blob->uids || !blob->sigs ) { rc = GCRYERR_NO_MEM; goto leave; @@ -516,17 +561,44 @@ kbx_create_blob ( KBXBLOB *retkbx, KBNODE keyblock ) if( rc ) goto leave; - *retkbx = blob; leave: release_kid_list( blob->temp_kids ); blob->temp_kids = NULL; if ( rc ) { kbx_release_blob ( blob ); + *r_blob = NULL; + } + else { + *r_blob = blob; } return rc; } +int +kbx_new_blob ( KBXBLOB *r_blob, char *image, size_t imagelen ) +{ + KBXBLOB blob; + + *r_blob = NULL; + blob = gcry_calloc (1, sizeof *blob ); + if( !blob ) + return GCRYERR_NO_MEM; + blob->blob = image; + blob->bloblen = imagelen; + *r_blob = blob; + return 0; +} + + + +const char * +kbx_get_blob_image ( KBXBLOB blob, size_t *n ) +{ + *n = blob->bloblen; + return blob->blob; +} + void kbx_release_blob ( KBXBLOB blob ) { @@ -537,6 +609,9 @@ kbx_release_blob ( KBXBLOB blob ) gcry_free( blob->keys ); gcry_free( blob->uids ); gcry_free( blob->sigs ); + + gcry_free ( blob->blob ); + gcry_free( blob ); } @@ -556,17 +631,21 @@ get16( const byte *buffer ) { ulong a; a = *buffer << 8; - a |= buffer[0]; + a |= buffer[1]; return a; } int -kbx_dump_blob ( FILE *fp, const byte* buffer, size_t length ) +kbx_dump_blob ( FILE *fp, KBXBLOB blob ) { - #if 0 - ulong n; + const byte *buffer = blob->blob; + size_t length = blob->bloblen; + ulong n, nkeys, keyinfolen; + ulong nuids, uidinfolen; + ulong nsigs, siginfolen; ulong keyblock_off, keyblock_len; + const byte *p; if( length < 40 ) { fprintf( fp, "blob too short\n"); @@ -579,8 +658,8 @@ kbx_dump_blob ( FILE *fp, const byte* buffer, size_t length ) else length = n; /* ignore the rest */ fprintf( fp, "Length: %lu\n", n ); - fprintf( fp, "Type: %d\n", buffer[4] ), - fprintf( fp, "Version: %d\n", buffer[5] ), + fprintf( fp, "Type: %d\n", buffer[4] ); + fprintf( fp, "Version: %d\n", buffer[5] ); if( buffer[4] != 2 ) { fprintf( fp, "can't dump this blob type\n" ); return 0; @@ -593,8 +672,224 @@ kbx_dump_blob ( FILE *fp, const byte* buffer, size_t length ) fprintf( fp, "Keyblock-Offset: %lu\n", keyblock_off ); fprintf( fp, "Keyblock-Length: %lu\n", keyblock_len ); - #endif + nkeys = get16( buffer + 16 ); + fprintf( fp, "Key-Count: %lu\n", nkeys ); + keyinfolen = get16( buffer + 18 ); + fprintf( fp, "Key-Info-Length: %lu\n", keyinfolen ); + /* fixme: check bounds */ + p = buffer + 20; + for(n=0; n < nkeys; n++, p += keyinfolen ) { + int i; + ulong kidoff, kflags; + + fprintf( fp, "Key-%lu-Fpr: ", n ); + for(i=0; i < 20; i++ ) + fprintf( fp, "%02X", p[i] ); + kidoff = get32( p + 20 ); + fprintf( fp, "\nKey-%lu-Kid-Off: %lu\n", n, kidoff ); + fprintf( fp, "Key-%lu-Kid: ", n ); + /* fixme: check bounds */ + for(i=0; i < 8; i++ ) + fprintf( fp, "%02X", buffer[kidoff+i] ); + kflags = get16( p + 24 ); + fprintf( fp, "\nKey-%lu-Flags: %04lX\n", n, kflags ); + } + + + nuids = get16( p ); + fprintf( fp, "Uid-Count: %lu\n", nuids ); + uidinfolen = get16( p + 2 ); + fprintf( fp, "Uid-Info-Length: %lu\n", uidinfolen ); + /* fixme: check bounds */ + p += 4; + for(n=0; n < nuids; n++, p += uidinfolen ) { + ulong uidoff, uidlen, uflags; + + uidoff = get32( p ); + uidlen = get32( p+4 ); + fprintf( fp, "Uid-%lu-Off: %lu\n", n, uidoff ); + fprintf( fp, "Uid-%lu-Len: %lu\n", n, uidlen ); + fprintf( fp, "Uid-%lu: \"", n ); + print_string( fp, buffer+uidoff, uidlen, '\"' ); + fputs("\"\n", fp ); + uflags = get16( p + 8 ); + fprintf( fp, "Uid-%lu-Flags: %04lX\n", n, uflags ); + fprintf( fp, "Uid-%lu-Validity: %d\n", n, p[10] ); + } + + nsigs = get16( p ); + fprintf( fp, "Sig-Count: %lu\n", nsigs ); + siginfolen = get16( p + 2 ); + fprintf( fp, "Sig-Info-Length: %lu\n", siginfolen ); + /* fixme: check bounds */ + p += 4; + for(n=0; n < nsigs; n++, p += siginfolen ) { + ulong sflags; + + sflags = get32( p ); + fprintf( fp, "Sig-%lu-Expire: ", n ); + if( !sflags ) + fputs( "[not checked]", fp ); + else if( sflags == 1 ) + fputs( "[missing key]", fp ); + else if( sflags == 2 ) + fputs( "[bad signature]", fp ); + else if( sflags < 0x10000000 ) + fprintf( fp, "[bad flag %0lx]", sflags ); + else if( sflags == 0xffffffff ) + fputs( "0", fp ); + else + fputs( strtimestamp( sflags ), fp ); + putc('\n', fp ); + } + + fprintf( fp, "Ownertrust: %d\n", p[0] ); + fprintf( fp, "All-Validity: %d\n", p[1] ); + p += 4; + n = get32( p ); p += 4; + fprintf( fp, "Recheck-After: %s\n", n? strtimestamp(n) : "0" ); + n = get32( p ); p += 4; + fprintf( fp, "Latest-Timestamp: %s\n", strtimestamp(n) ); + n = get32( p ); p += 4; + fprintf( fp, "Created-At: %s\n", strtimestamp(n) ); + n = get32( p ); p += 4; + fprintf( fp, "Reserved-Space: %lu\n", n ); + + + /* check that the keyblock is at the correct offset and other bounds */ + + + fprintf( fp, "Blob-Checksum: [MD5-hash]\n" ); + return 0; +} + +/**************** + * 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 +kbx_blob_has_fpr ( KBXBLOB blob, const byte *fpr ) +{ + 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 */ + } + return -1; +} + +/**************** + * 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 +kbx_blob_has_kid ( KBXBLOB blob, const byte *keyidbuf, size_t keyidlen ) +{ + 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 */ + } + return -1; +} + + + +int +kbx_blob_has_uid ( KBXBLOB blob, + int (*cmp)(const byte *, size_t, void *), void *opaque ) +{ + 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 */ + } + return -1; } diff --git a/g10/kbxfile.c b/g10/kbxfile.c index 33bac3a44..7bf615098 100644 --- a/g10/kbxfile.c +++ b/g10/kbxfile.c @@ -22,7 +22,7 @@ * We will change the whole system to use only KBX. This file here * will implement the methods needed to operate on plain KBXfiles. * Most stuff from getkey and ringedit will be replaced by stuff here. - * To make things even mor easier we will only allow one updateable kbxfile + * To make things even more easier we will only allow one updateable kbxfile * and optionally some read-only files. */ @@ -35,11 +35,298 @@ #include <gcrypt.h> #include "kbx.h" +#include "options.h" +#include "util.h" +#include "i18n.h" +#include "main.h" + +/**************** + * Read the blob at the current fileposition and return an allocated + * pointer nto the blob if it was found. + * Fixme: return a blob object. + */ +static int +do_search_by_fpr ( const char *filename, FILE *a, const char *fpr, + KBXBLOB *r_blob ) +{ + KBXBLOB blob; + int rc; + + *r_blob = NULL; + rc = kbx_read_blob ( &blob, a ); + if ( rc && rc != -1 ) { + log_error (_("file `%s': error reading blob\n"), filename ); + } + else if ( !rc ) { + rc = kbx_blob_has_fpr ( blob, fpr ); + } + else + log_info ("eof\n"); + + if ( !rc ) { + *r_blob = blob; + } + else { + kbx_release_blob ( blob ); + } + return rc; +} + +int +kbxfile_search_by_fpr( const char *filename, const byte *fpr ) +{ + FILE *fp; + KBXBLOB blob; + int rc; + + fp = fopen ( filename, "rb" ); + if( !fp ) { + log_error(_("can't open `%s': %s\n"), filename, strerror(errno) ); + return 1; + } + + while ( (rc=do_search_by_fpr ( filename, fp, fpr, &blob )) == -1 ) + ; + if ( !rc ) { + fputs ("FOUND\n", stderr ); + kbx_dump_blob ( stderr, blob ); + kbx_release_blob ( blob ); + } + + fclose (fp); + return -1; +} + + +/**************** + * Read the blob at the current fileposition and return an allocated + * pointer nto the blob if it was found. + * Fixme: return a blob object. + */ +static int +do_search_by_keyid ( const char *filename, FILE *a, + const byte *keyidbuf, size_t keyidlen, KBXBLOB *r_blob ) +{ + KBXBLOB blob; + int rc; + + *r_blob = NULL; + rc = kbx_read_blob ( &blob, a ); + if ( rc && rc != -1 ) { + log_error (_("file `%s': error reading blob\n"), filename ); + } + else if ( !rc ) { + rc = kbx_blob_has_kid ( blob, keyidbuf, keyidlen ); + } + else + rc = GPGERR_GENERAL; /* eof */ + + if ( !rc ) { + *r_blob = blob; + } + else { + kbx_release_blob ( blob ); + } + return rc; +} + +/**************** + * Look for a KBX described by an keyid. This function will in + * turn return each matching keyid because there may me duplicates + * (which can't happen for fingerprints) + * mode 10 = short keyid + * 11 = long keyid + */ +int +kbxfile_search_by_kid ( const char *filename, u32 *kid, int mode ) +{ + FILE *fp; + KBXBLOB blob; + int rc; + byte kbuf[8], *kbufptr; + int kbuflen; + + fp = fopen ( filename, "rb" ); + if( !fp ) { + log_error(_("can't open `%s': %s\n"), filename, strerror(errno) ); + return 1; + } + + kbuf[0] = kid[0] >> 24; + kbuf[1] = kid[0] >> 16; + kbuf[2] = kid[0] >> 8; + kbuf[3] = kid[0]; + kbuf[4] = kid[1] >> 24; + kbuf[5] = kid[1] >> 16; + kbuf[6] = kid[1] >> 8; + kbuf[7] = kid[1]; + if ( mode == 10 ) { + kbufptr=kbuf+4; + kbuflen = 4; + } + else if (mode == 11 ) { + kbufptr=kbuf; + kbuflen = 8; + } + else { + BUG(); + } + + do { + while ( (rc=do_search_by_keyid ( filename, fp, + kbufptr, kbuflen, &blob )) == -1 ) + ; + if ( !rc ) { + fputs ("FOUND:\n", stderr ); + kbx_dump_blob ( stderr, blob ); + kbx_release_blob ( blob ); + } + } while ( !rc ); + + fclose (fp); + return -1; +} + + +static int +do_search_by_uid ( const char *filename, FILE *a, + int (*cmpfnc)(const byte*,size_t,void*), void *cmpdata, + KBXBLOB *r_blob ) +{ + KBXBLOB blob; + int rc; + + *r_blob = NULL; + rc = kbx_read_blob ( &blob, a ); + if ( rc && rc != -1 ) { + log_error (_("file `%s': error reading blob\n"), filename ); + } + else if ( !rc ) { + rc = kbx_blob_has_uid ( blob, cmpfnc, cmpdata ); + } + else + rc = GPGERR_GENERAL; /* eof */ + + if ( !rc ) { + *r_blob = blob; + } + else { + kbx_release_blob ( blob ); + } + return rc; +} + + +static int +substr_compare ( const byte *buf, size_t buflen, void *opaque ) +{ + return !!memistr ( buf, buflen, opaque ); +} int -kbxfile_search_by_fpr( void ) +kbxfile_search_by_uid ( const char *filename, const char *name ) { + FILE *fp; + KBXBLOB blob; + int rc; + byte kbuf[8], *kbufptr; + int kbuflen; + + fp = fopen ( filename, "rb" ); + if( !fp ) { + log_error(_("can't open `%s': %s\n"), filename, strerror(errno) ); + return 1; + } + + + do { + while ( (rc=do_search_by_uid ( filename, fp, + substr_compare, name, &blob )) == -1 ) + ; + if ( !rc ) { + fputs ("FOUND:\n", stderr ); + kbx_dump_blob ( stderr, blob ); + kbx_release_blob ( blob ); + } + } while ( !rc ); + + fclose ( fp ); return -1; } + + +void +export_as_kbxfile(void) +{ + + KBPOS kbpos; + KBNODE keyblock = NULL; + int rc=0; + + rc = enum_keyblocks( 0, &kbpos, &keyblock ); + if( rc ) { + if( rc != -1 ) + log_error("enum_keyblocks(open) failed: %s\n", gpg_errstr(rc) ); + goto leave; + } + + while( !(rc = enum_keyblocks( 1, &kbpos, &keyblock )) ) { + KBXBLOB blob; + const char *p; + size_t n; + + merge_keys_and_selfsig( keyblock ); + rc = kbx_create_blob ( &blob, keyblock ); + if( rc ) { + log_error("kbx_create_blob failed: %s\n", gpg_errstr(rc) ); + goto leave; + } + p = kbx_get_blob_image ( blob, &n ); + fwrite( p, n, 1, stdout ); + kbx_release_blob ( blob ); + } + + if( rc && rc != -1 ) + log_error("enum_keyblocks(read) failed: %s\n", gpg_errstr(rc)); + + leave: + enum_keyblocks( 2, &kbpos, &keyblock ); /* close */ + release_kbnode( keyblock ); +} + + +static int +do_print_kbxfile( const char *filename, FILE *a ) +{ + KBXBLOB blob; + int rc; + + rc = kbx_read_blob ( &blob, a ); + if ( rc && rc != -1 ) { + log_error (_("file `%s': error reading blob\n"), filename ); + } + else if ( ! rc ) + kbx_dump_blob ( stdout, blob ); + kbx_release_blob ( blob ); + return rc; +} + +void +print_kbxfile( const char *filename ) +{ + FILE *fp; + + fp = fopen ( filename, "rb" ); + if( !fp ) { + log_error(_("can't open `%s': %s\n"), filename, strerror(errno) ); + return 1; + } + + while ( !do_print_kbxfile( filename, fp ) ) + ; + + fclose (fp); +} + diff --git a/g10/kbxio.c b/g10/kbxio.c new file mode 100644 index 000000000..6c4437bf8 --- /dev/null +++ b/g10/kbxio.c @@ -0,0 +1,75 @@ +/* kbxio.c - KBX I/O handling + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <assert.h> +#include <gcrypt.h> + +#include "iobuf.h" +#include "util.h" +#include "kbx.h" + + +int +kbx_read_blob ( KBXBLOB *r_blob, FILE *a ) +{ + char *image; + size_t imagelen = 0; + int c1, c2, c3, c4; + int rc; + + *r_blob = NULL; + if ( (c1 = getc ( a )) == EOF + || (c2 = getc ( a )) == EOF + || (c3 = getc ( a )) == EOF + || (c4 = getc ( a )) == EOF ) { + if ( c1 == EOF && !ferror ( a ) ) + return -1; + return GPGERR_GENERAL; + } + imagelen = (c1 << 24) | (c2 << 16) | (c3 << 8 ) | c4; + if ( imagelen > 500000 ) { /* sanity check:blob too large */ + return GPGERR_GENERAL; + } + else if ( imagelen < 4 ) { /* blobtoo short */ + return GPGERR_GENERAL; + } + image = gcry_malloc ( imagelen ); + if ( !image ) { + return GPGERR_GENERAL; + } + + image[0] = c1; image[1] = c2; image[2] = c3; image[3] = c4; + if ( fread ( image+4, imagelen-4, 1, a ) != 1 ) { + gcry_free ( image ); + return GPGERR_GENERAL; + } + + rc = kbx_new_blob ( r_blob, image, imagelen ); + return rc; +} + + + diff --git a/g10/kbxutil.c b/g10/kbxutil.c new file mode 100644 index 000000000..95fcb9cce --- /dev/null +++ b/g10/kbxutil.c @@ -0,0 +1,442 @@ +/* gpg.c - The GnuPG utility (main for gpg) + * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <unistd.h> + +#include <gcrypt.h> + +#include "packet.h" +#include "iobuf.h" +#include "util.h" +#include "main.h" +#include "options.h" +#include "keydb.h" +#include "filter.h" +#include "ttyio.h" +#include "i18n.h" +#include "gnupg-defs.h" +#include "kbx.h" + + +enum cmd_and_opt_values { aNull = 0, + oArmor = 'a', + aDetachedSign = 'b', + aSym = 'c', + aDecrypt = 'd', + aEncr = 'e', + oInteractive = 'i', + oKOption = 'k', + oDryRun = 'n', + oOutput = 'o', + oQuiet = 'q', + oRecipient = 'r', + aSign = 's', + oTextmodeShort= 't', + oUser = 'u', + oVerbose = 'v', + oCompress = 'z', + oNotation = 'N', + oBatch = 500, + aClearsign, + aStore, + aKeygen, + aSignEncr, + aSignKey, + aLSignKey, + aListPackets, + aEditKey, + aDeleteKey, + aDeleteSecretKey, + aKMode, + aKModeC, + aImport, + aFastImport, + aVerify, + aListKeys, + aListSigs, + aListSecretKeys, + aSendKeys, + aRecvKeys, + aExport, + aExportAll, + aExportSecret, + aCheckKeys, + aGenRevoke, + aPrimegen, + aPrintMD, + aPrintHMAC, + aPrintMDs, + aCheckTrustDB, + aUpdateTrustDB, + aFixTrustDB, + aListTrustDB, + aListTrustPath, + aExportOwnerTrust, + aImportOwnerTrust, + aDeArmor, + aEnArmor, + aGenRandom, + + oTextmode, + oFingerprint, + oWithFingerprint, + oAnswerYes, + oAnswerNo, + oKeyring, + oSecretKeyring, + oDefaultKey, + oDefRecipient, + oDefRecipientSelf, + oNoDefRecipient, + oOptions, + oDebug, + oDebugAll, + oStatusFD, + oNoComment, + oNoVersion, + oEmitVersion, + oCompletesNeeded, + oMarginalsNeeded, + oMaxCertDepth, + oLoadExtension, + oRFC1991, + oOpenPGP, + oCipherAlgo, + oDigestAlgo, + oCompressAlgo, + oPasswdFD, + oNoVerbose, + oTrustDBName, + oNoSecmemWarn, + oNoArmor, + oNoDefKeyring, + oNoGreeting, + oNoTTY, + oNoOptions, + oNoBatch, + oHomedir, + oWithColons, + oWithKeyData, + oSkipVerify, + oCompressKeys, + oCompressSigs, + oAlwaysTrust, + oEmuChecksumBug, + oRunAsShmCP, + oSetFilename, + oSetPolicyURL, + oUseEmbeddedFilename, + oComment, + oDefaultComment, + oThrowKeyid, + oForceV3Sigs, + oForceMDC, + oS2KMode, + oS2KDigest, + oS2KCipher, + oCharset, + oNotDashEscaped, + oEscapeFrom, + oLockOnce, + oLockMultiple, + oKeyServer, + oEncryptTo, + oNoEncryptTo, + oLoggerFD, + oUtf8Strings, + oNoUtf8Strings, + oDisableCipherAlgo, + oDisablePubkeyAlgo, + oAllowNonSelfsignedUID, + oNoLiteral, + oSetFilesize, + oEntropyDLLName, + + aFindByFpr, + aFindByKid, + aFindByUid, +aTest }; + + +static ARGPARSE_OPTS opts[] = { + + { 300, NULL, 0, N_("@Commands:\n ") }, + + { aFindByFpr, "find-by-fpr", 0, "|FPR| find key using it's fingerprnt" }, + { aFindByKid, "find-by-kid", 0, "|KID| find key using it's keyid" }, + { aFindByUid, "find-by-uid", 0, "|NAME| find key by user name" }, + + { 301, NULL, 0, N_("@\nOptions:\n ") }, + + { oArmor, "armor", 0, N_("create ascii armored output")}, + { oArmor, "armour", 0, "@" }, + { oCompress, NULL, 1, N_("|N|set compress level N (0 disables)") }, + { oOutput, "output", 2, N_("use as output file")}, + { oVerbose, "verbose", 0, N_("verbose") }, + { oQuiet, "quiet", 0, N_("be somewhat more quiet") }, + { oDryRun, "dry-run", 0, N_("do not make any changes") }, + { oOptions, "options" , 2, N_("read options from file")}, + + { oDebug, "debug" ,4|16, N_("set debugging flags")}, + { oDebugAll, "debug-all" ,0, N_("enable full debugging")}, + + +{0} }; + + + +int gpg_errors_seen = 0; + + +static const char * +my_strusage( int level ) +{ + const char *p; + switch( level ) { + case 11: p = "kbxutil (GnuPG)"; + break; + case 13: p = VERSION; break; + case 17: p = PRINTABLE_OS_NAME; break; + case 19: p = + _("Please report bugs to <gnupg-bugs@gnu.org>.\n"); + break; + case 1: + case 40: p = + _("Usage: kbxutil [options] [files] (-h for help)"); + break; + case 41: p = + _("Syntax: kbxutil [options] [files]\n" + "list, export, import KBX data\n"); + break; + + + default: p = NULL; + } + return p; +} + + +static void +i18n_init(void) +{ + #ifdef USE_SIMPLE_GETTEXT + set_gettext_file( PACKAGE ); + #else + #ifdef ENABLE_NLS + #ifdef HAVE_LC_MESSAGES + setlocale( LC_TIME, "" ); + setlocale( LC_MESSAGES, "" ); + #else + setlocale( LC_ALL, "" ); + #endif + bindtextdomain( PACKAGE, GNUPG_LOCALEDIR ); + textdomain( PACKAGE ); + #endif + #endif +} + + +static void +wrong_args( const char *text ) +{ + log_error("usage: kbxutil %s\n", text); + gpg_exit ( 1 ); +} + + +static int +hextobyte( const byte *s ) +{ + int c; + + if( *s >= '0' && *s <= '9' ) + c = 16 * (*s - '0'); + else if( *s >= 'A' && *s <= 'F' ) + c = 16 * (10 + *s - 'A'); + else if( *s >= 'a' && *s <= 'f' ) + c = 16 * (10 + *s - 'a'); + else + return -1; + s++; + if( *s >= '0' && *s <= '9' ) + c += *s - '0'; + else if( *s >= 'A' && *s <= 'F' ) + c += 10 + *s - 'A'; + else if( *s >= 'a' && *s <= 'f' ) + c += 10 + *s - 'a'; + else + return -1; + return c; +} + +static char * +format_fingerprint ( const char *s ) +{ + int i, c; + byte fpr[20]; + + for (i=0; i < 20 && *s; ) { + if ( *s == ' ' || *s == '\t' ) { + s++; + continue; + } + c = hextobyte(s); + if (c == -1) { + return NULL; + } + fpr[i++] = c; + s += 2; + } + return gcry_xstrdup ( fpr ); +} + +static int +format_keyid ( const char *s, u32 *kid ) +{ + char helpbuf[9]; + switch ( strlen ( s ) ) { + case 8: + kid[0] = 0; + kid[1] = strtoul( s, NULL, 16 ); + return 10; + + case 16: + mem2str( helpbuf, s, 9 ); + kid[0] = strtoul( helpbuf, NULL, 16 ); + kid[1] = strtoul( s+8, NULL, 16 ); + return 11; + } + return 0; /* error */ +} + + + +int +main( int argc, char **argv ) +{ + ARGPARSE_ARGS pargs; + enum cmd_and_opt_values cmd = 0; + + set_strusage( my_strusage ); + log_set_name("kbxutil"); + /* check that the libraries are suitable. Do it here because + * the option parse may need services of the library */ + if ( !gcry_check_version ( "1.1.0a" ) ) { + log_fatal(_("libgcrypt is too old (need %s, have %s)\n"), + VERSION, gcry_check_version(NULL) ); + } + + create_dotlock(NULL); /* register locking cleanup */ + i18n_init(); + + + pargs.argc = &argc; + pargs.argv = &argv; + pargs.flags= 1; /* do not remove the args */ + while( arg_parse( &pargs, opts) ) { + switch( pargs.r_opt ) { + case oVerbose: + opt.verbose++; + gcry_control( GCRYCTL_SET_VERBOSITY, (int)opt.verbose ); + break; + case oDebug: opt.debug |= pargs.r.ret_ulong; break; + case oDebugAll: opt.debug = ~0; break; + + case aFindByFpr: + case aFindByKid: + case aFindByUid: + cmd = pargs.r_opt; + break; + + default : pargs.err = 2; break; + } + } + if( log_get_errorcount(0) ) + gpg_exit(2); + + if ( !cmd ) { /* default is to list a KBX file */ + if( !argc ) { + print_kbxfile( NULL ); + } + else { + for ( ; argc; argc--, argv++ ) { + print_kbxfile( *argv ); + } + } + } + else if ( cmd == aFindByFpr ) { + char *fpr; + if ( argc != 2 ) + wrong_args ("kbxfile foingerprint"); + fpr = format_fingerprint ( argv[1] ); + if ( !fpr ) + log_error ("invalid formatted fingerprint\n"); + else { + kbxfile_search_by_fpr ( argv[0], fpr ); + gcry_free ( fpr ); + } + } + else if ( cmd == aFindByKid ) { + u32 kid[2]; + int mode; + + if ( argc != 2 ) + wrong_args ("kbxfile short-or-long-keyid"); + mode = format_keyid ( argv[1], kid ); + if ( !mode ) + log_error ("invalid formatted keyID\n"); + else { + kbxfile_search_by_kid ( argv[0], kid, mode ); + } + } + else if ( cmd == aFindByUid ) { + if ( argc != 2 ) + wrong_args ("kbxfile userID"); + kbxfile_search_by_uid ( argv[0], argv[1] ); + } + else + log_error ("unsupported action\n"); + + gpg_exit(0); + return 8; /*NEVER REACHED*/ +} + + +void +gpg_exit( int rc ) +{ + if( opt.debug & DBG_MEMSTAT_VALUE ) { + gcry_control( GCRYCTL_DUMP_MEMORY_STATS ); + gcry_control( GCRYCTL_DUMP_RANDOM_STATS ); + } + if( opt.debug ) + gcry_control( GCRYCTL_DUMP_SECMEM_STATS ); + rc = rc? rc : log_get_errorcount(0)? 2 : + gpg_errors_seen? 1 : 0; + exit(rc ); +} + + |