diff options
Diffstat (limited to 'g10/seckey-cert.c')
-rw-r--r-- | g10/seckey-cert.c | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/g10/seckey-cert.c b/g10/seckey-cert.c index 85b0ed7af..f126ba01b 100644 --- a/g10/seckey-cert.c +++ b/g10/seckey-cert.c @@ -141,6 +141,7 @@ check_elg( PKT_secret_cert *cert ) return 0; } + static int protect_elg( PKT_secret_cert *cert, DEK *dek ) { @@ -174,6 +175,126 @@ protect_elg( PKT_secret_cert *cert, DEK *dek ) return 0; } +static int +check_dsa( PKT_secret_cert *cert ) +{ + byte *buffer; + u16 csum=0; + int res; + unsigned nbytes; + u32 keyid[2]; + DSA_secret_key skey; + char save_iv[8]; + + if( cert->d.dsa.is_protected ) { /* remove the protection */ + DEK *dek = NULL; + MPI test_x; + BLOWFISH_context *blowfish_ctx=NULL; + + switch( cert->d.dsa.protect.algo ) { + case CIPHER_ALGO_NONE: BUG(); break; + case CIPHER_ALGO_BLOWFISH: + keyid_from_skc( cert, keyid ); + if( cert->d.dsa.protect.s2k == 1 + || cert->d.dsa.protect.s2k == 3 ) + dek = get_passphrase_hash( keyid, NULL, + cert->d.dsa.protect.salt ); + else + dek = get_passphrase_hash( keyid, NULL, NULL ); + + blowfish_ctx = m_alloc_secure( sizeof *blowfish_ctx ); + blowfish_setkey( blowfish_ctx, dek->key, dek->keylen ); + m_free(dek); /* pw is in secure memory, so m_free() burns it */ + blowfish_setiv( blowfish_ctx, NULL ); + memcpy(save_iv, cert->d.dsa.protect.iv, 8 ); + blowfish_decode_cfb( blowfish_ctx, + cert->d.dsa.protect.iv, + cert->d.dsa.protect.iv, 8 ); + mpi_set_secure(cert->d.dsa.x ); + /*fixme: maybe it is better to set the buffer secure with a + * new get_buffer_secure() function */ + buffer = mpi_get_buffer( cert->d.dsa.x, &nbytes, NULL ); + csum = checksum_u16( nbytes*8 ); + blowfish_decode_cfb( blowfish_ctx, buffer, buffer, nbytes ); + csum += checksum( buffer, nbytes ); + test_x = mpi_alloc_secure( mpi_get_nlimbs(cert->d.dsa.x) ); + mpi_set_buffer( test_x, buffer, nbytes, 0 ); + m_free( buffer ); + m_free( blowfish_ctx ); + /* now let's see wether we have used the right passphrase */ + if( csum != cert->d.dsa.csum ) { + mpi_free(test_x); + memcpy( cert->d.dsa.protect.iv, save_iv, 8 ); + return G10ERR_BAD_PASS; + } + + skey.p = cert->d.dsa.p; + skey.q = cert->d.dsa.q; + skey.g = cert->d.dsa.g; + skey.y = cert->d.dsa.y; + skey.x = test_x; + res = dsa_check_secret_key( &skey ); + memset( &skey, 0, sizeof skey ); + if( !res ) { + mpi_free(test_x); + memcpy( cert->d.dsa.protect.iv, save_iv, 8 ); + return G10ERR_BAD_PASS; + } + mpi_set(cert->d.dsa.x, test_x); + mpi_free(test_x); + cert->d.dsa.is_protected = 0; + break; + + default: + return G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */ + } + } + else { /* not protected */ + buffer = mpi_get_buffer( cert->d.dsa.x, &nbytes, NULL ); + csum = checksum_u16( nbytes*8 ); + csum += checksum( buffer, nbytes ); + m_free( buffer ); + if( csum != cert->d.dsa.csum ) + return G10ERR_CHECKSUM; + } + + return 0; +} + + +static int +protect_dsa( PKT_secret_cert *cert, DEK *dek ) +{ + byte *buffer; + unsigned nbytes; + + if( !cert->d.dsa.is_protected ) { /* add the protection */ + BLOWFISH_context *blowfish_ctx=NULL; + + switch( cert->d.dsa.protect.algo ) { + case CIPHER_ALGO_NONE: BUG(); break; + case CIPHER_ALGO_BLOWFISH: + blowfish_ctx = m_alloc_secure( sizeof *blowfish_ctx ); + blowfish_setkey( blowfish_ctx, dek->key, dek->keylen ); + blowfish_setiv( blowfish_ctx, NULL ); + blowfish_encode_cfb( blowfish_ctx, + cert->d.dsa.protect.iv, + cert->d.dsa.protect.iv, 8 ); + buffer = mpi_get_buffer( cert->d.dsa.x, &nbytes, NULL ); + blowfish_encode_cfb( blowfish_ctx, buffer, buffer, nbytes ); + mpi_set_buffer( cert->d.dsa.x, buffer, nbytes, 0 ); + m_free( buffer ); + m_free( blowfish_ctx ); + cert->d.dsa.is_protected = 1; + break; + + default: + return G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */ + } + } + return 0; +} + #ifdef HAVE_RSA_CIPHER static int @@ -282,6 +403,8 @@ check_secret_key( PKT_secret_cert *cert ) log_error("Invalid passphrase; please try again ...\n"); if( cert->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) rc = check_elg( cert ); + else if( cert->pubkey_algo == PUBKEY_ALGO_DSA ) + rc = check_dsa( cert ); #ifdef HAVE_RSA_CIPHER else if( cert->pubkey_algo == PUBKEY_ALGO_RSA ) rc = check_rsa( cert ); @@ -303,6 +426,8 @@ is_secret_key_protected( PKT_secret_cert *cert ) { if( cert->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) return cert->d.elg.is_protected? cert->d.elg.protect.algo : 0; + else if( cert->pubkey_algo == PUBKEY_ALGO_DSA ) + return cert->d.dsa.is_protected? cert->d.dsa.protect.algo : 0; #ifdef HAVE_RSA_CIPHER else if( cert->pubkey_algo == PUBKEY_ALGO_RSA ) return cert->d.rsa.is_protected? cert->d.rsa.protect_algo : 0; @@ -323,6 +448,8 @@ protect_secret_key( PKT_secret_cert *cert, DEK *dek ) if( cert->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) return protect_elg( cert, dek ); + else if( cert->pubkey_algo == PUBKEY_ALGO_DSA ) + return protect_dsa( cert, dek ); else return G10ERR_PUBKEY_ALGO; } |