diff --git a/README b/README index 55be1b292..1f2879c86 100644 --- a/README +++ b/README @@ -57,15 +57,10 @@ 4) You end up with a binary "g10" in /usr/local/bin + 5) create a directory ".g10" under your hoem directory ("mkdir ~/.g10") - Resources - --------- - G10 needs a directory "~/.g10" to store the default keyrings - and other files. - - Key Generation -------------- @@ -75,8 +70,9 @@ good random numbers for prime number generation, it uses a /dev/random which will emit only bytes if the kernel can gather enough entropy. If you see no progress, you should start some other activities such - as mouse moves or a "find /". Because we have no hardware device - to generate random we have to use this method. + as mouse moves, "find /" or using the keyboard (on another window). + Because we have no hardware device to generate random we have to use + this method. Key generation shows progress by printing different characters to stderr: @@ -109,17 +105,18 @@ g10 --sign-key Donald - To sign the key of of "Donald" with your default userid + This let you sign the key of "Donald" with your default userid. g10 --sign-key -u Karl -u Joe Donald - To sign the key of of "Donald" with the userids of "Karl" and "Joe". + This let you sign the key of of "Donald" with the userids of "Karl" + and "Joe". All existing signatures are checked, if some are invalid, a menu is offered to delete some of them, and the you are asked for every user wether you want to sign this key. - You may remove a signature at any time by usiing the option "--edit-sig", - which also asks for the sigs to remove. + You may remove a signature at any time using the option "--edit-sig", + which asks for the sigs to remove. Sign @@ -166,17 +163,6 @@ Ditto, but sign the file with the user id "Suttner" - - Examine a data or key file - -------------------------- - - g10 --list-packets datafile - - Use this to list the contents of a data file. If the file is encrypted - you are asked for the passphrase, so that G10 is able to look at the - inner structure of a encrypted packet. - - Batch mode ---------- If you use the option "--batch", G10 runs in non-interactive mode and @@ -185,7 +171,7 @@ you can use the option "--passhrase-fd n", which works like PGPs PGPPASSFD. - Batch mode also causes PGP to terminate as soon as a BAD signature is + Batch mode also causes G10 to terminate as soon as a BAD signature is detected. @@ -196,6 +182,56 @@ stderr to get detailed informations about the errors. + Esoteric commands + ----------------- + + g10 --list-packets datafile + + Use this to list the contents of a data file. If the file is encrypted + you are asked for the passphrase, so that G10 is able to look at the + inner structure of a encrypted packet. + + --quick-random + + Do not use the stroing random generator but a faster one. This can be + used to generate keys for tests; those are marked as insecure. + + --list-trustdb + + List the contents of the trustdb in a human readable format + + --list-trustdb + + List the tree of certificates for the given usernames + + --list-trust-path depth username + + List the possible trust paths for the given username, up to the specified + depth. If depth is negative, duplicate introducers are not listed, + because those would increase the trust probabilty only minimal. + (you must use the special option "--" to stop option parsing when + using a negative number) + + --print-mds filenames + + List all available message digest values for the fiven filenames + + --gen-prime n + + Generate and print a simple prime number of size n + + --gen-prime n q + + Generate a prime number suitable for ElGamal signatures of size n with + a q as largest primefactor of n-1. + + --gen-prime n q 1 + + Ditto, but calculate a generator too. + + + For more options/commands see the file g10/OPTIONS. + Debug Flags ----------- @@ -213,7 +249,7 @@ 32 memory allocation stuff 64 caching 128 show memory statistics at exit - + 256 trust verification stuff Other Notes diff --git a/VERSION b/VERSION index b1e80bb24..845639eef 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.3 +0.1.4 diff --git a/acconfig.h b/acconfig.h index 113ec9f0f..3f83ef1b3 100644 --- a/acconfig.h +++ b/acconfig.h @@ -50,4 +50,20 @@ @BOTTOM@ +/* The AC_CHECK_SIZEOF() fails for some machines. + * we provide some fallback values here */ +#if !SIZEOF_UNSIGNED_SHORT + #undef SIZEOF_UNSIGNED_SHORT + #define SIZEOF_UNSIGNED_SHORT 2 +#endif +#if !SIZEOF_UNSIGNED_INT + #undef SIZEOF_UNSIGNED_INT + #define SIZEOF_UNSIGNED_INT 4 +#endif +#if !SIZEOF_UNSIGNED_LONG + #undef SIZEOF_UNSIGNED_LONG + #define SIZEOF_UNSIGNED_LONG 4 +#endif + + #endif /*G10_CONFIG_H*/ diff --git a/cipher/random.c b/cipher/random.c index b082022af..dbf71478b 100644 --- a/cipher/random.c +++ b/cipher/random.c @@ -167,6 +167,10 @@ the OS a chance to collect more entropy! (Need %d more bytes)\n", length ); #else /* not HAVE_DEV_RANDOM */ +#ifndef RAND_MAX /* for SunOS */ + #define RAND_MAX 32767 +#endif + static void fill_buffer( byte *buffer, size_t length, int level ) { @@ -178,11 +182,20 @@ fill_buffer( byte *buffer, size_t length, int level ) "it compile - it is in no way a strong RNG!\n\n" "DON'T USE ANY DATA GENERATED BY THIS PROGRAM!!\n\n"); initialized=1; + #ifdef HAVE_RAND srand(make_timestamp()*getpid()); + #else + srandom(make_timestamp()*getpid()); + #endif } + #ifdef HAVE_RAND while( length-- ) *buffer++ = ((unsigned)(1 + (int) (256.0*rand()/(RAND_MAX+1.0)))-1); + #else + while( length-- ) + *buffer++ = ((unsigned)(1 + (int) (256.0*random()/(RAND_MAX+1.0)))-1); + #endif } #endif diff --git a/config.h.in b/config.h.in index 2a3bd36e4..94550ccf5 100644 --- a/config.h.in +++ b/config.h.in @@ -72,6 +72,9 @@ /* The number of bytes in a unsigned short. */ #undef SIZEOF_UNSIGNED_SHORT +/* Define if you have the rand function. */ +#undef HAVE_RAND + /* Define if you have the stpcpy function. */ #undef HAVE_STPCPY @@ -81,6 +84,9 @@ /* Define if you have the strlwr function. */ #undef HAVE_STRLWR +/* Define if you have the strtoul function. */ +#undef HAVE_STRTOUL + /* Define if you have the tcgetattr function. */ #undef HAVE_TCGETATTR @@ -91,4 +97,20 @@ #undef HAVE_ZLIB_H +/* The AC_CHECK_SIZEOF() fails for some machines. + * we provide some fallback values here */ +#if !SIZEOF_UNSIGNED_SHORT + #undef SIZEOF_UNSIGNED_SHORT + #define SIZEOF_UNSIGNED_SHORT 2 +#endif +#if !SIZEOF_UNSIGNED_INT + #undef SIZEOF_UNSIGNED_INT + #define SIZEOF_UNSIGNED_INT 4 +#endif +#if !SIZEOF_UNSIGNED_LONG + #undef SIZEOF_UNSIGNED_LONG + #define SIZEOF_UNSIGNED_LONG 4 +#endif + + #endif /*G10_CONFIG_H*/ diff --git a/configure.in b/configure.in index 6a97d416a..39e87761b 100644 --- a/configure.in +++ b/configure.in @@ -8,7 +8,7 @@ AC_CONFIG_AUX_DIR(scripts) AC_CONFIG_HEADER(config.h) -VERSION=`cat ./VERSION` +VERSION=`cat $srcdir/VERSION` PACKAGE=g10 AC_SUBST(VERSION) AC_SUBST(PACKAGE) @@ -90,10 +90,6 @@ dnl Checks for libraries. dnl Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS(unistd.h) -AC_CHECK_HEADERS(zlib.h, - [LIBS="$LIBS -lz"], - AC_MSG_WARN([zlib missing - creating without ZLIB support!]) - ) dnl Checks for typedefs, structures, and compiler characteristics. @@ -150,12 +146,20 @@ AC_CHECK_SIZEOF(unsigned short, 2) AC_CHECK_SIZEOF(unsigned int, 4) AC_CHECK_SIZEOF(unsigned long, 4) +if test "$ac_cv_sizeof_unsigned_short" = "0" \ + || test "$ac_cv_sizeof_unsigned_int" = "0" \ + || test "$ac_cv_sizeof_unsigned_long" = "0"; then + AC_MSG_WARN([Hmmm, something is wrong with the sizes - using defaults]); +fi dnl Checks for library functions. AC_FUNC_VPRINTF -AC_CHECK_FUNCS(strerror stpcpy strlwr tcgetattr) +AC_CHECK_FUNCS(strerror stpcpy strlwr tcgetattr rand strtoul) + + + dnl check wether we have a random device AC_CACHE_CHECK(for random device, ac_cv_have_dev_random, @@ -175,8 +179,8 @@ if test "$ac_cv_mpi_config_done" = yes; then AC_MSG_RESULT(done) else ac_cv_mpi_config_done="" -if test -f ./mpi/config.links ; then - . ./mpi/config.links +if test -f $srcdir/mpi/config.links ; then + . $srcdir/mpi/config.links ac_cv_mpi_extra_asm_modules="$mpi_extra_modules" AC_LINK_FILES( ${mpi_ln_src}, ${mpi_ln_dst} ) ac_cv_mpi_config_done="yes" @@ -198,11 +202,18 @@ fi AC_SUBST(MPI_EXTRA_ASM_OBJS) +dnl Do we have zlib? Must do it here because Solaris failed +dnl when compiling a conftest (due to the "-lz" from LIBS). +AC_CHECK_HEADERS(zlib.h, + [LIBS="$LIBS -lz"], + AC_MSG_WARN([zlib missing - creating without ZLIB support!]) + ) + dnl checking whether we have other cipher source files CIPHER_EXTRA_OBJS="" CIPHER_EXTRA_DIST="" AC_CACHE_CHECK(for extra cipher modules, ac_cv_have_rsa_cipher, -[if test -f cipher/rsa.c && test -f cipher/rsa.h; then +[if test -f $srcdir/cipher/rsa.c && test -f $srcdir/cipher/rsa.h; then ac_cv_have_rsa_cipher=yes; else ac_cv_have_rsa_cipher=no; fi]) if test $ac_cv_have_rsa_cipher = yes; then AC_DEFINE(HAVE_RSA_CIPHER) diff --git a/g10/build-packet.c b/g10/build-packet.c index a541c8cae..b0fd0859a 100644 --- a/g10/build-packet.c +++ b/g10/build-packet.c @@ -147,9 +147,11 @@ calc_packet_length( PACKET *pkt ) static int do_comment( IOBUF out, int ctb, PKT_comment *rem ) { - write_header(out, ctb, rem->len); - if( iobuf_write( out, rem->data, rem->len ) ) - return G10ERR_WRITE_FILE; + if( !opt.no_comment ) { + write_header(out, ctb, rem->len); + if( iobuf_write( out, rem->data, rem->len ) ) + return G10ERR_WRITE_FILE; + } return 0; } diff --git a/g10/comment.c b/g10/comment.c index 4d5045260..00bbac7dd 100644 --- a/g10/comment.c +++ b/g10/comment.c @@ -57,9 +57,10 @@ write_comment( IOBUF out, const char *s ) KBNODE make_comment_node( const char *s ) { - PACKET *pkt = m_alloc_clear( sizeof *pkt ); + PACKET *pkt; size_t n = strlen(s); + pkt = m_alloc_clear( sizeof *pkt ); pkt->pkttype = PKT_COMMENT; pkt->pkt.comment = m_alloc( sizeof *pkt->pkt.comment + n - 1 ); pkt->pkt.comment->len = n; diff --git a/g10/g10.c b/g10/g10.c index a00a3f97a..d36717a31 100644 --- a/g10/g10.c +++ b/g10/g10.c @@ -190,6 +190,7 @@ main( int argc, char **argv ) { 531, "list-trustdb",0 , "\r"}, { 532, "quick-random", 0, "\r"}, { 533, "list-trust-path",0, "\r"}, + { 534, "no-comment", 0, "do not write comment packets"}, {0} }; ARGPARSE_ARGS pargs; @@ -336,6 +337,7 @@ main( int argc, char **argv ) case 531: set_cmd( &cmd, aListTrustDB); break; case 532: quick_random_gen(1); break; case 533: set_cmd( &cmd, aListTrustPath); break; + case 534: opt.no_comment=1; break; default : errors++; pargs.err = configfp? 1:2; break; } } diff --git a/g10/options.h b/g10/options.h index 3b72547ce..7a9a4c587 100644 --- a/g10/options.h +++ b/g10/options.h @@ -39,7 +39,7 @@ struct { int def_cipher_algo; int def_pubkey_algo; int def_digest_algo; - int reserved9; + int no_comment; int reserved10; int reserved11; int reserved12; diff --git a/g10/pkclist.c b/g10/pkclist.c index bd871a9df..5381ac301 100644 --- a/g10/pkclist.c +++ b/g10/pkclist.c @@ -34,16 +34,35 @@ #include "trustdb.h" #include "ttyio.h" +/**************** + * Returns true if a ownertrust has changed. + */ static int -query_ownertrust( PKT_public_cert *pkc ) +query_ownertrust( ulong lid ) { char *p; + int rc; size_t n; u32 keyid[2]; + PKT_public_cert *pkc ; + int changed=0; - keyid_from_pkc( pkc, keyid ); - tty_printf("No ownertrust specified for:\n" - "%4u%c/%08lX %s \"", + rc = keyid_from_trustdb( lid, keyid ); + if( rc ) { + log_error("ooops: can't get keyid for lid %lu\n", lid); + return 0; + } + + pkc = m_alloc_clear( sizeof *pkc ); + rc = get_pubkey( pkc, keyid ); + if( rc ) { + log_error("keyid %08lX: pubkey not found: %s\n", + (ulong)keyid[1], g10_errstr(rc) ); + return 0; + } + + tty_printf("No ownertrust defined for %lu:\n" + "%4u%c/%08lX %s \"", lid, nbits_from_pkc( pkc ), pubkey_letter( pkc->pubkey_algo ), (ulong)keyid[1], datestr_from_pkc( pkc ) ); p = get_user_id( keyid, &n ); @@ -72,7 +91,16 @@ query_ownertrust( PKT_public_cert *pkc ) "to do with the (implicitly created) web-of-certificates.\n"); } else if( !p[1] && (*p >= '1' && *p <= '4') ) { - /* okay */ + unsigned trust; + switch( *p ) { + case '1': trust = TRUST_UNDEFINED; break; + case '2': trust = TRUST_NEVER ; break; + case '3': trust = TRUST_MARGINAL ; break; + case '4': trust = TRUST_FULLY ; break; + default: BUG(); + } + if( !update_ownertrust( lid, trust ) ) + changed++; break; } else if( *p == 's' || *p == 'S' ) { @@ -81,10 +109,53 @@ query_ownertrust( PKT_public_cert *pkc ) m_free(p); p = NULL; } m_free(p); - return 0; + m_free(pkc); + return changed; } +/**************** + * Try to add some more owner trusts (interactive) + * Returns: -1 if no ownertrust were added. + */ +static int +add_ownertrust( PKT_public_cert *pkc ) +{ + int rc; + void *context = NULL; + ulong lid; + unsigned trust; + int any=0; + + tty_printf( +"Could not find a valid trust path to the key. Lets see, wether we\n" +"can assign some missing owner trust values.\n\n"); + + rc = query_trust_record( pkc ); + if( rc ) { + log_error("Ooops: not in trustdb\n"); + return -1; + } + + lid = pkc->local_id; + while( !(rc=enum_trust_web( &context, &lid )) ) { + rc = get_ownertrust( lid, &trust ); + if( rc ) + log_fatal("Ooops: couldn't get ownertrust for %lu\n", lid); + if( trust == TRUST_UNDEFINED || trust == TRUST_EXPIRED || + trust == TRUST_UNKNOWN ) { + if( query_ownertrust( lid ) ) + any=1; + } + } + if( rc == -1 ) + rc = 0; + enum_trust_web( &context, NULL ); /* close */ + + + return rc? rc : any? 0:-1; +} + /**************** * Check wether we can trust this pkc which has a trustlevel of TRUSTLEVEL @@ -119,7 +190,15 @@ do_we_trust( PKT_public_cert *pkc, int trustlevel ) if( opt.batch || opt.answer_no ) log_info("no info to calculate a trust probability\n"); else { - query_ownertrust( pkc ); + rc = add_ownertrust( pkc ); + if( !rc ) { + rc = check_trust( pkc, &trustlevel ); + if( rc ) + log_fatal("trust check after add_ownertrust failed: %s\n", + g10_errstr(rc) ); + /* FIXME: this is recursive; we better should unroll it */ + return do_we_trust( pkc, trustlevel ); + } } return 0; /* no */ @@ -137,7 +216,7 @@ do_we_trust( PKT_public_cert *pkc, int trustlevel ) return 1; /* yes */ case TRUST_ULTIMATE: - log_info("Our own key is always good.\n"); + log_info("Our own keys is always good.\n"); return 1; /* yes */ default: BUG(); diff --git a/g10/trustdb.c b/g10/trustdb.c index 51ee9b885..4f8975107 100644 --- a/g10/trustdb.c +++ b/g10/trustdb.c @@ -110,15 +110,28 @@ struct local_id_info { }; +typedef struct trust_info TRUST_INFO; +struct trust_info { + ulong lid; + unsigned trust; +}; + + typedef struct trust_seg_list *TRUST_SEG_LIST; struct trust_seg_list { TRUST_SEG_LIST next; int nseg; /* number of segmens */ int dup; - ulong seg[1]; /* segment list */ + TRUST_INFO seg[1]; /* segment list */ }; +typedef struct { + TRUST_SEG_LIST tsl; + int index; +} ENUM_TRUST_WEB_CONTEXT; + + static void create_db( const char *fname ); static void open_db(void); static int read_record( ulong recnum, TRUSTREC *rec ); @@ -134,11 +147,12 @@ static int qry_lid_table_flag( LOCAL_ID_INFO *tbl, ulong lid, unsigned *flag ); static void upd_lid_table_flag( LOCAL_ID_INFO *tbl, ulong lid, unsigned flag ); static void print_user_id( const char *text, u32 *keyid ); -static int do_list_path( ulong *stack, int depth, int max_depth, +static int do_list_path( TRUST_INFO *stack, int depth, int max_depth, LOCAL_ID_INFO *lids, TRUST_SEG_LIST *tslist ); static int list_sigs( ulong pubkey_id ); -static int do_check( ulong pubkeyid, int *trustlevel ); +static int propagate_trust( TRUST_SEG_LIST tslist ); +static int do_check( ulong pubkeyid, unsigned *trustlevel ); static char *db_name; @@ -147,6 +161,9 @@ static int db_fd = -1; * which are the ones from our secrings */ static LOCAL_ID_INFO *ultikey_table; +static ulong last_trust_web_key; +static TRUST_SEG_LIST last_trust_web_tslist; + #define buftoulong( p ) ((*(byte*)(p) << 24) | (*((byte*)(p)+1)<< 16) | \ (*((byte*)(p)+2) << 8) | (*((byte*)(p)+3))) #define buftoushort( p ) ((*((byte*)(p)) << 8) | (*((byte*)(p)+1))) @@ -642,13 +659,15 @@ void list_trust_path( int max_depth, const char *username ) { int rc; + int wipe=0; int i; TRUSTREC rec; PKT_public_cert *pkc = m_alloc_clear( sizeof *pkc ); - if( max_depth < 0 ) - max_depth = MAX_LIST_SIGS_DEPTH+1; - + if( max_depth < 0 ) { + wipe = 1; + max_depth = -max_depth; + } if( (rc = get_pubkey_byname( pkc, username )) ) log_error("user '%s' not found: %s\n", username, g10_errstr(rc) ); @@ -658,37 +677,53 @@ list_trust_path( int max_depth, const char *username ) else if( rc == -1 ) log_error("user '%s' not in trustdb\n", username); else { - LOCAL_ID_INFO *lids; - LOCAL_ID_INFO *work; - ulong stack[MAX_LIST_SIGS_DEPTH]; TRUST_SEG_LIST tsl, tslist = NULL; - lids = new_lid_table(); - stack[0] = pkc->local_id; - rc = do_list_path( stack, 1, max_depth, lids, &tslist ); - /* wipe out duplicates */ - work = new_lid_table(); - for( tsl=tslist; tsl; tsl = tsl->next ) { - for(i=1; i < tsl->nseg-1; i++ ) { - if( ins_lid_table_item( work, tsl->seg[i], 0 ) ) { - tsl->dup = 1; /* mark as duplicate */ - break; - } - } + if( !qry_lid_table_flag( ultikey_table, pkc->local_id, NULL ) ) { + tslist = m_alloc( sizeof *tslist ); + tslist->nseg = 1; + tslist->dup = 0; + tslist->seg[0].lid = pkc->local_id; + tslist->seg[0].trust = 0; + tslist->next = NULL; + rc = 0; } - release_lid_table(work); + else { + LOCAL_ID_INFO *lids = new_lid_table(); + TRUST_INFO stack[MAX_LIST_SIGS_DEPTH]; - release_lid_table(lids); + stack[0].lid = pkc->local_id; + stack[0].trust = 0; + rc = do_list_path( stack, 1, max_depth, lids, &tslist ); + if( wipe ) { /* wipe out duplicates */ + LOCAL_ID_INFO *work; + + work = new_lid_table(); + for( tsl=tslist; tsl; tsl = tsl->next ) { + for(i=1; i < tsl->nseg-1; i++ ) { + if( ins_lid_table_item( work, tsl->seg[i].lid, 0 ) ) { + tsl->dup = 1; /* mark as duplicate */ + break; + } + } + } + release_lid_table(work); + } + release_lid_table(lids); + } if( rc ) log_error("user '%s' list problem: %s\n", username, g10_errstr(rc)); + rc = propagate_trust( tslist ); + if( rc ) + log_error("user '%s' trust problem: %s\n", username, g10_errstr(rc)); for(tsl = tslist; tsl; tsl = tsl->next ) { int i; if( tsl->dup ) continue; - printf("tslist segs:" ); + printf("trust path:" ); for(i=0; i < tsl->nseg; i++ ) - printf(" %lu", tsl->seg[i]); + printf(" %lu/%02x", tsl->seg[i].lid, tsl->seg[i].trust ); putchar('\n'); } } @@ -855,8 +890,7 @@ keyid_from_local_id( ulong lid, u32 *keyid ) /**************** - * Verify, that all our public keys are in the trustDB and marked as - * ultimately trusted. + * Verify, that all our public keys are in the trustDB. */ static int verify_own_certs() @@ -866,7 +900,6 @@ verify_own_certs() PKT_secret_cert *skc = m_alloc_clear( sizeof *skc ); PKT_public_cert *pkc = m_alloc_clear( sizeof *pkc ); u32 keyid[2]; - int trust; while( !(rc=enum_secret_keys( &enum_context, skc) ) ) { /* fixed: to be sure that it is a secret key of our own, @@ -895,23 +928,21 @@ verify_own_certs() rc = G10ERR_GENERAL; goto leave; } - /* look into the trustdb */ - rc = check_trust( pkc, &trust ); - if( rc ) { - log_info("keyid %08lX: problem in trustdb: %s\n", (ulong)keyid[1], - g10_errstr(rc) ); - goto leave; - } - if( trust == TRUST_UNKNOWN ) { + + /* make sure that the pubkey is in the trustdb */ + rc = query_trust_record( pkc ); + if( rc == -1 ) { /* put it into the trustdb */ rc = insert_trust_record( pkc ); - if( rc ) - log_error("keyid %08lX: insert failed: %s\n", - (ulong)keyid[1], g10_errstr(rc) ); - else - log_info("keyid %08lX: inserted\n", (ulong)keyid[1] ); + if( rc ) { + log_error("keyid %08lX: can't put it into the trustdb\n", + (ulong)keyid[1] ); + goto leave; + } } - else { - /* FIXME: we should chek the other values */ + else if( rc ) { + log_error("keyid %08lX: query record failed\n", (ulong)keyid[1] ); + goto leave; + } if( DBG_TRUST ) @@ -921,6 +952,7 @@ verify_own_certs() log_error("keyid %08lX: already in ultikey_table\n", (ulong)keyid[1]); + release_secret_cert_parts( skc ); release_public_cert_parts( pkc ); } @@ -1042,7 +1074,7 @@ list_sigs( ulong pubkey_id ) static int -do_list_path( ulong *stack, int depth, int max_depth, +do_list_path( TRUST_INFO *stack, int depth, int max_depth, LOCAL_ID_INFO *lids, TRUST_SEG_LIST *tslist ) { SIGREC_CONTEXT sx; @@ -1057,12 +1089,13 @@ do_list_path( ulong *stack, int depth, int max_depth, return 0; } memset( &sx, 0, sizeof sx ); - sx.pubkey_id = stack[depth-1]; + sx.pubkey_id = stack[depth-1].lid; while( !(rc = walk_sigrecs( &sx )) ) { TRUST_SEG_LIST tsl, t2, tl; int i; - stack[depth] = sx.sig_id; + stack[depth].lid = sx.sig_id; + stack[depth].trust = 0; if( qry_lid_table_flag( lids, sx.sig_id, &last_depth) ) { /*printf("%2lu/%d: marked\n", sx.sig_id, depth );*/ ins_lid_table_item( lids, sx.sig_id, depth); @@ -1078,7 +1111,7 @@ do_list_path( ulong *stack, int depth, int max_depth, /*printf("%2lu/%d: already visited\n", sx.sig_id, depth)*/; else if( !qry_lid_table_flag( ultikey_table, sx.sig_id, NULL ) ) { /* found end of path; store it, ordered by path length */ - tsl = m_alloc( sizeof *tsl + depth*sizeof(ulong) ); + tsl = m_alloc( sizeof *tsl + depth*sizeof(TRUST_INFO) ); tsl->nseg = depth+1; tsl->dup = 0; for(i=0; i <= depth; i++ ) @@ -1268,19 +1301,110 @@ build_sigrecs( ulong pubkeyid ) return rc; } +/**************** + * Make a list of trust paths + */ +static int +make_tsl( ulong pubkey_id, TRUST_SEG_LIST *ret_tslist ) +{ + int i, rc; + LOCAL_ID_INFO *lids = new_lid_table(); + TRUST_INFO stack[MAX_LIST_SIGS_DEPTH]; + TRUST_SEG_LIST tsl, tslist; + int max_depth = 4; + tslist = *ret_tslist = NULL; + if( !qry_lid_table_flag( ultikey_table, pubkey_id, NULL ) ) { + tslist = m_alloc( sizeof *tslist ); + tslist->nseg = 1; + tslist->dup = 0; + tslist->seg[0].lid = pubkey_id; + tslist->seg[0].trust = 0; + tslist->next = NULL; + rc = 0; + } + else { + stack[0].lid = pubkey_id; + stack[0].trust = 0; + rc = do_list_path( stack, 1, max_depth, lids, &tslist ); + } + if( !rc ) { /* wipe out duplicates */ + LOCAL_ID_INFO *work = new_lid_table(); + for( tsl=tslist; tsl; tsl = tsl->next ) { + for(i=1; i < tsl->nseg-1; i++ ) { + if( ins_lid_table_item( work, tsl->seg[i].lid, 0 ) ) { + tsl->dup = 1; /* mark as duplicate */ + break; + } + } + } + release_lid_table(work); + *ret_tslist = tslist; + } + else + ; /* FIXME: release tslist */ + release_lid_table(lids); + return rc; +} /**************** + * Given a trust segment list tslist, walk over all paths and fill in + * the trust information for each segment. What this function does is + * to assign a trustvalue to the first segment (which is the requested key) + * of each path. * + * FIXME: We have to do more thinks here. e.g. we should never increase + * the trust value. + * + * Do not do it for duplicates. */ static int -do_check( ulong pubkeyid, int *trustlevel ) +propagate_trust( TRUST_SEG_LIST tslist ) { - int rc=0; + int i, rc; + unsigned trust; + TRUST_SEG_LIST tsl; + + for(tsl = tslist; tsl; tsl = tsl->next ) { + if( tsl->dup ) + continue; + assert( tsl->nseg ); + /* the last segment is always a ultimately trusted one, so we can + * assign a fully trust to the next one */ + i = tsl->nseg-1; + tsl->seg[i].trust = TRUST_ULTIMATE; + trust = TRUST_FULLY; + for(i-- ; i >= 0; i-- ) { + tsl->seg[i].trust = trust; + if( i > 0 ) { + /* get the trust of this pubkey */ + rc = get_ownertrust( tsl->seg[i].lid, &trust ); + if( rc ) + return rc; + } + } + } + return 0; +} + + +/**************** + * we have the pubkey record but nothing more is known + */ +static int +do_check( ulong pubkeyid, unsigned *trustlevel ) +{ + int i, rc=0; ulong rnum; TRUSTREC rec; + TRUST_SEG_LIST tsl, tsl2, tslist; + int marginal, fully; + int fully_needed = 4; + int marginal_needed = 6; + + *trustlevel = TRUST_UNDEFINED; /* verify the cache */ @@ -1294,11 +1418,64 @@ do_check( ulong pubkeyid, int *trustlevel ) if( rc ) return rc; /* error while looking for sigrec or building sigrecs */ + /* fixme: take it from the cache if it is valid */ + + /* Make a list of all possible trust-paths */ + rc = make_tsl( pubkeyid, &tslist ); + if( rc ) + return rc; + rc = propagate_trust( tslist ); + if( rc ) + return rc; + for(tsl = tslist; tsl; tsl = tsl->next ) { + if( tsl->dup ) + continue; + + log_debug("tslist segs:" ); + for(i=0; i < tsl->nseg; i++ ) + fprintf(stderr, " %lu/%02x", tsl->seg[i].lid, tsl->seg[i].trust ); + putc('\n',stderr); + } + + /* and look wether there is a trusted path. + * We only have to look at the first segment, because + * propagate_trust has investigated all other segments */ + marginal = fully = 0; + for(tsl = tslist; tsl; tsl = tsl->next ) { + if( tsl->dup ) + continue; + if( tsl->seg[0].trust == TRUST_ULTIMATE ) { + *trustlevel = TRUST_ULTIMATE; /* our own key */ + break; + } + if( tsl->seg[0].trust == TRUST_FULLY ) { + marginal++; + fully++; + } + else if( tsl->seg[0].trust == TRUST_MARGINAL ) + marginal++; + + if( fully >= fully_needed ) { + *trustlevel = TRUST_FULLY; + break; + } + } + if( !tsl && marginal >= marginal_needed ) + *trustlevel = TRUST_MARGINAL; + + /* cache the tslist */ + if( last_trust_web_key ) { + for( tsl = last_trust_web_tslist; tsl; tsl = tsl2 ) { + tsl2 = tsl->next; + m_free(tsl); + } + } + last_trust_web_key = pubkeyid; + last_trust_web_tslist = tslist; return 0; } - /********************************************************* **************** API Interface ************************ *********************************************************/ @@ -1375,10 +1552,10 @@ init_trustdb( int level ) * is not necessary to check this if we use a local pubring. Hmmmm. */ int -check_trust( PKT_public_cert *pkc, int *r_trustlevel ) +check_trust( PKT_public_cert *pkc, unsigned *r_trustlevel ) { TRUSTREC rec; - int trustlevel = TRUST_UNKNOWN; + unsigned trustlevel = TRUST_UNKNOWN; int rc=0; if( DBG_TRUST ) @@ -1409,10 +1586,6 @@ check_trust( PKT_public_cert *pkc, int *r_trustlevel ) log_error("check_trust: do_check failed: %s\n", g10_errstr(rc)); return rc; } - if( !rec.r.pubkey.ownertrust ) - trustlevel = TRUST_UNDEFINED; - else - trustlevel = TRUST_EXPIRED; leave: @@ -1423,29 +1596,109 @@ check_trust( PKT_public_cert *pkc, int *r_trustlevel ) } + + +/**************** + * Enumerate all keys, which are needed to build all trust paths for + * the given key. This function dies not return the key itself or + * the ultimate key. + * + * 1) create a void pointer and initialize it to NULL + * 2) pass this void pointer by reference to this function. + * Set lid to the key you want to enumerate and pass it by reference. + * 3) call this function as long as it does not return -1 + * to indicate EOF. LID does contain the next key used to build the web + * 4) Always call this function a last time with LID set to NULL, + * so that it can free it's context. + */ int -get_ownertrust( PKT_public_cert *pkc, int *r_otrust ) +enum_trust_web( void **context, ulong *lid ) +{ + ENUM_TRUST_WEB_CONTEXT *c = *context; + + if( !c ) { /* make a new context */ + c = m_alloc_clear( sizeof *c ); + *context = c; + if( *lid != last_trust_web_key ) + log_bug("enum_trust_web: nyi\n"); + c->tsl = last_trust_web_tslist; + c->index = 1; + } + + if( !lid ) { /* free the context */ + m_free( c ); + *context = NULL; + return 0; + } + + while( c->tsl ) { + if( !c->tsl->dup && c->index < c->tsl->nseg-1 ) { + *lid = c->tsl->seg[c->index].lid; + c->index++; + return 0; + } + c->index = 1; + c->tsl = c->tsl->next; + } + return -1; /* eof */ +} + + +/**************** + * Return the assigned ownertrust value for the given LID + */ +int +get_ownertrust( ulong lid, unsigned *r_otrust ) { TRUSTREC rec; - int rc; - /* get the pubkey record */ + if( read_record( lid, &rec ) ) { + log_error("get_ownertrust: read record failed\n"); + return G10ERR_TRUSTDB; + } + if( r_otrust ) + *r_otrust = rec.r.pubkey.ownertrust; + return 0; +} + +int +keyid_from_trustdb( ulong lid, u32 *keyid ) +{ + TRUSTREC rec; + + if( read_record( lid, &rec ) ) { + log_error("keyid_from_trustdb: read record failed\n"); + return G10ERR_TRUSTDB; + } + if( keyid ) { + keyid[0] = rec.r.pubkey.keyid[0]; + keyid[1] = rec.r.pubkey.keyid[1]; + } + return 0; +} + + +int +query_trust_record( PKT_public_cert *pkc ) +{ + TRUSTREC rec; + int rc=0; + if( pkc->local_id ) { if( read_record( pkc->local_id, &rec ) ) { - log_error("get_ownertrust: read record failed\n"); + log_error("query_trust_record: read record failed\n"); return G10ERR_TRUSTDB; } } else { /* no local_id: scan the trustdb */ if( (rc=scan_record_by_pkc( pkc, &rec, 2 )) && rc != -1 ) { - log_error("get_ownertrust: scan_record_by_pkc(2) failed: %s\n", + log_error("query_trust_record: scan_record_by_pkc(2) failed: %s\n", g10_errstr(rc)); return rc; } else if( rc == -1 ) return rc; } - *r_otrust = rec.r.pubkey.ownertrust; return 0; } @@ -1494,23 +1747,23 @@ insert_trust_record( PKT_public_cert *pkc ) int -update_trust_record( PKT_public_cert *pkc, int new_trust ) +update_ownertrust( ulong lid, unsigned new_trust ) { TRUSTREC rec; - ulong recnum; - - assert( pkc->local_id ); - - if( read_record( pkc->local_id, &rec ) ) { - log_error("update_trust_record: read failed\n"); + if( read_record( lid, &rec ) ) { + log_error("update_ownertrust: read failed\n"); return G10ERR_TRUSTDB; } /* check keyid, fingerprint etc ? */ + if( rec.rectype != 2 ) { + log_error("update_ownertrust: invalid record type\n"); + return G10ERR_TRUSTDB; + } - rec.r.pubkey.ownertrust = 0; - if( write_record( recnum, &rec ) ) { - log_error("insert_trust_record: write failed\n"); + rec.r.pubkey.ownertrust = new_trust; + if( write_record( lid, &rec ) ) { + log_error("update_ownertrust: write failed\n"); return G10ERR_TRUSTDB; } diff --git a/g10/trustdb.h b/g10/trustdb.h index 75ead66bd..ee604de1a 100644 --- a/g10/trustdb.h +++ b/g10/trustdb.h @@ -36,9 +36,13 @@ void list_trustdb(const char *username); void list_trust_path( int max_depth, const char *username ); int init_trustdb( int level ); -int check_trust( PKT_public_cert *pkc, int *r_trustlevel ); -int get_ownertrust( PKT_public_cert *pkc, int *r_otrust ); +int check_trust( PKT_public_cert *pkc, unsigned *r_trustlevel ); +int enum_trust_web( void **context, ulong *lid ); +int get_ownertrust( ulong lid, unsigned *r_otrust ); +int keyid_from_trustdb( ulong lid, u32 *keyid ); +int query_trust_record( PKT_public_cert *pkc ); int insert_trust_record( PKT_public_cert *pkc ); +int update_ownertrust( ulong lid, unsigned new_trust ); int verify_private_data(void); int sign_private_data(void); diff --git a/include/iobuf.h b/include/iobuf.h index e381445a5..81e23f267 100644 --- a/include/iobuf.h +++ b/include/iobuf.h @@ -54,7 +54,7 @@ struct iobuf_struct { IOBUF chain; /* next iobuf used for i/o if any (passed to filter) */ int no, subno; const char *desc; - void *opaque; /* can be used to old any information */ + void *opaque; /* can be used to hold any information */ /* this value is copied to all instances */ }; diff --git a/include/util.h b/include/util.h index a33b7f21f..fe834e1a2 100644 --- a/include/util.h +++ b/include/util.h @@ -121,7 +121,9 @@ char *stpcpy(char *a,const char *b); #ifndef HAVE_STRLWR char *strlwr(char *a); #endif - +#ifndef HAVE_STRTOUL + #define strtoul(a,b,c) ((unsigned long)strtol((a),(b),(c))) +#endif /******** some macros ************/ #ifndef STR diff --git a/mpi/longlong.h b/mpi/longlong.h index c341c3d19..c92435570 100644 --- a/mpi/longlong.h +++ b/mpi/longlong.h @@ -1,4 +1,5 @@ /* longlong.h -- definitions for mixed size 32/64 bit arithmetic. + Note: I added some stuff for use with g10 Copyright (C) 1991, 1992, 1993, 1994, 1996 Free Software Foundation, Inc. @@ -1440,6 +1441,7 @@ extern const #endif unsigned char __clz_tab[]; +#define MPI_INTERNAL_NEED_CLZ_TAB 1 #define count_leading_zeros(count, x) \ do { \ UWtype __xr = (x); \ diff --git a/mpi/mpi-bit.c b/mpi/mpi-bit.c index 864dc0236..d1f440a9a 100644 --- a/mpi/mpi-bit.c +++ b/mpi/mpi-bit.c @@ -26,6 +26,28 @@ #include "longlong.h" +#ifdef MPI_INTERNAL_NEED_CLZ_TAB +unsigned char +__clz_tab[] = +{ + 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, +}; +#endif + + + + + + + + /**************** * Return the number of bits in A. */ diff --git a/util/argparse.c b/util/argparse.c index c6c0302b9..89c873ce0 100644 --- a/util/argparse.c +++ b/util/argparse.c @@ -286,7 +286,7 @@ optfile_parse( FILE *fp, const char *filename, unsigned *lineno, else if( state == 3 ) { /* skip leading spaces of the argument */ if( !isspace(c) ) { i = 0; - keyword[i] = c; + keyword[i++] = c; state = 4; } }