diff --git a/TODO b/TODO index 03f4faa4b..21e51d0c1 100644 --- a/TODO +++ b/TODO @@ -4,15 +4,13 @@ this shoud espceially done for the buffer in the chain. * add a way to difference between errors and eof in the underflow/flush function of iobuf. - * filter all output read from the input when displaying it to the user. + * check that all output is filtered when displayed. * keyring editing * add trust stuff * make ttyio.c work (hide passwords etc..) - * add detached signatures * add option file handling. * use correct ASN values for DEK encoding * add checking of armor trailers - * fix the memory stuff (secure memory) * add real secure memory * look for a way to reuse RSA signatures * find a way to remove the armor filter after it @@ -24,10 +22,12 @@ * enable a SIGSEGV handler while using zlib functions * PGP writes the signature and then the file, this is not - a good idea, we can't write such files if we take input rom stdin. + a good idea, we can't write such files if we take input from stdin. So the solution will: accept such packet, but write signature the corret way: first the data and then the signature[s] this is much easier to check, also we must read the entire data before we can check wether we have the pubkey or not. The one-pass signature packets should be implemented to avoid this. + * compress does not work always! + diff --git a/cipher/elgamal.c b/cipher/elgamal.c index a7450e068..63ec06f57 100644 --- a/cipher/elgamal.c +++ b/cipher/elgamal.c @@ -95,7 +95,7 @@ gen_k( MPI p ) if( DBG_CIPHER ) fputc('.', stderr); mpi_set_bytes( k, nbits, get_random_byte, 1 ); - mpi_set_bit( k, nbits-1 ); /* make sure it's high (needed?) */ + mpi_set_bit( k, nbits-1 ); /* make sure it's high (really needed?) */ if( mpi_cmp( k, p_1 ) >= 0 ) continue; /* is not smaller than (p-1) */ if( mpi_gcd( temp, k, p_1 ) ) @@ -136,7 +136,7 @@ elg_generate( ELG_public_key *pk, ELG_secret_key *sk, unsigned nbits ) fputc('.', stderr); mpi_set_bytes( x, nbits, get_random_byte, 1 ); /* fixme: should be 2 */ mpi_set_bit( x, nbits-1 ); /* make sure it's high (needed?) */ - } while( mpi_cmp( x, p ) >= 0 ); /* x must be samller than p */ + } while( mpi_cmp( x, p ) >= 0 ); /* x must be smaller than p */ y = mpi_alloc(nbits/BITS_PER_MPI_LIMB); mpi_powm( y, g, x, p ); diff --git a/cipher/primegen.c b/cipher/primegen.c index d69f09ac3..49ec8f659 100644 --- a/cipher/primegen.c +++ b/cipher/primegen.c @@ -98,8 +98,7 @@ gen_prime( unsigned nbits, int secret ) } if( x ) continue; /* found a multiple of a already known prime */ - if( DBG_CIPHER ) - fputc('.', stderr); + fputc('.', stderr); mpi_add_ui( prime, prime, step ); @@ -108,8 +107,7 @@ gen_prime( unsigned nbits, int secret ) mpi_powm( result, val_2, prime, prime ); if( mpi_cmp_ui(result, 2) ) continue; /* stepping (fermat test failed) */ - if( DBG_CIPHER ) - fputc('+', stderr); + fputc('+', stderr); /* perform stronger tests */ if( !is_not_prime(prime, nbits, 5, &count2 ) ) { @@ -120,8 +118,9 @@ gen_prime( unsigned nbits, int secret ) break; /* step loop, cont with a new prime */ } } + + fputc('\n', stderr); if( DBG_CIPHER ) { - fputc('\n', stderr); log_debug("performed %u simple and %u stronger tests\n", count1, count2 ); log_mpidump("found prime: ", prime ); @@ -134,8 +133,7 @@ gen_prime( unsigned nbits, int secret ) return prime; } } - if( DBG_CIPHER ) - fputc(':', stderr); /* restart with a new random value */ + fputc(':', stderr); /* restart with a new random value */ } } @@ -179,8 +177,7 @@ is_not_prime( MPI n, unsigned nbits, int steps, int *count ) if( j == k ) goto leave; } - if( DBG_CIPHER ) - fputc('+', stderr); + fputc('+', stderr); } rc = 0; /* may be a prime */ diff --git a/cipher/rsa.c b/cipher/rsa.c index a1f08457b..db82b48d7 100644 --- a/cipher/rsa.c +++ b/cipher/rsa.c @@ -157,6 +157,22 @@ rsa_generate( RSA_public_key *pk, RSA_secret_key *sk, unsigned nbits ) } +/**************** + * Test wether the secret key is valid. + * Returns: true if this is a valid key. + */ +int +rsa_check_secret_key( RSA_secret_key *sk ) +{ + int rc; + MPI temp = mpi_alloc( mpi_get_nlimbs(sk->p)*2 ); + + mpi_mul(temp, sk->p, sk->q ); + rc = mpi_cmp( temp, sk->n ); + mpi_free(temp); + return !rc; +} + /**************** diff --git a/cipher/rsa.h b/cipher/rsa.h index a9980d0bc..1b6d189bf 100644 --- a/cipher/rsa.h +++ b/cipher/rsa.h @@ -46,6 +46,7 @@ typedef struct { void rsa_free_public_key( RSA_public_key *pk ); void rsa_free_secret_key( RSA_secret_key *sk ); void rsa_generate( RSA_public_key *pk, RSA_secret_key *sk, unsigned nbits ); +int rsa_check_secret_key( RSA_secret_key *sk ); void rsa_public(MPI output, MPI input, RSA_public_key *skey ); void rsa_secret(MPI output, MPI input, RSA_secret_key *skey ); diff --git a/g10/build-packet.c b/g10/build-packet.c index 6d9957f17..25d708ceb 100644 --- a/g10/build-packet.c +++ b/g10/build-packet.c @@ -169,13 +169,13 @@ do_public_cert( IOBUF out, int ctb, PKT_public_cert *pkc ) write_16(a, pkc->valid_days ); iobuf_put(a, pkc->pubkey_algo ); if( pkc->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) { - mpi_encode(a, pkc->d.elg.p ); - mpi_encode(a, pkc->d.elg.g ); - mpi_encode(a, pkc->d.elg.y ); + mpi_write(a, pkc->d.elg.p ); + mpi_write(a, pkc->d.elg.g ); + mpi_write(a, pkc->d.elg.y ); } else if( pkc->pubkey_algo == PUBKEY_ALGO_RSA ) { - mpi_encode(a, pkc->d.rsa.rsa_n ); - mpi_encode(a, pkc->d.rsa.rsa_e ); + mpi_write(a, pkc->d.rsa.rsa_n ); + mpi_write(a, pkc->d.rsa.rsa_e ); } else { rc = G10ERR_PUBKEY_ALGO; @@ -191,6 +191,31 @@ do_public_cert( IOBUF out, int ctb, PKT_public_cert *pkc ) return rc; } + +/**************** + * Make a hash value from the public key certificate + */ +void +hash_public_cert( MD_HANDLE *md, PKT_public_cert *pkc ) +{ + PACKET pkt; + int rc = 0; + int c; + IOBUF a = iobuf_temp(); + + /* build the packet */ + init_packet(&pkt); + pkt.pkttype = PKT_PUBLIC_CERT; + pkt.pkt.public_cert = pkc; + if( (rc = build_packet( a, &pkt )) ) + log_fatal("build public_cert for hashing failed: %s\n", g10_errstr(rc)); + while( (c=iobuf_get(a)) != -1 ) + md_putchar( md, c ); + + iobuf_cancel(a); +} + + static int do_secret_cert( IOBUF out, int ctb, PKT_secret_cert *skc ) { @@ -202,48 +227,33 @@ do_secret_cert( IOBUF out, int ctb, PKT_secret_cert *skc ) write_16(a, skc->valid_days ); iobuf_put(a, skc->pubkey_algo ); if( skc->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) { - mpi_encode(a, skc->d.elg.p ); - mpi_encode(a, skc->d.elg.g ); - mpi_encode(a, skc->d.elg.y ); + mpi_write(a, skc->d.elg.p ); + mpi_write(a, skc->d.elg.g ); + mpi_write(a, skc->d.elg.y ); iobuf_put(a, skc->d.elg.protect_algo ); - skc->d.elg.calc_csum = 0; if( skc->d.elg.protect_algo ) { assert( skc->d.elg.is_protected == 1 ); assert( skc->d.elg.protect_algo == CIPHER_ALGO_BLOWFISH ); iobuf_write(a, skc->d.elg.protect.blowfish.iv, 8 ); - mpi_write_csum(a, (byte*)skc->d.elg.x, &skc->d.elg.calc_csum ); - } - else { /* not protected */ - assert( !skc->d.elg.is_protected ); - mpi_encode_csum(a, skc->d.elg.x, &skc->d.elg.calc_csum ); } - write_16(a, skc->d.elg.calc_csum ); + mpi_write(a, skc->d.elg.x ); + write_16(a, skc->d.elg.csum ); } else if( skc->pubkey_algo == PUBKEY_ALGO_RSA ) { - mpi_encode(a, skc->d.rsa.rsa_n ); - mpi_encode(a, skc->d.rsa.rsa_e ); + mpi_write(a, skc->d.rsa.rsa_n ); + mpi_write(a, skc->d.rsa.rsa_e ); iobuf_put(a, skc->d.rsa.protect_algo ); - skc->d.rsa.calc_csum = 0; if( skc->d.rsa.protect_algo ) { assert( skc->d.rsa.is_protected == 1 ); assert( skc->d.rsa.protect_algo == CIPHER_ALGO_BLOWFISH ); iobuf_write(a, skc->d.rsa.protect.blowfish.iv, 8 ); - - mpi_write_csum(a, (byte*)skc->d.rsa.rsa_d, &skc->d.rsa.calc_csum ); - mpi_write_csum(a, (byte*)skc->d.rsa.rsa_p, &skc->d.rsa.calc_csum ); - mpi_write_csum(a, (byte*)skc->d.rsa.rsa_q, &skc->d.rsa.calc_csum ); - mpi_write_csum(a, (byte*)skc->d.rsa.rsa_u, &skc->d.rsa.calc_csum ); } - else { /* Not protected: You fool you! */ - assert( !skc->d.rsa.is_protected ); - mpi_encode_csum(a, skc->d.rsa.rsa_d, &skc->d.rsa.calc_csum ); - mpi_encode_csum(a, skc->d.rsa.rsa_p, &skc->d.rsa.calc_csum ); - mpi_encode_csum(a, skc->d.rsa.rsa_q, &skc->d.rsa.calc_csum ); - mpi_encode_csum(a, skc->d.rsa.rsa_u, &skc->d.rsa.calc_csum ); - } - - write_16(a, skc->d.rsa.calc_csum ); + mpi_write(a, skc->d.rsa.rsa_d ); + mpi_write(a, skc->d.rsa.rsa_p ); + mpi_write(a, skc->d.rsa.rsa_q ); + mpi_write(a, skc->d.rsa.rsa_u ); + write_16(a, skc->d.rsa.csum ); } else { rc = G10ERR_PUBKEY_ALGO; @@ -270,11 +280,11 @@ do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc ) write_32(a, enc->keyid[1] ); iobuf_put(a,enc->pubkey_algo ); if( enc->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) { - mpi_encode(a, enc->d.elg.a ); - mpi_encode(a, enc->d.elg.b ); + mpi_write(a, enc->d.elg.a ); + mpi_write(a, enc->d.elg.b ); } else if( enc->pubkey_algo == PUBKEY_ALGO_RSA ) { - mpi_encode(a, enc->d.rsa.rsa_integer ); + mpi_write(a, enc->d.rsa.rsa_integer ); } else { rc = G10ERR_PUBKEY_ALGO; @@ -379,14 +389,14 @@ do_signature( IOBUF out, int ctb, PKT_signature *sig ) iobuf_put(a, sig->d.elg.digest_algo ); iobuf_put(a, sig->d.elg.digest_start[0] ); iobuf_put(a, sig->d.elg.digest_start[1] ); - mpi_encode(a, sig->d.elg.a ); - mpi_encode(a, sig->d.elg.b ); + mpi_write(a, sig->d.elg.a ); + mpi_write(a, sig->d.elg.b ); } else if( sig->pubkey_algo == PUBKEY_ALGO_RSA ) { iobuf_put(a, sig->d.rsa.digest_algo ); iobuf_put(a, sig->d.rsa.digest_start[0] ); iobuf_put(a, sig->d.rsa.digest_start[1] ); - mpi_encode(a, sig->d.rsa.rsa_integer ); + mpi_write(a, sig->d.rsa.rsa_integer ); } else { rc = G10ERR_PUBKEY_ALGO; diff --git a/g10/free-packet.c b/g10/free-packet.c index fa116ba62..dfd6f4b08 100644 --- a/g10/free-packet.c +++ b/g10/free-packet.c @@ -100,26 +100,15 @@ free_secret_cert( PKT_secret_cert *cert ) mpi_free( cert->d.elg.p ); mpi_free( cert->d.elg.g ); mpi_free( cert->d.elg.y ); - if( cert->d.rsa.is_protected ) - m_free( cert->d.elg.x ); - else - mpi_free( cert->d.elg.x ); + mpi_free( cert->d.elg.x ); } else if( cert->pubkey_algo == PUBKEY_ALGO_RSA ) { mpi_free( cert->d.rsa.rsa_n ); mpi_free( cert->d.rsa.rsa_e ); - if( cert->d.rsa.is_protected ) { - m_free( cert->d.rsa.rsa_d ); - m_free( cert->d.rsa.rsa_p ); - m_free( cert->d.rsa.rsa_q ); - m_free( cert->d.rsa.rsa_u ); - } - else { - mpi_free( cert->d.rsa.rsa_d ); - mpi_free( cert->d.rsa.rsa_p ); - mpi_free( cert->d.rsa.rsa_q ); - mpi_free( cert->d.rsa.rsa_u ); - } + mpi_free( cert->d.rsa.rsa_d ); + mpi_free( cert->d.rsa.rsa_p ); + mpi_free( cert->d.rsa.rsa_q ); + mpi_free( cert->d.rsa.rsa_u ); } m_free(cert); } diff --git a/g10/g10.c b/g10/g10.c index 747cba196..88bde47cc 100644 --- a/g10/g10.c +++ b/g10/g10.c @@ -124,6 +124,8 @@ main( int argc, char **argv ) { 512, "cache-all" ,0, "hold everything in memory"}, { 513, "gen-prime" , 1, "\rgenerate a prime of length n" }, { 514, "test" , 0, "\rdevelopment usage" }, + { 515, "change-passphrase", 0, "change the passphrase of your secret keyring"}, + { 515, "fingerprint", 0, "show the fingerprints"}, {0} }; ARGPARSE_ARGS pargs = { &argc, &argv, 0 }; IOBUF a; @@ -136,11 +138,14 @@ main( int argc, char **argv ) int nrings=0; armor_filter_context_t afx; const char *s; + int detached_sig = 0; opt.compress = -1; /* defaults to default compression level */ while( arg_parse( &pargs, opts) ) { switch( pargs.r_opt ) { - case 'v': opt.verbose++; break; + case 'v': opt.verbose++; + opt.list_sigs=1; + break; case 'z': opt.compress = pargs.r.ret_int; break; @@ -151,7 +156,7 @@ main( int argc, char **argv ) opt.outfile_is_stdout = 1; break; case 'e': action = action == aSign? aSignEncr : aEncr; break; - case 'b': opt.detached_sig = 1; + case 'b': detached_sig = 1; /* fall trough */ case 's': action = action == aEncr? aSignEncr : aSign; break; case 'l': /* store the local users */ @@ -171,13 +176,14 @@ main( int argc, char **argv ) case 502: opt.answer_no = 1; break; case 503: action = aKeygen; break; case 507: action = aStore; break; - case 508: opt.check_sigs = 1; break; + case 508: opt.check_sigs = 1; opt.list_sigs = 1; break; case 509: add_keyring(pargs.r.ret_str); nrings++; break; case 510: opt.debug |= pargs.r.ret_ulong; break; case 511: opt.debug = ~0; break; case 512: opt.cache_all = 1; break; case 513: action = aPrimegen; break; case 514: action = aTest; break; + case 515: opt.fingerprint = 1; break; default : pargs.err = 2; break; } } @@ -230,7 +236,7 @@ main( int argc, char **argv ) case aSign: /* sign the given file */ if( argc > 1 ) usage(1); - if( (rc = sign_file(fname, opt.detached_sig, locusr)) ) + if( (rc = sign_file(fname, detached_sig, locusr)) ) log_error("sign_file('%s'): %s\n", fname_print, g10_errstr(rc) ); break; diff --git a/g10/keydb.h b/g10/keydb.h index 21423cfbb..bd8928086 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -50,6 +50,8 @@ unsigned nbits_from_skc( PKT_secret_cert *skc ); const char *datestr_from_pkc( PKT_public_cert *pkc ); const char *datestr_from_skc( PKT_secret_cert *skc ); 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 ); diff --git a/g10/keygen.c b/g10/keygen.c index 3cbbf89e1..a4ed697c4 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -51,9 +51,44 @@ answer_is_yes( const char *s ) } +static u16 +checksum_u16( unsigned n ) +{ + u16 a; + + a = (n >> 8) & 0xff; + a |= n & 0xff; + return a; +} + +static u16 +checksum( byte *p, unsigned n ) +{ + u16 a; + + for(a=0; n; n-- ) + a += *p++; + return a; +} + +static u16 +checksum_mpi( MPI a ) +{ + u16 csum; + byte *buffer; + unsigned nbytes; + + buffer = mpi_get_buffer( a, &nbytes, NULL ); + csum = checksum_u16( nbytes*8 ); + csum += checksum( buffer, nbytes ); + m_free( buffer ); + return csum; +} + + static void -write_uid( IOBUF out, const char *s ) +write_uid( IOBUF out, const char *s, PKT_user_id **upkt ) { PACKET pkt; size_t n = strlen(s); @@ -65,13 +100,44 @@ write_uid( IOBUF out, const char *s ) strcpy(pkt.pkt.user_id->name, s); if( (rc = build_packet( out, &pkt )) ) log_error("build_packet(user_id) failed: %s\n", g10_errstr(rc) ); + if( upkt ) { + *upkt = pkt.pkt.user_id; + pkt.pkt.user_id = NULL; + } free_packet( &pkt ); } +static int +write_selfsig( IOBUF out, PKT_public_cert *pkc, PKT_user_id *uid, + PKT_secret_cert *skc ) +{ + PACKET pkt; + PKT_signature *sig; + int rc=0; + + if( opt.verbose ) + log_info("writing self signature\n"); + + rc = make_keysig_packet( &sig, pkc, uid, skc, 0x13, DIGEST_ALGO_RMD160 ); + if( rc ) { + log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) ); + return rc; + } + + pkt.pkttype = PKT_SIGNATURE; + pkt.pkt.signature = sig; + if( (rc = build_packet( out, &pkt )) ) + log_error("build_packet(signature) failed: %s\n", g10_errstr(rc) ); + free_packet( &pkt ); + return rc; +} + + #ifdef HAVE_RSA_CIPHER static int -gen_rsa(unsigned nbits, IOBUF pub_io, IOBUF sec_io) +gen_rsa(unsigned nbits, IOBUF pub_io, IOBUF sec_io, DEK *dek, + PKT_public_cert **ret_pkc, PKT_secret_cert **ret_skc ) { int rc; PACKET pkt1, pkt2; @@ -80,6 +146,9 @@ gen_rsa(unsigned nbits, IOBUF pub_io, IOBUF sec_io) RSA_public_key pk; RSA_secret_key sk; + init_packet(&pkt1); + init_packet(&pkt2); + rsa_generate( &pk, &sk, nbits ); skc = m_alloc( sizeof *skc ); @@ -96,15 +165,28 @@ gen_rsa(unsigned nbits, IOBUF pub_io, IOBUF sec_io) skc->d.rsa.rsa_p = sk.p; skc->d.rsa.rsa_q = sk.q; skc->d.rsa.rsa_u = sk.u; - skc->d.rsa.calc_csum = 0; - skc->d.rsa.is_protected = 0; /* FIXME!!! */ - skc->d.rsa.protect_algo = 0; /* should be blowfish */ - /*memcpy(skc->d.rsa.protect.blowfish.iv,"12345678", 8);*/ + skc->d.rsa.csum = checksum_mpi( skc->d.rsa.rsa_d ); + skc->d.rsa.csum += checksum_mpi( skc->d.rsa.rsa_p ); + skc->d.rsa.csum += checksum_mpi( skc->d.rsa.rsa_q ); + skc->d.rsa.csum += checksum_mpi( skc->d.rsa.rsa_u ); + if( !dek ) { + skc->d.rsa.is_protected = 0; + skc->d.rsa.protect_algo = 0; + } + else { + 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( 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) ); + goto leave; + } + } - init_packet(&pkt1); pkt1.pkttype = PKT_PUBLIC_CERT; pkt1.pkt.public_cert = pkc; - init_packet(&pkt2); pkt2.pkttype = PKT_SECRET_CERT; pkt2.pkt.secret_cert = skc; @@ -116,6 +198,10 @@ gen_rsa(unsigned nbits, IOBUF pub_io, IOBUF sec_io) log_error("build secret_cert packet failed: %s\n", g10_errstr(rc) ); goto leave; } + *ret_pkc = pkt1.pkt.public_cert; + pkt1.pkt.public_cert = NULL; + *ret_skc = pkt1.pkt.secret_cert; + pkt1.pkt.secret_cert = NULL; leave: free_packet(&pkt1); @@ -125,14 +211,19 @@ gen_rsa(unsigned nbits, IOBUF pub_io, IOBUF sec_io) #endif /*HAVE_RSA_CIPHER*/ static int -gen_elg(unsigned nbits, IOBUF pub_io, IOBUF sec_io) +gen_elg(unsigned nbits, IOBUF pub_io, IOBUF sec_io, DEK *dek, + PKT_public_cert **ret_pkc, PKT_secret_cert **ret_skc ) { int rc; PACKET pkt1, pkt2; - PKT_secret_cert *skc; + PKT_secret_cert *skc, *unprotected_skc; PKT_public_cert *pkc; ELG_public_key pk; ELG_secret_key sk; + unsigned nbytes; + + init_packet(&pkt1); + init_packet(&pkt2); elg_generate( &pk, &sk, nbits ); @@ -150,15 +241,25 @@ gen_elg(unsigned nbits, IOBUF pub_io, IOBUF sec_io) skc->d.elg.y = sk.y; skc->d.elg.x = sk.x; - skc->d.elg.calc_csum = 0; - skc->d.elg.is_protected = 0; /* FIXME!!! */ - skc->d.elg.protect_algo = 0; /* should be blowfish */ - /*memcpy(skc->d.elg.protect.blowfish.iv,"12345678", 8);*/ + skc->d.elg.csum = checksum_mpi( skc->d.elg.x ); + unprotected_skc = copy_secret_cert( NULL, skc ); + if( !dek ) { + skc->d.elg.is_protected = 0; + skc->d.elg.protect_algo = 0; + } + else { + skc->d.elg.is_protected = 0; + skc->d.elg.protect_algo = CIPHER_ALGO_BLOWFISH; + randomize_buffer(skc->d.elg.protect.blowfish.iv, 8, 1); + rc = protect_secret_key( skc, dek ); + if( rc ) { + log_error("protect_secret_key failed: %s\n", g10_errstr(rc) ); + goto leave; + } + } - init_packet(&pkt1); pkt1.pkttype = PKT_PUBLIC_CERT; pkt1.pkt.public_cert = pkc; - init_packet(&pkt2); pkt2.pkttype = PKT_SECRET_CERT; pkt2.pkt.secret_cert = skc; @@ -170,10 +271,17 @@ gen_elg(unsigned nbits, IOBUF pub_io, IOBUF sec_io) log_error("build secret_cert packet failed: %s\n", g10_errstr(rc) ); goto leave; } + *ret_pkc = pkt1.pkt.public_cert; + pkt1.pkt.public_cert = NULL; + *ret_skc = unprotected_skc; + unprotected_skc = NULL; + leave: free_packet(&pkt1); free_packet(&pkt2); + if( unprotected_skc ) + free_secret_cert( unprotected_skc ); return rc; } @@ -192,6 +300,10 @@ generate_keypair() char *uid = NULL; IOBUF pub_io = NULL; IOBUF sec_io = NULL; + PKT_public_cert *pkc = NULL; + PKT_secret_cert *skc = NULL; + PKT_user_id *upkt = NULL; + DEK *dek = NULL; int rc; int algo; const char *algo_name; @@ -301,6 +413,28 @@ generate_keypair() } } #endif + + + tty_printf( "You need a Passphrase to protect your secret key.\n\n" ); + + dek = m_alloc_secure( sizeof *dek ); + dek->algo = CIPHER_ALGO_BLOWFISH; + rc = make_dek_from_passphrase( dek , 2 ); + if( rc == -1 ) { + m_free(dek); dek = NULL; + tty_printf( + "You don't what a passphrase - this is probably a *bad* idea!\n" + "I will do it anyway. You can change your passphrase at anytime,\n" + "using this program with the option \"--change-passphrase\"\n\n" ); + } + else if( rc ) { + m_free(dek); dek = NULL; + m_free(uid); + log_error("Error getting the passphrase: %s\n", g10_errstr(rc) ); + return; + } + + /* now check wether we a are allowed to write the keyrings */ if( !(rc=overwrite_filep( pub_fname )) ) { if( !(pub_io = iobuf_create( pub_fname )) ) @@ -334,23 +468,41 @@ generate_keypair() return; } - write_comment( pub_io, "#public key created by G10 pre-release " VERSION ); write_comment( sec_io, "#secret key created by G10 pre-release " VERSION ); if( algo == PUBKEY_ALGO_ELGAMAL ) - gen_elg(nbits, pub_io, sec_io); + rc = gen_elg(nbits, pub_io, sec_io, dek, &pkc, &skc); #ifdef HAVE_RSA_CIPHER else if( algo == PUBKEY_ALGO_RSA ) - gen_rsa(nbits, pub_io, sec_io); + rc = gen_rsa(nbits, pub_io, sec_io, dek, &pkc, &skc); #endif else log_bug(NULL); - write_uid(pub_io, uid ); - write_uid(sec_io, uid ); - m_free(uid); + if( !rc ) + write_uid(pub_io, uid, &upkt ); + if( !rc ) + write_uid(sec_io, uid, NULL ); + if( !rc ) + rc = write_selfsig(pub_io, pkc, upkt, skc ); - iobuf_close(pub_io); - iobuf_close(sec_io); + if( rc ) { + iobuf_cancel(pub_io); + iobuf_cancel(sec_io); + tty_printf("Key generation failed: %s\n", g10_errstr(rc) ); + } + else { + iobuf_close(pub_io); + iobuf_close(sec_io); + tty_printf("public and secret key created and signed.\n" ); + } + if( pkc ) + free_public_cert( pkc ); + if( skc ) + free_secret_cert( skc ); + if( upkt ) + free_user_id( upkt ); + m_free(uid); + m_free(dek); } diff --git a/g10/keyid.c b/g10/keyid.c index 7453754a2..e3a16d86b 100644 --- a/g10/keyid.c +++ b/g10/keyid.c @@ -171,3 +171,110 @@ datestr_from_sig( PKT_signature *sig ) return buffer; } + +/**************** . + * Return a byte array with the fingerprint for the given PKC/SKC + * The length of the array is returned in ret_len. Caller must free + * the array. + */ +byte * +fingerprint_from_skc( PKT_secret_cert *skc, size_t *ret_len ) +{ + PKT_public_cert pkc; + byte *p; + + pkc.pubkey_algo = skc->pubkey_algo; + if( pkc.pubkey_algo == PUBKEY_ALGO_ELGAMAL ) { + pkc.timestamp = skc->timestamp; + pkc.valid_days = skc->valid_days; + pkc.pubkey_algo = skc->pubkey_algo; + pkc.d.elg.p = skc->d.elg.p; + pkc.d.elg.g = skc->d.elg.g; + pkc.d.elg.y = skc->d.elg.y; + } + else if( pkc.pubkey_algo == PUBKEY_ALGO_RSA ) { + pkc.d.rsa.rsa_n = skc->d.rsa.rsa_n; + pkc.d.rsa.rsa_e = skc->d.rsa.rsa_e; + } + p = fingerprint_from_pkc( &pkc, ret_len ); + memset(&pkc, 0, sizeof pkc); /* not really needed */ + return p; +} + +byte * +fingerprint_from_pkc( PKT_public_cert *pkc, size_t *ret_len ) +{ + byte *p, *buf, *array; + size_t len; + unsigned n; + + if( pkc->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) { + RMDHANDLE md; + const char *dp; + + md = rmd160_open(0); + + { u32 a = pkc->timestamp; + rmd160_putchar( md, a >> 24 ); + rmd160_putchar( md, a >> 16 ); + rmd160_putchar( md, a >> 8 ); + rmd160_putchar( md, a ); + } + { u16 a = pkc->valid_days; + rmd160_putchar( md, a >> 8 ); + rmd160_putchar( md, a ); + } + rmd160_putchar( md, pkc->pubkey_algo ); + p = buf = mpi_get_buffer( pkc->d.elg.p, &n, NULL ); + for( ; !*p && n; p++, n-- ) + ; + rmd160_putchar( md, n>>8); rmd160_putchar( md, n ); rmd160_write( md, p, n ); + m_free(buf); + p = buf = mpi_get_buffer( pkc->d.elg.g, &n, NULL ); + for( ; !*p && n; p++, n-- ) + ; + rmd160_putchar( md, n>>8); rmd160_putchar( md, n ); rmd160_write( md, p, n ); + m_free(buf); + p = buf = mpi_get_buffer( pkc->d.elg.y, &n, NULL ); + for( ; !*p && n; p++, n-- ) + ; + rmd160_putchar( md, n>>8); rmd160_putchar( md, n ); rmd160_write( md, p, n ); + m_free(buf); + + dp = rmd160_final(md); + array = m_alloc( 20 ); + len = 20; + memcpy(array, dp, 20 ); + rmd160_close(md); + } + else if( pkc->pubkey_algo == PUBKEY_ALGO_RSA ) { + MD5HANDLE md; + + md = md5_open(0); + p = buf = mpi_get_buffer( pkc->d.rsa.rsa_n, &n, NULL ); + for( ; !*p && n; p++, n-- ) + ; + md5_write( md, p, n ); + m_free(buf); + p = buf = mpi_get_buffer( pkc->d.rsa.rsa_e, &n, NULL ); + for( ; !*p && n; p++, n-- ) + ; + md5_write( md, p, n ); + m_free(buf); + md5_final(md); + array = m_alloc( 16 ); + len = 16; + memcpy(array, md5_read(md), 16 ); + md5_close(md); + } + else { + array = m_alloc(1); + len = 0; /* ooops */ + } + + *ret_len = len; + return array; +} + + + diff --git a/g10/mainproc.c b/g10/mainproc.c index 9418da4e4..a04b0fc1f 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -342,7 +342,7 @@ proc_plaintext( CTX c, PACKET *pkt ) printf("txt: plain text data name='%.*s'\n", pt->namelen, pt->name); free_md_filter_context( &c->mfx ); /* fixme: take the digest algo to use from the - * onpass_sig packet (if we have these) */ + * onepass_sig packet (if we have these) */ c->mfx.md = md_open(DIGEST_ALGO_RMD160, 0); result = handle_plaintext( pt, &c->mfx ); if( !result ) @@ -450,6 +450,34 @@ print_userid( PACKET *pkt ) } +static void +print_fingerprint( PKT_public_cert *pkc, PKT_secret_cert *skc ) +{ + byte *array, *p; + size_t i, n; + + p = array = skc? fingerprint_from_skc( skc, &n ) + : fingerprint_from_pkc( pkc, &n ); + printf(" Key fingerprint ="); + 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 ); + } + } + putchar('\n'); + m_free(array); +} + + /**************** * List the certificate in a user friendly way */ @@ -478,6 +506,8 @@ list_node( CTX c, NODE node ) printf( "%*s", 31, "" ); print_userid( n2->pkt ); putchar('\n'); + if( opt.fingerprint && n2 == node->child ) + print_fingerprint( pkc, NULL ); list_node(c, n2 ); } } @@ -491,18 +521,20 @@ list_node( CTX c, NODE node ) datestr_from_skc( skc ) ); n2 = node->child; if( !n2 ) - printf("ERROR: no user id!"); + printf("ERROR: no user id!\n"); else { print_userid( n2->pkt ); + putchar('\n'); + if( opt.fingerprint && n2 == node->child ) + print_fingerprint( NULL, skc ); } - putchar('\n'); } else if( node->pkt->pkttype == PKT_USER_ID ) { /* list everything under this user id */ for(n2=node->child; n2; n2 = n2->next ) list_node(c, n2 ); } - else if( node->pkt->pkttype == PKT_SIGNATURE ) { + else if( node->pkt->pkttype == PKT_SIGNATURE ) { PKT_signature *sig = node->pkt->pkt.signature; int rc2; size_t n; @@ -510,6 +542,9 @@ list_node( CTX c, NODE node ) int sigrc = ' '; assert( !node->child ); + if( !opt.list_sigs ) + return; + if( opt.check_sigs ) { switch( (rc2=do_check_sig( c, node )) ) { diff --git a/g10/options.h b/g10/options.h index 2b65db20c..a23412fc8 100644 --- a/g10/options.h +++ b/g10/options.h @@ -32,8 +32,8 @@ struct { int answer_no; /* answer no on most questions */ int check_sigs; /* check key signatures */ int cache_all; - int detached_sig; - int reserved3; + int fingerprint; /* list fingerprints */ + int list_sigs; /* list signatures */ int reserved4; int reserved5; int reserved6; diff --git a/g10/packet.h b/g10/packet.h index 5694c8a5b..57adebe5f 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -124,7 +124,6 @@ typedef struct { MPI rsa_q; /* secret second prime number */ MPI rsa_u; /* secret multiplicative inverse */ u16 csum; /* checksum */ - u16 calc_csum; /* and a place to store the calculated csum */ byte is_protected; /* The above infos are protected and must */ /* be decrypteded before use */ byte protect_algo; /* cipher used to protect the secret informations*/ @@ -142,7 +141,6 @@ typedef struct { MPI y; /* g^x mod p */ MPI x; /* secret exponent */ u16 csum; /* checksum */ - u16 calc_csum; /* and a place to store the calculated csum */ byte is_protected; /* The above infos are protected and must */ /* be decrypteded before use */ byte protect_algo; /* cipher used to protect the secret informations*/ @@ -220,6 +218,7 @@ int parse_packet( IOBUF inp, PACKET *ret_pkt); /*-- build-packet.c --*/ int build_packet( IOBUF inp, PACKET *pkt ); u32 calc_packet_length( PACKET *pkt ); +void hash_public_cert( MD_HANDLE *md, PKT_public_cert *pkc ); /*-- free-packet.c --*/ void free_pubkey_enc( PKT_pubkey_enc *enc ); @@ -238,6 +237,7 @@ int signature_check( PKT_signature *sig, MD_HANDLE *digest ); /*-- seckey-cert.c --*/ int check_secret_key( PKT_secret_cert *cert ); +int protect_secret_key( PKT_secret_cert *cert, DEK *dek ); /*-- pubkey-enc.c --*/ int get_session_key( PKT_pubkey_enc *k, DEK *dek ); @@ -256,5 +256,9 @@ int ask_for_detached_datafile( md_filter_context_t *mfx ); /*-- comment.c --*/ int write_comment( IOBUF out, const char *s ); +/*-- sign.c --*/ +int make_keysig_packet( PKT_signature **ret_sig, PKT_public_cert *pkc, + PKT_user_id *uid, PKT_secret_cert *skc, + int sigclass, int digest_algo ); #endif /*G10_PACKET_H*/ diff --git a/g10/parse-packet.c b/g10/parse-packet.c index 6aef1b4fe..5badb0ec4 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -239,8 +239,8 @@ parse_publickey( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ) k->keyid[0], k->keyid[1]); if( k->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) { n = pktlen; - k->d.elg.a = mpi_decode(inp, &n ); pktlen -=n; - k->d.elg.b = mpi_decode(inp, &n ); pktlen -=n; + k->d.elg.a = mpi_read(inp, &n, 0); pktlen -=n; + k->d.elg.b = mpi_read(inp, &n, 0 ); pktlen -=n; if( list_mode ) { printf("\telg a: "); mpi_print(stdout, k->d.elg.a, mpi_print_mode ); @@ -251,7 +251,7 @@ parse_publickey( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ) } else if( k->pubkey_algo == PUBKEY_ALGO_RSA ) { n = pktlen; - k->d.rsa.rsa_integer = mpi_decode(inp, &n ); pktlen -=n; + k->d.rsa.rsa_integer = mpi_read(inp, &n, 0 ); pktlen -=n; if( list_mode ) { printf("\trsa integer: "); mpi_print(stdout, k->d.rsa.rsa_integer, mpi_print_mode ); @@ -304,8 +304,8 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen, sig->d.elg.digest_start[0] = iobuf_get_noeof(inp); pktlen--; sig->d.elg.digest_start[1] = iobuf_get_noeof(inp); pktlen--; n = pktlen; - sig->d.elg.a = mpi_decode(inp, &n ); pktlen -=n; - sig->d.elg.b = mpi_decode(inp, &n ); pktlen -=n; + sig->d.elg.a = mpi_read(inp, &n, 0 ); pktlen -=n; + sig->d.elg.b = mpi_read(inp, &n, 0 ); pktlen -=n; if( list_mode ) { printf("\tdigest algo %d, begin of digest %02x %02x\n", sig->d.elg.digest_algo, @@ -313,7 +313,7 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen, printf("\telg a: "); mpi_print(stdout, sig->d.elg.a, mpi_print_mode ); printf("\n\telg b: "); - mpi_print(stdout, sig->d.elg.a, mpi_print_mode ); + mpi_print(stdout, sig->d.elg.b, mpi_print_mode ); putchar('\n'); } } @@ -326,7 +326,7 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen, sig->d.rsa.digest_start[0] = iobuf_get_noeof(inp); pktlen--; sig->d.rsa.digest_start[1] = iobuf_get_noeof(inp); pktlen--; n = pktlen; - sig->d.rsa.rsa_integer = mpi_decode(inp, &n ); pktlen -=n; + sig->d.rsa.rsa_integer = mpi_read(inp, &n, 0 ); pktlen -=n; if( list_mode ) { printf("\tdigest algo %d, begin of digest %02x %02x\n", sig->d.rsa.digest_algo, @@ -439,9 +439,9 @@ parse_certificate( IOBUF inp, int pkttype, unsigned long pktlen, if( algorithm == PUBKEY_ALGO_ELGAMAL ) { MPI elg_p, elg_g, elg_y; - n = pktlen; elg_p = mpi_decode(inp, &n ); pktlen -=n; - n = pktlen; elg_g = mpi_decode(inp, &n ); pktlen -=n; - n = pktlen; elg_y = mpi_decode(inp, &n ); pktlen -=n; + n = pktlen; elg_p = mpi_read(inp, &n, 0 ); pktlen -=n; + n = pktlen; elg_g = mpi_read(inp, &n, 0 ); pktlen -=n; + n = pktlen; elg_y = mpi_read(inp, &n, 0 ); pktlen -=n; if( list_mode ) { printf( "\telg p: "); mpi_print(stdout, elg_p, mpi_print_mode ); @@ -483,32 +483,24 @@ parse_certificate( IOBUF inp, int pkttype, unsigned long pktlen, else cert->d.elg.is_protected = 0; - n = pktlen; mpibuf = mpi_read(inp, &n ); pktlen -=n; assert(n>=2); - cert->d.elg.x = (MPI)mpibuf; + n = pktlen; cert->d.elg.x = mpi_read(inp, &n, 1 ); pktlen -=n; cert->d.elg.csum = read_16(inp); pktlen -= 2; - cert->d.elg.calc_csum = 0; if( list_mode ) { printf("\t[secret value x is not shown]\n" "\tchecksum: %04hx\n", cert->d.elg.csum); } - if( !cert->d.elg.is_protected ) { /* convert buffer to MPIs */ - mpibuf = (byte*)cert->d.elg.x; - cert->d.elg.calc_csum += checksum( mpibuf ); - cert->d.elg.x = mpi_decode_buffer( mpibuf ); - m_free( mpibuf ); - /*log_mpidump("elg p=", cert->d.elg.p ); - log_mpidump("elg g=", cert->d.elg.g ); - log_mpidump("elg y=", cert->d.elg.y ); - log_mpidump("elg x=", cert->d.elg.x ); */ - } + /*log_mpidump("elg p=", cert->d.elg.p ); + log_mpidump("elg g=", cert->d.elg.g ); + log_mpidump("elg y=", cert->d.elg.y ); + log_mpidump("elg x=", cert->d.elg.x ); */ } } else if( algorithm == PUBKEY_ALGO_RSA ) { MPI rsa_pub_mod, rsa_pub_exp; - n = pktlen; rsa_pub_mod = mpi_decode(inp, &n ); pktlen -=n; - n = pktlen; rsa_pub_exp = mpi_decode(inp, &n ); pktlen -=n; + n = pktlen; rsa_pub_mod = mpi_read(inp, &n, 0); pktlen -=n; + n = pktlen; rsa_pub_exp = mpi_read(inp, &n, 0 ); pktlen -=n; if( list_mode ) { printf( "\tpublic modulus n: "); mpi_print(stdout, rsa_pub_mod, mpi_print_mode ); @@ -546,43 +538,22 @@ parse_certificate( IOBUF inp, int pkttype, unsigned long pktlen, else cert->d.rsa.is_protected = 0; - n = pktlen; mpibuf = mpi_read(inp, &n ); pktlen -=n; assert(n>=2); - cert->d.rsa.rsa_d = (MPI)mpibuf; - - n = pktlen; mpibuf = mpi_read(inp, &n ); pktlen -=n; assert(n>=2); - cert->d.rsa.rsa_p = (MPI)mpibuf; - - n = pktlen; mpibuf = mpi_read(inp, &n ); pktlen -=n; assert(n>=2); - cert->d.rsa.rsa_q = (MPI)mpibuf; - - n = pktlen; mpibuf = mpi_read(inp, &n ); pktlen -=n; assert(n>=2); - cert->d.rsa.rsa_u = (MPI)mpibuf; + n = pktlen; cert->d.rsa.rsa_d = mpi_read(inp, &n, 1 ); pktlen -=n; + n = pktlen; cert->d.rsa.rsa_p = mpi_read(inp, &n, 1 ); pktlen -=n; + n = pktlen; cert->d.rsa.rsa_q = mpi_read(inp, &n, 1 ); pktlen -=n; + n = pktlen; cert->d.rsa.rsa_u = mpi_read(inp, &n, 1 ); pktlen -=n; cert->d.rsa.csum = read_16(inp); pktlen -= 2; - cert->d.rsa.calc_csum = 0; if( list_mode ) { printf("\t[secret values d,p,q,u are not shown]\n" "\tchecksum: %04hx\n", cert->d.rsa.csum); } - if( !cert->d.rsa.is_protected ) { /* convert buffer to MPIs */ - #define X(a) do { \ - mpibuf = (byte*)cert->d.rsa.rsa_##a; \ - cert->d.rsa.calc_csum += checksum( mpibuf ); \ - cert->d.rsa.rsa_##a = mpi_decode_buffer( mpibuf ); \ - m_free( mpibuf ); \ - } while(0) - X(d); - X(p); - X(q); - X(u); - #undef X - /* log_mpidump("rsa n=", cert->d.rsa.rsa_n ); - log_mpidump("rsa e=", cert->d.rsa.rsa_e ); - log_mpidump("rsa d=", cert->d.rsa.rsa_d ); - log_mpidump("rsa p=", cert->d.rsa.rsa_p ); - log_mpidump("rsa q=", cert->d.rsa.rsa_q ); - log_mpidump("rsa u=", cert->d.rsa.rsa_u ); */ - } + /* log_mpidump("rsa n=", cert->d.rsa.rsa_n ); + log_mpidump("rsa e=", cert->d.rsa.rsa_e ); + log_mpidump("rsa d=", cert->d.rsa.rsa_d ); + log_mpidump("rsa p=", cert->d.rsa.rsa_p ); + log_mpidump("rsa q=", cert->d.rsa.rsa_q ); + log_mpidump("rsa u=", cert->d.rsa.rsa_u ); */ } } else if( list_mode ) @@ -671,34 +642,9 @@ parse_trust( IOBUF inp, int pkttype, unsigned long pktlen ) 1 = "we do not trust this key's ownership" 2 = "we have marginal confidence of this key's ownership" 3 = "we completely trust this key's ownership." - /* This one (3) requires either: - * - 1 ultimately trusted signature (SIGTRUST=7) - * - COMPLETES_NEEDED completely trusted signatures (SIGTRUST=6) - * - MARGINALS_NEEDED marginally trusted signatures (SIGTRUST=5) - */ if( c & 0x80 ) "warnonly" else if( prev_packet_is_a_signature ) { - Bits 0-2 - SIGTRUST bits - Trust bits for this signature. Value is - copied directly from OWNERTRUST bits of signer: - 000 - undefined, or uninitialized trust. - 001 - unknown - 010 - We do not trust this signature. - 011 - reserved - 100 - reserved - 101 - We reasonably trust this signature. - 110 - We completely trust this signature. - 111 - ultimately trusted signature (from the owner of the ring) - Bit 6 - CHECKED bit - This means that the key checking pass (pgp -kc, - also invoked automatically whenever keys are added to the - keyring) has tested this signature and found it good. If - this bit is not set, the maintenance pass considers this - signature untrustworthy. - Bit 7 - CONTIG bit - Means this signature leads up a contiguous trusted - certification path all the way back to the ultimately- - trusted keyring owner, where the buck stops. This bit is derived - from other trust packets. It is currently not used for anything - in PGP. } #endif } diff --git a/g10/passphrase.c b/g10/passphrase.c index 5a45f49bd..4e5e57bb3 100644 --- a/g10/passphrase.c +++ b/g10/passphrase.c @@ -44,13 +44,13 @@ get_passphrase_hash( u32 *keyid, char *text ) DEK *dek; if( keyid ) { - tty_printf("Need a pass phrase to unlock the secret key!\n"); + tty_printf("\nNeed a pass phrase to unlock the secret key!\n"); tty_printf("KeyID: %08lX\n\n", keyid[1] ); } - if( keyid && (p=getenv("PGPPATHPHRASE")) ) { + if( keyid && (p=getenv("G10PASSPHRASE")) ) { pw = m_alloc_secure(strlen(p)+1); strcpy(pw,p); - tty_printf("Taking it from $PGPPATHPHRASE !\n", keyid[1] ); + tty_printf("Taking it from $G10PASSPHRASE !\n", keyid[1] ); } else pw = tty_get_hidden("Enter pass phrase: " ); @@ -61,7 +61,7 @@ get_passphrase_hash( u32 *keyid, char *text ) m_free(pw); /* is allocated in secure memory, so it will be burned */ if( !p ) { tty_kill_prompt(); - tty_printf("\n\n"); + tty_printf("\n"); } return dek; } @@ -70,6 +70,7 @@ get_passphrase_hash( u32 *keyid, char *text ) /**************** * This function is used to construct a DEK from a user input. * It uses the default CIPHER + * Returns: 0 = okay, -1 No passphrase entered, > 0 error */ int make_dek_from_passphrase( DEK *dek, int mode ) @@ -88,7 +89,10 @@ make_dek_from_passphrase( DEK *dek, int mode ) } m_free(pw2); } - rc = hash_passphrase( dek, pw ); + if( !*pw ) + rc = -1; + else + rc = hash_passphrase( dek, pw ); m_free(pw); return rc; } diff --git a/g10/seckey-cert.c b/g10/seckey-cert.c index 689f473c9..85d93b4f9 100644 --- a/g10/seckey-cert.c +++ b/g10/seckey-cert.c @@ -35,12 +35,20 @@ #endif static u16 -checksum( byte *p ) +checksum_u16( unsigned n ) { - u16 n, a; + u16 a; + + a = (n >> 8) & 0xff; + a |= n & 0xff; + return a; +} + +static u16 +checksum( byte *p, unsigned n ) +{ + u16 a; - n = *p++ << 8; - n |= *p++; for(a=0; n; n-- ) a += *p++; return a; @@ -51,16 +59,16 @@ checksum( byte *p ) static int check_elg( PKT_secret_cert *cert ) { - byte iv[8]; - byte *mpibuf; - u16 n; - MPI temp_mpi; + byte *buffer; + u16 n, csum=0; int res; + unsigned nbytes; u32 keyid[2]; ELG_secret_key skey; if( cert->d.elg.is_protected ) { /* remove the protection */ DEK *dek = NULL; + MPI test_x; BLOWFISH_context *blowfish_ctx=NULL; switch( cert->d.elg.protect_algo ) { @@ -68,47 +76,87 @@ check_elg( PKT_secret_cert *cert ) case CIPHER_ALGO_BLOWFISH: keyid_from_skc( cert, keyid ); dek = get_passphrase_hash( keyid, NULL ); - m_free(dek); /* pw is in secure memory, so m_free() burns it */ - memset( iv, 0, BLOWFISH_BLOCKSIZE ); blowfish_ctx = m_alloc_secure( sizeof *blowfish_ctx ); - blowfish_setiv( blowfish_ctx, iv ); + blowfish_setkey( blowfish_ctx, dek->key, dek->keylen ); + m_free(dek); /* pw is in secure memory, so m_free() burns it */ + blowfish_setiv( blowfish_ctx, NULL ); blowfish_decode_cfb( blowfish_ctx, cert->d.elg.protect.blowfish.iv, cert->d.elg.protect.blowfish.iv, 8 ); - cert->d.elg.calc_csum = 0; - mpibuf = (byte*)cert->d.elg.x; - n = ((mpibuf[0] << 8) | mpibuf[1])-2; - blowfish_decode_cfb( blowfish_ctx, mpibuf+4, mpibuf+4, n ); - cert->d.elg.calc_csum += checksum( mpibuf ); - cert->d.elg.x = mpi_decode_buffer( mpibuf ); - m_free( mpibuf ); + buffer = mpi_get_buffer( cert->d.elg.x, &nbytes, NULL ); + csum = checksum_u16( nbytes*8 ); + blowfish_decode_cfb( blowfish_ctx, buffer, buffer, nbytes ); + csum += checksum( buffer, nbytes ); + test_x = mpi_alloc_secure( mpi_get_nlimbs(cert->d.elg.x) ); + mpi_set_buffer( test_x, buffer, nbytes, 0 ); + m_free( buffer ); m_free( blowfish_ctx ); - cert->d.elg.is_protected = 0; /* now let's see wether we have used the right passphrase */ - if( cert->d.elg.calc_csum != cert->d.elg.csum ) + if( csum != cert->d.elg.csum ) { + mpi_free(test_x); return G10ERR_BAD_PASS; + } skey.p = cert->d.elg.p; skey.g = cert->d.elg.g; skey.y = cert->d.elg.y; - skey.x = cert->d.elg.x; + skey.x = test_x; res = elg_check_secret_key( &skey ); memset( &skey, 0, sizeof skey ); - if( !res ) + if( !res ) { + mpi_free(test_x); return G10ERR_BAD_PASS; + } + mpi_set(cert->d.elg.x, test_x); + mpi_free(test_x); + cert->d.elg.is_protected = 0; break; default: return G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */ } } - /* must check the checksum here, because we didn't do it when - * parsing an unprotected certificate */ - if( cert->d.elg.calc_csum != cert->d.elg.csum ) { - log_error("checksum in secret key certificate is wrong\n"); - log_debug("stored csum=%04hx calculated csum=%04hx\n", - cert->d.elg.csum, cert->d.elg.calc_csum ); - return G10ERR_CHECKSUM; + else { /* not protected */ + buffer = mpi_get_buffer( cert->d.elg.x, &nbytes, NULL ); + csum = checksum_u16( nbytes*8 ); + csum += checksum( buffer, nbytes ); + m_free( buffer ); + if( csum != cert->d.elg.csum ) + return G10ERR_CHECKSUM; + } + + return 0; +} + +static int +protect_elg( PKT_secret_cert *cert, DEK *dek ) +{ + byte *buffer; + unsigned nbytes; + + if( !cert->d.elg.is_protected ) { /* add the protection */ + BLOWFISH_context *blowfish_ctx=NULL; + + switch( cert->d.elg.protect_algo ) { + case CIPHER_ALGO_NONE: log_bug(NULL); break; + case CIPHER_ALGO_BLOWFISH: + blowfish_ctx = m_alloc_secure( sizeof *blowfish_ctx ); + blowfish_setkey( blowfish_ctx, dek->key, dek->keylen ); + blowfish_setiv( blowfish_ctx, NULL ); + blowfish_encode_cfb( blowfish_ctx, + cert->d.elg.protect.blowfish.iv, + cert->d.elg.protect.blowfish.iv, 8 ); + buffer = mpi_get_buffer( cert->d.elg.x, &nbytes, NULL ); + blowfish_encode_cfb( blowfish_ctx, buffer, buffer, nbytes ); + mpi_set_buffer( cert->d.elg.x, buffer, nbytes, 0 ); + m_free( buffer ); + m_free( blowfish_ctx ); + cert->d.elg.is_protected = 1; + break; + + default: + return G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */ + } } return 0; } @@ -118,80 +166,86 @@ check_elg( PKT_secret_cert *cert ) static int check_rsa( PKT_secret_cert *cert ) { - byte iv[8]; - byte *mpibuf; - u16 n; - MPI temp_mpi; + byte *buffer; + u16 n, csum=0; int res; + unsigned nbytes; u32 keyid[2]; + RSA_secret_key skey; if( cert->d.rsa.is_protected ) { /* remove the protection */ DEK *dek = NULL; BLOWFISH_context *blowfish_ctx=NULL; switch( cert->d.rsa.protect_algo ) { - case CIPHER_ALGO_NONE: - log_bug("unprotect secret_cert is flagged protected\n"); - break; + /* FIXME: use test variables to check for the correct key */ + case CIPHER_ALGO_NONE: log_bug(NULL); break; case CIPHER_ALGO_BLOWFISH: keyid_from_skc( cert, keyid ); dek = get_passphrase_hash( keyid, NULL ); - - m_free(dek); /* pw is in secure memory, so m_free() burns it */ - memset( iv, 0, BLOWFISH_BLOCKSIZE ); blowfish_ctx = m_alloc_secure( sizeof *blowfish_ctx ); - blowfish_setiv( blowfish_ctx, iv ); + blowfish_setkey( blowfish_ctx, dek->key, dek->keylen ); + m_free(dek); /* pw is in secure memory, so m_free() burns it */ + blowfish_setiv( blowfish_ctx, NULL ); blowfish_decode_cfb( blowfish_ctx, cert->d.rsa.protect.blowfish.iv, cert->d.rsa.protect.blowfish.iv, 8 ); - cert->d.rsa.calc_csum = 0; - #define X(a) do { \ - mpibuf = (byte*)cert->d.rsa.rsa_##a; \ - n = ((mpibuf[0] << 8) | mpibuf[1])-2; \ - blowfish_decode_cfb( blowfish_ctx, \ - mpibuf+4, mpibuf+4, n ); \ - cert->d.rsa.calc_csum += checksum( mpibuf ); \ - cert->d.rsa.rsa_##a = mpi_decode_buffer( mpibuf ); \ - m_free( mpibuf ); \ - } while(0) + csum = 0; + #define X(a) do { \ + buffer = mpi_get_buffer( cert->d.rsa.rsa_##a, &nbytes, NULL );\ + csum += checksum_u16( nbytes*8 ); \ + blowfish_decode_cfb( blowfish_ctx, buffer, buffer, nbytes ); \ + csum += checksum( buffer, nbytes ); \ + mpi_set_buffer(cert->d.rsa.rsa_##a, buffer, nbytes, 0 ); \ + m_free( buffer ); \ + } while(0) X(d); X(p); X(q); X(u); - #undef X - m_free( blowfish_ctx ); - cert->d.rsa.is_protected = 0; - #if 0 - #define X(a) do { printf("\tRSA " #a ": "); \ - mpi_print(stdout, cert->d.rsa.rsa_##a, 1 ); \ - putchar('\n'); \ - } while(0) - X(n); X(e); X(d); X(p); X(q); X(u); #undef X - #endif + cert->d.rsa.is_protected = 0; + m_free( blowfish_ctx ); /* now let's see wether we have used the right passphrase */ - if( cert->d.rsa.calc_csum != cert->d.rsa.csum ) + if( csum != cert->d.rsa.csum ) return G10ERR_BAD_PASS; - temp_mpi = mpi_alloc(40); - mpi_mul(temp_mpi, cert->d.rsa.rsa_p, cert->d.rsa.rsa_q ); - res = mpi_cmp( temp_mpi, cert->d.rsa.rsa_n ); - mpi_free(temp_mpi); - if( res ) + + skey.d = cert->d.rsa.rsa_d; + skey.p = cert->d.rsa.rsa_p; + skey.q = cert->d.rsa.rsa_q; + skey.u = cert->d.rsa.rsa_u; + res = rsa_check_secret_key( &skey ); + memset( &skey, 0, sizeof skey ); + if( !res ) return G10ERR_BAD_PASS; break; default: - return G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */ + return G10ERR_CIPHER_ALGO; /* unsupported protection algorithm */ } } - /* must check the checksum here, because we didn't do it when - * parsing an unprotected certificate */ - if( cert->d.rsa.calc_csum != cert->d.rsa.csum ) { - log_error("checksum in secret key certificate is wrong\n"); - log_debug("stored csum=%04hx calculated csum=%04hx\n", - cert->d.rsa.csum, cert->d.rsa.calc_csum ); - return G10ERR_CHECKSUM; + else { /* not protected */ + csum =0; + buffer = mpi_get_buffer( cert->d.rsa.rsa_d, &nbytes, NULL ); + csum += checksum_u16( nbytes*8 ); + csum += checksum( buffer, nbytes ); + m_free( buffer ); + buffer = mpi_get_buffer( cert->d.rsa.rsa_p, &nbytes, NULL ); + csum += checksum_u16( nbytes*8 ); + csum += checksum( buffer, nbytes ); + m_free( buffer ); + buffer = mpi_get_buffer( cert->d.rsa.rsa_q, &nbytes, NULL ); + csum += checksum_u16( nbytes*8 ); + csum += checksum( buffer, nbytes ); + m_free( buffer ); + buffer = mpi_get_buffer( cert->d.rsa.rsa_u, &nbytes, NULL ); + csum += checksum_u16( nbytes*8 ); + csum += checksum( buffer, nbytes ); + m_free( buffer ); + if( csum != cert->d.rsa.csum ) + return G10ERR_CHECKSUM; } + return 0; } #endif /*HAVE_RSA_CIPHER*/ @@ -201,15 +255,44 @@ check_rsa( PKT_secret_cert *cert ) /**************** * Check the secret key certificate + * Ask up to 3 time for a correct passphrase */ int check_secret_key( PKT_secret_cert *cert ) { + int rc = G10ERR_BAD_PASS; + int i; + + for(i=0; i < 3 && rc == G10ERR_BAD_PASS; i++ ) { + if( i ) + log_error("Invalid passphrase; please try again ...\n"); + if( cert->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) + rc = check_elg( cert ); + #ifdef HAVE_RSA_CIPHER + else if( cert->pubkey_algo == PUBKEY_ALGO_RSA ) + rc = check_rsa( cert ); + #endif + else + rc = G10ERR_PUBKEY_ALGO; + } + return rc; +} + + +/**************** + * Protect the secret key certificate with the passphrase from DEK + */ +int +protect_secret_key( PKT_secret_cert *cert, DEK *dek ) +{ + if( !dek ) + return 0; + if( cert->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) - return check_elg( cert ); - #ifdef HAVE_RSA_CIPHER + return protect_elg( cert, dek ); + #ifdef 0 /* noy yet implemented */ else if( cert->pubkey_algo == PUBKEY_ALGO_RSA ) - return check_rsa( cert ); + return protect_rsa( cert, dek ); #endif else return G10ERR_PUBKEY_ALGO; diff --git a/g10/sig-check.c b/g10/sig-check.c index 841423878..d5f0afb9e 100644 --- a/g10/sig-check.c +++ b/g10/sig-check.c @@ -212,3 +212,5 @@ signature_check( PKT_signature *sig, MD_HANDLE *digest ) return rc; } + + diff --git a/include/errors.h b/include/errors.h index 7ad3181c4..cdd4a0549 100644 --- a/include/errors.h +++ b/include/errors.h @@ -49,5 +49,6 @@ #define G10ERR_NI_PUBKEY 27 #define G10ERR_NI_CIPHER 28 #define G10ERR_SIG_CLASS 29 +#define G10ERR_BAD_MPI 30 #endif /*G10_ERRORS_H*/ diff --git a/include/memory.h b/include/memory.h index aa8bb706d..32eb3906b 100644 --- a/include/memory.h +++ b/include/memory.h @@ -33,6 +33,7 @@ #define m_realloc(n,m) m_debug_realloc((n),(m), M_DBGINFO(__LINE__) ) #define m_free(n) m_debug_free((n), M_DBGINFO(__LINE__) ) #define m_check(n) m_debug_check((n), M_DBGINFO(__LINE__) ) +#define m_copy(a) m_debug_copy((a), M_DBGINFO(__LINE__) ) void *m_debug_alloc( size_t n, const char *info ); void *m_debug_alloc_clear( size_t n, const char *info ); @@ -41,6 +42,7 @@ void *m_debug_alloc_secure_clear( size_t n, const char *info ); void *m_debug_realloc( void *a, size_t n, const char *info ); void m_debug_free( void *p, const char *info ); void m_debug_check( const void *a, const char *info ); +void *m_debug_copy( const void *a, const char *info ); #else void *m_alloc( size_t n ); @@ -50,6 +52,7 @@ void *m_alloc_secure_clear( size_t n ); void *m_realloc( void *a, size_t n ); void m_free( void *p ); void m_check( const void *a ); +void *m_copy( void *a ); #endif diff --git a/include/mpi.h b/include/mpi.h index cf3623273..ce60f16a8 100644 --- a/include/mpi.h +++ b/include/mpi.h @@ -52,15 +52,16 @@ int mpi_debug_mode; typedef struct mpi_struct { int alloced; /* array size (# of allocated limbs) */ int nlimbs; /* number of valid limbs */ + int nbits; /* the real number of valid bits (info only) */ int sign; /* indicates a negative number */ - int secure; /* array mut be allocated in secure memory space */ + int secure; /* array must be allocated in secure memory space */ mpi_limb_t *d; /* array with the limbs */ } *MPI; #define MPI_NULL NULL -#define mpi_get_nlimbs(a) ((a)->nlimbs) -#define mpi_is_neg(a) ((a)->sign) +#define mpi_get_nlimbs(a) ((a)->nlimbs) +#define mpi_is_neg(a) ((a)->sign) /*-- mpiutil.c --*/ @@ -90,23 +91,18 @@ void mpi_m_check( MPI a ); void mpi_swap( MPI a, MPI b); /*-- mpicoder.c --*/ -int mpi_encode( IOBUF out, MPI a ); -int mpi_encode_csum( IOBUF out, MPI a, u16 *csum ); -int mpi_write( IOBUF out, byte *a); -int mpi_write_csum( IOBUF out, byte *a, u16 *csum); +int mpi_write( IOBUF out, MPI a ); #ifdef M_DEBUG - #define mpi_decode(a,b) mpi_debug_decode((a),(b), M_DBGINFO( __LINE__ ) ) - #define mpi_decode_buffer(a) mpi_debug_decode_buffer((a), M_DBGINFO( __LINE__ ) ) - MPI mpi_debug_decode(IOBUF inp, unsigned *nread, const char *info); - MPI mpi_debug_decode_buffer(byte *buffer, const char *info ); + #define mpi_read(a,b,c) mpi_debug_read((a),(b),(c), M_DBGINFO( __LINE__ ) ) + MPI mpi_debug_read(IOBUF inp, unsigned *nread, int secure, const char *info); #else - MPI mpi_decode(IOBUF inp, unsigned *nread); - MPI mpi_decode_buffer(byte *buffer ); + MPI mpi_read(IOBUF inp, unsigned *nread, int secure); #endif -byte *mpi_read(IOBUF inp, unsigned *ret_nread); int mpi_fromstr(MPI val, const char *str); int mpi_print( FILE *fp, MPI a, int mode ); u32 mpi_get_keyid( MPI a, u32 *keyid ); +byte *mpi_get_buffer( MPI a, unsigned *nbytes, int *sign ); +void mpi_set_buffer( MPI a, const byte *buffer, unsigned nbytes, int sign ); /*-- mpi-add.c --*/ void mpi_add_ui(MPI w, MPI u, ulong v ); diff --git a/mpi/mpicoder.c b/mpi/mpicoder.c index 23454c0f9..43b97beea 100644 --- a/mpi/mpicoder.c +++ b/mpi/mpicoder.c @@ -24,13 +24,13 @@ #include #include "mpi.h" +#include "mpi-internal.h" #include "iobuf.h" #include "memory.h" #include "util.h" #ifdef M_DEBUG - #undef mpi_decode - #undef mpi_decode_buffer + #undef mpi_read #endif #define MAX_EXTERN_MPI_BITS 16384 @@ -39,89 +39,52 @@ * write an mpi to out. */ int -mpi_encode( IOBUF out, MPI a ) -{ - u16 dummy; - return mpi_encode_csum( out, a, &dummy ); -} - -int -mpi_encode_csum( IOBUF out, MPI a, u16 *csum ) +mpi_write( IOBUF out, MPI a ) { int i; - byte c; unsigned nbits = a->nlimbs * BITS_PER_MPI_LIMB; mpi_limb_t limb; -#if BYTES_PER_MPI_LIMB != 4 - #error Make this function work with other LIMB sizes -#endif + /* fixme: use a->nbits if valid */ if( nbits > MAX_EXTERN_MPI_BITS ) log_bug("mpi_encode: mpi too large (%u bits)\n", nbits); - iobuf_put(out, (c=nbits >>8) ); *csum += c; - iobuf_put(out, (c=nbits) ); *csum += c; + iobuf_put(out, (nbits >>8) ); + iobuf_put(out, (nbits) ); for(i=a->nlimbs-1; i >= 0; i-- ) { limb = a->d[i]; - iobuf_put(out, (c=limb >> 24) ); *csum += c; - iobuf_put(out, (c=limb >> 16) ); *csum += c; - iobuf_put(out, (c=limb >> 8) ); *csum += c; - iobuf_put(out, (c=limb ) ); *csum += c; + #if BYTES_PER_MPI_LIMB == 4 + iobuf_put(out, (limb >> 24) ); + iobuf_put(out, (limb >> 16) ); + iobuf_put(out, (limb >> 8) ); + iobuf_put(out, (limb ) ); + #elif BYTES_PER_MPI_LIMB == 8 + iobuf_put(out, (limb >> 56) ); + iobuf_put(out, (limb >> 48) ); + iobuf_put(out, (limb >> 40) ); + iobuf_put(out, (limb >> 32) ); + iobuf_put(out, (limb >> 24) ); + iobuf_put(out, (limb >> 16) ); + iobuf_put(out, (limb >> 8) ); + iobuf_put(out, (limb ) ); + #else + #error Make this function work with other LIMB sizes + #endif } return 0; } -/**************** - * encode the MPI into a newly allocated buffer, the buffer is - * so constructed, that it can be used for mpi_write. The caller - * must free the returned buffer. The buffer is allocated in the same - * type of memory space as A is. - */ -byte * -mpi_encode_buffer( MPI a ) -{ - abort(); - return NULL; -} /**************** - * write an mpi to out. This is a special function to handle - * encrypted values. It simply writes the buffer a to OUT. - * A is a special buffer, starting with 2 bytes giving it's length - * (in big endian order) and 2 bytes giving it's length in bits (also - * big endian) - */ -int -mpi_write( IOBUF out, byte *a) -{ - u16 dummy; - return mpi_write_csum( out, a, &dummy ); -} - -int -mpi_write_csum( IOBUF out, byte *a, u16 *csum) -{ - int rc; - unsigned n; - - n = *a++ << 8; - n |= *a++; - rc = iobuf_write(out, a, n ); - for( ; n; n--, a++ ) - *csum += *a; - return rc; -} - -/**************** - * Decode an external representation and return an MPI + * Read an external representation of an mpi and return the MPI * The external format is a 16 bit unsigned value stored in network byte order, * giving the number of bits for the following integer. The integer is stored * with MSB first (left padded with zeroes to align on a byte boundary). */ MPI #ifdef M_DEBUG -mpi_debug_decode(IOBUF inp, unsigned *ret_nread, const char *info) +mpi_debug_read(IOBUF inp, unsigned *ret_nread, int secure, const char *info) #else -mpi_decode(IOBUF inp, unsigned *ret_nread) +mpi_read(IOBUF inp, unsigned *ret_nread, int secure) #endif { int c, i, j; @@ -144,12 +107,15 @@ mpi_decode(IOBUF inp, unsigned *ret_nread) nbytes = (nbits+7) / 8; nlimbs = (nbytes+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB; #ifdef M_DEBUG - val = mpi_debug_alloc( nlimbs, info ); + val = secure? mpi_debug_alloc_secure( nlimbs, info ) + : mpi_debug_alloc( nlimbs, info ); #else - val = mpi_alloc( nlimbs ); + val = secure? mpi_alloc_secure( nlimbs ) + : mpi_alloc( nlimbs ); #endif i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB; i %= BYTES_PER_MPI_LIMB; + val->nbits = nbits; j= val->nlimbs = nlimbs; val->sign = 0; for( ; j > 0; j-- ) { @@ -171,103 +137,6 @@ mpi_decode(IOBUF inp, unsigned *ret_nread) } -/**************** - * Decode an MPI from the buffer, the buffer starts with two bytes giving - * the length of the data to follow, the original data follows. - * The MPI is alloced from secure MPI space - */ -MPI -#ifdef M_DEBUG -mpi_debug_decode_buffer(byte *buffer, const char *info ) -#else -mpi_decode_buffer(byte *buffer ) -#endif -{ - int i, j; - u16 buflen; - unsigned nbits, nbytes, nlimbs; - mpi_limb_t a; - byte *p = buffer; - MPI val; - - if( !buffer ) - log_bug("mpi_decode_buffer: no buffer\n"); - buflen = *p++ << 8; - buflen |= *p++; - nbits = *p++ << 8; - nbits |= *p++; - nbytes = (nbits+7) / 8; - if( nbytes+2 != buflen ) - log_bug("mpi_decode_buffer: length conflict\n"); - nlimbs = (nbytes+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB; - #ifdef M_DEBUG - val = mpi_debug_alloc_secure( nlimbs, info ); - #else - val = mpi_alloc_secure( nlimbs ); - #endif - i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB; - i %= BYTES_PER_MPI_LIMB; - j= val->nlimbs = nlimbs; - val->sign = 0; - for( ; j > 0; j-- ) { - a = 0; - for(; i < BYTES_PER_MPI_LIMB; i++ ) { - a <<= 8; - a |= *p++; - } - i = 0; - val->d[j-1] = a; - } - return val; -} - - -/**************** - * Read a MPI from the external medium and return it in a newly allocated - * buffer (This buffer is allocated in the secure memory space, because - * we properly need this to decipher this string). - * Return: the allocated string and in RET_NREAD the number of bytes - * read (including the 2 length bytes), the returned buffer will - * be prefixed with two bytes describing the length of the following - * data. - */ -byte * -mpi_read(IOBUF inp, unsigned *ret_nread) -{ - int c; - u16 buflen; - unsigned nbits, nbytes, nread; - byte *p, *buf; - - if( (c = iobuf_get(inp)) == -1 ) - return NULL; - nbits = c << 8; - if( (c = iobuf_get(inp)) == -1 ) - return NULL; - nbits |= c; - if( nbits > MAX_EXTERN_MPI_BITS ) { - log_error("mpi too large (%u bits)\n", nbits); - return NULL; - } - nread = 2; - - nbytes = (nbits+7) / 8; - buflen = nbytes + 2; - p = buf = m_alloc_secure( buflen+2 ); - *p++ = buflen >> 8; - *p++ = buflen & 0xff; - *p++ = nbits >> 8; - *p++ = nbits & 0xff; - for( ; nbytes ; nbytes--, nread++ ) - *p++ = iobuf_get(inp) & 0xff; - - if( nread > *ret_nread ) - log_error("Ooops: mpi crosses packet border"); - else - *ret_nread = nread; - return buf; -} - /**************** * Make a mpi from a character string. @@ -390,3 +259,96 @@ mpi_get_keyid( MPI a, u32 *keyid ) } +/**************** + * Return a m_alloced buffer with the MPI (msb first). + * NBYTES receives the length of this buffer. Caller must free the + * return string (This function does return a 0 byte buffer with NBYTES + * set to zero if the value of A is zero. If sign is not NULL, it will + * be set to the sign of the A. + */ +byte * +mpi_get_buffer( MPI a, unsigned *nbytes, int *sign ) +{ + byte *p, *buffer; + mpi_limb_t alimb; + int i; + + if( sign ) + *sign = a->sign; + *nbytes = a->nlimbs * BYTES_PER_MPI_LIMB; + p = buffer = a->secure ? m_alloc_secure( *nbytes) : m_alloc( *nbytes ); + + for(i=a->nlimbs-1; i >= 0; i-- ) { + alimb = a->d[i]; + #if BYTES_PER_MPI_LIMB == 4 + *p++ = alimb >> 24; + *p++ = alimb >> 16; + *p++ = alimb >> 8; + *p++ = alimb ; + #elif BYTES_PER_MPI_LIMB == 8 + *p++ = alimb >> 56; + *p++ = alimb >> 48; + *p++ = alimb >> 40; + *p++ = alimb >> 32; + *p++ = alimb >> 24; + *p++ = alimb >> 16; + *p++ = alimb >> 8; + *p++ = alimb ; + #else + #error please implement for this limb size. + #endif + } + return buffer; +} + +/**************** + * Use BUFFER to update MPI. + */ +void +mpi_set_buffer( MPI a, const byte *buffer, unsigned nbytes, int sign ) +{ + const byte *p; + mpi_limb_t alimb; + int nlimbs; + int i; + + nlimbs = (nbytes + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB; + RESIZE_IF_NEEDED(a, nlimbs); + a->sign = sign; + + for(i=0, p = buffer+nbytes-1; p >= buffer+BYTES_PER_MPI_LIMB; ) { + #if BYTES_PER_MPI_LIMB == 4 + alimb = *p-- ; + alimb |= *p-- << 8 ; + alimb |= *p-- << 16 ; + alimb |= *p-- << 24 ; + #elif BYTES_PER_MPI_LIMB == 8 + #else + #error please implement for this limb size. + #endif + a->d[i++] = alimb; + } + if( p >= buffer ) { + #if BYTES_PER_MPI_LIMB == 4 + alimb = *p-- ; + if( p >= buffer ) alimb |= *p-- << 8 ; + if( p >= buffer ) alimb |= *p-- << 16 ; + if( p >= buffer ) alimb |= *p-- << 24 ; + #elif BYTES_PER_MPI_LIMB == 8 + alimb = *p-- ; + if( p >= buffer ) alimb |= *p-- << 8 ; + if( p >= buffer ) alimb |= *p-- << 16 ; + if( p >= buffer ) alimb |= *p-- << 24 ; + if( p >= buffer ) alimb |= *p-- << 32 ; + if( p >= buffer ) alimb |= *p-- << 40 ; + if( p >= buffer ) alimb |= *p-- << 48 ; + if( p >= buffer ) alimb |= *p-- << 56 ; + #else + #error please implement for this limb size. + #endif + a->d[i++] = alimb; + } + a->nlimbs = i; + assert( i == nlimbs ); +} + diff --git a/util/memory.c b/util/memory.c index 54095df17..9ba9a8e82 100644 --- a/util/memory.c +++ b/util/memory.c @@ -456,3 +456,26 @@ m_is_secure( const void *p ) return p && ((byte*)p)[-1] == MAGIC_SEC_BYTE; } + +/**************** + * Make a copy of the memory block at a + */ +void * +FNAME(copy)( void *a FNAMEPRT ) +{ + void *b; + size_t n; + + if( !a ) + return a; + + n = m_size(a); + if( m_is_secure(a) ) + b = FNAME(alloc_secure)(n FNAMEARG); + else + b = FNAME(alloc)(n FNAMEARG); + memcpy(b, a, n ); + return b; +} + +