From 7b6f1902d02b0cec4a12d7b44b8d4583baa5bc0b Mon Sep 17 00:00:00 2001 From: Repo Admin Date: Thu, 9 Jan 2003 13:29:36 +0000 Subject: This commit was manufactured by cvs2svn to create branch 'GNUPG-1-9-BRANCH'. --- g10/pubkey-enc.c | 307 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 307 insertions(+) create mode 100644 g10/pubkey-enc.c (limited to 'g10/pubkey-enc.c') diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c new file mode 100644 index 000000000..1c52ce4de --- /dev/null +++ b/g10/pubkey-enc.c @@ -0,0 +1,307 @@ +/* pubkey-enc.c - public key encoded packet handling + * Copyright (C) 1998, 1999, 2000, 2001, 2002 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 "util.h" +#include "memory.h" +#include "packet.h" +#include "mpi.h" +#include "keydb.h" +#include "trustdb.h" +#include "cipher.h" +#include "status.h" +#include "options.h" +#include "main.h" +#include "i18n.h" + +static int get_it( PKT_pubkey_enc *k, + DEK *dek, PKT_secret_key *sk, u32 *keyid ); + + +/* check that the given algo is mentioned in one of the valid user IDs */ +static int +is_algo_in_prefs ( KBNODE keyblock, preftype_t type, int algo ) +{ + KBNODE k; + + for (k=keyblock; k; k=k->next) { + if (k->pkt->pkttype == PKT_USER_ID) { + PKT_user_id *uid = k->pkt->pkt.user_id; + prefitem_t *prefs = uid->prefs; + + if (uid->created && prefs && + !uid->is_revoked && !uid->is_expired ) { + for (; prefs->type; prefs++ ) + if (prefs->type == type && prefs->value == algo) + return 1; + } + } + } + return 0; +} + + +/**************** + * Get the session key from a pubkey enc packet and return + * it in DEK, which should have been allocated in secure memory. + */ +int +get_session_key( PKT_pubkey_enc *k, DEK *dek ) +{ + PKT_secret_key *sk = NULL; + int rc; + + rc = check_pubkey_algo2 (k->pubkey_algo, PUBKEY_USAGE_ENC); + if( rc ) + goto leave; + + if( (k->keyid[0] || k->keyid[1]) && !opt.try_all_secrets ) { + sk = m_alloc_clear( sizeof *sk ); + sk->pubkey_algo = k->pubkey_algo; /* we want a pubkey with this algo*/ + if( !(rc = get_seckey( sk, k->keyid )) ) + rc = get_it( k, dek, sk, k->keyid ); + } + else { /* anonymous receiver: Try all available secret keys */ + void *enum_context = NULL; + u32 keyid[2]; + char *p; + + for(;;) { + if( sk ) + free_secret_key( sk ); + sk = m_alloc_clear( sizeof *sk ); + rc=enum_secret_keys( &enum_context, sk, 1, 0); + if( rc ) { + rc = G10ERR_NO_SECKEY; + break; + } + if( sk->pubkey_algo != k->pubkey_algo ) + continue; + keyid_from_sk( sk, keyid ); + log_info(_("anonymous recipient; trying secret key %08lX ...\n"), + (ulong)keyid[1] ); + + if(!opt.try_all_secrets && !is_status_enabled()) + { + p=get_last_passphrase(); + set_next_passphrase(p); + m_free(p); + } + + rc = check_secret_key( sk, opt.try_all_secrets?1:-1 ); /* ask + only + once */ + if( !rc ) + rc = get_it( k, dek, sk, keyid ); + if( !rc ) { + log_info(_("okay, we are the anonymous recipient.\n") ); + break; + } + } + enum_secret_keys( &enum_context, NULL, 0, 0 ); /* free context */ + } + + leave: + if( sk ) + free_secret_key( sk ); + return rc; +} + + +static int +get_it( PKT_pubkey_enc *enc, DEK *dek, PKT_secret_key *sk, u32 *keyid ) +{ + int rc; + MPI plain_dek = NULL; + byte *frame = NULL; + unsigned n, nframe; + u16 csum, csum2; + + rc = pubkey_decrypt(sk->pubkey_algo, &plain_dek, enc->data, sk->skey ); + if( rc ) + goto leave; + frame = mpi_get_buffer( plain_dek, &nframe, NULL ); + mpi_free( plain_dek ); plain_dek = NULL; + + /* Now get the DEK (data encryption key) from the frame + * + * Old versions encode the DEK in in this format (msb is left): + * + * 0 1 DEK(16 bytes) CSUM(2 bytes) 0 RND(n bytes) 2 + * + * Later versions encode the DEK like this: + * + * 0 2 RND(n bytes) 0 A DEK(k bytes) CSUM(2 bytes) + * + * (mpi_get_buffer already removed the leading zero). + * + * RND are non-zero randow bytes. + * A is the cipher algorithm + * DEK is the encryption key (session key) with length k + * CSUM + */ + if( DBG_CIPHER ) + log_hexdump("DEK frame:", frame, nframe ); + n=0; + if( n + 7 > nframe ) + { rc = G10ERR_WRONG_SECKEY; goto leave; } + if( frame[n] == 1 && frame[nframe-1] == 2 ) { + log_info(_("old encoding of the DEK is not supported\n")); + rc = G10ERR_CIPHER_ALGO; + goto leave; + } + if( frame[n] != 2 ) /* somethink is wrong */ + { rc = G10ERR_WRONG_SECKEY; goto leave; } + for(n++; n < nframe && frame[n]; n++ ) /* skip the random bytes */ + ; + n++; /* and the zero byte */ + if( n + 4 > nframe ) + { rc = G10ERR_WRONG_SECKEY; goto leave; } + + dek->keylen = nframe - (n+1) - 2; + dek->algo = frame[n++]; + if( dek->algo == CIPHER_ALGO_IDEA ) + write_status(STATUS_RSA_OR_IDEA); + rc = check_cipher_algo( dek->algo ); + if( rc ) { + if( !opt.quiet && rc == G10ERR_CIPHER_ALGO ) { + log_info(_("cipher algorithm %d%s is unknown or disabled\n"), + dek->algo, dek->algo == CIPHER_ALGO_IDEA? " (IDEA)":""); + if(dek->algo==CIPHER_ALGO_IDEA) + idea_cipher_warn(0); + } + dek->algo = 0; + 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]; + memcpy( dek->key, frame+n, dek->keylen ); + for( csum2=0, n=0; n < dek->keylen; n++ ) + csum2 += dek->key[n]; + if( csum != csum2 ) { + rc = G10ERR_WRONG_SECKEY; + goto leave; + } + if( DBG_CIPHER ) + log_hexdump("DEK is:", dek->key, dek->keylen ); + /* check that the algo is in the preferences and whether it has expired */ + { + PKT_public_key *pk = NULL; + KBNODE pkb = get_pubkeyblock (keyid); + + if( !pkb ) { + rc = -1; + log_error("oops: public key not found for preference check\n"); + } + else if( pkb->pkt->pkt.public_key->selfsigversion > 3 + && dek->algo != CIPHER_ALGO_3DES + && !is_algo_in_prefs( pkb, PREFTYPE_SYM, dek->algo ) ) { + /* Don't print a note while we are not on verbose mode, + * the cipher is blowfish and the preferences have twofish + * listed */ + if( opt.verbose || dek->algo != CIPHER_ALGO_BLOWFISH + || !is_algo_in_prefs( pkb, PREFTYPE_SYM, CIPHER_ALGO_TWOFISH)) + log_info(_( + "NOTE: cipher algorithm %d not found in preferences\n"), + dek->algo ); + } + + if (!rc) { + KBNODE k; + + for (k=pkb; k; k = k->next) { + if (k->pkt->pkttype == PKT_PUBLIC_KEY + || k->pkt->pkttype == PKT_PUBLIC_SUBKEY){ + u32 aki[2]; + keyid_from_pk(k->pkt->pkt.public_key, aki); + + if (aki[0]==keyid[0] && aki[1]==keyid[1]) { + pk = k->pkt->pkt.public_key; + break; + } + } + } + if (!pk) + BUG (); + if ( pk->expiredate && pk->expiredate <= make_timestamp() ) { + log_info(_("NOTE: secret key %08lX expired at %s\n"), + (ulong)keyid[1], asctimestamp( pk->expiredate) ); + } + } + + if ( pk && pk->is_revoked ) { + log_info( _("NOTE: key has been revoked") ); + putc( '\n', log_stream() ); + show_revocation_reason( pk, 1 ); + } + + release_kbnode (pkb); + rc = 0; + } + + + leave: + mpi_free(plain_dek); + m_free(frame); + return rc; +} + + +/**************** + * Get the session key from the given string. + * String is supposed to be formatted as this: + * : + */ +int +get_override_session_key( DEK *dek, const char *string ) +{ + const char *s; + int i; + + if ( !string ) + return G10ERR_BAD_KEY; + dek->algo = atoi(string); + if ( dek->algo < 1 ) + return G10ERR_BAD_KEY; + if ( !(s = strchr ( string, ':' )) ) + return G10ERR_BAD_KEY; + s++; + for(i=0; i < DIM(dek->key) && *s; i++, s +=2 ) { + int c = hextobyte ( s ); + if (c == -1) + return G10ERR_BAD_KEY; + dek->key[i] = c; + } + if ( *s ) + return G10ERR_BAD_KEY; + dek->keylen = i; + return 0; +} + -- cgit v1.2.3