diff options
Diffstat (limited to 'g10')
-rw-r--r-- | g10/Makefile.am | 4 | ||||
-rw-r--r-- | g10/Makefile.in | 22 | ||||
-rw-r--r-- | g10/compress.c | 12 | ||||
-rw-r--r-- | g10/encode.c | 2 | ||||
-rw-r--r-- | g10/filter.h | 1 | ||||
-rw-r--r-- | g10/g10.c | 178 | ||||
-rw-r--r-- | g10/getkey.c | 36 | ||||
-rw-r--r-- | g10/kbnode.c | 79 | ||||
-rw-r--r-- | g10/keydb.h | 46 | ||||
-rw-r--r-- | g10/mainproc.c | 109 | ||||
-rw-r--r-- | g10/packet.h | 47 | ||||
-rw-r--r-- | g10/parse-packet.c | 43 | ||||
-rw-r--r-- | g10/pubkey-enc.c | 2 | ||||
-rw-r--r-- | g10/ringedit.c | 469 |
14 files changed, 913 insertions, 137 deletions
diff --git a/g10/Makefile.am b/g10/Makefile.am index c6361004d..eb3e8b238 100644 --- a/g10/Makefile.am +++ b/g10/Makefile.am @@ -13,6 +13,8 @@ g10_SOURCES = g10.c \ free-packet.c \ getkey.c \ keydb.h \ + ringedit.c \ + kbnode.c \ keygen.c \ main.h \ mainproc.c \ @@ -37,5 +39,5 @@ g10_SOURCES = g10.c \ LDADD = -L ../cipher -L ../mpi -L ../util -lcipher -lmpi -lutil -$(PROGRAMS): ../cipher/libcipher.a ../mpi/libmpi.a +$(PROGRAMS): ../cipher/libcipher.a ../mpi/libmpi.a ../util/libutil.a diff --git a/g10/Makefile.in b/g10/Makefile.in index 17a4df10b..8aeca74c4 100644 --- a/g10/Makefile.in +++ b/g10/Makefile.in @@ -51,6 +51,8 @@ g10_SOURCES = g10.c \ free-packet.c \ getkey.c \ keydb.h \ + ringedit.c \ + kbnode.c \ keygen.c \ main.h \ mainproc.c \ @@ -90,9 +92,10 @@ LIBS = @LIBS@ COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) LINK = $(CC) $(LDFLAGS) -o $@ g10_OBJECTS = g10.o build-packet.o compress.o encode.o encr-data.o \ -free-packet.o getkey.o keygen.o mainproc.o armor.o mdfilter.o cipher.o \ -openfile.o keyid.o parse-packet.o passphrase.o plaintext.o pubkey-enc.o \ -seckey-cert.o seskey.o sign.o comment.o sig-check.o +free-packet.o getkey.o ringedit.o kbnode.o keygen.o mainproc.o armor.o \ +mdfilter.o cipher.o openfile.o keyid.o parse-packet.o passphrase.o \ +plaintext.o pubkey-enc.o seckey-cert.o seskey.o sign.o comment.o \ +sig-check.o EXTRA_g10_SOURCES = g10_LDADD = $(LDADD) DIST_COMMON = Makefile.am Makefile.in @@ -111,11 +114,12 @@ DEP_FILES = $(srcdir)/.deps/armor.P $(srcdir)/.deps/build-packet.P \ $(srcdir)/.deps/cipher.P $(srcdir)/.deps/comment.P \ $(srcdir)/.deps/compress.P $(srcdir)/.deps/encode.P \ $(srcdir)/.deps/encr-data.P $(srcdir)/.deps/free-packet.P \ -$(srcdir)/.deps/g10.P $(srcdir)/.deps/getkey.P $(srcdir)/.deps/keygen.P \ -$(srcdir)/.deps/keyid.P $(srcdir)/.deps/mainproc.P \ -$(srcdir)/.deps/mdfilter.P $(srcdir)/.deps/openfile.P \ -$(srcdir)/.deps/parse-packet.P $(srcdir)/.deps/passphrase.P \ -$(srcdir)/.deps/plaintext.P $(srcdir)/.deps/pubkey-enc.P \ +$(srcdir)/.deps/g10.P $(srcdir)/.deps/getkey.P $(srcdir)/.deps/kbnode.P \ +$(srcdir)/.deps/keygen.P $(srcdir)/.deps/keyid.P \ +$(srcdir)/.deps/mainproc.P $(srcdir)/.deps/mdfilter.P \ +$(srcdir)/.deps/openfile.P $(srcdir)/.deps/parse-packet.P \ +$(srcdir)/.deps/passphrase.P $(srcdir)/.deps/plaintext.P \ +$(srcdir)/.deps/pubkey-enc.P $(srcdir)/.deps/ringedit.P \ $(srcdir)/.deps/seckey-cert.P $(srcdir)/.deps/seskey.P \ $(srcdir)/.deps/sig-check.P $(srcdir)/.deps/sign.P SOURCES = $(g10_SOURCES) @@ -285,7 +289,7 @@ mostlyclean-generic distclean-generic clean-generic \ maintainer-clean-generic clean mostlyclean distclean maintainer-clean -$(PROGRAMS): ../cipher/libcipher.a ../mpi/libmpi.a +$(PROGRAMS): ../cipher/libcipher.a ../mpi/libmpi.a ../util/libutil.a .SUFFIXES: .SUFFIXES: .c .o diff --git a/g10/compress.c b/g10/compress.c index d0e2bc539..2b10c983b 100644 --- a/g10/compress.c +++ b/g10/compress.c @@ -106,7 +106,13 @@ init_uncompress( compress_filter_context_t *zfx, z_stream *zs ) int level; - if( (rc = inflateInit( zs )) != Z_OK ) { + /**************** + * PGP uses a windowsize of 13 bits. Using a negative value for + * it forces zlib not to expect a zlib header. This is a + * undocumented feature, Peter Gutmann told me about. + */ + if( (rc = zfx->pgpmode? inflateInit2( zs, -13) + : inflateInit( zs )) != Z_OK ) { log_fatal("zlib problem: %s\n", zs->msg? zs->msg : rc == Z_MEM_ERROR ? "out of core" : rc == Z_VERSION_ERROR ? "invalid lib version" : @@ -265,7 +271,9 @@ handle_compressed( PKT_compressed *cd ) compress_filter_context_t cfx; memset( &cfx, 0, sizeof cfx ); - if( cd->algorithm != 2 ) + if( cd->algorithm == 1 ) + cfx.pgpmode = 1; + else if( cd->algorithm != 2 ) return G10ERR_COMPR_ALGO; iobuf_push_filter( cd->buf, compress_filter, &cfx ); diff --git a/g10/encode.c b/g10/encode.c index 99c9adfa2..3bcdbe909 100644 --- a/g10/encode.c +++ b/g10/encode.c @@ -239,7 +239,7 @@ encode_crypt( const char *filename, STRLIST remusr ) pkey.y = pkc->d.elg.y; if( DBG_CIPHER ) log_mpidump("Plain DEK frame: ", frame); - elg_encrypted( enc->d.elg.a, enc->d.elg.b, frame, &pkey); + elg_encrypt( enc->d.elg.a, enc->d.elg.b, frame, &pkey); mpi_free( frame ); if( DBG_CIPHER ) { log_mpidump("Encry DEK a: ", enc->d.elg.a ); diff --git a/g10/filter.h b/g10/filter.h index ec34696a4..72029c61f 100644 --- a/g10/filter.h +++ b/g10/filter.h @@ -48,6 +48,7 @@ typedef struct { unsigned inbufsize; byte *outbuf; unsigned outbufsize; + int pgpmode; } compress_filter_context_t; @@ -19,6 +19,7 @@ */ #include <config.h> +#include <errno.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> @@ -34,6 +35,8 @@ #include "cipher.h" #include "filter.h" +static void print_hex( byte *p, size_t n ); +static void print_mds( const char *fname ); static void do_test(int); const char * @@ -126,29 +129,86 @@ main( int argc, char **argv ) { 514, "test" , 0, "\rdevelopment usage" }, { 515, "change-passphrase", 0, "change the passphrase of your secret keyring"}, { 515, "fingerprint", 0, "show the fingerprints"}, + { 516, "print-mds" , 0, "print all message digests"}, + { 517, "secret-keyring" ,2, "add this secret keyring to the list" }, + { 518, "config" , 2, "use this config file" }, + {0} }; - ARGPARSE_ARGS pargs = { &argc, &argv, 0 }; + ARGPARSE_ARGS pargs; IOBUF a; int rc; enum { aNull, aSym, aStore, aEncr, aPrimegen, aKeygen, aSign, aSignEncr, - aTest, + aTest, aPrintMDs, } action = aNull; + int orig_argc; + char **orig_argv; const char *fname, *fname_print; STRLIST sl, remusr= NULL, locusr=NULL; - int nrings=0; + int nrings=0, sec_nrings=0; armor_filter_context_t afx; const char *s; int detached_sig = 0; + FILE *configfp = NULL; + char *configname = NULL; + unsigned configlineno; + int parse_verbose = 0; + int default_config =1; + int errors=0; + opt.compress = -1; /* defaults to default compression level */ + + /* check wether we have a config file on the commandline */ + orig_argc = argc; + orig_argv = argv; + pargs.argc = &argc; + pargs.argv = &argv; + pargs.flags= 1; /* do not remove the args */ while( arg_parse( &pargs, opts) ) { + if( pargs.r_opt == 'v' ) + parse_verbose++; + else if( pargs.r_opt == 518 ) { + /* yes there is one, so we do not try the default one, but + * read the option file when it is encountered at the commandline + */ + default_config = 0; + } + } + + if( default_config ) + configname = make_filename("~/.g10", "options", NULL ); + + argc = orig_argc; + argv = orig_argv; + pargs.argc = &argc; + pargs.argv = &argv; + pargs.flags= 1; /* do not remove the args */ + next_pass: + if( configname ) { + configlineno = 0; + configfp = fopen( configname, "r" ); + if( !configfp ) { + if( default_config ) { + if( parse_verbose ) + log_info("note: no default option file '%s'\n", configname ); + } + else + log_fatal("option file '%s': %s\n", + configname, strerror(errno) ); + m_free(configname); configname = NULL; + } + if( parse_verbose ) + log_info("reading options from '%s'\n", configname ); + default_config = 0; + } + + while( optfile_parse( configfp, configname, &configlineno, + &pargs, opts) ) { switch( pargs.r_opt ) { case 'v': opt.verbose++; opt.list_sigs=1; break; - case 'z': - opt.compress = pargs.r.ret_int; - break; + case 'z': opt.compress = pargs.r.ret_int; break; case 'a': opt.armor = 1; break; case 'c': action = aSym; break; case 'o': opt.outfile = pargs.r.ret_str; @@ -184,9 +244,29 @@ main( int argc, char **argv ) case 513: action = aPrimegen; break; case 514: action = aTest; break; case 515: opt.fingerprint = 1; break; - default : pargs.err = 2; break; + case 516: action = aPrintMDs; break; + case 517: add_secret_keyring(pargs.r.ret_str); sec_nrings++; break; + case 518: + /* config files may not be nested (silently ignore them) */ + if( !configfp ) { + m_free(configname); + configname = m_strdup(pargs.r.ret_str); + goto next_pass; + } + break; + default : errors++; pargs.err = configfp? 1:2; break; } } + if( configfp ) { + fclose( configfp ); + configfp = NULL; + m_free(configname); configname = NULL; + goto next_pass; + } + m_free( configname ); configname = NULL; + if( errors ) + exit(2); + set_debug(); if( opt.verbose > 1 ) set_packet_list_mode(1); @@ -197,6 +277,9 @@ main( int argc, char **argv ) fputs(s, stderr); } + if( !sec_nrings ) { /* add default secret rings */ + add_keyring("../keys/secring.g10"); + } if( !nrings ) { /* add default rings */ add_keyring("../keys/ring.pgp"); add_keyring("../keys/pubring.g10"); @@ -251,6 +334,15 @@ main( int argc, char **argv ) putchar('\n'); break; + case aPrintMDs: + if( !argc ) + print_mds(NULL); + else { + for(; argc; argc--, argv++ ) + print_mds(*argv); + } + break; + case aKeygen: /* generate a key (interactive) */ if( argc ) usage(1); @@ -279,6 +371,78 @@ main( int argc, char **argv ) } +static void +print_hex( byte *p, size_t n ) +{ + int i; + + if( n == 20 ) { + for(i=0; i < n ; i++, i++, p += 2 ) { + if( i == 10 ) + putchar(' '); + printf(" %02X%02X", *p, p[1] ); + } + } + else { + for(i=0; i < n ; i++, p++ ) { + if( i && !(i%8) ) + putchar(' '); + printf(" %02X", *p ); + } + } +} + +static void +print_mds( const char *fname ) +{ + FILE *fp; + char buf[1024]; + size_t n; + MD5HANDLE md5; + RMDHANDLE rmd160; + SHA1HANDLE sha1; + + if( !fname ) { + fp = stdin; + fname = "[stdin]"; + } + else + fp = fopen( fname, "rb" ); + if( !fp ) { + log_error("%s: %s\n", fname, strerror(errno) ); + return; + } + + md5 = md5_open(0); + rmd160 = rmd160_open(0); + sha1 = sha1_open(0); + + while( (n=fread( buf, 1, DIM(buf), fp )) ) { + md5_write( md5, buf, n ); + rmd160_write( rmd160, buf, n ); + sha1_write( sha1, buf, n ); + } + if( ferror(fp) ) + log_error("%s: %s\n", fname, strerror(errno) ); + else { + byte *p; + + md5_final(md5); + printf( "%s: MD5 =", fname ); print_hex(md5_read(md5), 16 ); + printf("\n%s: RMD160 =", fname ); print_hex(rmd160_final(rmd160), 20 ); + printf("\n%s: SHA1 =", fname ); print_hex(sha1_final(sha1), 20 ); + putchar('\n'); + } + + + md5_close(md5); + rmd160_close(rmd160); + sha1_close(sha1); + + if( fp != stdin ) + fclose(fp); +} + static void do_test(int times) diff --git a/g10/getkey.c b/g10/getkey.c index c7ea1686a..b079cca19 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -52,6 +52,7 @@ typedef struct pkc_cache_entry { } *pkc_cache_entry_t; static STRLIST keyrings; +static STRLIST secret_keyrings; static keyid_list_t unknown_keyids; static user_id_db_t user_id_db; @@ -69,6 +70,7 @@ void add_keyring( const char *name ) { STRLIST sl; + int rc; /* FIXME: check wether this one is available etc */ /* my be we should do this later */ @@ -76,6 +78,28 @@ add_keyring( const char *name ) strcpy(sl->d, name ); sl->next = keyrings; keyrings = sl; + + /* FIXME: We should remove much out of this mpdule and + * combine it with the keyblock stuff from ringedit.c + * For now we will simple add the filename as keyblock resource + */ + rc = add_keyblock_resource( name ); + if( rc ) + log_error("keyblock resource '%s': %s\n", name, rc ); +} + +void +add_secret_keyring( const char *name ) +{ + STRLIST sl; + int rc; + + /* FIXME: check wether this one is available etc */ + /* my be we should do this later */ + sl = m_alloc( sizeof *sl + strlen(name) ); + strcpy(sl->d, name ); + sl->next = secret_keyrings; + secret_keyrings = sl; } @@ -255,10 +279,12 @@ get_pubkey_by_name( PKT_public_cert *pkc, const char *name ) int get_seckey( PKT_secret_cert *skc, u32 *keyid ) { + STRLIST sl; int rc=0; - if( !(rc=scan_secret_keyring( skc, keyid, NULL, "../keys/secring.g10" ) ) ) - goto found; + for(sl = secret_keyrings; sl; sl = sl->next ) + if( !(rc=scan_secret_keyring( skc, keyid, NULL, sl->d )) ) + goto found; /* fixme: look at other places */ goto leave; @@ -280,10 +306,12 @@ get_seckey( PKT_secret_cert *skc, u32 *keyid ) int get_seckey_by_name( PKT_secret_cert *skc, const char *name ) { + STRLIST sl; int rc=0; - if( !(rc=scan_secret_keyring( skc, NULL, name, "../keys/secring.g10" ) ) ) - goto found; + for(sl = secret_keyrings; sl; sl = sl->next ) + if( !(rc=scan_secret_keyring( skc, NULL, name, sl->d ) ) ) + goto found; /* fixme: look at other places */ goto leave; diff --git a/g10/kbnode.c b/g10/kbnode.c new file mode 100644 index 000000000..d148cb450 --- /dev/null +++ b/g10/kbnode.c @@ -0,0 +1,79 @@ +/* kbnode.c - keyblock node utility functions + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 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. + * + * G10 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 <assert.h> +#include "util.h" +#include "memory.h" +#include "packet.h" +#include "keydb.h" + + + +KBNODE +new_kbnode( PACKET *pkt ) +{ + KBNODE n = m_alloc( sizeof *n ); + n->next = NULL; + n->pkt = pkt; + n->child = NULL; + return n; +} + + +void +release_kbnode( KBNODE n ) +{ + KBNODE n2; + + while( n ) { + n2 = n->next; + release_kbnode( n->child ); + free_packet( n->pkt ); + m_free( n ); + n = n2; + } +} + + +/**************** + * Return the parent node of KBNODE from the tree with ROOT + */ +KBNODE +find_kbparent( KBNODE root, KBNODE node ) +{ + KBNODE n, n2; + + for( ; root; root = root->child) { + for( n = root; n; n = n->next) { + for( n2 = n->child; n2; n2 = n2->next ) { + if( n2 == node ) + return n; + } + } + } + log_bug(NULL); +} + + + diff --git a/g10/keydb.h b/g10/keydb.h index bd8928086..a81b258d7 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -26,12 +26,43 @@ #include "cipher.h" + +/**************** + * A Keyblock are all packets which form an entire certificate; + * i.e. the public key, certificate, trust packets, user ids, + * signatures, and subkey. + * + * This structure is also used to bind arbitrary packets together. + */ + +typedef struct kbnode_struct *KBNODE; +struct kbnode_struct { + PACKET *pkt; + KBNODE next; /* used to form a link list */ + KBNODE child; +}; + +/**************** + * A data structre to hold informations about the external position + * of a keyblock. + */ +struct keyblock_pos_struct { + int resno; /* resource number */ + ulong offset; /* position information */ + ulong length; /* length of thge keyblock */ + int last_block; +}; +typedef struct keyblock_pos_struct KBPOS; + + + /*-- passphrase.h --*/ DEK *get_passphrase_hash( u32 *keyid, char *text ); int make_dek_from_passphrase( DEK *dek, int mode ); /*-- getkey.c --*/ void add_keyring( const char *name ); +void add_secret_keyring( const char *name ); void cache_public_cert( PKT_public_cert *pkc ); void cache_user_id( PKT_user_id *uid, u32 *keyid ); int get_pubkey( PKT_public_cert *pkc, u32 *keyid ); @@ -53,6 +84,21 @@ const char *datestr_from_sig( PKT_signature *sig ); byte *fingerprint_from_skc( PKT_secret_cert *skc, size_t *ret_len ); byte *fingerprint_from_pkc( PKT_public_cert *pkc, size_t *ret_len ); +/*-- kbnode.c --*/ +KBNODE new_kbnode( PACKET *pkt ); +void release_kbnode( KBNODE n ); +KBNODE find_kbparent( KBNODE root, KBNODE node ); + +/*-- ringedit.c --*/ +int add_keyblock_resource( const char *filename ); +int get_keyblock_handle( const char *filename, KBPOS *kbpos ); +int search_keyblock( PACKET *pkt, KBPOS *kbpos ); +int lock_keyblock( KBPOS *kbpos ); +int unlock_keyblock( KBPOS *kbpos ); +int read_keyblock( KBPOS *kbpos, KBNODE *ret_root ); +int insert_keyblock( KBPOS *kbpos, KBNODE root ); +int delete_keyblock( KBPOS *kbpos ); +int update_keyblock( KBPOS *kbpos, KBNODE root ); #endif /*G10_KEYDB_H*/ diff --git a/g10/mainproc.c b/g10/mainproc.c index a04b0fc1f..a8b621289 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -36,25 +36,6 @@ /**************** - * We need to glue the packets together. This done by a - * tree of packets, which will released whenever a new start packet - * is encounterd. Start packets are: [FIXME] - * - * pubkey - * userid userid - * sig, sig, sig sig, sig - * - */ - -typedef struct node_struct *NODE; -struct node_struct { - PACKET *pkt; - NODE next; /* used to form a link list */ - NODE child; -}; - - -/**************** * Structure to hold the context */ @@ -66,17 +47,14 @@ typedef struct { DEK *dek; int last_was_pubkey_enc; int opt_list; - NODE cert; /* the current certificate */ + KBNODE cert; /* the current certificate */ int have_data; } *CTX; - - - -static void list_node( CTX c, NODE node ); -static void proc_tree( CTX c, NODE node ); +static void list_node( CTX c, KBNODE node ); +static void proc_tree( CTX c, KBNODE node ); static int pubkey_letter( int algo ) @@ -92,60 +70,13 @@ pubkey_letter( int algo ) } - -static NODE -new_node( PACKET *pkt ) -{ - NODE n = m_alloc( sizeof *n ); - n->next = NULL; - n->pkt = pkt; - n->child = NULL; - return n; -} - - -static void -release_node( NODE n ) -{ - NODE n2; - - while( n ) { - n2 = n->next; - release_node( n->child ); - free_packet( n->pkt ); - m_free( n ); - n = n2; - } -} - - -/**************** - * Return the parent node of NODE from the tree with ROOT - */ -static NODE -find_parent( NODE root, NODE node ) -{ - NODE n, n2; - - for( ; root; root = root->child) { - for( n = root; n; n = n->next) { - for( n2 = n->child; n2; n2 = n2->next ) { - if( n2 == node ) - return n; - } - } - } - log_bug(NULL); -} - - static void release_cert( CTX c ) { if( !c->cert ) return; proc_tree(c, c->cert ); - release_node( c->cert ); + release_kbnode( c->cert ); c->cert = NULL; } @@ -153,7 +84,7 @@ release_cert( CTX c ) static int add_onepass_sig( CTX c, PACKET *pkt ) { - NODE node; + KBNODE node; if( c->cert ) { /* add another packet */ @@ -161,12 +92,12 @@ add_onepass_sig( CTX c, PACKET *pkt ) log_error("add_onepass_sig: another packet is in the way\n"); release_cert( c ); } - node = new_node( pkt ); + node = new_kbnode( pkt ); node->next = c->cert; c->cert = node; } else /* insert the first one */ - c->cert = node = new_node( pkt ); + c->cert = node = new_kbnode( pkt ); return 1; } @@ -176,7 +107,7 @@ static int add_public_cert( CTX c, PACKET *pkt ) { release_cert( c ); - c->cert = new_node( pkt ); + c->cert = new_kbnode( pkt ); return 1; } @@ -184,7 +115,7 @@ static int add_secret_cert( CTX c, PACKET *pkt ) { release_cert( c ); - c->cert = new_node( pkt ); + c->cert = new_kbnode( pkt ); return 1; } @@ -193,7 +124,7 @@ static int add_user_id( CTX c, PACKET *pkt ) { u32 keyid[2]; - NODE node, n1, n2; + KBNODE node, n1, n2; if( !c->cert ) { log_error("orphaned user id\n" ); @@ -209,7 +140,7 @@ add_user_id( CTX c, PACKET *pkt ) return 0; } /* add a new user id node at the end */ - node = new_node( pkt ); + node = new_kbnode( pkt ); if( !(n2=n1->child) ) n1->child = node; else { @@ -225,7 +156,7 @@ static int add_signature( CTX c, PACKET *pkt ) { u32 keyid[2]; - NODE node, n1, n2; + KBNODE node, n1, n2; if( !c->cert ) { /* orphaned signature (no certificate) @@ -239,7 +170,7 @@ add_signature( CTX c, PACKET *pkt ) * The childs direct under the root are the signatures * (there is no need to keep the correct sequence of packets) */ - node = new_node( pkt ); + node = new_kbnode( pkt ); node->next = c->cert->child; c->cert->child = node; return 1; @@ -259,7 +190,7 @@ add_signature( CTX c, PACKET *pkt ) return 0; } /* and add a new signature node id at the end */ - node = new_node( pkt ); + node = new_kbnode( pkt ); if( !(n2=n1->child) ) n1->child = node; else { @@ -380,7 +311,7 @@ proc_compressed( CTX c, PACKET *pkt ) * Returns: 0 = valid signature or an error code */ static int -do_check_sig( CTX c, NODE node ) +do_check_sig( CTX c, KBNODE node ) { PKT_signature *sig; MD_HANDLE *md; @@ -403,7 +334,7 @@ do_check_sig( CTX c, NODE node ) } else if( (sig->sig_class&~3) == 0x10 ) { /* classes 0x10 .. 0x13 */ if( c->cert->pkt->pkttype == PKT_PUBLIC_CERT ) { - NODE n1 = find_parent( c->cert, node ); + KBNODE n1 = find_kbparent( c->cert, node ); if( n1 && n1->pkt->pkttype == PKT_USER_ID ) { @@ -483,9 +414,9 @@ print_fingerprint( PKT_public_cert *pkc, PKT_secret_cert *skc ) */ static void -list_node( CTX c, NODE node ) +list_node( CTX c, KBNODE node ) { - register NODE n2; + register KBNODE n2; if( !node ) ; @@ -645,9 +576,9 @@ print_keyid( FILE *fp, u32 *keyid ) * Preocess the tree which starts at node */ static void -proc_tree( CTX c, NODE node ) +proc_tree( CTX c, KBNODE node ) { - NODE n1; + KBNODE n1; int rc; if( node->pkt->pkttype == PKT_PUBLIC_CERT ) diff --git a/g10/packet.h b/g10/packet.h index 57adebe5f..609bf8853 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -54,11 +54,11 @@ typedef struct { byte pubkey_algo; /* algorithm used for public key scheme */ union { struct { - MPI rsa_integer; /* integer containing the DEK */ - } rsa; - struct { MPI a, b; /* integers with the encrypteded DEK */ } elg; + struct { + MPI rsa_integer; /* integer containing the DEK */ + } rsa; } d; } PKT_pubkey_enc; @@ -82,13 +82,13 @@ typedef struct { struct { byte digest_algo; /* algorithm used for digest (DIGEST_ALGO_xxxx) */ byte digest_start[2]; /* first 2 byte of the digest */ - MPI rsa_integer; /* the encrypted digest */ - } rsa; + MPI a, b; /* integers with the digest */ + } elg; struct { byte digest_algo; /* algorithm used for digest (DIGEST_ALGO_xxxx) */ byte digest_start[2]; /* first 2 byte of the digest */ - MPI a, b; /* integers with the digest */ - } elg; + MPI rsa_integer; /* the encrypted digest */ + } rsa; } d; } PKT_signature; @@ -100,14 +100,14 @@ typedef struct { md_filter_context_t mfx; union { struct { - MPI rsa_n; /* public modulus */ - MPI rsa_e; /* public exponent */ - } rsa; - struct { MPI p; /* prime */ MPI g; /* group generator */ MPI y; /* g^x mod p */ } elg; + struct { + MPI rsa_n; /* public modulus */ + MPI rsa_e; /* public exponent */ + } rsa; } d; } PKT_public_cert; @@ -117,12 +117,10 @@ typedef struct { byte pubkey_algo; /* algorithm used for public key scheme */ union { struct { - MPI rsa_n; /* public modulus */ - MPI rsa_e; /* public exponent */ - MPI rsa_d; /* secret descryption exponent */ - MPI rsa_p; /* secret first prime number */ - MPI rsa_q; /* secret second prime number */ - MPI rsa_u; /* secret multiplicative inverse */ + MPI p; /* prime */ + MPI g; /* group generator */ + MPI y; /* g^x mod p */ + MPI x; /* secret exponent */ u16 csum; /* checksum */ byte is_protected; /* The above infos are protected and must */ /* be decrypteded before use */ @@ -134,12 +132,14 @@ typedef struct { * to plain storage */ } blowfish; } protect; - } rsa; + } elg; struct { - MPI p; /* prime */ - MPI g; /* group generator */ - MPI y; /* g^x mod p */ - MPI x; /* secret exponent */ + MPI rsa_n; /* public modulus */ + MPI rsa_e; /* public exponent */ + MPI rsa_d; /* secret descryption exponent */ + MPI rsa_p; /* secret first prime number */ + MPI rsa_q; /* secret second prime number */ + MPI rsa_u; /* secret multiplicative inverse */ u16 csum; /* checksum */ byte is_protected; /* The above infos are protected and must */ /* be decrypteded before use */ @@ -151,7 +151,7 @@ typedef struct { * to plain storage */ } blowfish; } protect; - } elg; + } rsa; } d; } PKT_secret_cert; @@ -213,6 +213,7 @@ int proc_packets( IOBUF a ); /*-- parse-packet.c --*/ int set_packet_list_mode( int mode ); +int search_packet( IOBUF inp, PACKET *pkt, int pkttype, ulong *retpos ); int parse_packet( IOBUF inp, PACKET *ret_pkt); /*-- build-packet.c --*/ diff --git a/g10/parse-packet.c b/g10/parse-packet.c index 5badb0ec4..70eef4007 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -36,6 +36,8 @@ static mpi_print_mode = 0; static list_mode = 0; +static int parse( IOBUF inp, PACKET *pkt, int reqtype, + ulong *retpos, int *skip ); static void skip_packet( IOBUF inp, int pkttype, unsigned long pktlen ); static void skip_rest( IOBUF inp, unsigned long pktlen ); static int parse_publickey( IOBUF inp, int pkttype, unsigned long pktlen, @@ -109,12 +111,47 @@ set_packet_list_mode( int mode ) int parse_packet( IOBUF inp, PACKET *pkt ) { + int skip, rc; + + do { + rc = parse( inp, pkt, 0, NULL, &skip ); + } while( skip ); + return rc; +} + +/**************** + * Like parse packet, but do only return packet of the given type. + */ +int +search_packet( IOBUF inp, PACKET *pkt, int pkttype, ulong *retpos ) +{ + int skip, rc; + + do { + rc = parse( inp, pkt, pkttype, retpos, &skip ); + } while( skip ); + return rc; +} + + +/**************** + * Parse packet. Set the variable skip points to to 1 if the packet + * should be skipped; this is the case if either there is a + * requested packet type and the parsed packet doesn't match or the + * packet-type is 0, indicating deleted stuff. + */ +static int +parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos, int *skip ) +{ int rc, ctb, pkttype, lenbytes; unsigned long pktlen; byte hdr[5]; int hdrlen; + *skip = 0; assert( !pkt->pkt.generic ); + if( retpos ) + *retpos = iobuf_tell(inp); if( (ctb = iobuf_get(inp)) == -1 ) return -1; hdrlen=0; @@ -139,6 +176,12 @@ parse_packet( IOBUF inp, PACKET *pkt ) } } + if( !pkttype || (reqtype && pkttype != reqtype) ) { + skip_packet(inp, pkttype, pktlen); + *skip = 1; + return 0; + } + if( DBG_PACKET ) log_debug("parse_packet(iob=%d): type=%d length=%lu\n", iobuf_id(inp), pkttype, pktlen ); diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c index ba6a6f15a..f3f02abde 100644 --- a/g10/pubkey-enc.c +++ b/g10/pubkey-enc.c @@ -58,7 +58,7 @@ get_session_key( PKT_pubkey_enc *k, DEK *dek ) skey.g = skc->d.elg.g; skey.y = skc->d.elg.y; skey.x = skc->d.elg.x; - elg_decrypted( dek_frame, k->d.elg.a, k->d.elg.b, &skey ); + elg_decrypt( dek_frame, k->d.elg.a, k->d.elg.b, &skey ); memset( &skey, 0, sizeof skey ); } #ifdef HAVE_RSA_CIPHER diff --git a/g10/ringedit.c b/g10/ringedit.c new file mode 100644 index 000000000..e4380c3d1 --- /dev/null +++ b/g10/ringedit.c @@ -0,0 +1,469 @@ +/* ringedit.c - Function for key ring editing + * Copyright (c) 1997 by Werner Koch (dd9jn) + * + * This file is part of G10. + * + * G10 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. + * + * G10 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 + */ + + +/**************** + * This module supplies function for: + * + * - Search for a key block (pubkey and all other stuff) and return a + * handle for it. + * + * - Lock/Unlock a key block + * + * - Read a key block into a tree + * + * - Update a key block + * + * - Insert a new key block + * + * - Delete a key block + * + * FIXME: Add backup stuff + * FIXME: Keep track of all nodes, so that a change is propagated + * to all nodes. (or use shallow copies and ref-counting?) + */ + + + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include "util.h" +#include "packet.h" +#include "memory.h" +#include "mpi.h" +#include "iobuf.h" +#include "keydb.h" + + +struct resource_table_struct { + int used; + char *fname; + IOBUF iobuf; +}; + +#define MAX_RESOURCES 10 +static struct resource_table_struct resource_table[MAX_RESOURCES]; + + +static int keyring_search( PACKET *pkt, KBPOS *kbpos, IOBUF iobuf ); +static int keyring_read( KBPOS *kbpos, KBNODE *ret_root ); +static int keyring_insert( KBPOS *kbpos, KBNODE root ); +static int keyring_delete( KBPOS *kbpos ); + + + +static int +check_pos( KBPOS *kbpos ) +{ + if( kbpos->resno < 0 || kbpos->resno >= MAX_RESOURCES ) + return G10ERR_GENERAL; + if( !resource_table[kbpos->resno].used ) + return G10ERR_GENERAL; + return 0; +} + + + +/**************************************************************** + ****************** public functions **************************** + ****************************************************************/ + +/**************** + * Register a resource (which currently may ionly be a keyring file). + */ +int +add_keyblock_resource( const char *filename ) +{ + IOBUF iobuf; + int i; + + for(i=0; i < MAX_RESOURCES; i++ ) + if( !resource_table[i].used ) + break; + if( i == MAX_RESOURCES ) + return G10ERR_RESOURCE_LIMIT; + + iobuf = iobuf_open( filename ); + if( !iobuf ) + return G10ERR_OPEN_FILE; + resource_table[i].used = 1; + resource_table[i].fname = m_strdup(filename); + resource_table[i].iobuf = iobuf; + return 0; +} + + +/**************** + * Get a keyblock handle KBPOS from a filename. This can be used + * to get a handle for insert_keyblock for a new keyblock. + */ +int +get_keyblock_handle( const char *filename, KBPOS *kbpos ) +{ + int i; + + for(i=0; i < MAX_RESOURCES; i++ ) + if( resource_table[i].used ) { + /* fixme: dos needs case insensitive file compare */ + if( !strcmp( resource_table[i].fname, filename ) ) { + memset( kbpos, 0, sizeof *kbpos ); + kbpos->resno = i; + return 0; + } + } + return -1; /* not found */ +} + +/**************** + * Search a keyblock which starts with the given packet and put all + * informations into KBPOS, which can be used later to access this key block. + * This function looks into all registered keyblock sources. + * PACKET must be a packet with either a secret_cert or a public_cert + * + * This function is intended to check wether a given certificate + * is already in a keyring or to prepare it for editing. + * + * Returns: 0 if found, -1 if not found or an errorcode. + */ +int +search_keyblock( PACKET *pkt, KBPOS *kbpos ) +{ + int i, rc, last_rc=-1; + + for(i=0; i < MAX_RESOURCES; i++ ) { + if( resource_table[i].used ) { + /* note: here we have to add different search functions, + * depending on the type of the resource */ + rc = keyring_search( pkt, kbpos, resource_table[i].iobuf ); + if( !rc ) { + kbpos->resno = i; + return 0; + } + if( rc != -1 ) { + log_error("error searching resource %d: %s\n", + i, g10_errstr(rc)); + last_rc = rc; + } + } + } + return last_rc; +} + + + +/**************** + * Lock the keyblock; wait until it's available + * This function may change the internal data in kbpos, in cases + * when the to be locked keyblock has been modified. + * fixme: remove this function and add an option to search_keyblock()? + */ +int +lock_keyblock( KBPOS *kbpos ) +{ + int rc; + + if( (rc=check_pos(kbpos)) ) + return rc; + return 0; +} + +/**************** + * Release a lock on a keyblock + */ +int +unlock_keyblock( KBPOS *kbpos ) +{ + int rc; + + if( (rc=check_pos(kbpos)) ) + return rc; + return 0; +} + +/**************** + * Read a complete keyblock and return the root in ret_root. + */ +int +read_keyblock( KBPOS *kbpos, KBNODE *ret_root ) +{ + int rc; + + if( (rc=check_pos(kbpos)) ) + return rc; + return keyring_read( kbpos, ret_root ); +} + +/**************** + * Insert the keyblock described by ROOT into the keyring described + * by KBPOS. This actually appends the data to the keyfile. + */ +int +insert_keyblock( KBPOS *kbpos, KBNODE root ) +{ + int rc; + + if( (rc=check_pos(kbpos)) ) + return rc; + + rc = keyring_insert( kbpos, root ); + + return rc; +} + +/**************** + * Delete the keyblock described by KBPOS. + * The current code simply changes the keyblock in the keyring + * to packet of type 0 with the correct length. To help detecting errors, + * zero bytes are written. + */ +int +delete_keyblock( KBPOS *kbpos ) +{ + int rc; + + if( (rc=check_pos(kbpos)) ) + return rc; + + rc = keyring_delete( kbpos ); + + return rc; +} + + +/**************** + * Update the keyblock at KBPOS with the one in ROOT. + */ +int +update_keyblock( KBPOS *kbpos, KBNODE root ) +{ + int rc; + KBPOS kbpos2; + + /* we do it the simple way: */ + memset( &kbpos2, 0, sizeof kbpos2 ); + kbpos2.resno = kbpos->resno; + rc = insert_keyblock( &kbpos2, root ); + if( !rc ) + rc = delete_keyblock( kbpos ); + + return rc; +} + + +/**************************************************************** + ********** Functions which operates on regular keyrings ******** + ****************************************************************/ + + +/**************** + * search one keyring, return 0 if found, -1 if not found or an errorcode. + */ +static int +keyring_search( PACKET *req, KBPOS *kbpos, IOBUF iobuf ) +{ + int rc; + PACKET pkt; + int save_mode; + ulong offset; + int pkttype = req->pkttype; + PKT_public_cert *req_pkc = req->pkt.public_cert; + PKT_secret_cert *req_skc = req->pkt.secret_cert; + + init_packet(&pkt); + save_mode = set_packet_list_mode(0); + + if( iobuf_seek( iobuf, 0 ) ) { + log_error("can't rewind keyring file: %s\n", g10_errstr(rc)); + rc = G10ERR_KEYRING_OPEN; + goto leave; + } + + while( !(rc=search_packet(iobuf, &pkt, pkttype, &offset)) ) { + if( pkt.pkttype == PKT_SECRET_CERT ) { + PKT_secret_cert *skc = pkt.pkt.secret_cert; + + if( req_skc->timestamp == skc->timestamp + && req_skc->valid_days == skc->valid_days + && req_skc->pubkey_algo == skc->pubkey_algo + && ( ( skc->pubkey_algo == PUBKEY_ALGO_ELGAMAL + && !mpi_cmp( req_skc->d.elg.p, skc->d.elg.p ) + && !mpi_cmp( req_skc->d.elg.g, skc->d.elg.g ) + && !mpi_cmp( req_skc->d.elg.y, skc->d.elg.y ) + && !mpi_cmp( req_skc->d.elg.x, skc->d.elg.x ) + ) + || ( skc->pubkey_algo == PUBKEY_ALGO_RSA + && !mpi_cmp( req_skc->d.rsa.rsa_n, skc->d.rsa.rsa_n ) + && !mpi_cmp( req_skc->d.rsa.rsa_e, skc->d.rsa.rsa_e ) + && !mpi_cmp( req_skc->d.rsa.rsa_d, skc->d.rsa.rsa_d ) + ) + ) + ) + break; /* found */ + } + else if( pkt.pkttype == PKT_PUBLIC_CERT ) { + PKT_public_cert *pkc = pkt.pkt.public_cert; + + if( req_pkc->timestamp == pkc->timestamp + && req_pkc->valid_days == pkc->valid_days + && req_pkc->pubkey_algo == pkc->pubkey_algo + && ( ( pkc->pubkey_algo == PUBKEY_ALGO_ELGAMAL + && !mpi_cmp( req_pkc->d.elg.p, pkc->d.elg.p ) + && !mpi_cmp( req_pkc->d.elg.g, pkc->d.elg.g ) + && !mpi_cmp( req_pkc->d.elg.y, pkc->d.elg.y ) + ) + || ( pkc->pubkey_algo == PUBKEY_ALGO_RSA + && !mpi_cmp( req_pkc->d.rsa.rsa_n, pkc->d.rsa.rsa_n ) + && !mpi_cmp( req_pkc->d.rsa.rsa_e, pkc->d.rsa.rsa_e ) + ) + ) + ) + break; /* found */ + } + else + log_bug(NULL); + free_packet(&pkt); + } + if( !rc ) + kbpos->offset = offset; + + leave: + free_packet(&pkt); + set_packet_list_mode(save_mode); + return rc; +} + + +static int +keyring_read( KBPOS *kbpos, KBNODE *ret_root ) +{ + PACKET *pkt; + int rc; + KBNODE root = NULL; + KBNODE node, n1, n2; + IOBUF a; + + if( (rc=check_pos(kbpos)) ) + return rc; + a = resource_table[kbpos->resno].iobuf; + + pkt = m_alloc( sizeof *pkt ); + init_packet(pkt); + while( (rc=parse_packet(a, pkt)) != -1 ) { + if( rc ) { /* ignore errors */ + free_packet( pkt ); + continue; + } + switch( pkt->pkttype ) { + case PKT_PUBLIC_CERT: + case PKT_SECRET_CERT: + if( root ) + break; + root = new_kbnode( pkt ); + pkt = m_alloc( sizeof *pkt ); + init_packet(pkt); + break; + + case PKT_USER_ID: + if( !root ) { + log_error("read_keyblock: orphaned user id\n" ); + rc = G10ERR_INV_KEYRING; /* or wron kbpos */ + break; + } + /* append the user id */ + node = new_kbnode( pkt ); + if( !(n1=root->child) ) + root->child = node; + else { + for( ; n1->next; n1 = n1->next) + ; + n1->next = node; + } + pkt = m_alloc( sizeof *pkt ); + init_packet(pkt); + break; + + case PKT_SIGNATURE: + if( !root ) { + log_error("read_keyblock: no root for signature\n" ); + rc = G10ERR_INV_KEYRING; /* or wrong kbpos */ + break; + } + if( !root->child ) { + log_error("read_keyblock: no userid for signature\n" ); + rc = G10ERR_INV_KEYRING; + break; + } + /* goto the last user id */ + for(n1=root->child; n1->next; n1 = n1->next ) + ; + /* append the signature node */ + node = new_kbnode( pkt ); + if( !(n2=n1->child) ) + n1->child = node; + else { + for( ; n2->next; n2 = n2->next) + ; + n2->next = node; + } + pkt = m_alloc( sizeof *pkt ); + init_packet(pkt); + break; + + default: /* ignore all other packets. FIXME: we should not do this */ + free_packet( pkt ); + break; + } + } + kbpos->last_block = rc == -1; /* flag, that this is the last block */ + if( rc == -1 && root ) + rc = 0; + + if( rc ) + release_kbnode( root ); + else { + *ret_root = root; + kbpos->length = iobuf_tell( a ) - kbpos->offset; + } + free_packet( pkt ); + m_free( pkt ); + return rc; +} + + +static int +keyring_insert( KBPOS *kbpos, KBNODE root ) +{ + return -1; +} + +static int +keyring_delete( KBPOS *kbpos ) +{ + return -1; +} + + +/**************************************************************** + ********** Functions which operates on databases *************** + ****************************************************************/ + |