From 37d2adfe61d9671086fa701b779c3b47895afe4c Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Sat, 13 Jun 1998 06:59:14 +0000 Subject: [PATCH] a whole bunch of internal cleanups --- checks/conventional.test | 2 +- checks/defs.inc | 6 +- checks/encrypt-dsa.test | 2 +- checks/encrypt.test | 2 +- checks/run-gpg | 3 +- cipher/Makefile.am | 5 +- cipher/cast5.c | 12 +- cipher/pubkey.c | 377 ++++++++++++++++++++++++++++++++++++-- g10/ChangeLog | 10 + g10/Makefile.am | 3 - g10/build-packet.c | 137 ++++---------- g10/dsa.c | 69 ------- g10/elg.c | 92 ---------- g10/encode.c | 40 ++-- g10/free-packet.c | 171 ++++------------- g10/keygen.c | 36 ++-- g10/keyid.c | 385 +++++++++++---------------------------- g10/main.h | 14 -- g10/packet.h | 33 +--- g10/parse-packet.c | 155 ++++++---------- g10/pubkey-enc.c | 44 +---- g10/ringedit.c | 68 ++++--- g10/rsa.c | 89 --------- g10/seckey-cert.c | 75 ++------ g10/sig-check.c | 8 +- g10/sign.c | 109 ++++++----- include/cipher.h | 19 ++ tools/mk-tdata | Bin 11769 -> 35331 bytes 28 files changed, 819 insertions(+), 1147 deletions(-) delete mode 100644 g10/dsa.c delete mode 100644 g10/elg.c delete mode 100644 g10/rsa.c diff --git a/checks/conventional.test b/checks/conventional.test index 295db822b..0a2aabe57 100755 --- a/checks/conventional.test +++ b/checks/conventional.test @@ -10,7 +10,7 @@ for i in plain-2 data-32000 ; do done for i in plain-1 data-80000 ; do echo "Hier spricht HAL" | ./run-gpg --passphrase-fd 0 \ - --cipher-algo cast -c -o x --yes $i + --cipher-algo cast5 -c -o x --yes $i echo "Hier spricht HAL" | ./run-gpg --passphrase-fd 0 -o y --yes x cmp $i y || error "$i: mismatch" done diff --git a/checks/defs.inc b/checks/defs.inc index 32711c916..14c657543 100755 --- a/checks/defs.inc +++ b/checks/defs.inc @@ -21,8 +21,10 @@ dsa_usrname2="0xCB879DE9" dsa_keyrings="--keyring ./pubring.pkr --secret-keyring ./secring.skr" -plain_files="plain-1 plain-2 plain-3" -data_files="data-500 data-9000 data-32000 data-80000" +#plain_files="plain-1 plain-2 plain-3" +#data_files="data-500 data-9000 data-32000 data-80000" +plain_files="plain-1 plain-2" +data_files="data-500 data-9000" exp_files="" diff --git a/checks/encrypt-dsa.test b/checks/encrypt-dsa.test index d506e8890..d83cdd968 100755 --- a/checks/encrypt-dsa.test +++ b/checks/encrypt-dsa.test @@ -11,7 +11,7 @@ done # and with cast for i in $plain_files $data_files ; do - ./run-gpg $dsa_keyrings --cipher-algo cast -e \ + ./run-gpg $dsa_keyrings --cipher-algo cast5 -e \ -o x --yes -r "$dsa_usrname2" $i ./run-gpg $dsa_keyrings -o y --yes x cmp $i y || error "$i: mismatch" diff --git a/checks/encrypt.test b/checks/encrypt.test index daf3be6ee..85a67eb37 100755 --- a/checks/encrypt.test +++ b/checks/encrypt.test @@ -9,7 +9,7 @@ for i in $plain_files $data_files ; do cmp $i y || error "$i: mismatch" done for i in $plain_files $data_files ; do - ./run-gpg -e -o x --yes -r "$usrname2" --cipher-algo cast $i + ./run-gpg -e -o x --yes -r "$usrname2" --cipher-algo cast5 $i ./run-gpg -o y --yes x cmp $i y || error "$i: mismatch" done diff --git a/checks/run-gpg b/checks/run-gpg index 3420bf98e..9a3ffee8f 100755 --- a/checks/run-gpg +++ b/checks/run-gpg @@ -6,6 +6,7 @@ if ! ../g10/gpg --homedir . $* 2>err.tmp.$$ ; then rm err.tmp.$$ exit 1 fi -grep -v 'gpg: Good signature from' err.tmp.$$ || true +grep -v 'gpg: Good signature from' err.tmp.$$ \ + | grep -v 'gpg: Signature made ' || true rm err.tmp.$$ diff --git a/cipher/Makefile.am b/cipher/Makefile.am index 10d1c8091..53ba749a8 100644 --- a/cipher/Makefile.am +++ b/cipher/Makefile.am @@ -6,6 +6,9 @@ noinst_LIBRARIES = libcipher.a libcipher_a_SOURCES = cipher.c \ + pubkey.c \ + md.c \ + md.h \ dynload.c \ dynload.h \ blowfish.c \ @@ -32,8 +35,6 @@ libcipher_a_SOURCES = cipher.c \ sha1.c \ dsa.h \ dsa.c \ - md.c \ - md.h \ misc.c \ smallprime.c diff --git a/cipher/cast5.c b/cipher/cast5.c index 5e29debe6..0bd90f9df 100644 --- a/cipher/cast5.c +++ b/cipher/cast5.c @@ -594,17 +594,17 @@ setkey( CAST5_context *c, byte *key, unsigned keylen ) const char * cast5_get_info( int algo, size_t *keylen, size_t *blocksize, size_t *contextsize, - void (**setkey)( void *c, byte *key, unsigned keylen ), - void (**encrypt)( void *c, byte *outbuf, byte *inbuf ), - void (**decrypt)( void *c, byte *outbuf, byte *inbuf ) + void (**r_setkey)( void *c, byte *key, unsigned keylen ), + void (**r_encrypt)( void *c, byte *outbuf, byte *inbuf ), + void (**r_decrypt)( void *c, byte *outbuf, byte *inbuf ) ) { *keylen = 128; *blocksize = CAST5_BLOCKSIZE; *contextsize = sizeof(CAST5_context); - *setkey = FNCCAST_SETKEY(setkey); - *encrypt= FNCCAST_CRYPT(encrypt_block); - *decrypt= FNCCAST_CRYPT(decrypt_block); + *r_setkey = FNCCAST_SETKEY(setkey); + *r_encrypt= FNCCAST_CRYPT(encrypt_block); + *r_decrypt= FNCCAST_CRYPT(decrypt_block); if( algo == CIPHER_ALGO_CAST5 ) return "CAST5"; diff --git a/cipher/pubkey.c b/cipher/pubkey.c index 3ffc1ca33..0a4b3430d 100644 --- a/cipher/pubkey.c +++ b/cipher/pubkey.c @@ -30,32 +30,199 @@ #include "cipher.h" #include "dynload.h" +/**************** + * Return the number of public key material numbers + */ +int +pubkey_get_npkey( int algo ) +{ + if( is_ELGAMAL(algo) ) + return 3; + if( is_RSA(algo) ) + return 2; + if( algo == PUBKEY_ALGO_DSA ) + return 4; + return 0; +} /**************** - * This is the interface for the public key decryption. + * Return the number of secret key material numbers + */ +int +pubkey_get_nskey( int algo ) +{ + if( is_ELGAMAL(algo) ) + return 4; + if( is_RSA(algo) ) + return 6; + if( algo == PUBKEY_ALGO_DSA ) + return 5; + return 0; +} + +/**************** + * Return the number of signature material numbers + */ +int +pubkey_get_nsig( int algo ) +{ + if( is_ELGAMAL(algo) ) + return 2; + if( is_RSA(algo) ) + return 1; + if( algo == PUBKEY_ALGO_DSA ) + return 2; + return 0; +} + +/**************** + * Return the number of encryption material numbers + */ +int +pubkey_get_nenc( int algo ) +{ + if( is_ELGAMAL(algo) ) + return 2; + if( is_RSA(algo) ) + return 1; + return 0; +} + +/**************** + * Get the number of nbits from the public key + */ +unsigned +pubkey_nbits( int algo, MPI *pkey ) +{ + if( is_ELGAMAL( algo ) ) + return mpi_get_nbits( pkey[0] ); + + if( algo == PUBKEY_ALGO_DSA ) + return mpi_get_nbits( pkey[0] ); + + if( is_RSA( algo) ) + return mpi_get_nbits( pkey[0] ); + + return 0; +} + + +int +pubkey_check_secret_key( int algo, MPI *skey ) +{ + int rc = 0; + + if( is_ELGAMAL(algo) ) { + ELG_secret_key sk; + sk.p = skey[0]; + sk.g = skey[1]; + sk.y = skey[2]; + sk.x = skey[3]; + if( !elg_check_secret_key( &sk ) ) + rc = G10ERR_BAD_SECKEY; + } + else if( algo == PUBKEY_ALGO_DSA ) { + DSA_secret_key sk; + sk.p = skey[0]; + sk.q = skey[1]; + sk.g = skey[2]; + sk.y = skey[3]; + sk.x = skey[4]; + if( !dsa_check_secret_key( &sk ) ) + rc = G10ERR_BAD_SECKEY; + } + #ifdef HAVE_RSA_CIPHER + else if( is_RSA(k->pubkey_algo) ) { + /* FIXME */ + RSA_secret_key sk; + assert( ndata == 1 && nskey == 6 ); + sk.n = skey[0]; + sk.e = skey[1]; + sk.d = skey[2]; + sk.p = skey[3]; + sk.q = skey[4]; + sk.u = skey[5]; + plain = mpi_alloc_secure( mpi_get_nlimbs(sk.n) ); + rsa_secret( plain, data[0], &sk ); + } + #endif + else + rc = G10ERR_PUBKEY_ALGO; + return rc; +} + + +/**************** + * This is the interface to the public key encryption. + * Encrypt DATA with PKEY and put it into RESARR which + * should be an array of MPIs of size PUBKEY_MAX_NENC (or less if the + * algorithm allows this - check with pubkey_get_nenc() ) + */ +int +pubkey_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey ) +{ + if( DBG_CIPHER ) { + int i; + log_debug("pubkey_encrypt: algo=%d\n", algo ); + for(i=0; i < pubkey_get_npkey(algo); i++ ) + log_mpidump(" pkey:", pkey[i] ); + log_mpidump(" data:", data ); + } + /* FIXME: check that data fits into the key */ + if( is_ELGAMAL(algo) ) { + ELG_public_key pk; + pk.p = pkey[0]; + pk.g = pkey[1]; + pk.y = pkey[2]; + resarr[0] = mpi_alloc( mpi_get_nlimbs( pk.p ) ); + resarr[1] = mpi_alloc( mpi_get_nlimbs( pk.p ) ); + elg_encrypt( resarr[0], resarr[1], data, &pk ); + } + #ifdef HAVE_RSA_CIPHER + else if( algo == PUBKEY_ALGO_RSA || algo == PUBKEY_ALGO_RSA_E ) { + RSA_public_key pk; + pk.n = pkey[0]; + pk.e = pkey[1]; + resarr[0] = mpi_alloc( mpi_get_nlimbs( pk.p ) ); + rsa_public( resarr[0], data, &pk ); + } + #endif + else + return G10ERR_PUBKEY_ALGO; + + if( DBG_CIPHER ) { + int i; + for(i=0; i < pubkey_get_nenc(algo); i++ ) + log_mpidump(" encr:", resarr[i] ); + } + return 0; +} + + + +/**************** + * This is the interface to the public key decryption. * ALGO gives the algorithm to use and this implicitly determines * the size of the arrays. * result is a pointer to a mpi variable which will receive a * newly allocated mpi or NULL in case of an error. */ int -pubkey_decrypt( int algo, MPI *result, int ndata, MPI *data, - int nskey, MPI *skey ) +pubkey_decrypt( int algo, MPI *result, MPI *data, MPI *skey ) { MPI plain = NULL; - *result = NULL; /* so the caller can do always do an mpi_free */ + *result = NULL; /* so the caller can always do an mpi_free */ if( DBG_CIPHER ) { int i; log_debug("pubkey_decrypt: algo=%d\n", algo ); - for(i=0; i < nskey; i++ ) + for(i=0; i < pubkey_get_nskey(algo); i++ ) log_mpidump(" skey:", skey[i] ); - for(i=0; i < ndata; i++ ) + for(i=0; i < pubkey_get_nenc(algo); i++ ) log_mpidump(" data:", data[i] ); } if( is_ELGAMAL(algo) ) { ELG_secret_key sk; - assert( ndata == 2 && nskey == 4 ); sk.p = skey[0]; sk.g = skey[1]; sk.y = skey[2]; @@ -63,22 +230,204 @@ pubkey_decrypt( int algo, MPI *result, int ndata, MPI *data, plain = mpi_alloc_secure( mpi_get_nlimbs( sk.p ) ); elg_decrypt( plain, data[0], data[1], &sk ); } - else if( is_RSA(k->pubkey_algo) ) { + #ifdef HAVE_RSA_CIPHER + else if( algo == PUBKEY_ALGO_RSA || algo == PUBKEY_ALGO_RSA_E ) { RSA_secret_key sk; - assert( ndata == 1 && nskey == 6 ); - sk.e = skey[0]; - sk.n = skey[1]; - sk.p = skey[2]; - sk.q = skey[3]; - sk.d = skey[4]; + sk.n = skey[0]; + sk.e = skey[1]; + sk.d = skey[2]; + sk.p = skey[3]; + sk.q = skey[4]; sk.u = skey[5]; plain = mpi_alloc_secure( mpi_get_nlimbs(sk.n) ); rsa_secret( plain, data[0], &sk ); } + #endif else return G10ERR_PUBKEY_ALGO; + *result = plain; return 0; } +/**************** + * This is the interface to the public key signing. + * Sign hash with skey and put the result into resarr which + * should be an array of MPIs of size PUBKEY_MAX_NSIG (or less if the + * algorithm allows this - check with pubkey_get_nsig() ) + */ +int +pubkey_sign( int algo, MPI *resarr, MPI data, MPI *skey ) +{ + if( DBG_CIPHER ) { + int i; + log_debug("pubkey_sign: algo=%d\n", algo ); + for(i=0; i < pubkey_get_nskey(algo); i++ ) + log_mpidump(" skey:", skey[i] ); + log_mpidump(" data:", data ); + } + + if( is_ELGAMAL(algo) ) { + ELG_secret_key sk; + sk.p = skey[0]; + sk.g = skey[1]; + sk.y = skey[2]; + sk.x = skey[3]; + resarr[0] = mpi_alloc( mpi_get_nlimbs( sk.p ) ); + resarr[1] = mpi_alloc( mpi_get_nlimbs( sk.p ) ); + elg_sign( resarr[0], resarr[1], data, &sk ); + } + else if( algo == PUBKEY_ALGO_DSA ) { + DSA_secret_key sk; + sk.p = skey[0]; + sk.q = skey[1]; + sk.g = skey[2]; + sk.y = skey[3]; + sk.x = skey[4]; + resarr[0] = mpi_alloc( mpi_get_nlimbs( sk.p ) ); + resarr[1] = mpi_alloc( mpi_get_nlimbs( sk.p ) ); + dsa_sign( resarr[0], resarr[1], data, &sk ); + } + #ifdef HAVE_RSA_CIPHER + else if( algo == PUBKEY_ALGO_RSA || algo == PUBKEY_ALGO_RSA_S ) { + RSA_secret_key sk; + sk.n = skey[0]; + sk.e = skey[1]; + sk.d = skey[2]; + sk.p = skey[3]; + sk.q = skey[4]; + sk.u = skey[5]; + plain = mpi_alloc_secure( mpi_get_nlimbs(sk.n) ); + rsa_sign( plain, data[0], &sk ); + } + #endif + else + return G10ERR_PUBKEY_ALGO; + + if( DBG_CIPHER ) { + int i; + for(i=0; i < pubkey_get_nsig(algo); i++ ) + log_mpidump(" sig:", resarr[i] ); + } + + return 0; +} + +/**************** + * Verify a public key signature. + * Return 0 if the signature is good + */ +int +pubkey_verify( int algo, MPI hash, MPI *data, MPI *pkey ) +{ + int rc = 0; + + if( is_ELGAMAL( algo ) ) { + ELG_public_key pk; + pk.p = pkey[0]; + pk.g = pkey[1]; + pk.y = pkey[2]; + if( !elg_verify( data[0], data[1], hash, &pk ) ) + rc = G10ERR_BAD_SIGN; + } + else if( algo == PUBKEY_ALGO_DSA ) { + DSA_public_key pk; + pk.p = pkey[0]; + pk.q = pkey[1]; + pk.g = pkey[2]; + pk.y = pkey[3]; + if( !dsa_verify( data[0], data[1], hash, &pk ) ) + rc = G10ERR_BAD_SIGN; + } + #ifdef HAVE_RSA_CIPHER + else if( algo == PUBKEY_ALGO_RSA || algo == PUBKEY_ALGO_RSA_S ) { + RSA_public_key pk; + int i, j, c, old_enc; + byte *dp; + const byte *asn; + size_t mdlen, asnlen; + + pk.e = pkey[0]; + pk.n = pkey[1]; + result = mpi_alloc(40); + rsa_public( result, data[0], &pk ); + + old_enc = 0; + for(i=j=0; (c=mpi_getbyte(result, i)) != -1; i++ ) { + if( !j ) { + if( !i && c != 1 ) + break; + else if( i && c == 0xff ) + ; /* skip the padding */ + else if( i && !c ) + j++; + else + break; + } + else if( ++j == 18 && c != 1 ) + break; + else if( j == 19 && c == 0 ) { + old_enc++; + break; + } + } + if( old_enc ) { + log_error("old encoding scheme is not supported\n"); + rc = G10ERR_GENERAL; + goto leave; + } + + if( (rc=check_digest_algo(sig->digest_algo)) ) + goto leave; /* unsupported algo */ + md_enable( digest, sig->digest_algo ); + asn = md_asn_oid( sig->digest_algo, &asnlen, &mdlen ); + + for(i=mdlen,j=asnlen-1; (c=mpi_getbyte(result, i)) != -1 && j >= 0; + i++, j-- ) + if( asn[j] != c ) + break; + if( j != -1 || mpi_getbyte(result, i) ) { /* ASN is wrong */ + rc = G10ERR_BAD_PUBKEY; + goto leave; + } + for(i++; (c=mpi_getbyte(result, i)) != -1; i++ ) + if( c != 0xff ) + break; + i++; + if( c != sig->digest_algo || mpi_getbyte(result, i) ) { + /* Padding or leading bytes in signature is wrong */ + rc = G10ERR_BAD_PUBKEY; + goto leave; + } + if( mpi_getbyte(result, mdlen-1) != sig->digest_start[0] + || mpi_getbyte(result, mdlen-2) != sig->digest_start[1] ) { + /* Wrong key used to check the signature */ + rc = G10ERR_BAD_PUBKEY; + goto leave; + } + + /* complete the digest */ + md_putc( digest, sig->sig_class ); + { u32 a = sig->timestamp; + md_putc( digest, (a >> 24) & 0xff ); + md_putc( digest, (a >> 16) & 0xff ); + md_putc( digest, (a >> 8) & 0xff ); + md_putc( digest, a & 0xff ); + } + md_final( digest ); + dp = md_read( digest, sig->digest_algo ); + for(i=mdlen-1; i >= 0; i--, dp++ ) { + if( mpi_getbyte( result, i ) != *dp ) { + rc = G10ERR_BAD_SIGN; + break; + } + } + } + #endif + else + rc = G10ERR_PUBKEY_ALGO; + + return rc; +} + diff --git a/g10/ChangeLog b/g10/ChangeLog index a10527cf1..d6ed0cc6d 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,13 @@ +Thu Jun 11 13:26:44 1998 Werner Koch (wk@isil.d.shuttle.de) + + * packet.h: Mjor chnages to the structure of public key material + which is now stored in an array and not anaymore in a union of + algorithm specific structures. These is needed to make the system + more extendable and makes a lot of stuff much simpler. Changed + all over the system. + + * dsa.c, rsa.c, elg.c: Removed. + Wed Jun 10 07:22:02 1998 Werner Koch,mobil,,, (wk@tobold) * g10.c ("load-extension"): New option. diff --git a/g10/Makefile.am b/g10/Makefile.am index 3e20a48c2..520a945a8 100644 --- a/g10/Makefile.am +++ b/g10/Makefile.am @@ -26,9 +26,6 @@ common_source = \ mdfilter.c \ textfilter.c \ cipher.c \ - elg.c \ - dsa.c \ - rsa.c \ misc.c \ options.h \ openfile.c \ diff --git a/g10/build-packet.c b/g10/build-packet.c index 33709e7da..7048ad9a8 100644 --- a/g10/build-packet.c +++ b/g10/build-packet.c @@ -177,6 +177,7 @@ static int do_public_cert( IOBUF out, int ctb, PKT_public_cert *pkc ) { int rc = 0; + int n, i; IOBUF a = iobuf_temp(); if( !pkc->version ) @@ -187,31 +188,14 @@ do_public_cert( IOBUF out, int ctb, PKT_public_cert *pkc ) if( pkc->version < 4 ) write_16(a, pkc->valid_days ); iobuf_put(a, pkc->pubkey_algo ); - if( is_ELGAMAL(pkc->pubkey_algo) ) { - 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_DSA ) { - mpi_write(a, pkc->d.dsa.p ); - mpi_write(a, pkc->d.dsa.q ); - mpi_write(a, pkc->d.dsa.g ); - mpi_write(a, pkc->d.dsa.y ); - } - else if( is_RSA(pkc->pubkey_algo) ) { - mpi_write(a, pkc->d.rsa.n ); - mpi_write(a, pkc->d.rsa.e ); - } - else { - rc = G10ERR_PUBKEY_ALGO; - goto leave; - } + n = pubkey_get_npkey( pkc->pubkey_algo ); + for(i=0; i < n; i++ ) + mpi_write(a, pkc->pkey[i] ); write_header2(out, ctb, iobuf_get_temp_length(a), pkc->hdrbytes, 1 ); if( iobuf_write_temp( out, a ) ) rc = G10ERR_WRITE_FILE; - leave: iobuf_close(a); return rc; } @@ -227,7 +211,7 @@ hash_public_cert( MD_HANDLE md, PKT_public_cert *pkc ) int rc = 0; int c; IOBUF a = iobuf_temp(); - #if 1 + #if 0 FILE *fp = fopen("dump.pkc", "a"); int i=0; @@ -241,7 +225,7 @@ hash_public_cert( MD_HANDLE md, 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 ) { - #if 1 + #if 0 fprintf( fp," %02x", c ); if( (++i == 24) ) { putc('\n', fp); @@ -250,7 +234,7 @@ hash_public_cert( MD_HANDLE md, PKT_public_cert *pkc ) #endif md_putc( md, c ); } - #if 1 + #if 0 putc('\n', fp); fclose(fp); #endif @@ -262,6 +246,7 @@ static int do_secret_cert( IOBUF out, int ctb, PKT_secret_cert *skc ) { int rc = 0; + int i, nskey, npkey; IOBUF a = iobuf_temp(); if( !skc->version ) @@ -272,11 +257,18 @@ do_secret_cert( IOBUF out, int ctb, PKT_secret_cert *skc ) if( skc->version < 4 ) write_16(a, skc->valid_days ); iobuf_put(a, skc->pubkey_algo ); - if( is_ELGAMAL(skc->pubkey_algo) ) { - mpi_write(a, skc->d.elg.p ); - mpi_write(a, skc->d.elg.g ); - mpi_write(a, skc->d.elg.y ); - if( skc->is_protected ) { + nskey = pubkey_get_nskey( skc->pubkey_algo ); + npkey = pubkey_get_npkey( skc->pubkey_algo ); + assert( npkey < nskey ); + + for(i=0; i < npkey; i++ ) + mpi_write(a, skc->skey[i] ); + if( skc->is_protected ) { + if( is_RSA(skc->pubkey_algo) && skc->version < 4 ) { + iobuf_put(a, skc->protect.algo ); + iobuf_write(a, skc->protect.iv, 8 ); + } + else { iobuf_put(a, 0xff ); iobuf_put(a, skc->protect.algo ); iobuf_put(a, skc->protect.s2k.mode ); @@ -288,60 +280,17 @@ do_secret_cert( IOBUF out, int ctb, PKT_secret_cert *skc ) write_32(a, skc->protect.s2k.count ); iobuf_write(a, skc->protect.iv, 8 ); } - else - iobuf_put(a, 0 ); - - mpi_write(a, skc->d.elg.x ); - write_16(a, skc->csum ); - } - else if( skc->pubkey_algo == PUBKEY_ALGO_DSA ) { - mpi_write(a, skc->d.dsa.p ); - mpi_write(a, skc->d.dsa.q ); - mpi_write(a, skc->d.dsa.g ); - mpi_write(a, skc->d.dsa.y ); - if( skc->is_protected ) { - iobuf_put(a, 0xff ); - iobuf_put(a, skc->protect.algo ); - iobuf_put(a, skc->protect.s2k.mode ); - iobuf_put(a, skc->protect.s2k.hash_algo ); - if( skc->protect.s2k.mode == 1 - || skc->protect.s2k.mode == 4 ) - iobuf_write(a, skc->protect.s2k.salt, 8 ); - if( skc->protect.s2k.mode == 4 ) - write_32(a, skc->protect.s2k.count ); - iobuf_write(a, skc->protect.iv, 8 ); - } - else - iobuf_put(a, 0 ); - - mpi_write(a, skc->d.dsa.x ); - write_16(a, skc->csum ); - } - else if( is_RSA(skc->pubkey_algo) ) { - mpi_write(a, skc->d.rsa.n ); - mpi_write(a, skc->d.rsa.e ); - if( skc->is_protected ) { - iobuf_put(a, skc->protect.algo ); - iobuf_write(a, skc->protect.iv, 8 ); - } - else - iobuf_put(a, 0 ); - mpi_write(a, skc->d.rsa.d ); - mpi_write(a, skc->d.rsa.p ); - mpi_write(a, skc->d.rsa.q ); - mpi_write(a, skc->d.rsa.u ); - write_16(a, skc->csum ); - } - else { - rc = G10ERR_PUBKEY_ALGO; - goto leave; } + else + iobuf_put(a, 0 ); + for( ; i < nskey; i++ ) + mpi_write(a, skc->skey[i] ); + write_16(a, skc->csum ); write_header2(out, ctb, iobuf_get_temp_length(a), skc->hdrbytes, 1 ); if( iobuf_write_temp( out, a ) ) rc = G10ERR_WRITE_FILE; - leave: iobuf_close(a); return rc; } @@ -381,29 +330,21 @@ static int do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc ) { int rc = 0; + int n, i; IOBUF a = iobuf_temp(); write_version( a, ctb ); write_32(a, enc->keyid[0] ); write_32(a, enc->keyid[1] ); iobuf_put(a,enc->pubkey_algo ); - if( is_ELGAMAL(enc->pubkey_algo) ) { - mpi_write(a, enc->d.elg.a ); - mpi_write(a, enc->d.elg.b ); - } - else if( is_RSA(enc->pubkey_algo) ) { - mpi_write(a, enc->d.rsa.rsa_integer ); - } - else { - rc = G10ERR_PUBKEY_ALGO; - goto leave; - } + n = pubkey_get_nenc( enc->pubkey_algo ); + for(i=0; i < n; i++ ) + mpi_write(a, enc->data[i] ); write_header(out, ctb, iobuf_get_temp_length(a) ); if( iobuf_write_temp( out, a ) ) rc = G10ERR_WRITE_FILE; - leave: iobuf_close(a); return rc; } @@ -650,6 +591,7 @@ static int do_signature( IOBUF out, int ctb, PKT_signature *sig ) { int rc = 0; + int n, i; IOBUF a = iobuf_temp(); if( !sig->version ) @@ -684,27 +626,14 @@ do_signature( IOBUF out, int ctb, PKT_signature *sig ) } iobuf_put(a, sig->digest_start[0] ); iobuf_put(a, sig->digest_start[1] ); - if( is_ELGAMAL(sig->pubkey_algo) ) { - mpi_write(a, sig->d.elg.a ); - mpi_write(a, sig->d.elg.b ); - } - else if( sig->pubkey_algo == PUBKEY_ALGO_DSA ) { - mpi_write(a, sig->d.dsa.r ); - mpi_write(a, sig->d.dsa.s ); - } - else if( is_RSA(sig->pubkey_algo) ) { - mpi_write(a, sig->d.rsa.rsa_integer ); - } - else { - rc = G10ERR_PUBKEY_ALGO; - goto leave; - } + n = pubkey_get_nsig( sig->pubkey_algo ); + for(i=0; i < n; i++ ) + mpi_write(a, sig->data[i] ); write_header(out, ctb, iobuf_get_temp_length(a) ); if( iobuf_write_temp( out, a ) ) rc = G10ERR_WRITE_FILE; - leave: iobuf_close(a); return rc; } diff --git a/g10/dsa.c b/g10/dsa.c deleted file mode 100644 index 9bcb013a5..000000000 --- a/g10/dsa.c +++ /dev/null @@ -1,69 +0,0 @@ -/* dsa.c - * Copyright (C) 1998 Free Software Foundation, Inc. - * - * This file is part of GNUPG. - * - * GNUPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GNUPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include -#include -#include -#include -#include -#include - -#include "options.h" -#include "packet.h" -#include "errors.h" -#include "iobuf.h" -#include "keydb.h" -#include "memory.h" -#include "util.h" -#include "main.h" - - -void -g10_dsa_sign( PKT_secret_cert *skc, PKT_signature *sig, - MD_HANDLE md, int digest_algo ) -{ - MPI frame; - byte *dp; - - assert( sig->pubkey_algo == PUBKEY_ALGO_DSA ); - if( !digest_algo ) - digest_algo = md_get_algo(md); - - dp = md_read( md, digest_algo ); - sig->digest_algo = digest_algo; - sig->digest_start[0] = dp[0]; - sig->digest_start[1] = dp[1]; - sig->d.dsa.r = mpi_alloc( mpi_get_nlimbs(skc->d.dsa.p) ); - sig->d.dsa.s = mpi_alloc( mpi_get_nlimbs(skc->d.dsa.p) ); - frame = mpi_alloc( (md_digest_length(digest_algo)+BYTES_PER_MPI_LIMB-1) - / BYTES_PER_MPI_LIMB ); - mpi_set_buffer( frame, md_read(md, digest_algo), - md_digest_length(digest_algo), 0 ); - if( DBG_CIPHER ) - log_mpidump("used sig frame: ", frame); - dsa_sign( sig->d.dsa.r, sig->d.dsa.s, frame, &skc->d.dsa ); - mpi_free(frame); - if( opt.verbose ) { - char *ustr = get_user_id_string( sig->keyid ); - log_info("DSA signature from: %s\n", ustr ); - m_free(ustr); - } -} - diff --git a/g10/elg.c b/g10/elg.c deleted file mode 100644 index cca66d565..000000000 --- a/g10/elg.c +++ /dev/null @@ -1,92 +0,0 @@ -/* elg.c - * Copyright (C) 1998 Free Software Foundation, Inc. - * - * This file is part of GNUPG. - * - * GNUPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GNUPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include -#include -#include -#include -#include -#include - -#include "options.h" -#include "packet.h" -#include "errors.h" -#include "iobuf.h" -#include "keydb.h" -#include "memory.h" -#include "util.h" -#include "main.h" - -void -g10_elg_encrypt( PKT_public_cert *pkc, PKT_pubkey_enc *enc, DEK *dek ) -{ - MPI frame; - - assert( is_ELGAMAL(enc->pubkey_algo) ); - - enc->d.elg.a = mpi_alloc( mpi_get_nlimbs(pkc->d.elg.p) ); - enc->d.elg.b = mpi_alloc( mpi_get_nlimbs(pkc->d.elg.p) ); - keyid_from_pkc( pkc, enc->keyid ); - frame = encode_session_key( dek, mpi_get_nbits(pkc->d.elg.p) ); - if( DBG_CIPHER ) - log_mpidump("Plain DEK frame: ", frame); - elg_encrypt( enc->d.elg.a, enc->d.elg.b, frame, &pkc->d.elg ); - mpi_free( frame ); - if( DBG_CIPHER ) { - log_mpidump("Encry DEK a: ", enc->d.elg.a ); - log_mpidump(" DEK b: ", enc->d.elg.b ); - } - if( opt.verbose ) { - char *ustr = get_user_id_string( enc->keyid ); - log_info("ElGamal encrypted for: %s\n", ustr ); - m_free(ustr); - } -} - - -void -g10_elg_sign( PKT_secret_cert *skc, PKT_signature *sig, - MD_HANDLE md, int digest_algo ) -{ - MPI frame; - byte *dp; - - assert( is_ELGAMAL(sig->pubkey_algo) ); - if( !digest_algo ) - digest_algo = md_get_algo(md); - - dp = md_read( md, digest_algo ); - sig->digest_algo = digest_algo; - sig->digest_start[0] = dp[0]; - sig->digest_start[1] = dp[1]; - sig->d.elg.a = mpi_alloc( mpi_get_nlimbs(skc->d.elg.p) ); - sig->d.elg.b = mpi_alloc( mpi_get_nlimbs(skc->d.elg.p) ); - frame = encode_md_value( md, digest_algo, mpi_get_nbits(skc->d.elg.p)); - if( DBG_CIPHER ) - log_mpidump("calc sig frame (elg): ", frame); - elg_sign( sig->d.elg.a, sig->d.elg.b, frame, &skc->d.elg ); - mpi_free(frame); - if( opt.verbose ) { - char *ustr = get_user_id_string( sig->keyid ); - log_info("ElGamal signature from: %s\n", ustr ); - m_free(ustr); - } -} - diff --git a/g10/encode.c b/g10/encode.c index d3d88ca7b..3d4ad9917 100644 --- a/g10/encode.c +++ b/g10/encode.c @@ -329,26 +329,36 @@ write_pubkey_enc_from_list( PKC_LIST pkc_list, DEK *dek, IOBUF out ) int rc; for( ; pkc_list; pkc_list = pkc_list->next ) { + MPI frame; pkc = pkc_list->pkc; enc = m_alloc_clear( sizeof *enc ); enc->pubkey_algo = pkc->pubkey_algo; - if( is_ELGAMAL(enc->pubkey_algo) ) - g10_elg_encrypt( pkc, enc, dek ); - else if( is_RSA(enc->pubkey_algo) ) - g10_rsa_encrypt( pkc, enc, dek ); - else - BUG(); - /* and write it */ - init_packet(&pkt); - pkt.pkttype = PKT_PUBKEY_ENC; - pkt.pkt.pubkey_enc = enc; - rc = build_packet( out, &pkt ); - free_pubkey_enc(enc); - if( rc ) { - log_error("build pubkey_enc packet failed: %s\n", g10_errstr(rc) ); - return rc; + keyid_from_pkc( pkc, enc->keyid ); + frame = encode_session_key( dek, pubkey_nbits( pkc->pubkey_algo, + pkc->pkey ) ); + rc = pubkey_encrypt( pkc->pubkey_algo, enc->data, frame, pkc->pkey ); + mpi_free( frame ); + if( rc ) + log_error("pubkey_encrypt failed: %s\n", g10_errstr(rc) ); + else { + if( opt.verbose ) { + char *ustr = get_user_id_string( enc->keyid ); + log_info("%s encrypted for: %s\n", + pubkey_algo_to_string(enc->pubkey_algo), ustr ); + m_free(ustr); + } + /* and write it */ + init_packet(&pkt); + pkt.pkttype = PKT_PUBKEY_ENC; + pkt.pkt.pubkey_enc = enc; + rc = build_packet( out, &pkt ); + if( rc ) + log_error("build_packet(pubkey_enc) failed: %s\n", g10_errstr(rc)); } + free_pubkey_enc(enc); + if( rc ) + return rc; } return 0; } diff --git a/g10/free-packet.c b/g10/free-packet.c index 3cf82c8ac..12382b4db 100644 --- a/g10/free-packet.c +++ b/g10/free-packet.c @@ -40,28 +40,20 @@ free_symkey_enc( PKT_symkey_enc *enc ) void free_pubkey_enc( PKT_pubkey_enc *enc ) { - if( is_ELGAMAL(enc->pubkey_algo) ) { - mpi_free( enc->d.elg.a ); - mpi_free( enc->d.elg.b ); - } - else if( is_RSA(enc->pubkey_algo) ) - mpi_free( enc->d.rsa.rsa_integer ); + int n, i; + n = pubkey_get_nenc( enc->pubkey_algo ); + for(i=0; i < n; i++ ) + mpi_free( enc->data[i] ); m_free(enc); } void free_seckey_enc( PKT_signature *sig ) { - if( is_ELGAMAL(sig->pubkey_algo) ) { - mpi_free( sig->d.elg.a ); - mpi_free( sig->d.elg.b ); - } - else if( sig->pubkey_algo == PUBKEY_ALGO_DSA ) { - mpi_free( sig->d.dsa.r ); - mpi_free( sig->d.dsa.s ); - } - else if( is_RSA(sig->pubkey_algo) ) - mpi_free( sig->d.rsa.rsa_integer ); + int n, i; + n = pubkey_get_nenc( sig->pubkey_algo ); + for(i=0; i < n; i++ ) + mpi_free( sig->data[i] ); m_free(sig->hashed_data); m_free(sig->unhashed_data); m_free(sig); @@ -72,23 +64,15 @@ free_seckey_enc( PKT_signature *sig ) void release_public_cert_parts( PKT_public_cert *cert ) { - if( is_ELGAMAL(cert->pubkey_algo) ) { - mpi_free( cert->d.elg.p ); cert->d.elg.p = NULL; - mpi_free( cert->d.elg.g ); cert->d.elg.g = NULL; - mpi_free( cert->d.elg.y ); cert->d.elg.y = NULL; - } - else if( cert->pubkey_algo == PUBKEY_ALGO_DSA ) { - mpi_free( cert->d.dsa.p ); cert->d.dsa.p = NULL; - mpi_free( cert->d.dsa.q ); cert->d.dsa.q = NULL; - mpi_free( cert->d.dsa.g ); cert->d.dsa.g = NULL; - mpi_free( cert->d.dsa.y ); cert->d.dsa.y = NULL; - } - else if( is_RSA(cert->pubkey_algo) ) { - mpi_free( cert->d.rsa.n ); cert->d.rsa.n = NULL; - mpi_free( cert->d.rsa.e ); cert->d.rsa.e = NULL; + int n, i; + n = pubkey_get_npkey( cert->pubkey_algo ); + for(i=0; i < n; i++ ) { + mpi_free( cert->pkey[i] ); + cert->pkey[i] = NULL; } } + void free_public_cert( PKT_public_cert *cert ) { @@ -99,50 +83,26 @@ free_public_cert( PKT_public_cert *cert ) PKT_public_cert * copy_public_cert( PKT_public_cert *d, PKT_public_cert *s ) { + int n, i; + if( !d ) d = m_alloc(sizeof *d); memcpy( d, s, sizeof *d ); - if( is_ELGAMAL(s->pubkey_algo) ) { - d->d.elg.p = mpi_copy( s->d.elg.p ); - d->d.elg.g = mpi_copy( s->d.elg.g ); - d->d.elg.y = mpi_copy( s->d.elg.y ); - } - else if( s->pubkey_algo == PUBKEY_ALGO_DSA ) { - d->d.dsa.p = mpi_copy( s->d.dsa.p ); - d->d.dsa.q = mpi_copy( s->d.dsa.q ); - d->d.dsa.g = mpi_copy( s->d.dsa.g ); - d->d.dsa.y = mpi_copy( s->d.dsa.y ); - } - else if( is_RSA(s->pubkey_algo) ) { - d->d.rsa.n = mpi_copy( s->d.rsa.n ); - d->d.rsa.e = mpi_copy( s->d.rsa.e ); - } + n = pubkey_get_npkey( s->pubkey_algo ); + for(i=0; i < n; i++ ) + d->pkey[i] = mpi_copy( s->pkey[i] ); return d; } void release_secret_cert_parts( PKT_secret_cert *cert ) { - if( is_ELGAMAL(cert->pubkey_algo) ) { - mpi_free( cert->d.elg.p ); cert->d.elg.p = NULL; - mpi_free( cert->d.elg.g ); cert->d.elg.g = NULL; - mpi_free( cert->d.elg.y ); cert->d.elg.y = NULL; - mpi_free( cert->d.elg.x ); cert->d.elg.x = NULL; - } - else if( cert->pubkey_algo == PUBKEY_ALGO_DSA ) { - mpi_free( cert->d.dsa.p ); cert->d.dsa.p = NULL; - mpi_free( cert->d.dsa.q ); cert->d.dsa.q = NULL; - mpi_free( cert->d.dsa.g ); cert->d.dsa.g = NULL; - mpi_free( cert->d.dsa.y ); cert->d.dsa.y = NULL; - mpi_free( cert->d.dsa.x ); cert->d.dsa.x = NULL; - } - else if( is_RSA(cert->pubkey_algo) ) { - mpi_free( cert->d.rsa.n ); cert->d.rsa.n = NULL; - mpi_free( cert->d.rsa.e ); cert->d.rsa.e = NULL; - mpi_free( cert->d.rsa.d ); cert->d.rsa.d = NULL; - mpi_free( cert->d.rsa.p ); cert->d.rsa.p = NULL; - mpi_free( cert->d.rsa.q ); cert->d.rsa.q = NULL; - mpi_free( cert->d.rsa.u ); cert->d.rsa.u = NULL; + int n, i; + + n = pubkey_get_nskey( cert->pubkey_algo ); + for(i=0; i < n; i++ ) { + mpi_free( cert->skey[i] ); + cert->skey[i] = NULL; } } @@ -156,30 +116,14 @@ free_secret_cert( PKT_secret_cert *cert ) PKT_secret_cert * copy_secret_cert( PKT_secret_cert *d, PKT_secret_cert *s ) { + int n, i; + if( !d ) d = m_alloc(sizeof *d); memcpy( d, s, sizeof *d ); - if( is_ELGAMAL(s->pubkey_algo) ) { - d->d.elg.p = mpi_copy( s->d.elg.p ); - d->d.elg.g = mpi_copy( s->d.elg.g ); - d->d.elg.y = mpi_copy( s->d.elg.y ); - d->d.elg.x = mpi_copy( s->d.elg.x ); - } - else if( s->pubkey_algo == PUBKEY_ALGO_DSA ) { - d->d.dsa.p = mpi_copy( s->d.dsa.p ); - d->d.dsa.q = mpi_copy( s->d.dsa.q ); - d->d.dsa.g = mpi_copy( s->d.dsa.g ); - d->d.dsa.y = mpi_copy( s->d.dsa.y ); - d->d.dsa.x = mpi_copy( s->d.dsa.x ); - } - else if( is_RSA(s->pubkey_algo) ) { - d->d.rsa.n = mpi_copy( s->d.rsa.n ); - d->d.rsa.e = mpi_copy( s->d.rsa.e ); - d->d.rsa.d = mpi_copy( s->d.rsa.d ); - d->d.rsa.p = mpi_copy( s->d.rsa.p ); - d->d.rsa.q = mpi_copy( s->d.rsa.q ); - d->d.rsa.u = mpi_copy( s->d.rsa.u ); - } + n = pubkey_get_nskey( s->pubkey_algo ); + for(i=0; i < n; i++ ) + d->skey[i] = mpi_copy( s->skey[i] ); return d; } @@ -298,6 +242,8 @@ free_packet( PACKET *pkt ) int cmp_public_certs( PKT_public_cert *a, PKT_public_cert *b ) { + int n, i; + if( a->timestamp != b->timestamp ) return -1; if( a->valid_days != b->valid_days ) @@ -305,28 +251,9 @@ cmp_public_certs( PKT_public_cert *a, PKT_public_cert *b ) if( a->pubkey_algo != b->pubkey_algo ) return -1; - if( is_ELGAMAL(a->pubkey_algo) ) { - if( mpi_cmp( a->d.elg.p , b->d.elg.p ) ) - return -1; - if( mpi_cmp( a->d.elg.g , b->d.elg.g ) ) - return -1; - if( mpi_cmp( a->d.elg.y , b->d.elg.y ) ) - return -1; - } - else if( a->pubkey_algo == PUBKEY_ALGO_DSA ) { - if( mpi_cmp( a->d.dsa.p , b->d.dsa.p ) ) - return -1; - if( mpi_cmp( a->d.dsa.q , b->d.dsa.q ) ) - return -1; - if( mpi_cmp( a->d.dsa.g , b->d.dsa.g ) ) - return -1; - if( mpi_cmp( a->d.dsa.y , b->d.dsa.y ) ) - return -1; - } - else if( is_RSA(a->pubkey_algo) ) { - if( mpi_cmp( a->d.rsa.n , b->d.rsa.n ) ) - return -1; - if( mpi_cmp( a->d.rsa.e , b->d.rsa.e ) ) + n = pubkey_get_npkey( b->pubkey_algo ); + for(i=0; i < n; i++ ) { + if( mpi_cmp( a->pkey[i], b->pkey[i] ) ) return -1; } @@ -339,6 +266,8 @@ cmp_public_certs( PKT_public_cert *a, PKT_public_cert *b ) int cmp_public_secret_cert( PKT_public_cert *pkc, PKT_secret_cert *skc ) { + int n, i; + if( pkc->timestamp != skc->timestamp ) return -1; if( pkc->valid_days != skc->valid_days ) @@ -346,31 +275,11 @@ cmp_public_secret_cert( PKT_public_cert *pkc, PKT_secret_cert *skc ) if( pkc->pubkey_algo != skc->pubkey_algo ) return -1; - if( is_ELGAMAL(pkc->pubkey_algo) ) { - if( mpi_cmp( pkc->d.elg.p , skc->d.elg.p ) ) - return -1; - if( mpi_cmp( pkc->d.elg.g , skc->d.elg.g ) ) - return -1; - if( mpi_cmp( pkc->d.elg.y , skc->d.elg.y ) ) + n = pubkey_get_npkey( pkc->pubkey_algo ); + for(i=0; i < n; i++ ) { + if( mpi_cmp( pkc->pkey[i] , skc->skey[i] ) ) return -1; } - else if( pkc->pubkey_algo == PUBKEY_ALGO_DSA ) { - if( mpi_cmp( pkc->d.dsa.p , skc->d.dsa.p ) ) - return -1; - if( mpi_cmp( pkc->d.dsa.q , skc->d.dsa.q ) ) - return -1; - if( mpi_cmp( pkc->d.dsa.g , skc->d.dsa.g ) ) - return -1; - if( mpi_cmp( pkc->d.dsa.y , skc->d.dsa.y ) ) - return -1; - } - else if( is_RSA(pkc->pubkey_algo) ) { - if( mpi_cmp( pkc->d.rsa.n , skc->d.rsa.n ) ) - return -1; - if( mpi_cmp( pkc->d.rsa.e , skc->d.rsa.e ) ) - return -1; - } - return 0; } diff --git a/g10/keygen.c b/g10/keygen.c index 367c22de5..63c162fb2 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -155,17 +155,17 @@ gen_elg(unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek, skc->version = pkc->version = version; skc->valid_days = pkc->valid_days = valid_days; skc->pubkey_algo = pkc->pubkey_algo = PUBKEY_ALGO_ELGAMAL; - pkc->d.elg.p = pk.p; - pkc->d.elg.g = pk.g; - pkc->d.elg.y = pk.y; - skc->d.elg.p = sk.p; - skc->d.elg.g = sk.g; - skc->d.elg.y = sk.y; - skc->d.elg.x = sk.x; + pkc->pkey[0] = pk.p; + pkc->pkey[1] = pk.g; + pkc->pkey[2] = pk.y; + skc->skey[0] = sk.p; + skc->skey[1] = sk.g; + skc->skey[2] = sk.y; + skc->skey[3] = sk.x; skc->is_protected = 0; skc->protect.algo = 0; - skc->csum = checksum_mpi( skc->d.elg.x ); + skc->csum = checksum_mpi( skc->skey[3] ); if( ret_skc ) /* not a subkey: return an unprotected version of the skc */ *ret_skc = copy_secret_cert( NULL, skc ); @@ -296,19 +296,19 @@ gen_dsa(unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek, */ skc->valid_days = pkc->valid_days = valid_days; skc->pubkey_algo = pkc->pubkey_algo = PUBKEY_ALGO_DSA; - pkc->d.dsa.p = pk.p; - pkc->d.dsa.q = pk.q; - pkc->d.dsa.g = pk.g; - pkc->d.dsa.y = pk.y; - skc->d.dsa.p = sk.p; - skc->d.dsa.q = sk.q; - skc->d.dsa.g = sk.g; - skc->d.dsa.y = sk.y; - skc->d.dsa.x = sk.x; + pkc->pkey[0] = pk.p; + pkc->pkey[1] = pk.q; + pkc->pkey[2] = pk.g; + pkc->pkey[3] = pk.y; + skc->skey[0] = sk.p; + skc->skey[1] = sk.q; + skc->skey[2] = sk.g; + skc->skey[3] = sk.y; + skc->skey[4] = sk.x; skc->is_protected = 0; skc->protect.algo = 0; - skc->csum = checksum_mpi( skc->d.dsa.x ); + skc->csum = checksum_mpi( skc->skey[4] ); if( ret_skc ) /* not a subkey: return an unprotected version of the skc */ *ret_skc = copy_secret_cert( NULL, skc ); diff --git a/g10/keyid.c b/g10/keyid.c index 55c0c49ae..dc24904c7 100644 --- a/g10/keyid.c +++ b/g10/keyid.c @@ -47,182 +47,72 @@ pubkey_letter( int algo ) } } -/* this is special code for V3 which uses ElGamal and - * calculates a fingerprint like V4, but with rmd160 - * and a version byte of 3. Returns an md handle, caller must - * do md_close() - */ static MD_HANDLE -v3_elg_fingerprint_md( PKT_public_cert *pkc ) +do_fingerprint_md( PKT_public_cert *pkc ) { MD_HANDLE md; - byte *buf1, *buf2, *buf3; - byte *p1, *p2, *p3; - unsigned n1, n2, n3; - unsigned nb1, nb2, nb3; unsigned n; + unsigned nb[PUBKEY_MAX_NPKEY]; + unsigned nn[PUBKEY_MAX_NPKEY]; + byte *pp[PUBKEY_MAX_NPKEY]; + int i; + int npkey = pubkey_get_npkey( pkc->pubkey_algo ); - nb1 = mpi_get_nbits(pkc->d.elg.p); - p1 = buf1 = mpi_get_buffer( pkc->d.elg.p, &n1, NULL ); - nb2 = mpi_get_nbits(pkc->d.elg.g); - p2 = buf2 = mpi_get_buffer( pkc->d.elg.g, &n2, NULL ); - nb3 = mpi_get_nbits(pkc->d.elg.y); - p3 = buf3 = mpi_get_buffer( pkc->d.elg.y, &n3, NULL ); - - /* calculate length of packet (1+4+2+1+2+n1+2+n2+2+n3) */ - n = 14 + n1 + n2 + n3; - md = md_open( DIGEST_ALGO_RMD160, 0); + md = md_open( pkc->version < 4 ? DIGEST_ALGO_RMD160 : DIGEST_ALGO_SHA1, 0); + n = pkc->version < 4 ? 8 : 6; + for(i=0; i < npkey; i++ ) { + nb[i] = mpi_get_nbits(pkc->pkey[i]); + pp[i] = mpi_get_buffer( pkc->pkey[i], nn+i, NULL ); + n += 2 + nn[i]; + } md_putc( md, 0x99 ); /* ctb */ md_putc( md, n >> 8 ); /* 2 byte length header */ md_putc( md, n ); - md_putc( md, 3 ); /* version */ + if( pkc->version < 4 ) + md_putc( md, 3 ); + else + md_putc( md, 4 ); + { u32 a = pkc->timestamp; md_putc( md, a >> 24 ); md_putc( md, a >> 16 ); md_putc( md, a >> 8 ); md_putc( md, a ); } - { u16 a = pkc->valid_days; + if( pkc->version < 4 ) { + u16 a = pkc->valid_days; md_putc( md, a >> 8 ); md_putc( md, a ); } md_putc( md, pkc->pubkey_algo ); - md_putc( md, nb1>>8); md_putc( md, nb1 ); md_write( md, p1, n1 ); - md_putc( md, nb2>>8); md_putc( md, nb2 ); md_write( md, p2, n2 ); - md_putc( md, nb3>>8); md_putc( md, nb3 ); md_write( md, p3, n3 ); - m_free(buf1); - m_free(buf2); - m_free(buf3); - md_final( md ); - - return md; -} - -static MD_HANDLE -elg_fingerprint_md( PKT_public_cert *pkc ) -{ - MD_HANDLE md; - byte *buf1, *buf3, *buf4 ; - byte *p1, *p3, *p4; - unsigned n1, n3, n4; - unsigned nb1, nb3, nb4; - unsigned n; - - nb1 = mpi_get_nbits(pkc->d.elg.p); - p1 = buf1 = mpi_get_buffer( pkc->d.elg.p, &n1, NULL ); - nb3 = mpi_get_nbits(pkc->d.elg.g); - p3 = buf3 = mpi_get_buffer( pkc->d.elg.g, &n3, NULL ); - nb4 = mpi_get_nbits(pkc->d.elg.y); - p4 = buf4 = mpi_get_buffer( pkc->d.elg.y, &n4, NULL ); - - /* calculate length of packet */ - n = 12 + n1 + n3 +n4 ; - md = md_open( DIGEST_ALGO_SHA1, 0); - - md_putc( md, 0x99 ); /* ctb */ - md_putc( md, n >> 8 ); /* 2 byte length header */ - md_putc( md, n ); - md_putc( md, 4 ); /* version */ - { u32 a = pkc->timestamp; - md_putc( md, a >> 24 ); - md_putc( md, a >> 16 ); - md_putc( md, a >> 8 ); - md_putc( md, a ); + for(i=0; i < npkey; i++ ) { + md_putc( md, nb[i]>>8); + md_putc( md, nb[i] ); + md_write( md, pp[i], nn[i] ); + m_free(pp[i]); } - md_putc( md, pkc->pubkey_algo ); - md_putc( md, nb1>>8); md_putc( md, nb1 ); md_write( md, p1, n1 ); - md_putc( md, nb3>>8); md_putc( md, nb3 ); md_write( md, p3, n3 ); - md_putc( md, nb4>>8); md_putc( md, nb4 ); md_write( md, p4, n4 ); - m_free(buf1); - m_free(buf3); - m_free(buf4); - md_final( md ); - - return md; -} - - -static MD_HANDLE -dsa_fingerprint_md( PKT_public_cert *pkc ) -{ - MD_HANDLE md; - byte *buf1, *buf2, *buf3, *buf4 ; - byte *p1, *p2, *p3, *p4; - unsigned n1, n2, n3, n4; - unsigned nb1, nb2, nb3, nb4; - unsigned n; - - nb1 = mpi_get_nbits(pkc->d.dsa.p); - p1 = buf1 = mpi_get_buffer( pkc->d.dsa.p, &n1, NULL ); - nb2 = mpi_get_nbits(pkc->d.dsa.q); - p2 = buf2 = mpi_get_buffer( pkc->d.dsa.q, &n2, NULL ); - nb3 = mpi_get_nbits(pkc->d.dsa.g); - p3 = buf3 = mpi_get_buffer( pkc->d.dsa.g, &n3, NULL ); - nb4 = mpi_get_nbits(pkc->d.dsa.y); - p4 = buf4 = mpi_get_buffer( pkc->d.dsa.y, &n4, NULL ); - - /* calculate length of packet */ - n = 14 + n1 + n2 + n3 +n4 ; - md = md_open( DIGEST_ALGO_SHA1, 0); - - md_putc( md, 0x99 ); /* ctb */ - md_putc( md, n >> 8 ); /* 2 byte length header */ - md_putc( md, n ); - md_putc( md, 4 ); /* version */ - { u32 a = pkc->timestamp; - md_putc( md, a >> 24 ); - md_putc( md, a >> 16 ); - md_putc( md, a >> 8 ); - md_putc( md, a ); - } - md_putc( md, pkc->pubkey_algo ); - md_putc( md, nb1>>8); md_putc( md, nb1 ); md_write( md, p1, n1 ); - md_putc( md, nb2>>8); md_putc( md, nb2 ); md_write( md, p2, n2 ); - md_putc( md, nb3>>8); md_putc( md, nb3 ); md_write( md, p3, n3 ); - md_putc( md, nb4>>8); md_putc( md, nb4 ); md_write( md, p4, n4 ); - m_free(buf1); - m_free(buf2); - m_free(buf3); - m_free(buf4); md_final( md ); return md; } static MD_HANDLE -elg_fingerprint_md_skc( PKT_secret_cert *skc ) +do_fingerprint_md_skc( PKT_secret_cert *skc ) { PKT_public_cert pkc; + int npkey = pubkey_get_npkey( skc->pubkey_algo ); /* npkey is correct! */ + int i; pkc.pubkey_algo = skc->pubkey_algo; pkc.version = skc->version; 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; - if( pkc.version < 4 ) - return v3_elg_fingerprint_md( &pkc ); - else - return elg_fingerprint_md( &pkc ); -} - -static MD_HANDLE -dsa_fingerprint_md_skc( PKT_secret_cert *skc ) -{ - PKT_public_cert pkc; - - pkc.pubkey_algo = skc->pubkey_algo; - pkc.timestamp = skc->timestamp; - pkc.pubkey_algo = skc->pubkey_algo; - pkc.d.dsa.p = skc->d.dsa.p; - pkc.d.dsa.q = skc->d.dsa.q; - pkc.d.dsa.g = skc->d.dsa.g; - pkc.d.dsa.y = skc->d.dsa.y; - return dsa_fingerprint_md( &pkc ); + for( i=0; i < npkey; i++ ) + pkc.pkey[i] = skc->skey[i]; + return do_fingerprint_md( &pkc ); } @@ -239,35 +129,20 @@ keyid_from_skc( PKT_secret_cert *skc, u32 *keyid ) if( !keyid ) keyid = dummy_keyid; - if( is_ELGAMAL(skc->pubkey_algo) ) { - const byte *dp; - MD_HANDLE md; - md = elg_fingerprint_md_skc(skc); - if( skc->version < 4 ) - dp = md_read( md, DIGEST_ALGO_RMD160 ); - else - dp = md_read( md, DIGEST_ALGO_SHA1 ); - keyid[0] = dp[12] << 24 | dp[13] << 16 | dp[14] << 8 | dp[15] ; - keyid[1] = dp[16] << 24 | dp[17] << 16 | dp[18] << 8 | dp[19] ; - lowbits = keyid[1]; - md_close(md); - } - else if( skc->pubkey_algo == PUBKEY_ALGO_DSA ) { - const byte *dp; - MD_HANDLE md; - md = dsa_fingerprint_md_skc(skc); - dp = md_read( md, DIGEST_ALGO_SHA1 ); - keyid[0] = dp[12] << 24 | dp[13] << 16 | dp[14] << 8 | dp[15] ; - keyid[1] = dp[16] << 24 | dp[17] << 16 | dp[18] << 8 | dp[19] ; - lowbits = keyid[1]; - md_close(md); - } - else if( is_RSA(skc->pubkey_algo) ) { - lowbits = mpi_get_keyid( skc->d.rsa.n, keyid ); + if( skc->version < 4 && is_RSA(skc->pubkey_algo) ) { + lowbits = mpi_get_keyid( skc->skey[0], keyid ); /* take n */ } else { - keyid[0] = keyid[1] = lowbits = 0; + const byte *dp; + MD_HANDLE md; + md = do_fingerprint_md_skc(skc); + dp = md_read( md, 0 ); + keyid[0] = dp[12] << 24 | dp[13] << 16 | dp[14] << 8 | dp[15] ; + keyid[1] = dp[16] << 24 | dp[17] << 16 | dp[18] << 8 | dp[19] ; + lowbits = keyid[1]; + md_close(md); } + return lowbits; } @@ -285,37 +160,18 @@ keyid_from_pkc( PKT_public_cert *pkc, u32 *keyid ) if( !keyid ) keyid = dummy_keyid; - if( is_ELGAMAL(pkc->pubkey_algo) ) { - const byte *dp; - MD_HANDLE md; - if( pkc->version < 4 ) { - md = v3_elg_fingerprint_md(pkc); - dp = md_read( md, DIGEST_ALGO_RMD160 ); - } - else { - md = elg_fingerprint_md(pkc); - dp = md_read( md, DIGEST_ALGO_SHA1 ); - } - keyid[0] = dp[12] << 24 | dp[13] << 16 | dp[14] << 8 | dp[15] ; - keyid[1] = dp[16] << 24 | dp[17] << 16 | dp[18] << 8 | dp[19] ; - lowbits = keyid[1]; - md_close(md); - } - else if( pkc->pubkey_algo == PUBKEY_ALGO_DSA ) { - const byte *dp; - MD_HANDLE md; - md = dsa_fingerprint_md(pkc); - dp = md_read( md, DIGEST_ALGO_SHA1 ); - keyid[0] = dp[12] << 24 | dp[13] << 16 | dp[14] << 8 | dp[15] ; - keyid[1] = dp[16] << 24 | dp[17] << 16 | dp[18] << 8 | dp[19] ; - lowbits = keyid[1]; - md_close(md); - } - else if( is_RSA(pkc->pubkey_algo) ) { - lowbits = mpi_get_keyid( pkc->d.rsa.n, keyid ); + if( pkc->version < 4 && is_RSA(pkc->pubkey_algo) ) { + lowbits = mpi_get_keyid( pkc->pkey[0], keyid ); /* from n */ } else { - keyid[0] = keyid[1] = lowbits = 0; + const byte *dp; + MD_HANDLE md; + md = do_fingerprint_md(pkc); + dp = md_read( md, 0 ); + keyid[0] = dp[12] << 24 | dp[13] << 16 | dp[14] << 8 | dp[15] ; + keyid[1] = dp[16] << 24 | dp[17] << 16 | dp[18] << 8 | dp[19] ; + lowbits = keyid[1]; + md_close(md); } return lowbits; @@ -338,17 +194,7 @@ keyid_from_sig( PKT_signature *sig, u32 *keyid ) unsigned nbits_from_pkc( PKT_public_cert *pkc ) { - if( is_ELGAMAL(pkc->pubkey_algo) ) { - return mpi_get_nbits( pkc->d.elg.p ); - } - else if( pkc->pubkey_algo == PUBKEY_ALGO_DSA ) { - return mpi_get_nbits( pkc->d.dsa.p ); - } - else if( is_RSA(pkc->pubkey_algo) ) { - return mpi_get_nbits( pkc->d.rsa.n ); - } - else - return 0; + return pubkey_nbits( pkc->pubkey_algo, pkc->pkey ); } /**************** @@ -357,17 +203,7 @@ nbits_from_pkc( PKT_public_cert *pkc ) unsigned nbits_from_skc( PKT_secret_cert *skc ) { - if( is_ELGAMAL(skc->pubkey_algo) ) { - return mpi_get_nbits( skc->d.elg.p ); - } - else if( skc->pubkey_algo == PUBKEY_ALGO_DSA ) { - return mpi_get_nbits( skc->d.dsa.p ); - } - else if( is_RSA(skc->pubkey_algo) ) { - return mpi_get_nbits( skc->d.rsa.n ); - } - else - return 0; + return pubkey_nbits( skc->pubkey_algo, skc->skey ); } /**************** @@ -417,40 +253,6 @@ datestr_from_sig( PKT_signature *sig ) * 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; - pkc.version = skc->version; - if( is_ELGAMAL(pkc.pubkey_algo) ) { - 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_DSA ) { - pkc.timestamp = skc->timestamp; - pkc.valid_days = skc->valid_days; - pkc.pubkey_algo = skc->pubkey_algo; - pkc.d.dsa.p = skc->d.dsa.p; - pkc.d.dsa.q = skc->d.dsa.q; - pkc.d.dsa.g = skc->d.dsa.g; - pkc.d.dsa.y = skc->d.dsa.y; - } - else if( is_RSA(pkc.pubkey_algo) ) { - pkc.d.rsa.n = skc->d.rsa.n; - pkc.d.rsa.e = skc->d.rsa.e; - } - p = fingerprint_from_pkc( &pkc, ret_len ); - memset(&pkc, 0, sizeof pkc); /* not really needed */ - return p; -} - @@ -462,38 +264,15 @@ fingerprint_from_pkc( PKT_public_cert *pkc, size_t *ret_len ) size_t len; unsigned n; - if( is_ELGAMAL(pkc->pubkey_algo) ) { - MD_HANDLE md; - if( pkc->version < 4 ) { - md = v3_elg_fingerprint_md(pkc); - dp = md_read( md, DIGEST_ALGO_RMD160 ); - } - else { - md = elg_fingerprint_md(pkc); - dp = md_read( md, DIGEST_ALGO_SHA1 ); - } - array = m_alloc( 20 ); - len = 20; - memcpy(array, dp, 20 ); - md_close(md); - } - else if( pkc->pubkey_algo == PUBKEY_ALGO_DSA ) { - MD_HANDLE md; - md = dsa_fingerprint_md(pkc); - dp = md_read( md, DIGEST_ALGO_SHA1 ); - array = m_alloc( 20 ); - len = 20; - memcpy(array, dp, 20 ); - md_close(md); - } - else if( is_RSA(pkc->pubkey_algo) ) { + if( pkc->version < 4 && is_RSA(pkc->pubkey_algo) ) { + /* RSA in version 3 packets is special */ MD_HANDLE md; md = md_open( DIGEST_ALGO_MD5, 0); - p = buf = mpi_get_buffer( pkc->d.rsa.n, &n, NULL ); + p = buf = mpi_get_buffer( pkc->pkey[0], &n, NULL ); md_write( md, p, n ); m_free(buf); - p = buf = mpi_get_buffer( pkc->d.rsa.e, &n, NULL ); + p = buf = mpi_get_buffer( pkc->pkey[1], &n, NULL ); md_write( md, p, n ); m_free(buf); md_final(md); @@ -503,8 +282,52 @@ fingerprint_from_pkc( PKT_public_cert *pkc, size_t *ret_len ) md_close(md); } else { - array = m_alloc(1); - len = 0; /* ooops */ + MD_HANDLE md; + md = do_fingerprint_md(pkc); + dp = md_read( md, 0 ); + len = md_digest_length( md_get_algo( md ) ); + array = m_alloc( len ); + memcpy(array, dp, len ); + md_close(md); + } + + *ret_len = len; + return array; +} + +byte * +fingerprint_from_skc( PKT_secret_cert *skc, size_t *ret_len ) +{ + byte *p, *buf, *array; + const char *dp; + size_t len; + unsigned n; + + if( skc->version < 4 && is_RSA(skc->pubkey_algo) ) { + /* RSA in version 3 packets is special */ + MD_HANDLE md; + + md = md_open( DIGEST_ALGO_MD5, 0); + p = buf = mpi_get_buffer( skc->skey[1], &n, NULL ); + md_write( md, p, n ); + m_free(buf); + p = buf = mpi_get_buffer( skc->skey[0], &n, NULL ); + md_write( md, p, n ); + m_free(buf); + md_final(md); + array = m_alloc( 16 ); + len = 16; + memcpy(array, md_read(md, DIGEST_ALGO_MD5), 16 ); + md_close(md); + } + else { + MD_HANDLE md; + md = do_fingerprint_md_skc(skc); + dp = md_read( md, 0 ); + len = md_digest_length( md_get_algo( md ) ); + array = m_alloc( len ); + memcpy(array, dp, len ); + md_close(md); } *ret_len = len; diff --git a/g10/main.h b/g10/main.h index 017bb781b..56fd3c9d5 100644 --- a/g10/main.h +++ b/g10/main.h @@ -91,20 +91,6 @@ MPI encode_md_value( MD_HANDLE md, int hash_algo, unsigned nbits ); KBNODE make_comment_node( const char *s ); KBNODE make_mpi_comment_node( const char *s, MPI a ); -/*-- elg.c --*/ -void g10_elg_encrypt( PKT_public_cert *pkc, PKT_pubkey_enc *enc, DEK *dek ); -void g10_elg_sign( PKT_secret_cert *skc, PKT_signature *sig, - MD_HANDLE md, int digest_algo ); - -/*-- dsa.c --*/ -void g10_dsa_sign( PKT_secret_cert *skc, PKT_signature *sig, - MD_HANDLE md, int digest_algo ); - -/*-- rsa.c --*/ -void g10_rsa_encrypt( PKT_public_cert *pkc, PKT_pubkey_enc *enc, DEK *dek ); -void g10_rsa_sign( PKT_secret_cert *skc, PKT_signature *sig, - MD_HANDLE md, int digest_algo ); - /*-- import.c --*/ int import_pubkeys( const char *filename ); /*-- export.c --*/ diff --git a/g10/packet.h b/g10/packet.h index cb9740cc6..4f04e1ae4 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -68,8 +68,7 @@ typedef struct { u32 keyid[2]; /* 64 bit keyid */ byte version; byte pubkey_algo; /* algorithm used for public key scheme */ - int mpi_count; /* 1 for rsa, 2 for ELG */ - MPI material[2]; /* (ELG needs 2) + MPI data[PUBKEY_MAX_NENC]; } PKT_pubkey_enc; @@ -94,20 +93,16 @@ typedef struct { byte *hashed_data; /* all subpackets with hashed data (v4 only) */ byte *unhashed_data; /* ditto for unhashed data */ byte digest_start[2]; /* first 2 bytes of the digest */ - union { - struct { - MPI a, b; /* integers with the digest */ - } elg; - struct { - MPI r, s; /* integers with the digest */ - } dsa; - struct { - MPI rsa_integer; /* the encrypted digest */ - } rsa; - } d; + MPI data[PUBKEY_MAX_NSIG]; } PKT_signature; +/**************** + * Note about the pkey/skey elements: We assume that the secret keys + * has the same elemts as the public key at the begin of the array, so + * that npkey < nskey and it is possible to compare the secret and + * public keys by comparing the first npkey elements of pkey againts skey. + */ typedef struct { u32 timestamp; /* certificate made */ u16 valid_days; /* valid for this number of days */ @@ -115,11 +110,7 @@ typedef struct { byte version; byte pubkey_algo; /* algorithm used for public key scheme */ ulong local_id; /* internal use, valid if > 0 */ - union { - ELG_public_key elg; - DSA_public_key dsa; - RSA_public_key rsa; - } d; + MPI pkey[PUBKEY_MAX_NPKEY]; } PKT_public_cert; typedef struct { @@ -137,11 +128,7 @@ typedef struct { STRING2KEY s2k; byte iv[8]; /* initialization vector for CFB mode */ } protect; - union { - ELG_secret_key elg; - DSA_secret_key dsa; - RSA_secret_key rsa; - } d; + MPI skey[PUBKEY_MAX_NSKEY]; u16 csum; /* checksum */ } PKT_secret_cert; diff --git a/g10/parse-packet.c b/g10/parse-packet.c index e1f023261..0ee6e7d37 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -318,6 +318,7 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos, break; case PKT_RING_TRUST: parse_trust(inp, pkttype, pktlen); + rc = 0; break; case PKT_PLAINTEXT: rc = parse_plaintext(inp, pkttype, pktlen, pkt ); @@ -502,6 +503,7 @@ static int parse_pubkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ) { unsigned n; + int i, ndata; PKT_pubkey_enc *k; k = packet->pkt.pubkey_enc = m_alloc(sizeof *packet->pkt.pubkey_enc ); @@ -520,31 +522,20 @@ parse_pubkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ) if( list_mode ) printf(":pubkey enc packet: version %d, algo %d, keyid %08lX%08lX\n", k->version, k->pubkey_algo, (ulong)k->keyid[0], (ulong)k->keyid[1]); - if( is_ELGAMAL(k->pubkey_algo) ) { - n = pktlen; - k->d.elg.a = mpi_read(inp, &n, 0); pktlen -=n; - n = pktlen; - 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 ); - printf("\n\telg b: "); - mpi_print(stdout, k->d.elg.b, mpi_print_mode ); - putchar('\n'); - } - } - else if( is_RSA(k->pubkey_algo) ) { - n = pktlen; - 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 ); - putchar('\n'); - } - } - else if( list_mode ) - printf("\tunknown algorithm %d\n", k->pubkey_algo ); + ndata = pubkey_get_nenc(k->pubkey_algo); + if( !ndata && list_mode ) + printf("\tunsupported algorithm %d\n", k->pubkey_algo ); + + for( i=0; i < ndata; i++ ) { + n = pktlen; + k->data[i] = mpi_read(inp, &n, 0); pktlen -=n; + if( list_mode ) { + printf("\tdata: "); + mpi_print(stdout, k->data[i], mpi_print_mode ); + putchar('\n'); + } + } leave: skip_rest(inp, pktlen); @@ -663,6 +654,7 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen, unsigned n; int is_v4=0; int rc=0; + int i, ndata; if( pktlen < 16 ) { log_error("packet(%d) too short\n", pkttype); @@ -763,44 +755,22 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen, parse_sig_subpkt( sig->unhashed_data,SIGSUBPKT_LIST_UNHASHED, NULL); } } - if( is_ELGAMAL(sig->pubkey_algo) ) { - n = pktlen; - sig->d.elg.a = mpi_read(inp, &n, 0 ); pktlen -=n; - n = pktlen; - sig->d.elg.b = mpi_read(inp, &n, 0 ); pktlen -=n; - if( list_mode ) { - printf("\telg a: "); - mpi_print(stdout, sig->d.elg.a, mpi_print_mode ); - printf("\n\telg b: "); - mpi_print(stdout, sig->d.elg.b, mpi_print_mode ); - putchar('\n'); - } - } - else if( sig->pubkey_algo == PUBKEY_ALGO_DSA ) { - n = pktlen; - sig->d.dsa.r = mpi_read(inp, &n, 0 ); pktlen -=n; - n = pktlen; - sig->d.dsa.s = mpi_read(inp, &n, 0 ); pktlen -=n; - if( list_mode ) { - printf("\tdsa r: "); - mpi_print(stdout, sig->d.elg.a, mpi_print_mode ); - printf("\n\tdsa s: "); - mpi_print(stdout, sig->d.elg.b, mpi_print_mode ); - putchar('\n'); - } - } - else if( is_RSA(sig->pubkey_algo) ) { - n = pktlen; - sig->d.rsa.rsa_integer = mpi_read(inp, &n, 0 ); pktlen -=n; - if( list_mode ) { - printf("\trsa integer: "); - mpi_print(stdout, sig->d.rsa.rsa_integer, mpi_print_mode ); - putchar('\n'); - } - } - else if( list_mode ) + + ndata = pubkey_get_nsig(sig->pubkey_algo); + if( !ndata && list_mode ) printf("\tunknown algorithm %d\n", sig->pubkey_algo ); + for( i=0; i < ndata; i++ ) { + n = pktlen; + sig->data[i] = mpi_read(inp, &n, 0 ); + pktlen -=n; + if( list_mode ) { + printf("\tdata: "); + mpi_print(stdout, sig->data[i], mpi_print_mode ); + putchar('\n'); + } + } + leave: skip_rest(inp, pktlen); @@ -932,17 +902,17 @@ parse_certificate( IOBUF inp, int pkttype, unsigned long pktlen, putchar('\n'); } if( pkttype == PKT_PUBLIC_CERT || pkttype == PKT_PUBKEY_SUBCERT ) { - pkt->pkt.public_cert->d.elg.p = elg_p; - pkt->pkt.public_cert->d.elg.g = elg_g; - pkt->pkt.public_cert->d.elg.y = elg_y; + pkt->pkt.public_cert->pkey[0] = elg_p; + pkt->pkt.public_cert->pkey[1] = elg_g; + pkt->pkt.public_cert->pkey[2] = elg_y; } else { PKT_secret_cert *cert = pkt->pkt.secret_cert; byte temp[8]; - pkt->pkt.secret_cert->d.elg.p = elg_p; - pkt->pkt.secret_cert->d.elg.g = elg_g; - pkt->pkt.secret_cert->d.elg.y = elg_y; + pkt->pkt.secret_cert->skey[0] = elg_p; + pkt->pkt.secret_cert->skey[1] = elg_g; + pkt->pkt.secret_cert->skey[2] = elg_y; cert->protect.algo = iobuf_get_noeof(inp); pktlen--; if( cert->protect.algo ) { cert->is_protected = 1; @@ -1032,20 +1002,16 @@ parse_certificate( IOBUF inp, int pkttype, unsigned long pktlen, * If the user is so careless, not to protect his secret key, * we can assume, that he operates an open system :=(. * So we put the key into secure memory when we unprotect it. */ - n = pktlen; cert->d.elg.x = mpi_read(inp, &n, 0 ); pktlen -=n; + n = pktlen; cert->skey[3] = mpi_read(inp, &n, 0 ); pktlen -=n; cert->csum = read_16(inp); pktlen -= 2; if( list_mode ) { printf("\telg x: "); - mpi_print(stdout, cert->d.elg.x, mpi_print_mode ); + mpi_print(stdout, cert->skey[3], mpi_print_mode ); putchar('\n'); printf("\t[secret value x is not shown]\n" "\tchecksum: %04hx\n", cert->csum); } - /*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_DSA ) { @@ -1066,19 +1032,19 @@ parse_certificate( IOBUF inp, int pkttype, unsigned long pktlen, putchar('\n'); } if( pkttype == PKT_PUBLIC_CERT || pkttype == PKT_PUBKEY_SUBCERT ) { - pkt->pkt.public_cert->d.dsa.p = dsa_p; - pkt->pkt.public_cert->d.dsa.q = dsa_q; - pkt->pkt.public_cert->d.dsa.g = dsa_g; - pkt->pkt.public_cert->d.dsa.y = dsa_y; + pkt->pkt.public_cert->pkey[0] = dsa_p; + pkt->pkt.public_cert->pkey[1] = dsa_q; + pkt->pkt.public_cert->pkey[2] = dsa_g; + pkt->pkt.public_cert->pkey[3] = dsa_y; } else { PKT_secret_cert *cert = pkt->pkt.secret_cert; byte temp[8]; - pkt->pkt.secret_cert->d.dsa.p = dsa_p; - pkt->pkt.secret_cert->d.dsa.q = dsa_q; - pkt->pkt.secret_cert->d.dsa.g = dsa_g; - pkt->pkt.secret_cert->d.dsa.y = dsa_y; + pkt->pkt.secret_cert->skey[0] = dsa_p; + pkt->pkt.secret_cert->skey[1] = dsa_q; + pkt->pkt.secret_cert->skey[2] = dsa_g; + pkt->pkt.secret_cert->skey[3] = dsa_y; cert->protect.algo = iobuf_get_noeof(inp); pktlen--; if( cert->protect.algo ) { cert->is_protected = 1; @@ -1164,18 +1130,13 @@ parse_certificate( IOBUF inp, int pkttype, unsigned long pktlen, * If the user is so careless, not to protect his secret key, * we can assume, that he operates an open system :=(. * So we put the key into secure memory when we unprotect it. */ - n = pktlen; cert->d.dsa.x = mpi_read(inp, &n, 0 ); pktlen -=n; + n = pktlen; cert->skey[4] = mpi_read(inp, &n, 0 ); pktlen -=n; cert->csum = read_16(inp); pktlen -= 2; if( list_mode ) { printf("\t[secret value x is not shown]\n" "\tchecksum: %04hx\n", cert->csum); } - /*log_mpidump("dsa p=", cert->d.dsa.p ); - log_mpidump("dsa q=", cert->d.dsa.q ); - log_mpidump("dsa g=", cert->d.dsa.g ); - log_mpidump("dsa y=", cert->d.dsa.y ); - log_mpidump("dsa x=", cert->d.dsa.x ); */ } } else if( is_RSA(algorithm) ) { @@ -1191,15 +1152,15 @@ parse_certificate( IOBUF inp, int pkttype, unsigned long pktlen, putchar('\n'); } if( pkttype == PKT_PUBLIC_CERT || pkttype == PKT_PUBKEY_SUBCERT ) { - pkt->pkt.public_cert->d.rsa.n = rsa_pub_mod; - pkt->pkt.public_cert->d.rsa.e = rsa_pub_exp; + pkt->pkt.public_cert->pkey[0] = rsa_pub_mod; + pkt->pkt.public_cert->pkey[1] = rsa_pub_exp; } else { PKT_secret_cert *cert = pkt->pkt.secret_cert; byte temp[8]; - pkt->pkt.secret_cert->d.rsa.n = rsa_pub_mod; - pkt->pkt.secret_cert->d.rsa.e = rsa_pub_exp; + pkt->pkt.secret_cert->skey[0] = rsa_pub_mod; + pkt->pkt.secret_cert->skey[1] = rsa_pub_exp; cert->protect.algo = iobuf_get_noeof(inp); pktlen--; if( list_mode ) printf( "\tprotect algo: %d\n", cert->protect.algo); @@ -1219,22 +1180,16 @@ parse_certificate( IOBUF inp, int pkttype, unsigned long pktlen, else cert->is_protected = 0; /* (See comments at the code for elg keys) */ - n = pktlen; cert->d.rsa.d = mpi_read(inp, &n, 0 ); pktlen -=n; - n = pktlen; cert->d.rsa.p = mpi_read(inp, &n, 0 ); pktlen -=n; - n = pktlen; cert->d.rsa.q = mpi_read(inp, &n, 0 ); pktlen -=n; - n = pktlen; cert->d.rsa.u = mpi_read(inp, &n, 0 ); pktlen -=n; + n = pktlen; cert->skey[2] = mpi_read(inp, &n, 0 ); pktlen -=n; + n = pktlen; cert->skey[3] = mpi_read(inp, &n, 0 ); pktlen -=n; + n = pktlen; cert->skey[4] = mpi_read(inp, &n, 0 ); pktlen -=n; + n = pktlen; cert->skey[5] = mpi_read(inp, &n, 0 ); pktlen -=n; cert->csum = read_16(inp); pktlen -= 2; if( list_mode ) { printf("\t[secret values d,p,q,u are not shown]\n" "\tchecksum: %04hx\n", cert->csum); } - /* log_mpidump("rsa n=", cert->d.rsa.n ); - log_mpidump("rsa e=", cert->d.rsa.e ); - log_mpidump("rsa d=", cert->d.rsa.d ); - log_mpidump("rsa p=", cert->d.rsa.p ); - log_mpidump("rsa q=", cert->d.rsa.q ); - log_mpidump("rsa u=", cert->d.rsa.u ); */ } } else if( list_mode ) diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c index 8b48255dc..ade155545 100644 --- a/g10/pubkey-enc.c +++ b/g10/pubkey-enc.c @@ -56,26 +56,9 @@ get_session_key( PKT_pubkey_enc *k, DEK *dek ) if( (rc = get_seckey( skc, k->keyid )) ) goto leave; - if( is_ELGAMAL(k->pubkey_algo) ) { - if( DBG_CIPHER ) { - log_mpidump("Encr DEK a:", k->d.elg.a ); - log_mpidump(" DEK b:", k->d.elg.b ); - } - plain_dek = mpi_alloc_secure( mpi_get_nlimbs(skc->d.elg.p) ); - elg_decrypt( plain_dek, k->d.elg.a, k->d.elg.b, &skc->d.elg ); - } - else if( is_RSA(k->pubkey_algo) ) { - if( DBG_CIPHER ) - log_mpidump("Encr DEK frame:", k->d.rsa.rsa_integer ); - - plain_dek = mpi_alloc_secure( mpi_get_nlimbs(skc->d.rsa.n) ); - rsa_secret( plain_dek, k->d.rsa.rsa_integer, &skc->d.rsa ); - } - else { - log_info("need some glue code for pubkey algo %d\n", k->pubkey_algo); - rc = G10ERR_PUBKEY_ALGO; /* unsupported algorithm */ + rc = pubkey_decrypt(k->pubkey_algo, &plain_dek, k->data, skc->skey ); + if( rc ) goto leave; - } free_secret_cert( skc ); skc = NULL; frame = mpi_get_buffer( plain_dek, &nframe, NULL ); mpi_free( plain_dek ); plain_dek = NULL; @@ -117,25 +100,18 @@ get_session_key( PKT_pubkey_enc *k, DEK *dek ) dek->keylen = nframe - (n+1) - 2; dek->algo = frame[n++]; - switch( dek->algo ) { - case CIPHER_ALGO_IDEA: + if( dek->algo == CIPHER_ALGO_IDEA ) write_status(STATUS_RSA_OR_IDEA); - rc = G10ERR_NI_CIPHER; - goto leave; - case CIPHER_ALGO_BLOWFISH160: - if( dek->keylen != 20 ) - { rc = G10ERR_WRONG_SECKEY; goto leave; } - break; - case CIPHER_ALGO_BLOWFISH: - case CIPHER_ALGO_CAST5: - if( dek->keylen != 16 ) - { rc = G10ERR_WRONG_SECKEY; goto leave; } - break; - default: + rc = check_cipher_algo( dek->algo ); + if( rc ) { dek->algo = 0; - rc = G10ERR_CIPHER_ALGO; goto leave; } + if( (dek->keylen*8) != cipher_get_keylen( dek->algo ) ) { + rc = G10ERR_WRONG_SECKEY; + goto leave; + } + /* copy the key to DEK and compare the checksum */ csum = frame[nframe-2] << 8; csum |= frame[nframe-1]; diff --git a/g10/ringedit.c b/g10/ringedit.c index 28faeddc1..a281d8bab 100644 --- a/g10/ringedit.c +++ b/g10/ringedit.c @@ -448,6 +448,35 @@ update_keyblock( KBPOS *kbpos, KBNODE root ) ********** Functions which operates on regular keyrings ******** ****************************************************************/ +static int +cmp_seckey( PKT_secret_cert *req_skc, PKT_secret_cert *skc ) +{ + int n,i; + + assert( req_skc->pubkey_algo == skc->pubkey_algo ); + + n = pubkey_get_nskey( req_skc->pubkey_algo ); + for(i=0; i < n; i++ ) { + if( mpi_cmp( req_skc->skey[i], skc->skey[i] ) ) + return -1; + } + return 0; +} + +static int +cmp_pubkey( PKT_public_cert *req_pkc, PKT_public_cert *pkc ) +{ + int n, i; + + assert( req_pkc->pubkey_algo == pkc->pubkey_algo ); + + n = pubkey_get_npkey( req_pkc->pubkey_algo ); + for(i=0; i < n; i++ ) { + if( mpi_cmp( req_pkc->pkey[i], pkc->pkey[i] ) ) + return -1; + } + return 0; +} /**************** * search one keyring, return 0 if found, -1 if not found or an errorcode. @@ -489,26 +518,7 @@ keyring_search( PACKET *req, KBPOS *kbpos, IOBUF iobuf, const char *fname ) if( req_skc->timestamp == skc->timestamp && req_skc->valid_days == skc->valid_days && req_skc->pubkey_algo == skc->pubkey_algo - && ( ( is_ELGAMAL(skc->pubkey_algo) - && !mpi_cmp( req_skc->d.elg.p, skc->d.elg.p ) - && !mpi_cmp( req_skc->d.elg.g, skc->d.elg.g ) - && !mpi_cmp( req_skc->d.elg.y, skc->d.elg.y ) - && !mpi_cmp( req_skc->d.elg.x, skc->d.elg.x ) - ) - || ( skc->pubkey_algo == PUBKEY_ALGO_DSA - && !mpi_cmp( req_skc->d.dsa.p, skc->d.dsa.p ) - && !mpi_cmp( req_skc->d.dsa.q, skc->d.dsa.q ) - && !mpi_cmp( req_skc->d.dsa.g, skc->d.dsa.g ) - && !mpi_cmp( req_skc->d.dsa.y, skc->d.dsa.y ) - && !mpi_cmp( req_skc->d.dsa.x, skc->d.dsa.x ) - ) - || ( is_RSA(skc->pubkey_algo) - && !mpi_cmp( req_skc->d.rsa.n, skc->d.rsa.n ) - && !mpi_cmp( req_skc->d.rsa.e, skc->d.rsa.e ) - && !mpi_cmp( req_skc->d.rsa.d, skc->d.rsa.d ) - ) - ) - ) + && !cmp_seckey( req_skc, skc) ) break; /* found */ } else if( pkt.pkttype == PKT_PUBLIC_CERT ) { @@ -517,23 +527,7 @@ keyring_search( PACKET *req, KBPOS *kbpos, IOBUF iobuf, const char *fname ) if( req_pkc->timestamp == pkc->timestamp && req_pkc->valid_days == pkc->valid_days && req_pkc->pubkey_algo == pkc->pubkey_algo - && ( ( is_ELGAMAL(pkc->pubkey_algo) - && !mpi_cmp( req_pkc->d.elg.p, pkc->d.elg.p ) - && !mpi_cmp( req_pkc->d.elg.g, pkc->d.elg.g ) - && !mpi_cmp( req_pkc->d.elg.y, pkc->d.elg.y ) - ) - || ( pkc->pubkey_algo == PUBKEY_ALGO_DSA - && !mpi_cmp( req_pkc->d.dsa.p, pkc->d.dsa.p ) - && !mpi_cmp( req_pkc->d.dsa.q, pkc->d.dsa.q ) - && !mpi_cmp( req_pkc->d.dsa.g, pkc->d.dsa.g ) - && !mpi_cmp( req_pkc->d.dsa.y, pkc->d.dsa.y ) - ) - || ( is_RSA(pkc->pubkey_algo) - && !mpi_cmp( req_pkc->d.rsa.n, pkc->d.rsa.n ) - && !mpi_cmp( req_pkc->d.rsa.e, pkc->d.rsa.e ) - ) - ) - ) + && !cmp_pubkey( req_pkc, pkc ) ) break; /* found */ } else diff --git a/g10/rsa.c b/g10/rsa.c deleted file mode 100644 index 36e0ef246..000000000 --- a/g10/rsa.c +++ /dev/null @@ -1,89 +0,0 @@ -/* rsa.c - glue code for RSA cipher - * Copyright (C) 1998 Free Software Foundation, Inc. - * - * This file is part of GNUPG. - * - * GNUPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GNUPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include -#include -#include -#include -#include -#include - -#include "options.h" -#include "packet.h" -#include "errors.h" -#include "iobuf.h" -#include "keydb.h" -#include "memory.h" -#include "util.h" -#include "main.h" - -void -g10_rsa_encrypt( PKT_public_cert *pkc, PKT_pubkey_enc *enc, DEK *dek ) -{ - #ifdef HAVE_RSA_CIPHER - assert( is_RSA(enc->pubkey_algo) ); - - keyid_from_pkc( pkc, enc->keyid ); - enc->d.rsa.rsa_integer = encode_session_key( dek, - mpi_get_nbits(pkc->d.rsa.rsa_n) ); - if( DBG_CIPHER ) - log_mpidump("Plain DEK frame: ", enc->d.rsa.rsa_integer); - rsa_public( enc->d.rsa.rsa_integer, enc->d.rsa.rsa_integer, &pkc->d.rsa); - if( DBG_CIPHER ) - log_mpidump("Encry DEK frame: ", enc->d.rsa.rsa_integer); - if( opt.verbose ) { - char *ustr = get_user_id_string( enc->keyid ); - log_info("RSA encrypted for: %s\n", ustr ); - m_free(ustr); - } - #else - BUG(); - #endif/* ! HAVE_RSA_CIPHER*/ -} - - -void -g10_rsa_sign( PKT_secret_cert *skc, PKT_signature *sig, - MD_HANDLE md, int digest_algo ) -{ - #ifdef HAVE_RSA_CIPHER - byte *dp; - - assert( is_RSA(sig->pubkey_algo) ); - if( !digest_algo ) - digest_algo = md_get_algo(md); - - dp = md_read( md, digest_algo ); - sig->digest_algo = digest_algo; - sig->digest_start[0] = dp[0]; - sig->digest_start[1] = dp[1]; - sig->d.rsa.rsa_integer = - encode_md_value( md, digest_algo, mpi_get_nbits(skc->d.rsa.rsa_n)); - rsa_secret( sig->d.rsa.rsa_integer, sig->d.rsa.rsa_integer, &skc->d.rsa ); - if( opt.verbose ) { - char *ustr = get_user_id_string( sig->keyid ); - log_info("RSA signature from: %s\n", ustr ); - m_free(ustr); - } - #else - BUG(); - #endif/* ! HAVE_RSA_CIPHER*/ -} - diff --git a/g10/seckey-cert.c b/g10/seckey-cert.c index 3373bd35e..41a09b281 100644 --- a/g10/seckey-cert.c +++ b/g10/seckey-cert.c @@ -67,17 +67,18 @@ do_check( PKT_secret_cert *cert ) switch( cert->pubkey_algo ) { case PUBKEY_ALGO_ELGAMAL: case PUBKEY_ALGO_ELGAMAL_E: - buffer = mpi_get_secure_buffer( cert->d.elg.x, &nbytes, NULL ); + /* FIXME: removed ELG knowledge from this function */ + buffer = mpi_get_secure_buffer( cert->skey[3], &nbytes, NULL ); cipher_decrypt( cipher_hd, buffer, buffer, nbytes ); - mpi_set_buffer( cert->d.elg.x, buffer, nbytes, 0 ); - csum = checksum_mpi( cert->d.elg.x ); + mpi_set_buffer( cert->skey[3], buffer, nbytes, 0 ); + csum = checksum_mpi( cert->skey[3] ); m_free( buffer ); break; case PUBKEY_ALGO_DSA: - buffer = mpi_get_secure_buffer( cert->d.dsa.x, &nbytes, NULL ); + buffer = mpi_get_secure_buffer( cert->skey[4], &nbytes, NULL ); cipher_decrypt( cipher_hd, buffer, buffer, nbytes ); - mpi_set_buffer( cert->d.dsa.x, buffer, nbytes, 0 ); - csum = checksum_mpi( cert->d.dsa.x ); + mpi_set_buffer( cert->skey[4], buffer, nbytes, 0 ); + csum = checksum_mpi( cert->skey[4] ); m_free( buffer ); break; #ifdef HAVE_RSA_CIPHER @@ -107,15 +108,6 @@ do_check( PKT_secret_cert *cert ) cipher_close( cipher_hd ); /* now let's see whether we have used the right passphrase */ if( csum != cert->csum ) { - if( cert->pubkey_algo == PUBKEY_ALGO_ELGAMAL_E ) { - /* very bad kludge to work around an early bug */ - csum -= checksum_u16( mpi_get_nbits(cert->d.elg.x) ); - nbytes = mpi_get_nlimbs(cert->d.elg.x) * 4; - csum += checksum_u16( nbytes*8 ); - if( !opt.batch && csum == cert->csum ) - log_info("Probably you have an old key - use " - "\"--change-passphrase\" to convert.\n"); - } if( csum != cert->csum ) { copy_secret_cert( cert, save_cert ); free_secret_cert( save_cert ); @@ -124,24 +116,8 @@ do_check( PKT_secret_cert *cert ) } } - switch( cert->pubkey_algo ) { - case PUBKEY_ALGO_ELGAMAL_E: - case PUBKEY_ALGO_ELGAMAL: - res = elg_check_secret_key( &cert->d.elg ); - break; - case PUBKEY_ALGO_DSA: - res = dsa_check_secret_key( &cert->d.dsa ); - break; - #ifdef HAVE_RSA_CIPHER - case PUBKEY_ALGO_RSA: - case PUBKEY_ALGO_RSA_E: - case PUBKEY_ALGO_RSA_S: - res = rsa_check_secret_key( &cert->d.rsa ); - break; - #endif - default: BUG(); - } - if( !res ) { + res = pubkey_check_secret_key( cert->pubkey_algo, cert->skey ); + if( res ) { copy_secret_cert( cert, save_cert ); free_secret_cert( save_cert ); memcpy( cert->protect.iv, save_iv, 8 ); @@ -154,10 +130,10 @@ do_check( PKT_secret_cert *cert ) switch( cert->pubkey_algo ) { case PUBKEY_ALGO_ELGAMAL_E: case PUBKEY_ALGO_ELGAMAL: - csum = checksum_mpi( cert->d.elg.x ); + csum = checksum_mpi( cert->skey[3] ); break; case PUBKEY_ALGO_DSA: - csum = checksum_mpi( cert->d.dsa.x ); + csum = checksum_mpi( cert->skey[4] ); break; #ifdef HAVE_RSA_CIPHER case PUBKEY_ALGO_RSA_E: @@ -184,19 +160,8 @@ do_check( PKT_secret_cert *cert ) #endif default: BUG(); } - if( csum != cert->csum ) { - if( cert->pubkey_algo == PUBKEY_ALGO_ELGAMAL_E ) { - /* very bad kludge to work around an early bug */ - csum -= checksum_u16( mpi_get_nbits(cert->d.elg.x) ); - nbytes = mpi_get_nlimbs(cert->d.elg.x) * 4; - csum += checksum_u16( nbytes*8 ); - if( !opt.batch && csum == cert->csum ) - log_info("Probably you have an old key - use " - "\"--change-passphrase\" to convert.\n"); - } - if( csum != cert->csum ) - return G10ERR_CHECKSUM; - } + if( csum != cert->csum ) + return G10ERR_CHECKSUM; } return 0; @@ -274,23 +239,17 @@ do_protect( void (*fnc)(CIPHER_HANDLE, byte *, byte *, unsigned), switch( cert->pubkey_algo ) { case PUBKEY_ALGO_ELGAMAL_E: - /* recalculate the checksum, so that --change-passphrase - * can be used to convert from the faulty to the correct one - * wk 06.04.98: - * fixme: remove this some time in the future. - */ - cert->csum = checksum_mpi( cert->d.elg.x ); case PUBKEY_ALGO_ELGAMAL: - buffer = mpi_get_buffer( cert->d.elg.x, &nbytes, NULL ); + buffer = mpi_get_buffer( cert->skey[3], &nbytes, NULL ); (*fnc)( fnc_hd, buffer, buffer, nbytes ); - mpi_set_buffer( cert->d.elg.x, buffer, nbytes, 0 ); + mpi_set_buffer( cert->skey[3], buffer, nbytes, 0 ); m_free( buffer ); break; case PUBKEY_ALGO_DSA: - buffer = mpi_get_buffer( cert->d.dsa.x, &nbytes, NULL ); + buffer = mpi_get_buffer( cert->skey[4], &nbytes, NULL ); (*fnc)( fnc_hd, buffer, buffer, nbytes ); - mpi_set_buffer( cert->d.dsa.x, buffer, nbytes, 0 ); + mpi_set_buffer( cert->skey[4], buffer, nbytes, 0 ); m_free( buffer ); break; diff --git a/g10/sig-check.c b/g10/sig-check.c index 6dc660916..a4c802c67 100644 --- a/g10/sig-check.c +++ b/g10/sig-check.c @@ -95,11 +95,10 @@ do_check( PKT_public_cert *pkc, PKT_signature *sig, MD_HANDLE digest ) } md_final( digest ); result = encode_md_value( digest, sig->digest_algo, - mpi_get_nbits(pkc->d.elg.p)); + mpi_get_nbits(pkc->pkey[0])); if( DBG_CIPHER ) log_mpidump("calc sig frame (elg): ", result); - if( !elg_verify( sig->d.elg.a, sig->d.elg.b, result, &pkc->d.elg ) ) - rc = G10ERR_BAD_SIGN; + rc = pubkey_verify( pkc->pubkey_algo, result, sig->data, pkc->pkey ); } else if( pkc->pubkey_algo == PUBKEY_ALGO_DSA ) { if( (rc=check_digest_algo(sig->digest_algo)) ) @@ -148,8 +147,7 @@ do_check( PKT_public_cert *pkc, PKT_signature *sig, MD_HANDLE digest ) md_digest_length(sig->digest_algo), 0 ); if( DBG_CIPHER ) log_mpidump("calc sig frame: ", result); - if( !dsa_verify( sig->d.dsa.r, sig->d.dsa.s, result, &pkc->d.dsa ) ) - rc = G10ERR_BAD_SIGN; + rc = pubkey_verify( pkc->pubkey_algo, result, sig->data, pkc->pkey ); } #ifdef HAVE_RSA_CIPHER else if( pkc->pubkey_algo == PUBKEY_ALGO_RSA diff --git a/g10/sign.c b/g10/sign.c index bd435a7c9..a85f1f952 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -38,22 +38,53 @@ #include "i18n.h" +static int +do_sign( PKT_secret_cert *skc, PKT_signature *sig, + MD_HANDLE md, int digest_algo ) +{ + MPI frame; + byte *dp; + int rc; + + if( !digest_algo ) + digest_algo = md_get_algo(md); + + dp = md_read( md, digest_algo ); + sig->digest_algo = digest_algo; + sig->digest_start[0] = dp[0]; + sig->digest_start[1] = dp[1]; + if( skc->pubkey_algo == PUBKEY_ALGO_DSA ) { + frame = mpi_alloc( (md_digest_length(digest_algo)+BYTES_PER_MPI_LIMB-1) + / BYTES_PER_MPI_LIMB ); + mpi_set_buffer( frame, md_read(md, digest_algo), + md_digest_length(digest_algo), 0 ); + } + else + frame = encode_md_value( md, digest_algo, mpi_get_nbits(skc->skey[0])); + rc = pubkey_sign( skc->pubkey_algo, sig->data, frame, skc->skey ); + mpi_free(frame); + if( rc ) + log_error("pubkey_sign failed: %s\n", g10_errstr(rc) ); + else { + if( opt.verbose ) { + char *ustr = get_user_id_string( sig->keyid ); + log_info("%s signature from: %s\n", + pubkey_algo_to_string(skc->pubkey_algo), ustr ); + m_free(ustr); + } + } + return rc; +} + + int complete_sig( PKT_signature *sig, PKT_secret_cert *skc, MD_HANDLE md ) { int rc=0; - if( (rc=check_secret_key( skc )) ) - ; - else if( is_ELGAMAL(sig->pubkey_algo) ) - g10_elg_sign( skc, sig, md, 0 ); - else if( sig->pubkey_algo == PUBKEY_ALGO_DSA ) - g10_dsa_sign( skc, sig, md, 0 ); - else if( is_RSA(sig->pubkey_algo) ) - g10_rsa_sign( skc, sig, md, 0 ); - else - BUG(); + if( !(rc=check_secret_key( skc )) ) + rc = do_sign( skc, sig, md, 0 ); /* fixme: should we check whether the signature is okay? * maybe by using an option */ @@ -334,27 +365,20 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr, } md_final( md ); - if( is_ELGAMAL(sig->pubkey_algo) ) - g10_elg_sign( skc, sig, md, hash_for(sig->pubkey_algo) ); - else if( sig->pubkey_algo == PUBKEY_ALGO_DSA ) - g10_dsa_sign( skc, sig, md, hash_for(sig->pubkey_algo) ); - else if( is_RSA(sig->pubkey_algo) ) - g10_rsa_sign( skc, sig, md, hash_for(sig->pubkey_algo) ); - else - BUG(); - + rc = do_sign( skc, sig, md, hash_for(sig->pubkey_algo) ); md_close( md ); - /* and write it */ - init_packet(&pkt); - pkt.pkttype = PKT_SIGNATURE; - pkt.pkt.signature = sig; - rc = build_packet( out, &pkt ); - free_packet( &pkt ); - if( rc ) { - log_error("build signature packet failed: %s\n", g10_errstr(rc) ); - goto leave; + if( !rc ) { /* and write it */ + init_packet(&pkt); + pkt.pkttype = PKT_SIGNATURE; + pkt.pkt.signature = sig; + rc = build_packet( out, &pkt ); + free_packet( &pkt ); + if( rc ) + log_error("build signature packet failed: %s\n", g10_errstr(rc) ); } + if( rc ) + goto leave; } @@ -538,27 +562,20 @@ clearsign_file( const char *fname, STRLIST locusr, const char *outfile ) } md_final( md ); - if( is_ELGAMAL(sig->pubkey_algo) ) - g10_elg_sign( skc, sig, md, hash_for(sig->pubkey_algo) ); - else if( sig->pubkey_algo == PUBKEY_ALGO_DSA ) - g10_dsa_sign( skc, sig, md, hash_for(sig->pubkey_algo) ); - else if( is_RSA(sig->pubkey_algo) ) - g10_rsa_sign( skc, sig, md, hash_for(sig->pubkey_algo) ); - else - BUG(); - + rc = do_sign( skc, sig, md, hash_for(sig->pubkey_algo) ); md_close( md ); - /* and write it */ - init_packet(&pkt); - pkt.pkttype = PKT_SIGNATURE; - pkt.pkt.signature = sig; - rc = build_packet( out, &pkt ); - free_packet( &pkt ); - if( rc ) { - log_error("build signature packet failed: %s\n", g10_errstr(rc) ); - goto leave; + if( !rc ) { /* and write it */ + init_packet(&pkt); + pkt.pkttype = PKT_SIGNATURE; + pkt.pkt.signature = sig; + rc = build_packet( out, &pkt ); + free_packet( &pkt ); + if( rc ) + log_error("build signature packet failed: %s\n", g10_errstr(rc) ); } + if( rc ) + goto leave; } diff --git a/include/cipher.h b/include/cipher.h index 186851a33..3fe56c2e3 100644 --- a/include/cipher.h +++ b/include/cipher.h @@ -84,6 +84,8 @@ struct cipher_handle_s { char does_not_matter[1]; }; #define CIPHER_MODE_DUMMY 5 /* used with algo DUMMY for no encryption */ + + int cipher_debug_mode; /*-- dynload.c --*/ @@ -102,6 +104,23 @@ void cipher_encrypt( CIPHER_HANDLE c, byte *out, byte *in, unsigned nbytes ); void cipher_decrypt( CIPHER_HANDLE c, byte *out, byte *in, unsigned nbytes ); void cipher_sync( CIPHER_HANDLE c ); +/*-- pubkey.c --*/ +#define PUBKEY_MAX_NPKEY 4 +#define PUBKEY_MAX_NSKEY 6 +#define PUBKEY_MAX_NSIG 2 +#define PUBKEY_MAX_NENC 2 + +int pubkey_get_npkey( int algo ); +int pubkey_get_nskey( int algo ); +int pubkey_get_nsig( int algo ); +int pubkey_get_nenc( int algo ); +unsigned pubkey_nbits( int algo, MPI *pkey ); +int pubkey_check_secret_key( int algo, MPI *skey ); +int pubkey_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey ); +int pubkey_decrypt( int algo, MPI *result, MPI *data, MPI *skey ); +int pubkey_sign( int algo, MPI *resarr, MPI hash, MPI *skey ); +int pubkey_verify( int algo, MPI hash, MPI *data, MPI *pkey ); + /*-- misc.c --*/ int string_to_pubkey_algo( const char *string ); diff --git a/tools/mk-tdata b/tools/mk-tdata index 7fcfb389fa82c4a49e208cdeb2cab18fd4575459..85e567d45947913b3005720f647d55331e49df22 100755 GIT binary patch literal 35331 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 Me*QF6XDa3W53R?jBLDyZ literal 11769 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