diff options
Diffstat (limited to 'g10')
-rw-r--r-- | g10/ChangeLog | 17 | ||||
-rw-r--r-- | g10/Makefile.am | 2 | ||||
-rw-r--r-- | g10/armor.c | 86 | ||||
-rw-r--r-- | g10/build-packet.c | 9 | ||||
-rw-r--r-- | g10/filter.h | 1 | ||||
-rw-r--r-- | g10/getkey.c | 54 | ||||
-rw-r--r-- | g10/keyedit.c | 79 | ||||
-rw-r--r-- | g10/keygen.c | 242 | ||||
-rw-r--r-- | g10/main.h | 1 | ||||
-rw-r--r-- | g10/mainproc.c | 49 | ||||
-rw-r--r-- | g10/misc.c | 12 | ||||
-rw-r--r-- | g10/packet.h | 6 | ||||
-rw-r--r-- | g10/parse-packet.c | 13 | ||||
-rw-r--r-- | g10/plaintext.c | 37 | ||||
-rw-r--r-- | g10/revoke.c | 2 | ||||
-rw-r--r-- | g10/sig-check.c | 17 | ||||
-rw-r--r-- | g10/sign.c | 34 | ||||
-rw-r--r-- | g10/status.c | 1 | ||||
-rw-r--r-- | g10/status.h | 2 | ||||
-rw-r--r-- | g10/trustdb.c | 2 |
20 files changed, 438 insertions, 228 deletions
diff --git a/g10/ChangeLog b/g10/ChangeLog index 15fd2c81b..1e110efe4 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,20 @@ +Wed Jun 24 16:40:22 1998 Werner Koch ([email protected]) + + * armor.c (armor_filter): Now creates valid onepass_sig packets + with all detected hash algorithms. + * mainproc.c (proc_plaintext): Now uses the hash algos as specified + in the onepass_sig packets (if there are any) + +Mon Jun 22 11:54:08 1998 Werner Koch ([email protected]) + + * plaintext.c (handle_plaintext): add arg to disable outout + * mainproc.c (proc_plaintext): disable output when in sigs_only mode. + +Thu Jun 18 13:17:27 1998 Werner Koch ([email protected]) + + * keygen.c: Removed all rsa packet stuff, chnaged defaults + for key generation. + Sun Jun 14 21:28:31 1998 Werner Koch ([email protected]) * misc.c (checksum_u16): Fixed a stupid bug which caused a diff --git a/g10/Makefile.am b/g10/Makefile.am index 520a945a8..579ec6075 100644 --- a/g10/Makefile.am +++ b/g10/Makefile.am @@ -3,7 +3,7 @@ INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/intl -I../intl EXTRA_DIST = OPTIONS pubring.asc OMIT_DEPENDENCIES = zlib.h zconf.h -LDFLAGS = -rdynamic +LDFLAGS = @LDFLAGS@ @DYNLINK_LDFLAGS@ needed_libs = ../cipher/libcipher.a ../mpi/libmpi.a ../util/libutil.a noinst_PROGRAMS = gpgd diff --git a/g10/armor.c b/g10/armor.c index 49352a1eb..541ba3e76 100644 --- a/g10/armor.c +++ b/g10/armor.c @@ -100,8 +100,10 @@ static char *tail_strings[] = { }; -static fhdr_state_t find_header( fhdr_state_t state, byte *buf, - size_t *r_buflen, IOBUF a, size_t n, unsigned *r_empty); +static fhdr_state_t find_header( fhdr_state_t state, + byte *buf, size_t *r_buflen, + IOBUF a, size_t n, + unsigned *r_empty, int *r_hashes ); static void @@ -227,7 +229,7 @@ parse_hash_header( const char *line ) found |= 2; else if( !strncmp( s, "MD5", s2-s ) ) found |= 4; - else if( !strncmp( s, "MD2", s2-s ) ) + else if( !strncmp( s, "TIGER", s2-s ) ) found |= 8; else return 0; @@ -250,7 +252,7 @@ parse_hash_header( const char *line ) */ static fhdr_state_t find_header( fhdr_state_t state, byte *buf, size_t *r_buflen, - IOBUF a, size_t n, unsigned *r_empty) + IOBUF a, size_t n, unsigned *r_empty, int *r_hashes ) { int c=0, i; const char *s; @@ -319,6 +321,7 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen, if( n < buflen || c == '\n' ) { if( n && buf[0] != '\r') { /* maybe a header */ if( strchr( buf, ':') ) { /* yes */ + int hashes; if( buf[n-1] == '\r' ) buf[--n] = 0; if( opt.verbose ) { @@ -326,12 +329,15 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen, print_string( stderr, buf, n, 0 ); putc('\n', stderr); } - if( clearsig && !parse_hash_header( buf ) ) { + if( clearsig && !(hashes=parse_hash_header( buf )) ) { log_error("invalid clearsig header\n"); state = fhdrERROR; } - else + else { state = fhdrWAITHeader; + if( r_hashes ) + *r_hashes |= hashes; + } } else state = fhdrCHECKDashEscaped3; @@ -602,7 +608,8 @@ check_input( armor_filter_context_t *afx, IOBUF a ) state = fhdrHASArmor; n = DIM(afx->helpbuf); - state = find_header( state, afx->helpbuf, &n, a, afx->helplen, &emplines); + state = find_header( state, afx->helpbuf, &n, a, + afx->helplen, &emplines, &afx->hashes); switch( state ) { case fhdrNOArmor: afx->inp_checked = 1; @@ -684,7 +691,8 @@ fake_packet( armor_filter_context_t *afx, IOBUF a, /* read a new one */ n = DIM(afx->helpbuf); afx->helpidx = 0; - state = find_header( state, afx->helpbuf, &n, a, 0, &emplines ); + state = find_header( state, afx->helpbuf, &n, a, 0, + &emplines, &afx->hashes ); switch( state) { case fhdrERROR: invalid_armor(); @@ -884,7 +892,7 @@ armor_filter( void *opaque, int control, *ret_len = n; } else if( control == IOBUFCTRL_UNDERFLOW ) { - if( size < 30 ) + if( size < 15+(4*15) ) /* need space for up to 4 onepass_sigs */ BUG(); /* supplied buffer too short */ if( afx->inp_eof ) { @@ -907,27 +915,53 @@ armor_filter( void *opaque, int control, afx->helplen = 0; } else if( afx->faked ) { - /* the buffer is at least 30 bytes long, so it + unsigned hashes = afx->hashes; + /* the buffer is at least 15+n*15 bytes long, so it * is easy to construct the packets */ - /* first a onepass signature packet */ - buf[0] = 0x90; /* old packet format, type 4, 1 length byte */ - buf[1] = 13; /* length */ - buf[2] = 3; /* version */ - buf[3] = 0x01; /* sigclass 0x01 (data in canonical text mode)*/ - buf[4] = 0; /* digest algo (don't know) */ - buf[5] = 0; /* public key algo (don't know) */ - memset(buf+6, 0, 8); /* don't know the keyid */ - buf[14] = 1; /* this is the last one */ + hashes &= 1|2|4|8; + if( !hashes ) + hashes |= 4; /* default to MD 5 */ + n=0; + do { + /* first some onepass signature packets */ + buf[n++] = 0x90; /* old format, type 4, 1 length byte */ + buf[n++] = 13; /* length */ + buf[n++] = 3; /* version */ + buf[n++] = 0x01; /* sigclass 0x01 (canonical text mode)*/ + if( hashes & 1 ) { + hashes &= ~1; + buf[n++] = DIGEST_ALGO_RMD160; + } + else if( hashes & 2 ) { + hashes &= ~2; + buf[n++] = DIGEST_ALGO_SHA1; + } + else if( hashes & 4 ) { + hashes &= ~4; + buf[n++] = DIGEST_ALGO_MD5; + } + else if( hashes & 8 ) { + hashes &= ~8; + buf[n++] = DIGEST_ALGO_TIGER; + } + else + buf[n++] = 0; /* (don't know) */ + + buf[n++] = 0; /* public key algo (don't know) */ + memset(buf+n, 0, 8); /* don't know the keyid */ + n += 8; + buf[n++] = !hashes; /* last one */ + } while( hashes ); /* followed by a plaintext packet */ - buf[15] = 0xaf; /* old packet format, type 11, var length */ - buf[16] = 0; /* set the length header */ - buf[17] = 6; - buf[18] = 't'; /* canonical text mode */ - buf[19] = 0; /* namelength */ - memset(buf+20, 0, 4); /* timestamp */ - n = 24; + buf[n++] = 0xaf; /* old packet format, type 11, var length */ + buf[n++] = 0; /* set the length header */ + buf[n++] = 6; + buf[n++] = 't'; /* canonical text mode */ + buf[n++] = 0; /* namelength */ + memset(buf+n, 0, 4); /* timestamp */ + n += 4; } else if( !rc ) rc = radix64_read( afx, a, &n, buf, size ); diff --git a/g10/build-packet.c b/g10/build-packet.c index 7048ad9a8..03e152e99 100644 --- a/g10/build-packet.c +++ b/g10/build-packet.c @@ -517,6 +517,11 @@ build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type, switch( type ) { case SIGSUBPKT_SIG_CREATED: case SIGSUBPKT_PRIV_ADD_SIG: + case SIGSUBPKT_PREF_SYM: + case SIGSUBPKT_PREF_HASH: + case SIGSUBPKT_PREF_COMPR: + case SIGSUBPKT_KS_FLAGS: + case SIGSUBPKT_KEY_EXPIRE: hashed = 1; break; default: hashed = 0; break; } @@ -538,8 +543,8 @@ build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type, : m_alloc( n+2 ); } - data[n0+0] = (n >> 8) & 0xff; - data[n0+1] = n & 0xff; + data[0] = (n >> 8) & 0xff; + data[1] = n & 0xff; data[n0+2] = buflen+1; data[n0+3] = type; memcpy(data+n0+4, buffer, buflen ); diff --git a/g10/filter.h b/g10/filter.h index 72b44086a..2dc8a3e87 100644 --- a/g10/filter.h +++ b/g10/filter.h @@ -37,6 +37,7 @@ typedef struct { byte helpbuf[100]; int helpidx, helplen; unsigned empty; /* empty line counter */ + int hashes; /* detected hash algorithms */ int faked; int parse_state; int inp_checked; /* set if inp has been checked */ diff --git a/g10/getkey.c b/g10/getkey.c index 5f607ec51..c8e8ea012 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -30,6 +30,7 @@ #include "iobuf.h" #include "keydb.h" #include "options.h" +#include "main.h" #define MAX_PKC_CACHE_ENTRIES 500 @@ -595,6 +596,58 @@ compare_name( const char *uid, size_t uidlen, const char *name, int mode ) } + +/**************** + * Assume that knode points to a public key packet and keyblock is + * the entire keyblock. This function adds all relevant information from + * a selfsignature to the public key. + */ + +static void +add_stuff_from_selfsig( KBNODE keyblock, KBNODE knode ) +{ + PKT_public_cert *pkc = knode->pkt->pkt.public_cert; + PKT_signature *sig; + KBNODE k; + u32 kid[2]; + + assert( knode->pkt->pkttype == PKT_PUBLIC_CERT + || knode->pkt->pkttype == PKT_PUBKEY_SUBCERT ); + + if( pkc->version < 4 ) + return; /* this is only needed for version >=4 packets */ + + /* find the selfsignature */ + if( knode->pkt->pkttype == PKT_PUBKEY_SUBCERT ) { + k = find_kbnode( keyblock, PKT_PUBLIC_CERT ); + if( !k ) + BUG(); /* keyblock without primary key!!! */ + keyid_from_pkc( knode->pkt->pkt.public_cert, kid ); + } + else + keyid_from_pkc( pkc, kid ); + for(k=keyblock; k; k = k->next ) { + if( k->pkt->pkttype == PKT_SIGNATURE + && (sig=k->pkt->pkt.signature)->sig_class >= 0x10 + && sig->sig_class <= 0x13 + && sig->keyid[0] == kid[0] + && sig->keyid[1] == kid[1] + && sig->version > 3 ) { + /* okay this is (the first) self-signature which can be used + * fixme: Check how to handle subkey bindings + * FIXME: We should only use this if the signature is valid + * but this is time consuming - we muts provide another + * way to handle this + */ + const byte *p; + p = parse_sig_subpkt( sig->hashed_data, SIGSUBPKT_KEY_EXPIRE, NULL ); + pkc->valid_days = p? ((buffer_to_u32(p)+86399L)/86400L):0; + /* fixme: add usage etc. to pkc */ + break; + } + } +} + /**************** * Lookup a key by scanning all keyrings * mode 1 = lookup by NAME (exact) @@ -718,6 +771,7 @@ lookup( PKT_public_cert *pkc, int mode, u32 *keyid, assert( k->pkt->pkttype == PKT_PUBLIC_CERT || k->pkt->pkttype == PKT_PUBKEY_SUBCERT ); copy_public_cert( pkc, k->pkt->pkt.public_cert ); + add_stuff_from_selfsig( keyblock, k ); if( ret_keyblock ) { *ret_keyblock = keyblock; keyblock = NULL; diff --git a/g10/keyedit.c b/g10/keyedit.c index f5c95ea32..8f3f16511 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -347,7 +347,7 @@ sign_key( const char *username, STRLIST locusr ) node->pkt->pkt.user_id, NULL, skc_rover->skc, - 0x10, 0 ); + 0x10, 0, NULL, NULL ); if( rc ) { log_error("make_keysig_packet failed: %s\n", g10_errstr(rc)); goto leave; @@ -720,7 +720,9 @@ int make_keysig_packet( PKT_signature **ret_sig, PKT_public_cert *pkc, PKT_user_id *uid, PKT_public_cert *subpkc, PKT_secret_cert *skc, - int sigclass, int digest_algo ) + int sigclass, int digest_algo, + int (*mksubpkt)(PKT_signature *, void *), void *opaque + ) { PKT_signature *sig; int rc=0; @@ -763,45 +765,50 @@ make_keysig_packet( PKT_signature **ret_sig, PKT_public_cert *pkc, sig->digest_algo = digest_algo; sig->timestamp = make_timestamp(); sig->sig_class = sigclass; - - if( sig->version >= 4 ) { + if( sig->version >= 4 ) build_sig_subpkt_from_sig( sig ); - md_putc( md, sig->version ); - } - md_putc( md, sig->sig_class ); - if( sig->version < 4 ) { - u32 a = sig->timestamp; - md_putc( md, (a >> 24) & 0xff ); - md_putc( md, (a >> 16) & 0xff ); - md_putc( md, (a >> 8) & 0xff ); - md_putc( md, a & 0xff ); - } - else { - byte buf[6]; - size_t n; - md_putc( md, sig->pubkey_algo ); - md_putc( md, sig->digest_algo ); - if( sig->hashed_data ) { - n = (sig->hashed_data[0] << 8) | sig->hashed_data[1]; - md_write( md, sig->hashed_data, n+2 ); - n += 6; + if( sig->version >= 4 && mksubpkt ) + rc = (*mksubpkt)( sig, opaque ); + + if( !rc ) { + if( sig->version >= 4 ) + md_putc( md, sig->version ); + md_putc( md, sig->sig_class ); + if( sig->version < 4 ) { + u32 a = sig->timestamp; + md_putc( md, (a >> 24) & 0xff ); + md_putc( md, (a >> 16) & 0xff ); + md_putc( md, (a >> 8) & 0xff ); + md_putc( md, a & 0xff ); } - else - n = 6; - /* add some magic */ - buf[0] = sig->version; - buf[1] = 0xff; - buf[2] = n >> 24; /* hmmm, n is only 16 bit, so this is always 0 */ - buf[3] = n >> 16; - buf[4] = n >> 8; - buf[5] = n; - md_write( md, buf, 6 ); + else { + byte buf[6]; + size_t n; + + md_putc( md, sig->pubkey_algo ); + md_putc( md, sig->digest_algo ); + if( sig->hashed_data ) { + n = (sig->hashed_data[0] << 8) | sig->hashed_data[1]; + md_write( md, sig->hashed_data, n+2 ); + n += 6; + } + else + n = 6; + /* add some magic */ + buf[0] = sig->version; + buf[1] = 0xff; + buf[2] = n >> 24; /* hmmm, n is only 16 bit, so this is always 0 */ + buf[3] = n >> 16; + buf[4] = n >> 8; + buf[5] = n; + md_write( md, buf, 6 ); - } - md_final(md); + } + md_final(md); - rc = complete_sig( sig, skc, md ); + rc = complete_sig( sig, skc, md ); + } md_close( md ); if( rc ) diff --git a/g10/keygen.c b/g10/keygen.c index 21c388bfc..b79f9b9ea 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -35,11 +35,6 @@ #include "i18n.h" -#if 0 - #define ENABLE_RSA_KEYGEN 1 -#endif - - static void write_uid( KBNODE root, const char *s ) { @@ -54,6 +49,65 @@ write_uid( KBNODE root, const char *s ) } + +static int +add_key_expire( PKT_signature *sig, void *opaque ) +{ + PKT_secret_cert *skc = opaque; + byte buf[8]; + u32 u; + + if( skc->valid_days ) { + u = skc->valid_days * 86400L; + buf[0] = (u >> 24) & 0xff; + buf[1] = (u >> 16) & 0xff; + buf[2] = (u >> 8) & 0xff; + buf[3] = u & 0xff; + build_sig_subpkt( sig, SIGSUBPKT_KEY_EXPIRE, buf, 4 ); + } + + return 0; +} + + +/**************** + * Add preference to the self signature packet. + * This is only called for packets with version > 3. + */ +static int +add_prefs( PKT_signature *sig, void *opaque ) +{ + byte buf[8]; + + add_key_expire( sig, opaque ); + + buf[0] = CIPHER_ALGO_BLOWFISH; + buf[1] = CIPHER_ALGO_CAST5; + build_sig_subpkt( sig, SIGSUBPKT_PREF_SYM, buf, 2 ); + + buf[0] = DIGEST_ALGO_RMD160; + buf[1] = DIGEST_ALGO_SHA1; + buf[2] = DIGEST_ALGO_TIGER; + buf[3] = DIGEST_ALGO_MD5; + build_sig_subpkt( sig, SIGSUBPKT_PREF_HASH, buf, 4 ); + + buf[0] = 2; + buf[1] = 1; + build_sig_subpkt( sig, SIGSUBPKT_PREF_COMPR, buf, 2 ); + + buf[0] = 0x80; /* no modify - It is reasonable that a key holder + * has the possibility to reject signatures from users + * who are known to sign everything without any + * validation - so a signed key should be send + * to the holder who in turn can put it on a keyserver + */ + build_sig_subpkt( sig, SIGSUBPKT_KS_FLAGS, buf, 1 ); + + return 0; +} + + + static int write_selfsig( KBNODE root, KBNODE pub_root, PKT_secret_cert *skc ) { @@ -79,7 +133,8 @@ write_selfsig( KBNODE root, KBNODE pub_root, PKT_secret_cert *skc ) pkc = node->pkt->pkt.public_cert; /* and make the signature */ - rc = make_keysig_packet( &sig, pkc, uid, NULL, skc, 0x13, 0 ); + rc = make_keysig_packet( &sig, pkc, uid, NULL, skc, 0x13, 0, + add_prefs, skc ); if( rc ) { log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) ); return rc; @@ -119,7 +174,8 @@ write_keybinding( KBNODE root, KBNODE pub_root, PKT_secret_cert *skc ) BUG(); /* and make the signature */ - rc = make_keysig_packet( &sig, pkc, NULL, subpkc, skc, 0x18, 0 ); + rc = make_keysig_packet( &sig, pkc, NULL, subpkc, skc, 0x18, 0, + add_key_expire, skc ); if( rc ) { log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) ); return rc; @@ -134,7 +190,7 @@ write_keybinding( KBNODE root, KBNODE pub_root, PKT_secret_cert *skc ) static int -gen_elg(unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek, +gen_elg(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek, STRING2KEY *s2k, PKT_secret_cert **ret_skc, u16 valid_days, int version ) { @@ -146,7 +202,8 @@ gen_elg(unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek, MPI skey[4]; MPI *factors; - rc = pubkey_generate( PUBKEY_ALGO_ELGAMAL, nbits, skey, &factors ); + assert( is_ELGAMAL(algo) ); + rc = pubkey_generate( algo, nbits, skey, &factors ); if( rc ) { log_error("pubkey_generate failed: %s\n", g10_errstr(rc) ); return rc; @@ -157,7 +214,7 @@ gen_elg(unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek, skc->timestamp = pkc->timestamp = make_timestamp(); skc->version = pkc->version = version; skc->valid_days = pkc->valid_days = valid_days; - skc->pubkey_algo = pkc->pubkey_algo = PUBKEY_ALGO_ELGAMAL; + skc->pubkey_algo = pkc->pubkey_algo = algo; pkc->pkey[0] = mpi_copy( skey[0] ); pkc->pkey[1] = mpi_copy( skey[1] ); pkc->pkey[2] = mpi_copy( skey[2] ); @@ -203,73 +260,6 @@ gen_elg(unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek, } - -#ifdef ENABLE_RSA_KEYGEN -static int -gen_rsa(unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek, - STRING2KEY *s2k, PKT_secret_cert **ret_skc, u16 valid_days ) -{ - int rc; - PACKET *pkt; - PKT_secret_cert *skc; - PKT_public_cert *pkc; - RSA_public_key pk; - RSA_secret_key sk; - - rsa_generate( &pk, &sk, nbits ); - - skc = m_alloc_clear( sizeof *skc ); - pkc = m_alloc_clear( sizeof *pkc ); - skc->timestamp = pkc->timestamp = make_timestamp(); - skc->valid_days = pkc->valid_days = valid_days; - skc->pubkey_algo = pkc->pubkey_algo = PUBKEY_ALGO_RSA; - memset(&pkc->mfx, 0, sizeof pkc->mfx); - pkc->d.rsa.rsa_n = pk.n; - pkc->d.rsa.rsa_e = pk.e; - skc->d.rsa.rsa_n = sk.n; - skc->d.rsa.rsa_e = sk.e; - skc->d.rsa.rsa_d = sk.d; - skc->d.rsa.rsa_p = sk.p; - skc->d.rsa.rsa_q = sk.q; - skc->d.rsa.rsa_u = sk.u; - skc->d.rsa.csum = checksum_mpi_counted_nbits( skc->d.rsa.rsa_d ); - skc->d.rsa.csum += checksum_mpi_counted_nbits( skc->d.rsa.rsa_p ); - skc->d.rsa.csum += checksum_mpi_counted_nbits( skc->d.rsa.rsa_q ); - skc->d.rsa.csum += checksum_mpi_counted_nbits( skc->d.rsa.rsa_u ); - - if( ret_skc ) /* not a subkey: return an unprotected version of the skc */ - *ret_skc = copy_secret_cert( NULL, skc ); - - if( dek ) { - skc->d.rsa.is_protected = 1; - skc->d.rsa.protect_algo = CIPHER_ALGO_BLOWFISH; - randomize_buffer( skc->d.rsa.protect.blowfish.iv, 8, 1); - skc->d.rsa.csum += checksum_counted_nbits( - skc->d.rsa.protect.blowfish.iv, 8 ); - rc = protect_secret_key( skc, dek ); - if( rc ) { - log_error("protect_secret_key failed: %s\n", g10_errstr(rc) ); - free_public_cert(pkc); - free_secret_cert(skc); - return rc; - } - } - - pkt = m_alloc_clear(sizeof *pkt); - pkt->pkttype = ret_skc ? PKT_PUBLIC_CERT : PKT_PUBKEY_SUBCERT; - pkt->pkt.public_cert = pkc; - add_kbnode(pub_root, new_kbnode( pkt )); - - pkt = m_alloc_clear(sizeof *pkt); - pkt->pkttype = ret_skc ? PKT_SECRET_CERT : PKT_SECKEY_SUBCERT; - pkt->pkt.secret_cert = skc; - add_kbnode(sec_root, new_kbnode( pkt )); - - return rc; -} -#endif /*ENABLE_RSA_KEYGEN*/ - - /**************** * Generate a DSA key */ @@ -298,15 +288,12 @@ gen_dsa(unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek, pkc = m_alloc_clear( sizeof *pkc ); skc->timestamp = pkc->timestamp = make_timestamp(); skc->version = pkc->version = 4; - /* valid days are not stored in the packet, but it is - * used here to put it into the signature. - */ skc->valid_days = pkc->valid_days = valid_days; skc->pubkey_algo = pkc->pubkey_algo = PUBKEY_ALGO_DSA; - pkc->pkey[0] = skey[0]; - pkc->pkey[1] = skey[1]; - pkc->pkey[2] = skey[2]; - pkc->pkey[3] = skey[3]; + pkc->pkey[0] = mpi_copy( skey[0] ); + pkc->pkey[1] = mpi_copy( skey[1] ); + pkc->pkey[2] = mpi_copy( skey[2] ); + pkc->pkey[3] = mpi_copy( skey[3] ); skc->skey[0] = skey[0]; skc->skey[1] = skey[1]; skc->skey[2] = skey[2]; @@ -317,7 +304,7 @@ gen_dsa(unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek, skc->csum = checksum_mpi_counted_nbits( skc->skey[4] ); if( ret_skc ) /* not a subkey: return an unprotected version of the skc */ - *ret_skc = copy_secret_cert( NULL, skc ); + *ret_skc = copy_secret_cert( NULL, skc ); if( dek ) { skc->protect.algo = dek->algo; @@ -383,47 +370,52 @@ check_valid_days( const char *s ) } +/**************** + * Returns o to create both a DSA and a ElGamal key. + */ static int -ask_algo( int *ret_v4 ) +ask_algo( int *ret_v4, int addmode ) { char *answer; int algo; - tty_printf(_("Please select the algorithm to use:\n" - " (1) ElGamal is the suggested one.\n" - " (2) ElGamal using v4 packets (OpenPGP)\n" - " (3) DSA can only be used for signatures.\n")); - #ifdef ENABLE_RSA_KEYGEN - tty_printf(_(" (4) RSA cannot be used in the U.S.\n")); - #endif + tty_printf(_("Please select what kind of key you want:\n")); + if( !addmode ) + tty_printf(_(" (%d) DSA and ElGamal (default)\n"), 1 ); + tty_printf( _(" (%d) ElGamal (sign and encrypt)\n"), 2 ); + tty_printf( _(" (%d) ElGamal (encrypt only)\n"), 3 ); + tty_printf( _(" (%d) DSA (sign only)\n"), 4 ); + tty_printf( _(" (%d) ElGamal in a v3 packet\n"), 5 ); - *ret_v4 = 0; + *ret_v4 = 1; for(;;) { - #ifdef ENABLE_RSA_KEYGEN - answer = tty_get(_("Your selection? (1,2,3,4) ")); - #else - answer = tty_get(_("Your selection? (1,2,3) ")); - #endif + answer = tty_get(_("Your selection? ")); tty_kill_prompt(); algo = *answer? atoi(answer): 1; m_free(answer); - if( algo == 1 || algo == 2 ) { - if( algo == 2 ) - *ret_v4 = 1; + if( algo == 1 && !addmode ) { + algo = 0; /* create both keys */ + break; + } + else if( algo == 2 ) { algo = PUBKEY_ALGO_ELGAMAL; break; } else if( algo == 3 ) { - *ret_v4 = 1; - algo = PUBKEY_ALGO_DSA; + algo = PUBKEY_ALGO_ELGAMAL_E; break; } - #ifdef ENABLE_RSA_KEYGEN else if( algo == 4 ) { - algo = PUBKEY_ALGO_RSA; + algo = PUBKEY_ALGO_DSA; + break; + } + else if( algo == 5 ) { + algo = PUBKEY_ALGO_ELGAMAL_E; + *ret_v4 = 0; break; } - #endif + else + tty_printf(_("Invalid selection.\n")); } return algo; } @@ -703,13 +695,9 @@ do_create( int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, "network and the disks) during the prime generation; this gives the random\n" "number generator a better chance to gain enough entropy.\n") ); - if( algo == PUBKEY_ALGO_ELGAMAL ) - rc = gen_elg(nbits, pub_root, sec_root, dek, s2k, + if( algo == PUBKEY_ALGO_ELGAMAL || algo == PUBKEY_ALGO_ELGAMAL_E ) + rc = gen_elg(algo, nbits, pub_root, sec_root, dek, s2k, skc, valid_days, v4_packet? 4:3 ); - #ifdef ENABLE_RSA_KEYGEN - else if( algo == PUBKEY_ALGO_RSA ) - rc = gen_rsa(nbits, pub_root, sec_root, dek, s2k, skc, valid_days ); - #endif else if( algo == PUBKEY_ALGO_DSA ) rc = gen_dsa(nbits, pub_root, sec_root, dek, s2k, skc, valid_days); else @@ -745,13 +733,19 @@ generate_keypair() int algo; int ndays; int v4; + int both = 0; if( opt.batch || opt.answer_yes || opt.answer_no ) { log_error(_("Key generation can only be used in interactive mode\n")); return; } - algo = ask_algo( &v4 ); + algo = ask_algo( &v4, 0 ); + if( !algo ) { + algo = PUBKEY_ALGO_ELGAMAL; + both = 1; + tty_printf(_("DSA keypair will have 1024 bits.\n")); + } nbits = ask_keysize( algo ); ndays = ask_valid_days(); uid = ask_user_id(); @@ -774,7 +768,12 @@ generate_keypair() pub_root = make_comment_node("#"); delete_kbnode(pub_root); sec_root = make_comment_node("#"); delete_kbnode(sec_root); - rc = do_create( algo, nbits, pub_root, sec_root, dek, s2k, &skc, ndays, v4); + if( both ) + rc = do_create( PUBKEY_ALGO_DSA, 1024, pub_root, sec_root, + dek, s2k, &skc, ndays, 1); + else + rc = do_create( algo, nbits, pub_root, sec_root, + dek, s2k, &skc, ndays, v4); if( !rc ) write_uid(pub_root, uid ); if( !rc ) @@ -784,6 +783,16 @@ generate_keypair() if( !rc ) rc = write_selfsig(sec_root, pub_root, skc); + if( both ) { + rc = do_create( algo, nbits, pub_root, sec_root, + dek, s2k, NULL, ndays, 1 ); + if( !rc ) + rc = write_keybinding(pub_root, pub_root, skc); + if( !rc ) + rc = write_keybinding(sec_root, pub_root, skc); + } + + if( !rc ) { KBPOS pub_kbpos; KBPOS sec_kbpos; @@ -958,7 +967,8 @@ generate_subkeypair( const char *username ) goto leave; - algo = ask_algo( &v4 ); + algo = ask_algo( &v4, 1 ); + assert(algo); nbits = ask_keysize( algo ); ndays = ask_valid_days(); diff --git a/g10/main.h b/g10/main.h index 0b30084e3..c50a07147 100644 --- a/g10/main.h +++ b/g10/main.h @@ -50,6 +50,7 @@ u16 checksum_u16( unsigned n ); u16 checksum( byte *p, unsigned n ); u16 checksum_mpi( MPI a ); u16 checksum_mpi_counted_nbits( MPI a ); +u32 buffer_to_u32( const byte *buffer ); /*-- encode.c --*/ int encode_symmetric( const char *filename ); diff --git a/g10/mainproc.c b/g10/mainproc.c index a807f85d9..a69217a3a 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -232,25 +232,42 @@ static void proc_plaintext( CTX c, PACKET *pkt ) { PKT_plaintext *pt = pkt->pkt.plaintext; - int rc; + int any, rc; + KBNODE n; if( opt.verbose ) log_info("original file name='%.*s'\n", pt->namelen, pt->name); free_md_filter_context( &c->mfx ); - /* FIXME: take the digest algo(s) to use from the - * onepass_sig packet (if we have these) - * And look at the sigclass to check whether we should use the - * textmode filter (sigclass 0x01) + /* fixme: look at the sigclass to check whether we should use the + * textmode filter (sigclass 0x01) */ - c->mfx.md = md_open( DIGEST_ALGO_RMD160, 0); - /*md_start_debug(c->mfx.md, "proc_plaintext");*/ - md_enable( c->mfx.md, DIGEST_ALGO_SHA1 ); - md_enable( c->mfx.md, DIGEST_ALGO_MD5 ); - if( !check_digest_algo(DIGEST_ALGO_TIGER) ) - md_enable( c->mfx.md, DIGEST_ALGO_TIGER ); - rc = handle_plaintext( pt, &c->mfx ); + c->mfx.md = md_open( 0, 0); + any = 0; + for(n=c->list; n; n = n->next ) { + if( n->pkt->pkttype == PKT_ONEPASS_SIG + && n->pkt->pkt.onepass_sig->digest_algo ) { + md_enable( c->mfx.md, n->pkt->pkt.onepass_sig->digest_algo ); + any = 1; + } + } + if( !any ) { /* no onepass sig packet: enable all algos */ + md_enable( c->mfx.md, DIGEST_ALGO_RMD160 ); + md_enable( c->mfx.md, DIGEST_ALGO_SHA1 ); + md_enable( c->mfx.md, DIGEST_ALGO_MD5 ); + } + if( c->mfx.md ) { + m_check(c->mfx.md); + if( c->mfx.md->list ) + m_check( c->mfx.md->list ); + } + rc = handle_plaintext( pt, &c->mfx, c->sigs_only ); if( rc ) log_error( "handle plaintext failed: %s\n", g10_errstr(rc)); + if( c->mfx.md ) { + m_check(c->mfx.md); + if( c->mfx.md->list ) + m_check( c->mfx.md->list ); + } free_packet(pkt); c->last_was_session_key = 0; } @@ -312,6 +329,12 @@ do_check_sig( CTX c, KBNODE node, int *is_selfsig ) if( (rc=check_digest_algo(algo)) ) return rc; + if( c->mfx.md ) { + m_check(c->mfx.md); + if( c->mfx.md->list ) + m_check( c->mfx.md->list ); + } + if( sig->sig_class == 0x00 ) { if( c->mfx.md ) md = md_copy( c->mfx.md ); @@ -792,7 +815,7 @@ check_sig_and_print( CTX c, KBNODE node ) tstr = asctime(localtime (&stamp)); astr = pubkey_algo_to_string( sig->pubkey_algo ); log_info(_("Signature made %.*s using %s key ID %08lX\n"), - strlen(tstr)-1, tstr, astr? astr: "?", (ulong)sig->keyid[1] ); + (int)strlen(tstr)-1, tstr, astr? astr: "?", (ulong)sig->keyid[1] ); rc = do_check_sig(c, node, NULL ); if( !rc || rc == G10ERR_BAD_SIGN ) { diff --git a/g10/misc.c b/g10/misc.c index 0c2b6ac4a..470307363 100644 --- a/g10/misc.c +++ b/g10/misc.c @@ -152,3 +152,15 @@ checksum_mpi_counted_nbits( MPI a ) return csum; } + +u32 +buffer_to_u32( const byte *buffer ) +{ + unsigned long a; + a = *buffer << 24; + a |= buffer[1] << 16; + a |= buffer[2] << 8; + a |= buffer[3]; + return a; +} + diff --git a/g10/packet.h b/g10/packet.h index 4f04e1ae4..c928cf46d 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -276,7 +276,7 @@ int decrypt_data( PKT_encrypted *ed, DEK *dek ); int encrypt_data( PKT_encrypted *ed, DEK *dek ); /*-- plaintext.c --*/ -int handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx ); +int handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,int nooutput); int ask_for_detached_datafile( md_filter_context_t *mfx, const char *inname ); /*-- comment.c --*/ @@ -286,6 +286,8 @@ int write_comment( IOBUF out, const char *s ); int make_keysig_packet( PKT_signature **ret_sig, PKT_public_cert *pkc, PKT_user_id *uid, PKT_public_cert *subpkc, PKT_secret_cert *skc, - int sigclass, int digest_algo ); + int sigclass, int digest_algo, + int (*mksubpkt)(PKT_signature *, void *), + void *opaque ); #endif /*G10_PACKET_H*/ diff --git a/g10/parse-packet.c b/g10/parse-packet.c index ba26089c5..bf26b7a39 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -32,6 +32,7 @@ #include "memory.h" #include "filter.h" #include "options.h" +#include "main.h" static int mpi_print_mode = 0; static int list_mode = 0; @@ -85,16 +86,6 @@ read_32(IOBUF inp) return a; } -static unsigned long -buffer_to_u32( const byte *buffer ) -{ - unsigned long a; - a = *buffer << 24; - a |= buffer[1] << 16; - a |= buffer[2] << 8; - a |= buffer[3]; - return a; -} int set_packet_list_mode( int mode ) @@ -622,6 +613,8 @@ parse_sig_subpkt( const byte *buffer, sigsubpkttype_t reqtype, size_t *ret_n ) *ret_n = n; switch( type ) { case SIGSUBPKT_SIG_CREATED: + case SIGSUBPKT_SIG_EXPIRE: + case SIGSUBPKT_KEY_EXPIRE: if( n < 4 ) break; return buffer; diff --git a/g10/plaintext.c b/g10/plaintext.c index cdf4fe2a2..161db58d4 100644 --- a/g10/plaintext.c +++ b/g10/plaintext.c @@ -40,16 +40,18 @@ * bytes from the plaintext. */ int -handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx ) +handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx, int nooutput ) { - char *fname; + char *fname = NULL; FILE *fp = NULL; int rc = 0; int c; int convert = pt->mode == 't'; /* create the filename as C string */ - if( opt.outfile ) { + if( nooutput ) + ; + else if( opt.outfile ) { fname = m_alloc( strlen( opt.outfile ) + 1); strcpy(fname, opt.outfile ); } @@ -59,14 +61,16 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx ) fname[pt->namelen] = 0; } - if( !*fname || (*fname=='-' && !fname[1])) { + if( nooutput ) + ; + else if( !*fname || (*fname=='-' && !fname[1])) { /* no filename or "-" given; write to stdout */ fp = stdout; } else if( overwrite_filep( fname ) ) goto leave; - if( fp ) + if( fp || nooutput ) ; else if( !(fp = fopen(fname,"wb")) ) { log_error("Error creating '%s': %s\n", fname, strerror(errno) ); @@ -86,10 +90,13 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx ) md_putc(mfx->md, c ); if( convert && c == '\r' ) continue; /* FIXME: this hack is too simple */ - if( putc( c, fp ) == EOF ) { - log_error("Error writing to '%s': %s\n", fname, strerror(errno) ); - rc = G10ERR_WRITE_FILE; - goto leave; + if( fp ) { + if( putc( c, fp ) == EOF ) { + log_error("Error writing to '%s': %s\n", + fname, strerror(errno) ); + rc = G10ERR_WRITE_FILE; + goto leave; + } } } } @@ -99,11 +106,13 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx ) md_putc(mfx->md, c ); if( convert && c == '\r' ) continue; /* FIXME: this hack is too simple */ - if( putc( c, fp ) == EOF ) { - log_error("Error writing to '%s': %s\n", - fname, strerror(errno) ); - rc = G10ERR_WRITE_FILE; - goto leave; + if( fp ) { + if( putc( c, fp ) == EOF ) { + log_error("Error writing to '%s': %s\n", + fname, strerror(errno) ); + rc = G10ERR_WRITE_FILE; + goto leave; + } } } iobuf_clear_eof(pt->buf); diff --git a/g10/revoke.c b/g10/revoke.c index cafe84de3..4819d91c2 100644 --- a/g10/revoke.c +++ b/g10/revoke.c @@ -159,7 +159,7 @@ gen_revoke( const char *uname ) /* create it */ - rc = make_keysig_packet( &sig, pkc, NULL, NULL, skc, 0x20, 0); + rc = make_keysig_packet( &sig, pkc, NULL, NULL, skc, 0x20, 0, NULL, NULL); if( rc ) { log_error("make_keysig_packet failed: %s\n", g10_errstr(rc)); goto leave; diff --git a/g10/sig-check.c b/g10/sig-check.c index 76f0aaca7..200d67048 100644 --- a/g10/sig-check.c +++ b/g10/sig-check.c @@ -31,6 +31,7 @@ #include "cipher.h" #include "main.h" #include "status.h" +#include "i18n.h" struct cmp_help_context_s { PKT_signature *sig; @@ -148,6 +149,7 @@ do_check( PKT_public_cert *pkc, PKT_signature *sig, MD_HANDLE digest ) MPI result = NULL; int rc=0; struct cmp_help_context_s ctx; + u32 cur_time; if( pkc->version == 4 && pkc->pubkey_algo == PUBKEY_ALGO_ELGAMAL_E ) { log_info("this is a PGP generated " @@ -158,6 +160,21 @@ do_check( PKT_public_cert *pkc, PKT_signature *sig, MD_HANDLE digest ) if( pkc->timestamp > sig->timestamp ) return G10ERR_TIME_CONFLICT; /* pubkey newer that signature */ + cur_time = make_timestamp(); + if( pkc->timestamp > cur_time ) { + log_info(_("public key created in future (time warp or clock problem)\n")); + return G10ERR_TIME_CONFLICT; + } + + if( pkc->valid_days && add_days_to_timestamp(pkc->timestamp, + pkc->valid_days) < cur_time ) { + log_info(_("warning: signature key expired %s\n"), strtimestamp( + add_days_to_timestamp(pkc->timestamp, + pkc->valid_days))); + write_status(STATUS_SIGEXPIRED); + } + + if( (rc=check_digest_algo(sig->digest_algo)) ) return rc; if( (rc=check_pubkey_algo(sig->pubkey_algo)) ) diff --git a/g10/sign.c b/g10/sign.c index 2505526ce..9245f67f7 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -98,7 +98,22 @@ hash_for(int pubkey_algo ) return DEFAULT_DIGEST_ALGO; } +static int +only_old_style( SKC_LIST skc_list ) +{ + SKC_LIST skc_rover = NULL; + int old_style = 0; + /* if there are only old style capable key we use the old sytle */ + for( skc_rover = skc_list; skc_rover; skc_rover = skc_rover->next ) { + PKT_secret_cert *skc = skc_rover->skc; + if( skc->pubkey_algo == PUBKEY_ALGO_RSA && skc->version < 4 ) + old_style = 1; + else + return 0; + } + return old_style; +} /**************** * Sign the files whose names are in FILENAME. @@ -131,6 +146,8 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr, SKC_LIST skc_list = NULL; SKC_LIST skc_rover = NULL; int multifile = 0; + int old_style = opt.rfc1991; + memset( &afx, 0, sizeof afx); memset( &zfx, 0, sizeof zfx); @@ -151,6 +168,8 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr, if( (rc=build_skc_list( locusr, &skc_list, 1, 1 )) ) goto leave; + if( !old_style ) + old_style = only_old_style( skc_list ); if( encrypt ) { if( (rc=build_pkc_list( remusr, &pkc_list, 2 )) ) goto leave; @@ -204,11 +223,13 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr, iobuf_push_filter( out, encrypt_filter, &efx ); } - if( opt.compress && !outfile ) + if( opt.compress && !outfile ) { + if( old_style ) + zfx.algo = 1; iobuf_push_filter( out, compress_filter, &zfx ); + } - - if( !detached && !opt.rfc1991 ) { + if( !detached && !old_style ) { /* loop over the secret certificates and build headers */ for( skc_rover = skc_list; skc_rover; skc_rover = skc_rover->next ) { PKT_secret_cert *skc; @@ -439,6 +460,7 @@ clearsign_file( const char *fname, STRLIST locusr, const char *outfile ) int rc = 0; SKC_LIST skc_list = NULL; SKC_LIST skc_rover = NULL; + int old_style = opt.rfc1991; memset( &afx, 0, sizeof afx); memset( &tfx, 0, sizeof tfx); @@ -446,6 +468,8 @@ clearsign_file( const char *fname, STRLIST locusr, const char *outfile ) if( (rc=build_skc_list( locusr, &skc_list, 1, 1 )) ) goto leave; + if( !old_style ) + old_style = only_old_style( skc_list ); /* prepare iobufs */ if( !(inp = iobuf_open(fname)) ) { @@ -469,9 +493,9 @@ clearsign_file( const char *fname, STRLIST locusr, const char *outfile ) goto leave; } - /* FIXME: This stuff is not correct if mutliple hash algos are used*/ + /* FIXME: This stuff is not correct if multiple hash algos are used*/ iobuf_writestr(out, "-----BEGIN PGP SIGNED MESSAGE-----\n" ); - if( opt.rfc1991 + if( old_style || (opt.def_digest_algo?opt.def_digest_algo:DEFAULT_DIGEST_ALGO) == DIGEST_ALGO_MD5 ) iobuf_writestr(out, "\n" ); diff --git a/g10/status.c b/g10/status.c index 2546626ba..35367fbba 100644 --- a/g10/status.c +++ b/g10/status.c @@ -53,6 +53,7 @@ write_status_text( int no, const char *text) case STATUS_LEAVE : s = "LEAVE\n"; break; case STATUS_ABORT : s = "ABORT\n"; break; case STATUS_GOODSIG: s = "GOODSIG\n"; break; + case STATUS_SIGEXPIRED: s = "SIGEXPIRED\n"; break; case STATUS_BADSIG : s = "BADSIG\n"; break; case STATUS_ERRSIG : s = "ERRSIG\n"; break; case STATUS_BADARMOR : s = "BADARMOR\n"; break; diff --git a/g10/status.h b/g10/status.h index 6b0950f5f..8b5ffdacd 100644 --- a/g10/status.h +++ b/g10/status.h @@ -33,7 +33,7 @@ #define STATUS_BADARMOR 7 #define STATUS_RSA_OR_IDEA 8 - +#define STATUS_SIGEXPIRED 9 /*-- status.c --*/ void set_status_fd( int fd ); diff --git a/g10/trustdb.c b/g10/trustdb.c index bb4942c41..6ee436128 100644 --- a/g10/trustdb.c +++ b/g10/trustdb.c @@ -1705,7 +1705,7 @@ check_trust( PKT_public_cert *pkc, unsigned *r_trustlevel ) TRUSTREC rec; unsigned trustlevel = TRUST_UNKNOWN; int rc=0; - int cur_time; + u32 cur_time; if( DBG_TRUST ) log_info("check_trust() called.\n"); |