diff options
Diffstat (limited to 'g10/seckey-cert.c')
-rw-r--r-- | g10/seckey-cert.c | 259 |
1 files changed, 141 insertions, 118 deletions
diff --git a/g10/seckey-cert.c b/g10/seckey-cert.c index 7356cb224..382ad7534 100644 --- a/g10/seckey-cert.c +++ b/g10/seckey-cert.c @@ -1,6 +1,6 @@ /* seckey-cert.c - secret key certificate packet handling * Copyright (C) 1998, 1999, 2000, 2001, 2002, - * 2003 Free Software Foundation, Inc. + * 2006 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -16,7 +16,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include <config.h> @@ -27,9 +28,7 @@ #include "gpg.h" #include "util.h" -#include "memory.h" #include "packet.h" -#include "mpi.h" #include "keydb.h" #include "cipher.h" #include "main.h" @@ -42,21 +41,21 @@ static int do_check( PKT_secret_key *sk, const char *tryagain_text, int mode, int *canceled ) { + gpg_error_t err; byte *buffer; u16 csum=0; int i, res; - unsigned nbytes; - gpg_error_t rc; + unsigned int nbytes; if( sk->is_protected ) { /* remove the protection */ DEK *dek = NULL; u32 keyid[4]; /* 4! because we need two of them */ - CIPHER_HANDLE cipher_hd=NULL; + gcry_cipher_hd_t cipher_hd=NULL; PKT_secret_key *save_sk; if( sk->protect.s2k.mode == 1001 ) { log_info(_("secret key parts are not available\n")); - return GPG_ERR_GENERAL; + return G10ERR_GENERAL; } if( sk->protect.algo == CIPHER_ALGO_NONE ) BUG(); @@ -68,8 +67,14 @@ do_check( PKT_secret_key *sk, const char *tryagain_text, int mode, write_status (STATUS_RSA_OR_IDEA); idea_cipher_warn (0); } - return GPG_ERR_CIPHER_ALGO; + return G10ERR_CIPHER_ALGO; } + if(gcry_md_test_algo (sk->protect.s2k.hash_algo)) + { + log_info(_("protection digest %d is not supported\n"), + sk->protect.s2k.hash_algo); + return G10ERR_DIGEST_ALGO; + } keyid_from_sk( sk, keyid ); keyid[2] = keyid[3] = 0; if( !sk->is_primary ) { @@ -80,39 +85,45 @@ do_check( PKT_secret_key *sk, const char *tryagain_text, int mode, &sk->protect.s2k, mode, tryagain_text, canceled ); if (!dek && canceled && *canceled) - return GPG_ERR_GENERAL; + return G10ERR_GENERAL; - rc = gcry_cipher_open (&cipher_hd, sk->protect.algo, - GCRY_CIPHER_MODE_CFB, - GCRY_CIPHER_SECURE - | (sk->protect.algo >= 100 ? - 0 : GCRY_CIPHER_ENABLE_SYNC)); - if (rc) - log_fatal ("cipher open failed: %s\n", gpg_strerror (rc) ); - rc = gcry_cipher_setkey (cipher_hd, dek->key, dek->keylen); - if (rc) - log_fatal ("set key failed: %s\n", gpg_strerror (rc) ); + err = gcry_cipher_open (&cipher_hd, sk->protect.algo, + GCRY_CIPHER_MODE_CFB, + (GCRY_CIPHER_SECURE + | (sk->protect.algo >= 100 ? + 0 : GCRY_CIPHER_ENABLE_SYNC))); + if (err) + log_fatal ("cipher open failed: %s\n", gpg_strerror (err) ); - xfree (dek); + err = gcry_cipher_setkey (cipher_hd, dek->key, dek->keylen); + if (err) + log_fatal ("set key failed: %s\n", gpg_strerror (err) ); + + xfree(dek); save_sk = copy_secret_key( NULL, sk ); - gcry_cipher_setiv (cipher_hd, sk->protect.iv, sk->protect.ivlen); + + gcry_cipher_setiv ( cipher_hd, sk->protect.iv, sk->protect.ivlen ); + csum = 0; if( sk->version >= 4 ) { - int ndata; - unsigned int ndatabits; + int ndata; + unsigned int ndatabits; byte *p, *data; u16 csumc = 0; i = pubkey_get_npkey(sk->pubkey_algo); - assert( gcry_mpi_get_flag (sk->skey[i], GCRYMPI_FLAG_OPAQUE )); - p = gcry_mpi_get_opaque( sk->skey[i], &ndatabits ); + + assert ( gcry_mpi_get_flag (sk->skey[i], GCRYMPI_FLAG_OPAQUE )); + p = gcry_mpi_get_opaque ( sk->skey[i], &ndatabits ); ndata = (ndatabits+7)/8; + if ( ndata > 1 ) csumc = p[ndata-2] << 8 | p[ndata-1]; - data = gcry_xmalloc_secure ( ndata ); - gcry_cipher_decrypt( cipher_hd, data, ndata, p, ndata ); - gcry_mpi_release ( sk->skey[i] ); sk->skey[i] = NULL ; + data = xmalloc_secure ( ndata ); + gcry_cipher_decrypt ( cipher_hd, data, ndata, p, ndata ); + gcry_mpi_release (sk->skey[i]); sk->skey[i] = NULL ; + p = data; if (sk->protect.sha1chk) { /* This is the new SHA1 checksum method to detect @@ -126,18 +137,19 @@ do_check( PKT_secret_key *sk, const char *tryagain_text, int mode, gcry_md_hd_t h; if ( gcry_md_open (&h, DIGEST_ALGO_SHA1, 1)) - BUG(); /* algo not available */ + BUG(); /* Algo not available. */ gcry_md_write (h, data, ndata - 20); gcry_md_final (h); if (!memcmp (gcry_md_read (h, DIGEST_ALGO_SHA1), - data + ndata - 20, 20) ) { - /* digest does match. We have to keep the old + data + ndata - 20, 20) ) + { + /* Digest does match. We have to keep the old style checksum in sk->csum, so that the test used for unprotected keys does work. This test gets used when we are adding new keys. */ sk->csum = csum = checksum (data, ndata-20); - } + } gcry_md_close (h); } } @@ -156,24 +168,27 @@ do_check( PKT_secret_key *sk, const char *tryagain_text, int mode, } } } - - /* must check it here otherwise the mpi_read_xx would fail + + /* Must check it here otherwise the mpi_read_xx would fail because the length may have an arbitrary value */ if( sk->csum == csum ) { for( ; i < pubkey_get_nskey(sk->pubkey_algo); i++ ) { - assert( gcry_is_secure( p ) ); - res = gcry_mpi_scan( &sk->skey[i], GCRYMPI_FMT_PGP, - p, ndata, &nbytes); - if( res ) - log_bug ("gcry_mpi_scan failed in do_check: %s\n", - gpg_strerror (res)); + if ( gcry_mpi_scan( &sk->skey[i], GCRYMPI_FMT_PGP, + p, ndata, &nbytes)) + { + /* Checksum was okay, but not correctly + decrypted. */ + sk->csum = 0; + csum = 1; + break; + } ndata -= nbytes; p += nbytes; } /* Note: at this point ndata should be 2 for a simple checksum or 20 for the sha1 digest */ } - xfree (data); + xfree(data); } else { for(i=pubkey_get_npkey(sk->pubkey_algo); @@ -182,12 +197,12 @@ do_check( PKT_secret_key *sk, const char *tryagain_text, int mode, int ndata; unsigned int ndatabits; - assert( gcry_mpi_get_flag (sk->skey[i], GCRYMPI_FLAG_OPAQUE)); - p = gcry_mpi_get_opaque( sk->skey[i], &ndatabits ); + assert (gcry_mpi_get_flag (sk->skey[i], GCRYMPI_FLAG_OPAQUE)); + p = gcry_mpi_get_opaque (sk->skey[i], &ndatabits); ndata = (ndatabits+7)/8; assert (ndata >= 2); assert (ndata == ((p[0] << 8 | p[1]) + 7)/8 + 2); - buffer = gcry_xmalloc_secure (ndata); + buffer = xmalloc_secure (ndata); gcry_cipher_sync (cipher_hd); buffer[0] = p[0]; buffer[1] = p[1]; @@ -195,33 +210,39 @@ do_check( PKT_secret_key *sk, const char *tryagain_text, int mode, p+2, ndata-2); csum += checksum (buffer, ndata); gcry_mpi_release (sk->skey[i]); - res = gcry_mpi_scan( &sk->skey[i], GCRYMPI_FMT_USG, - buffer, ndata, &ndata ); - if( res ) - log_bug ("gcry_mpi_scan failed in do_check: %s\n", - gpg_strerror (res)); - assert (sk->skey[i]); + err = gcry_mpi_scan( &sk->skey[i], GCRYMPI_FMT_USG, + buffer, ndata, &ndata ); xfree (buffer); + if (err) + { + /* Checksum was okay, but not correctly + decrypted. */ + sk->csum = 0; + csum = 1; + break; + } /* csum += checksum_mpi (sk->skey[i]); */ } } - gcry_cipher_close (cipher_hd); - /* now let's see whether we have used the right passphrase */ + gcry_cipher_close ( cipher_hd ); + + /* Now let's see whether we have used the correct passphrase. */ if( csum != sk->csum ) { copy_secret_key( sk, save_sk ); - passphrase_clear_cache ( keyid, sk->pubkey_algo ); + passphrase_clear_cache ( keyid, NULL, sk->pubkey_algo ); + free_secret_key( save_sk ); + return G10ERR_BAD_PASS; + } + + /* The checksum may fail, so we also check the key itself. */ + res = pk_check_secret_key ( sk->pubkey_algo, sk->skey ); + if( res ) { + copy_secret_key( sk, save_sk ); + passphrase_clear_cache ( keyid, NULL, sk->pubkey_algo ); free_secret_key( save_sk ); - return gpg_error (GPG_ERR_BAD_PASSPHRASE); + return G10ERR_BAD_PASS; } - /* the checksum may fail, so we also check the key itself */ - res = pk_check_secret_key (sk->pubkey_algo, sk->skey); - if (res) { - copy_secret_key( sk, save_sk ); - passphrase_clear_cache ( keyid, sk->pubkey_algo ); - free_secret_key( save_sk ); - return gpg_error (GPG_ERR_BAD_PASSPHRASE); - } free_secret_key( save_sk ); sk->is_protected = 0; } @@ -232,7 +253,7 @@ do_check( PKT_secret_key *sk, const char *tryagain_text, int mode, csum += checksum_mpi( sk->skey[i] ); } if( csum != sk->csum ) - return GPG_ERR_CHECKSUM; + return G10ERR_CHECKSUM; } return 0; @@ -252,7 +273,7 @@ check_secret_key( PKT_secret_key *sk, int n ) int i,mode; if (sk && sk->is_protected && sk->protect.s2k.mode == 1002) - return 0; /* Let the scdaemon handle it. */ + return 0; /* Let the scdaemon handle this. */ if(n<0) { @@ -265,7 +286,7 @@ check_secret_key( PKT_secret_key *sk, int n ) if( n < 1 ) n = (opt.batch && !opt.use_agent)? 1 : 3; /* use the default value */ - for(i=0; i < n && gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE; i++ ) { + for(i=0; i < n && gpg_err_code (rc) == G10ERR_BAD_PASS; i++ ) { int canceled = 0; const char *tryagain = NULL; if (i) { @@ -273,8 +294,7 @@ check_secret_key( PKT_secret_key *sk, int n ) log_info (_("%s ...\n"), _(tryagain)); } rc = do_check( sk, tryagain, mode, &canceled ); - if( gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE - && is_status_enabled() ) { + if ( gpg_err_code (rc) == G10ERR_BAD_PASS && is_status_enabled () ) { u32 kid[2]; char buf[50]; @@ -296,13 +316,14 @@ check_secret_key( PKT_secret_key *sk, int n ) * check whether the secret key is protected. * Returns: 0 not protected, -1 on error or the protection algorithm * -2 indicates a card stub. + * -3 indicates a not-online stub. */ int is_secret_key_protected( PKT_secret_key *sk ) { return sk->is_protected? - sk->protect.s2k.mode == 1002? -2 - : sk->protect.algo : 0; + sk->protect.s2k.mode == 1002? -2 : + sk->protect.s2k.mode == 1001? -3 : sk->protect.algo : 0; } @@ -324,54 +345,52 @@ protect_secret_key( PKT_secret_key *sk, DEK *dek ) if( !sk->is_protected ) { /* okay, apply the protection */ gcry_cipher_hd_t cipher_hd=NULL; - if( openpgp_cipher_test_algo( sk->protect.algo ) ) - { - rc = gpg_error (GPG_ERR_CIPHER_ALGO); /* unsupport - protection - algorithm */ - } + if ( openpgp_cipher_test_algo ( sk->protect.algo ) ) { + /* Unsupport protection algorithm. */ + rc = gpg_error (GPG_ERR_CIPHER_ALGO); + } else { print_cipher_algo_note( sk->protect.algo ); - rc = gcry_cipher_open (&cipher_hd, sk->protect.algo, + + if ( gcry_cipher_open (&cipher_hd, sk->protect.algo, GCRY_CIPHER_MODE_CFB, - GCRY_CIPHER_SECURE - | (sk->protect.algo >= 100 ? - 0 : GCRY_CIPHER_ENABLE_SYNC) ); - if (rc) + (GCRY_CIPHER_SECURE + | (sk->protect.algo >= 100 ? + 0 : GCRY_CIPHER_ENABLE_SYNC))) ) BUG(); - if( gcry_cipher_setkey( cipher_hd, dek->key, dek->keylen ) ) + if ( gcry_cipher_setkey ( cipher_hd, dek->key, dek->keylen ) ) log_info(_("WARNING: Weak key detected" " - please change passphrase again.\n")); - sk->protect.ivlen = gcry_cipher_get_algo_blklen(sk->protect.algo); + sk->protect.ivlen = gcry_cipher_get_algo_blklen (sk->protect.algo); assert( sk->protect.ivlen <= DIM(sk->protect.iv) ); if( sk->protect.ivlen != 8 && sk->protect.ivlen != 16 ) BUG(); /* yes, we are very careful */ gcry_create_nonce (sk->protect.iv, sk->protect.ivlen); - gcry_cipher_setiv( cipher_hd, sk->protect.iv, sk->protect.ivlen ); + gcry_cipher_setiv (cipher_hd, sk->protect.iv, sk->protect.ivlen); if( sk->version >= 4 ) { - unsigned char *bufarr[PUBKEY_MAX_NSKEY]; + byte *bufarr[PUBKEY_MAX_NSKEY]; unsigned narr[PUBKEY_MAX_NSKEY]; unsigned nbits[PUBKEY_MAX_NSKEY]; int ndata=0; byte *p, *data; - for(j=0, i = pubkey_get_npkey(sk->pubkey_algo); - i < pubkey_get_nskey(sk->pubkey_algo); i++, j++ ) { - assert( !gcry_mpi_get_flag( sk->skey[i], - GCRYMPI_FLAG_OPAQUE )); - - if( gcry_mpi_aprint( GCRYMPI_FMT_USG, bufarr+j, + for (j=0, i = pubkey_get_npkey(sk->pubkey_algo); + i < pubkey_get_nskey(sk->pubkey_algo); i++, j++ ) + { + assert (!gcry_mpi_get_flag (sk->skey[i], + GCRYMPI_FLAG_OPAQUE)); + if (gcry_mpi_aprint (GCRYMPI_FMT_USG, bufarr+j, narr+j, sk->skey[i])) - BUG(); - - nbits[j] = gcry_mpi_get_nbits( sk->skey[i] ); + BUG(); + nbits[j] = gcry_mpi_get_nbits (sk->skey[i]); ndata += narr[j] + 2; - } - for( ; j < PUBKEY_MAX_NSKEY; j++ ) - bufarr[j] = NULL; + } + for ( ; j < PUBKEY_MAX_NSKEY; j++ ) + bufarr[j] = NULL; + ndata += opt.simple_sk_checksum? 2 : 20; /* for checksum */ - data = xmalloc_secure ( ndata ); + data = xmalloc_secure( ndata ); p = data; for(j=0; j < PUBKEY_MAX_NSKEY && bufarr[j]; j++ ) { p[0] = nbits[j] >> 8 ; @@ -379,7 +398,7 @@ protect_secret_key( PKT_secret_key *sk, DEK *dek ) p += 2; memcpy(p, bufarr[j], narr[j] ); p += narr[j]; - xfree (bufarr[j]); + xfree(bufarr[j]); } if (opt.simple_sk_checksum) { @@ -395,10 +414,10 @@ protect_secret_key( PKT_secret_key *sk, DEK *dek ) gcry_md_hd_t h; if (gcry_md_open (&h, GCRY_MD_SHA1, 1)) - BUG(); /* algo not available */ + BUG(); /* Algo not available. */ gcry_md_write (h, data, ndata - 20); gcry_md_final (h); - memcpy (p, gcry_md_read (h, GCRY_MD_SHA1), 20); + memcpy (p, gcry_md_read (h, DIGEST_ALGO_SHA1), 20); p += 20; gcry_md_close (h); sk->csum = csum = 0; @@ -406,14 +425,15 @@ protect_secret_key( PKT_secret_key *sk, DEK *dek ) } assert( p == data+ndata ); - gcry_cipher_encrypt( cipher_hd, data, ndata, NULL, 0 ); - for(i = pubkey_get_npkey(sk->pubkey_algo); - i < pubkey_get_nskey(sk->pubkey_algo); i++ ) { - gcry_mpi_release ( sk->skey[i] ); + gcry_cipher_encrypt (cipher_hd, data, ndata, NULL, 0); + for (i = pubkey_get_npkey(sk->pubkey_algo); + i < pubkey_get_nskey(sk->pubkey_algo); i++ ) + { + gcry_mpi_release (sk->skey[i]); sk->skey[i] = NULL; - } + } i = pubkey_get_npkey(sk->pubkey_algo); - sk->skey[i] = gcry_mpi_set_opaque(NULL, data, ndata*8); + sk->skey[i] = gcry_mpi_set_opaque (NULL, data, ndata*8 ); } else { csum = 0; @@ -423,30 +443,33 @@ protect_secret_key( PKT_secret_key *sk, DEK *dek ) unsigned int nbits; csum += checksum_mpi (sk->skey[i]); - if( gcry_mpi_aprint( GCRYMPI_FMT_USG, &buffer, - &nbytes, sk->skey[i] ) ) - BUG(); + + if (gcry_mpi_aprint (GCRYMPI_FMT_USG, &buffer, + &nbytes, sk->skey[i] )) + BUG(); gcry_cipher_sync (cipher_hd); - assert (!gcry_mpi_get_flag( sk->skey[i], - GCRYMPI_FLAG_OPAQUE )); - data = xmalloc (nbytes+2); - nbits = gcry_mpi_get_nbits (sk->skey[i]); + assert (!gcry_mpi_get_flag (sk->skey[i], + GCRYMPI_FLAG_OPAQUE)); + + data = xmalloc (nbytes+2); /* fixme: need xtrymalloc. */ + nbits = gcry_mpi_get_nbits (sk->skey[i]); assert (nbytes == (nbits + 7)/8); data[0] = nbits >> 8; data[1] = nbits; gcry_cipher_encrypt (cipher_hd, data+2, nbytes, buffer, nbytes); - xfree ( buffer ); + xfree( buffer ); gcry_mpi_release (sk->skey[i]); - sk->skey[i] = gcry_mpi_set_opaque (NULL, data, - (nbytes+2)*8); + sk->skey[i] = gcry_mpi_set_opaque (NULL, + data, (nbytes+2)*8 ); } sk->csum = csum; } sk->is_protected = 1; - gcry_cipher_close( cipher_hd ); + gcry_cipher_close (cipher_hd); } } return rc; } + |