diff options
author | Repo Admin <nobody@gnupg.org> | 2003-01-09 14:29:36 +0100 |
---|---|---|
committer | Repo Admin <nobody@gnupg.org> | 2003-01-09 14:29:36 +0100 |
commit | 7b6f1902d02b0cec4a12d7b44b8d4583baa5bc0b (patch) | |
tree | 6556ef3a9255ffea9ca1dce8015940d30aa9d890 /g10 | |
parent | Taken from NewPG (diff) | |
download | gnupg2-7b6f1902d02b0cec4a12d7b44b8d4583baa5bc0b.tar.xz gnupg2-7b6f1902d02b0cec4a12d7b44b8d4583baa5bc0b.zip |
This commit was manufactured by cvs2svn to create branch
'GNUPG-1-9-BRANCH'.
Diffstat (limited to 'g10')
-rw-r--r-- | g10/delkey.c | 209 | ||||
-rw-r--r-- | g10/pubkey-enc.c | 307 | ||||
-rw-r--r-- | g10/status.h | 127 |
3 files changed, 643 insertions, 0 deletions
diff --git a/g10/delkey.c b/g10/delkey.c new file mode 100644 index 000000000..35c903cc0 --- /dev/null +++ b/g10/delkey.c @@ -0,0 +1,209 @@ +/* delkey.c - delete keys + * 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 <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <assert.h> +#include <ctype.h> + +#include "options.h" +#include "packet.h" +#include "errors.h" +#include "iobuf.h" +#include "keydb.h" +#include "memory.h" +#include "util.h" +#include "main.h" +#include "trustdb.h" +#include "filter.h" +#include "ttyio.h" +#include "status.h" +#include "i18n.h" + + +/**************** + * Delete a public or secret key from a keyring. + * r_sec_avail will be set if a secret key is available and the public + * key can't be deleted for that reason. + */ +static int +do_delete_key( const char *username, int secret, int *r_sec_avail ) +{ + int rc = 0; + KBNODE keyblock = NULL; + KBNODE node; + KEYDB_HANDLE hd = keydb_new (secret); + PKT_public_key *pk = NULL; + PKT_secret_key *sk = NULL; + u32 keyid[2]; + int okay=0; + int yes; + KEYDB_SEARCH_DESC desc; + int exactmatch; + + *r_sec_avail = 0; + + /* search the userid */ + classify_user_id (username, &desc); + exactmatch = (desc.mode == KEYDB_SEARCH_MODE_FPR + || desc.mode == KEYDB_SEARCH_MODE_FPR16 + || desc.mode == KEYDB_SEARCH_MODE_FPR20); + rc = desc.mode? keydb_search (hd, &desc, 1):G10ERR_INV_USER_ID; + if (rc) { + log_error (_("key `%s' not found: %s\n"), username, g10_errstr (rc)); + write_status_text( STATUS_DELETE_PROBLEM, "1" ); + goto leave; + } + + /* read the keyblock */ + rc = keydb_get_keyblock (hd, &keyblock ); + if (rc) { + log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) ); + goto leave; + } + + /* get the keyid from the keyblock */ + node = find_kbnode( keyblock, secret? PKT_SECRET_KEY:PKT_PUBLIC_KEY ); + if( !node ) { + log_error("Oops; key not found anymore!\n"); + rc = G10ERR_GENERAL; + goto leave; + } + + if( secret ) { + sk = node->pkt->pkt.secret_key; + keyid_from_sk( sk, keyid ); + } + else { + pk = node->pkt->pkt.public_key; + keyid_from_pk( pk, keyid ); + rc = seckey_available( keyid ); + if( !rc ) { + *r_sec_avail = 1; + rc = -1; + goto leave; + } + else if( rc != G10ERR_NO_SECKEY ) { + log_error("%s: get secret key: %s\n", username, g10_errstr(rc) ); + } + else + rc = 0; + } + + if( rc ) + rc = 0; + else if (opt.batch && exactmatch) + okay++; + else if( opt.batch && secret ) + { + log_error(_("can't do that in batchmode\n")); + log_info (_("(unless you specify the key by fingerprint)\n")); + } + else if( opt.batch && opt.answer_yes ) + okay++; + else if( opt.batch ) + { + log_error(_("can't do that in batchmode without \"--yes\"\n")); + log_info (_("(unless you specify the key by fingerprint)\n")); + } + else { + if( secret ) + print_seckey_info( sk ); + else + print_pubkey_info( pk ); + tty_printf( "\n" ); + + yes = cpr_get_answer_is_yes( secret? "delete_key.secret.okay" + : "delete_key.okay", + _("Delete this key from the keyring? ")); + if( !cpr_enabled() && secret && yes ) { + /* I think it is not required to check a passphrase; if + * the user is so stupid as to let others access his secret keyring + * (and has no backup) - it is up him to read some very + * basic texts about security. + */ + yes = cpr_get_answer_is_yes("delete_key.secret.okay", + _("This is a secret key! - really delete? ")); + } + if( yes ) + okay++; + } + + + if( okay ) { + rc = keydb_delete_keyblock (hd); + if (rc) { + log_error (_("deleting keyblock failed: %s\n"), g10_errstr(rc) ); + goto leave; + } + + /* Note that the ownertrust being cleared will trigger a + revalidation_mark(). This makes sense - only deleting keys + that have ownertrust set should trigger this. */ + + if (!secret && pk && clear_ownertrusts (pk)) { + if (opt.verbose) + log_info (_("ownertrust information cleared\n")); + } + } + + leave: + keydb_release (hd); + release_kbnode (keyblock); + return rc; +} + +/**************** + * Delete a public or secret key from a keyring. + */ +int +delete_keys( STRLIST names, int secret, int allow_both ) +{ + int rc, avail; + + for(;names;names=names->next) { + rc = do_delete_key (names->d, secret, &avail ); + if ( rc && avail ) { + if ( allow_both ) { + rc = do_delete_key (names->d, 1, &avail ); + if ( !rc ) + rc = do_delete_key (names->d, 0, &avail ); + } + else { + log_error(_( + "there is a secret key for public key \"%s\"!\n"),names->d); + log_info(_( + "use option \"--delete-secret-keys\" to delete it first.\n")); + write_status_text( STATUS_DELETE_PROBLEM, "2" ); + return rc; + } + } + + if(rc) { + log_error("%s: delete key failed: %s\n", names->d, g10_errstr(rc) ); + return rc; + } + } + + return 0; +} 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 <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#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: + * <algo-id>:<even-number-of-hex-digits> + */ +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; +} + diff --git a/g10/status.h b/g10/status.h new file mode 100644 index 000000000..44a7d6d32 --- /dev/null +++ b/g10/status.h @@ -0,0 +1,127 @@ +/* status.h + * Copyright (C) 1998, 1999, 2000, 2001 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 + */ +#ifndef G10_STATUS_H +#define G10_STATUS_H + + +#define STATUS_ENTER 1 +#define STATUS_LEAVE 2 +#define STATUS_ABORT 3 + +#define STATUS_GOODSIG 4 +#define STATUS_BADSIG 5 +#define STATUS_ERRSIG 6 + + +#define STATUS_BADARMOR 7 + +#define STATUS_RSA_OR_IDEA 8 +#define STATUS_KEYEXPIRED 9 +#define STATUS_KEYREVOKED 10 + +#define STATUS_TRUST_UNDEFINED 11 +#define STATUS_TRUST_NEVER 12 +#define STATUS_TRUST_MARGINAL 13 +#define STATUS_TRUST_FULLY 14 +#define STATUS_TRUST_ULTIMATE 15 + +#define STATUS_SHM_INFO 16 +#define STATUS_SHM_GET 17 +#define STATUS_SHM_GET_BOOL 18 +#define STATUS_SHM_GET_HIDDEN 19 + +#define STATUS_NEED_PASSPHRASE 20 +#define STATUS_VALIDSIG 21 +#define STATUS_SIG_ID 22 +#define STATUS_ENC_TO 23 +#define STATUS_NODATA 24 +#define STATUS_BAD_PASSPHRASE 25 +#define STATUS_NO_PUBKEY 26 +#define STATUS_NO_SECKEY 27 +#define STATUS_NEED_PASSPHRASE_SYM 28 +#define STATUS_DECRYPTION_FAILED 29 +#define STATUS_DECRYPTION_OKAY 30 +#define STATUS_MISSING_PASSPHRASE 31 +#define STATUS_GOOD_PASSPHRASE 32 +#define STATUS_GOODMDC 33 +#define STATUS_BADMDC 34 +#define STATUS_ERRMDC 35 +#define STATUS_IMPORTED 36 +#define STATUS_IMPORT_RES 37 +#define STATUS_FILE_START 38 +#define STATUS_FILE_DONE 39 +#define STATUS_FILE_ERROR 40 + +#define STATUS_BEGIN_DECRYPTION 41 +#define STATUS_END_DECRYPTION 42 +#define STATUS_BEGIN_ENCRYPTION 43 +#define STATUS_END_ENCRYPTION 44 + +#define STATUS_DELETE_PROBLEM 45 +#define STATUS_GET_BOOL 46 +#define STATUS_GET_LINE 47 +#define STATUS_GET_HIDDEN 48 +#define STATUS_GOT_IT 49 +#define STATUS_PROGRESS 50 +#define STATUS_SIG_CREATED 51 +#define STATUS_SESSION_KEY 52 +#define STATUS_NOTATION_NAME 53 +#define STATUS_NOTATION_DATA 54 +#define STATUS_POLICY_URL 55 +#define STATUS_BEGIN_STREAM 56 +#define STATUS_END_STREAM 57 +#define STATUS_KEY_CREATED 58 +#define STATUS_USERID_HINT 59 +#define STATUS_UNEXPECTED 60 +#define STATUS_INV_RECP 61 +#define STATUS_NO_RECP 62 +#define STATUS_ALREADY_SIGNED 63 +#define STATUS_SIGEXPIRED 64 +#define STATUS_EXPSIG 65 +#define STATUS_EXPKEYSIG 66 +#define STATUS_ATTRIBUTE 67 +#define STATUS_IMPORT_OK 68 +#define STATUS_IMPORT_CHECK 69 + +/*-- status.c --*/ +void set_status_fd ( int fd ); +int is_status_enabled ( void ); +void write_status ( int no ); +void write_status_text ( int no, const char *text ); +void write_status_buffer ( int no, + const char *buffer, size_t len, int wrap ); +void write_status_text_and_buffer ( int no, const char *text, + const char *buffer, size_t len, int wrap ); + +#ifdef USE_SHM_COPROCESSING + void init_shm_coprocessing ( ulong requested_shm_size, int lock_mem ); +#endif /*USE_SHM_COPROCESSING*/ + +int cpr_enabled(void); +char *cpr_get( const char *keyword, const char *prompt ); +char *cpr_get_no_help( const char *keyword, const char *prompt ); +char *cpr_get_utf8( const char *keyword, const char *prompt ); +char *cpr_get_hidden( const char *keyword, const char *prompt ); +void cpr_kill_prompt(void); +int cpr_get_answer_is_yes( const char *keyword, const char *prompt ); +int cpr_get_answer_yes_no_quit( const char *keyword, const char *prompt ); + + +#endif /*G10_STATUS_H*/ |