summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/gcryptref-digest.sgml17
-rw-r--r--g10/ChangeLog7
-rw-r--r--g10/Makefile.am8
-rw-r--r--g10/build-packet.c3
-rw-r--r--g10/gpg.c4
-rw-r--r--g10/gpgd.c2
-rw-r--r--g10/kbx.h21
-rw-r--r--g10/kbxblob.c399
-rw-r--r--g10/kbxfile.c291
-rw-r--r--g10/kbxio.c75
-rw-r--r--g10/kbxutil.c442
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;
diff --git a/g10/gpg.c b/g10/gpg.c
index 0c0b625bc..2b66509f4 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -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.
diff --git a/g10/kbx.h b/g10/kbx.h
index 6508d3eab..25825a4ec 100644
--- a/g10/kbx.h
+++ b/g10/kbx.h
@@ -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 );
+}
+
+