X-Git-Url: http://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blobdiff_plain;f=g10%2Fskclist.c;h=4cd7f332e1babafb75fc00d47cd34db7038c5870;hp=a0d69a49e933d73dabedc2a0c69a32e8fe63d54a;hb=f015552374d69e28292a12f2b91ab34d65c9b457;hpb=100fc8da591e38107c578dcbe39d6634c7731846 diff --git a/g10/skclist.c b/g10/skclist.c index a0d69a49e..4cd7f332e 100644 --- a/g10/skclist.c +++ b/g10/skclist.c @@ -1,11 +1,12 @@ -/* skclist.c - * Copyright (C) 1998 Free Software Foundation, Inc. +/* skclist.c - Build a list of secret keys + * Copyright (C) 1998, 1999, 2000, 2001, 2006, + * 2010 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, @@ -14,8 +15,7 @@ * 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 + * along with this program; if not, see . */ #include @@ -23,112 +23,248 @@ #include #include #include -#include -#include +#include "gpg.h" #include "options.h" #include "packet.h" -#include "errors.h" +#include "status.h" #include "keydb.h" #include "util.h" #include "i18n.h" -#include "main.h" + + +/* Return true if Libgcrypt's RNG is in faked mode. */ +int +random_is_faked (void) +{ + return !!gcry_control (GCRYCTL_FAKED_RANDOM_P, 0); +} void -release_sk_list( SK_LIST sk_list ) +release_sk_list (SK_LIST sk_list) { - SK_LIST sk_rover; + SK_LIST sk_rover; - for( ; sk_list; sk_list = sk_rover ) { - sk_rover = sk_list->next; - free_secret_key( sk_list->sk ); - gcry_free( sk_list ); + for (; sk_list; sk_list = sk_rover) + { + sk_rover = sk_list->next; + free_public_key (sk_list->pk); + xfree (sk_list); } } -int -build_sk_list( STRLIST locusr, SK_LIST *ret_sk_list, int unlock, - unsigned use ) +/* Check that we are only using keys which don't have + * the string "(insecure!)" or "not secure" or "do not use" + * in one of the user ids. */ +static int +is_insecure (PKT_public_key *pk) { - SK_LIST sk_list = NULL; - int rc; + u32 keyid[2]; + KBNODE node = NULL, u; + int insecure = 0; + + keyid_from_pk (pk, keyid); + node = get_pubkeyblock (keyid); + for (u = node; u; u = u->next) + { + if (u->pkt->pkttype == PKT_USER_ID) + { + PKT_user_id *id = u->pkt->pkt.user_id; + if (id->attrib_data) + continue; /* skip attribute packets */ + if (strstr (id->name, "(insecure!)") + || strstr (id->name, "not secure") + || strstr (id->name, "do not use") + || strstr (id->name, "(INSECURE!)")) + { + insecure = 1; + break; + } + } + } + release_kbnode (node); - if( !locusr ) { /* use the default one */ - PKT_secret_key *sk; + return insecure; +} + +static int +key_present_in_sk_list (SK_LIST sk_list, PKT_public_key *pk) +{ + for (; sk_list; sk_list = sk_list->next) + { + if (!cmp_public_keys (sk_list->pk, pk)) + return 0; + } + return -1; +} + +static int +is_duplicated_entry (strlist_t list, strlist_t item) +{ + for (; list && list != item; list = list->next) + { + if (!strcmp (list->d, item->d)) + return 1; + } + return 0; +} - sk = gcry_xcalloc( 1, sizeof *sk ); - sk->pubkey_usage = use; - if( (rc = get_seckey_byname( sk, NULL, unlock )) ) { - free_secret_key( sk ); sk = NULL; - log_error("no default secret key: %s\n", gpg_errstr(rc) ); + +gpg_error_t +build_sk_list (ctrl_t ctrl, + strlist_t locusr, SK_LIST *ret_sk_list, unsigned int use) +{ + gpg_error_t err; + SK_LIST sk_list = NULL; + + /* XXX: Change this function to use get_pubkeys instead of + getkey_byname to detect ambiguous key specifications and warn + about duplicate keyblocks. For ambiguous key specifications on + the command line or provided interactively, prompt the user to + select the best key. If a key specification is ambiguous and we + are in batch mode, die. */ + + if (!locusr) /* No user ids given - use the default key. */ + { + PKT_public_key *pk; + + pk = xmalloc_clear (sizeof *pk); + pk->req_usage = use; + if ((err = getkey_byname (ctrl, NULL, pk, NULL, 1, NULL))) + { + free_public_key (pk); + pk = NULL; + log_error ("no default secret key: %s\n", gpg_strerror (err)); + write_status_text (STATUS_INV_SGNR, get_inv_recpsgnr_code (err)); } - else if( !(rc=openpgp_pk_test_algo(sk->pubkey_algo, use)) ) { - SK_LIST r; - if( sk->version == 4 && (use & GCRY_PK_USAGE_SIGN) - && sk->pubkey_algo == GCRY_PK_ELG_E ) { - log_info("this is a PGP generated " - "ElGamal key which is NOT secure for signatures!\n"); - free_secret_key( sk ); sk = NULL; + else if ((err = openpgp_pk_test_algo2 (pk->pubkey_algo, use))) + { + free_public_key (pk); + pk = NULL; + log_error ("invalid default secret key: %s\n", gpg_strerror (err)); + write_status_text (STATUS_INV_SGNR, get_inv_recpsgnr_code (err)); + } + else + { + SK_LIST r; + + if (random_is_faked () && !is_insecure (pk)) + { + log_info (_("key is not flagged as insecure - " + "can't use it with the faked RNG!\n")); + free_public_key (pk); + pk = NULL; + write_status_text (STATUS_INV_SGNR, + get_inv_recpsgnr_code (GPG_ERR_NOT_TRUSTED)); } - else { - r = gcry_xmalloc( sizeof *r ); - r->sk = sk; sk = NULL; - r->next = sk_list; - r->mark = 0; - sk_list = r; + else + { + r = xmalloc (sizeof *r); + r->pk = pk; + pk = NULL; + r->next = sk_list; + r->mark = 0; + sk_list = r; } } - else { - free_secret_key( sk ); sk = NULL; - log_error("invalid default secret key: %s\n", gpg_errstr(rc) ); - } } - else { - for(; locusr; locusr = locusr->next ) { - PKT_secret_key *sk; - - sk = gcry_xcalloc( 1, sizeof *sk ); - sk->pubkey_usage = use; - if( (rc = get_seckey_byname( sk, locusr->d, unlock )) ) { - free_secret_key( sk ); sk = NULL; - log_error(_("skipped `%s': %s\n"), locusr->d, gpg_errstr(rc) ); + else /* Check the given user ids. */ + { + strlist_t locusr_orig = locusr; + + for (; locusr; locusr = locusr->next) + { + PKT_public_key *pk; + + err = 0; + /* Do an early check against duplicated entries. However + * this won't catch all duplicates because the user IDs may + * be specified in different ways. */ + if (is_duplicated_entry (locusr_orig, locusr)) + { + log_info (_("skipped \"%s\": duplicated\n"), locusr->d); + continue; + } + pk = xmalloc_clear (sizeof *pk); + pk->req_usage = use; + if ((err = getkey_byname (ctrl, NULL, pk, locusr->d, 1, NULL))) + { + free_public_key (pk); + pk = NULL; + log_error (_("skipped \"%s\": %s\n"), + locusr->d, gpg_strerror (err)); + write_status_text_and_buffer + (STATUS_INV_SGNR, get_inv_recpsgnr_code (err), + locusr->d, strlen (locusr->d), -1); + } + else if (!key_present_in_sk_list (sk_list, pk)) + { + free_public_key (pk); + pk = NULL; + log_info (_("skipped: secret key already present\n")); } - else if( !(rc=openpgp_pk_test_algo(sk->pubkey_algo, use)) ) { - SK_LIST r; - if( sk->version == 4 && (use & GCRY_PK_USAGE_SIGN) - && sk->pubkey_algo == GCRY_PK_ELG_E ) { - log_info(_("skipped `%s': this is a PGP generated " - "ElGamal key which is not secure for signatures!\n"), - locusr->d ); - free_secret_key( sk ); sk = NULL; + else if ((err = openpgp_pk_test_algo2 (pk->pubkey_algo, use))) + { + free_public_key (pk); + pk = NULL; + log_error ("skipped \"%s\": %s\n", locusr->d, gpg_strerror (err)); + write_status_text_and_buffer + (STATUS_INV_SGNR, get_inv_recpsgnr_code (err), + locusr->d, strlen (locusr->d), -1); + } + else + { + SK_LIST r; + + if (pk->version == 4 && (use & PUBKEY_USAGE_SIG) + && pk->pubkey_algo == PUBKEY_ALGO_ELGAMAL_E) + { + log_info (_("skipped \"%s\": %s\n"), locusr->d, + _("this is a PGP generated Elgamal key which" + " is not secure for signatures!")); + free_public_key (pk); + pk = NULL; + write_status_text_and_buffer + (STATUS_INV_SGNR, + get_inv_recpsgnr_code (GPG_ERR_WRONG_KEY_USAGE), + locusr->d, strlen (locusr->d), -1); } - else { - r = gcry_xmalloc( sizeof *r ); - r->sk = sk; sk = NULL; - r->next = sk_list; - r->mark = 0; - sk_list = r; + else if (random_is_faked () && !is_insecure (pk)) + { + log_info (_("key is not flagged as insecure - " + "can't use it with the faked RNG!\n")); + free_public_key (pk); + pk = NULL; + write_status_text_and_buffer + (STATUS_INV_SGNR, + get_inv_recpsgnr_code (GPG_ERR_NOT_TRUSTED), + locusr->d, strlen (locusr->d), -1); + } + else + { + r = xmalloc (sizeof *r); + r->pk = pk; + pk = NULL; + r->next = sk_list; + r->mark = 0; + sk_list = r; } - } - else { - free_secret_key( sk ); sk = NULL; - log_error("skipped `%s': %s\n", locusr->d, gpg_errstr(rc) ); } } } - - if( !rc && !sk_list ) { - log_error("no valid signators\n"); - rc = GPGERR_NO_USER_ID; + if (!err && !sk_list) + { + log_error ("no valid signators\n"); + write_status_text (STATUS_NO_SGNR, "0"); + err = gpg_error (GPG_ERR_NO_USER_ID); } - if( rc ) - release_sk_list( sk_list ); - else - *ret_sk_list = sk_list; - return rc; + if (err) + release_sk_list (sk_list); + else + *ret_sk_list = sk_list; + return err; } -