summaryrefslogtreecommitdiffstats
path: root/g10/pkclist.c
diff options
context:
space:
mode:
authorRepo Admin <nobody@gnupg.org>2002-10-19 09:55:27 +0200
committerRepo Admin <nobody@gnupg.org>2002-10-19 09:55:27 +0200
commit82a17c9fb3d64ccdd474c3bedf564368f77e84a4 (patch)
tree0c01ee8cea5f6f77e830955c6b97024752740a2b /g10/pkclist.c
parentBumped version number for cvs version (diff)
downloadgnupg2-82a17c9fb3d64ccdd474c3bedf564368f77e84a4.tar.xz
gnupg2-82a17c9fb3d64ccdd474c3bedf564368f77e84a4.zip
This commit was manufactured by cvs2svn to create branch
'GNUPG-1-9-BRANCH'.
Diffstat (limited to 'g10/pkclist.c')
-rw-r--r--g10/pkclist.c1303
1 files changed, 0 insertions, 1303 deletions
diff --git a/g10/pkclist.c b/g10/pkclist.c
deleted file mode 100644
index cb1c506e3..000000000
--- a/g10/pkclist.c
+++ /dev/null
@@ -1,1303 +0,0 @@
-/* pkclist.c
- * 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 "options.h"
-#include "packet.h"
-#include "errors.h"
-#include "keydb.h"
-#include "memory.h"
-#include "util.h"
-#include "main.h"
-#include "trustdb.h"
-#include "ttyio.h"
-#include "status.h"
-#include "photoid.h"
-#include "i18n.h"
-
-
-#define CONTROL_D ('D' - 'A' + 1)
-
-
-/****************
- * Show the revocation reason as it is stored with the given signature
- */
-static void
-do_show_revocation_reason( PKT_signature *sig )
-{
- size_t n, nn;
- const byte *p, *pp;
- int seq = 0;
- const char *text;
-
- while( (p = enum_sig_subpkt (sig->hashed, SIGSUBPKT_REVOC_REASON,
- &n, &seq, NULL )) ) {
- if( !n )
- continue; /* invalid - just skip it */
-
- if( *p == 0 )
- text = _("No reason specified");
- else if( *p == 0x01 )
- text = _("Key is superseded");
- else if( *p == 0x02 )
- text = _("Key has been compromised");
- else if( *p == 0x03 )
- text = _("Key is no longer used");
- else if( *p == 0x20 )
- text = _("User ID is no longer valid");
- else
- text = NULL;
-
- log_info( _("reason for revocation: ") );
- if( text )
- fputs( text, log_stream() );
- else
- fprintf( log_stream(), "code=%02x", *p );
- putc( '\n', log_stream() );
- n--; p++;
- pp = NULL;
- do {
- /* We don't want any empty lines, so skip them */
- while( n && *p == '\n' ) {
- p++;
- n--;
- }
- if( n ) {
- pp = memchr( p, '\n', n );
- nn = pp? pp - p : n;
- log_info( _("revocation comment: ") );
- print_string( log_stream(), p, nn, 0 );
- putc( '\n', log_stream() );
- p += nn; n -= nn;
- }
- } while( pp );
- }
-}
-
-/* Mode 0: try and find the revocation based on the pk (i.e. check
- subkeys, etc.) Mode 1: use only the revocation on the main pk */
-
-void
-show_revocation_reason( PKT_public_key *pk, int mode )
-{
- /* Hmmm, this is not so easy becuase we have to duplicate the code
- * used in the trustbd to calculate the keyflags. We need to find
- * a clean way to check revocation certificates on keys and
- * signatures. And there should be no duplicate code. Because we
- * enter this function only when the trustdb told us that we have
- * a revoked key, we could simply look for a revocation cert and
- * display this one, when there is only one. Let's try to do this
- * until we have a better solution. */
- KBNODE node, keyblock = NULL;
- byte fingerprint[MAX_FINGERPRINT_LEN];
- size_t fingerlen;
- int rc;
-
- /* get the keyblock */
- fingerprint_from_pk( pk, fingerprint, &fingerlen );
- rc = get_keyblock_byfprint( &keyblock, fingerprint, fingerlen );
- if( rc ) { /* that should never happen */
- log_debug( "failed to get the keyblock\n");
- return;
- }
-
- for( node=keyblock; node; node = node->next ) {
- if( (mode && node->pkt->pkttype == PKT_PUBLIC_KEY) ||
- ( ( node->pkt->pkttype == PKT_PUBLIC_KEY
- || node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
- && !cmp_public_keys( node->pkt->pkt.public_key, pk ) ) )
- break;
- }
- if( !node ) {
- log_debug("Oops, PK not in keyblock\n");
- release_kbnode( keyblock );
- return;
- }
- /* now find the revocation certificate */
- for( node = node->next; node ; node = node->next ) {
- if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
- break;
- if( node->pkt->pkttype == PKT_SIGNATURE
- && (node->pkt->pkt.signature->sig_class == 0x20
- || node->pkt->pkt.signature->sig_class == 0x28 ) ) {
- /* FIXME: we should check the signature here */
- do_show_revocation_reason ( node->pkt->pkt.signature );
- break;
- }
- }
-
- /* We didn't find it, so check if the whole key is revoked */
- if(!node && !mode)
- show_revocation_reason(pk,1);
-
- release_kbnode( keyblock );
-}
-
-
-static void
-show_paths (const PKT_public_key *pk, int only_first )
-{
- log_debug("not yet implemented\n");
-#if 0
- void *context = NULL;
- unsigned otrust, validity;
- int last_level, level;
-
- last_level = 0;
- while( (level=enum_cert_paths( &context, &lid, &otrust, &validity)) != -1){
- char *p;
- int c, rc;
- size_t n;
- u32 keyid[2];
- PKT_public_key *pk ;
-
- if( level < last_level && only_first )
- break;
- last_level = level;
-
- rc = keyid_from_lid( lid, keyid );
-
- if( rc ) {
- log_error("ooops: can't get keyid for lid %lu\n", lid);
- return;
- }
-
- pk = m_alloc_clear( sizeof *pk );
- rc = get_pubkey( pk, keyid );
- if( rc ) {
- log_error("key %08lX: public key not found: %s\n",
- (ulong)keyid[1], g10_errstr(rc) );
- return;
- }
-
- tty_printf("%*s%4u%c/%08lX.%lu %s \"",
- level*2, "",
- nbits_from_pk( pk ), pubkey_letter( pk->pubkey_algo ),
- (ulong)keyid[1], lid, datestr_from_pk( pk ) );
-
- c = trust_letter(otrust);
- if( c )
- putchar( c );
- else
- printf( "%02x", otrust );
- putchar('/');
- c = trust_letter(validity);
- if( c )
- putchar( c );
- else
- printf( "%02x", validity );
- putchar(' ');
-
- p = get_user_id( keyid, &n );
- tty_print_utf8_string( p, n ),
- m_free(p);
- tty_printf("\"\n");
- free_public_key( pk );
- }
- enum_cert_paths( &context, NULL, NULL, NULL ); /* release context */
-#endif
- tty_printf("\n");
-}
-
-
-
-
-/****************
- * mode: 0 = standard
- * 1 = Without key info and additional menu option 'm'
- * this does also add an option to set the key to ultimately trusted.
- * Returns:
- * -2 = nothing changed - caller should show some additional info
- * -1 = quit operation
- * 0 = nothing changed
- * 1 = new ownertrust now in new_trust
- */
-static int
-do_edit_ownertrust (PKT_public_key *pk, int mode,
- unsigned *new_trust, int defer_help )
-{
- char *p;
- size_t n;
- u32 keyid[2];
- int changed=0;
- int quit=0;
- int show=0;
- int did_help=defer_help;
-
- keyid_from_pk (pk, keyid);
- for(;;) {
- /* a string with valid answers */
- const char *ans = _("iImMqQsS");
-
- if( !did_help )
- {
- if( !mode )
- {
- KBNODE keyblock, un;
-
- tty_printf(_("No trust value assigned to:\n"
- "%4u%c/%08lX %s \""),
- nbits_from_pk( pk ), pubkey_letter( pk->pubkey_algo ),
- (ulong)keyid[1], datestr_from_pk( pk ) );
- p = get_user_id( keyid, &n );
- tty_print_utf8_string( p, n ),
- m_free(p);
- tty_printf("\"\n");
-
- keyblock = get_pubkeyblock (keyid);
- if (!keyblock)
- BUG ();
- for (un=keyblock; un; un = un->next) {
- if (un->pkt->pkttype != PKT_USER_ID )
- continue;
- if (un->pkt->pkt.user_id->is_revoked )
- continue;
- if (un->pkt->pkt.user_id->is_expired )
- continue;
- /* Only skip textual primaries */
- if (un->pkt->pkt.user_id->is_primary &&
- !un->pkt->pkt.user_id->attrib_data )
- continue;
-
- if(opt.show_photos && un->pkt->pkt.user_id->attrib_data)
- show_photos(un->pkt->pkt.user_id->attribs,
- un->pkt->pkt.user_id->numattribs,pk,NULL);
-
- tty_printf (" %s", _(" aka \""));
- tty_print_utf8_string (un->pkt->pkt.user_id->name,
- un->pkt->pkt.user_id->len );
- tty_printf("\"\n");
- }
-
- print_fingerprint (pk, NULL, 2);
- tty_printf("\n");
- }
- tty_printf (_(
- "Please decide how far you trust this user to correctly\n"
- "verify other users' keys (by looking at passports,\n"
- "checking fingerprints from different sources...)?\n\n"));
- tty_printf (_(" %d = Don't know\n"), 1);
- tty_printf (_(" %d = I do NOT trust\n"), 2);
- tty_printf (_(" %d = I trust marginally\n"), 3);
- tty_printf (_(" %d = I trust fully\n"), 4);
- if (mode)
- tty_printf (_(" %d = I trust ultimately\n"), 5);
-#if 0
- /* not yet implemented */
- tty_printf (_(" i = please show me more information\n") );
-#endif
- if( mode )
- tty_printf(_(" m = back to the main menu\n"));
- else
- {
- tty_printf(_(" s = skip this key\n"));
- tty_printf(_(" q = quit\n"));
- }
- tty_printf("\n");
- did_help = 1;
- }
- if( strlen(ans) != 8 )
- BUG();
- p = cpr_get("edit_ownertrust.value",_("Your decision? "));
- trim_spaces(p);
- cpr_kill_prompt();
- if( !*p )
- did_help = 0;
- else if( *p && p[1] )
- ;
- else if( !p[1] && (*p >= '1' && *p <= (mode?'5':'4')) )
- {
- unsigned int trust;
- switch( *p )
- {
- case '1': trust = TRUST_UNDEFINED; break;
- case '2': trust = TRUST_NEVER ; break;
- case '3': trust = TRUST_MARGINAL ; break;
- case '4': trust = TRUST_FULLY ; break;
- case '5': trust = TRUST_ULTIMATE ; break;
- default: BUG();
- }
- if (trust == TRUST_ULTIMATE
- && !cpr_get_answer_is_yes ("edit_ownertrust.set_ultimate.okay",
- _("Do you really want to set this key"
- " to ultimate trust? ")))
- ; /* no */
- else
- {
- *new_trust = trust;
- changed = 1;
- break;
- }
- }
-#if 0
- /* not yet implemented */
- else if( *p == ans[0] || *p == ans[1] )
- {
- tty_printf(_("Certificates leading to an ultimately trusted key:\n"));
- show = 1;
- break;
- }
-#endif
- else if( mode && (*p == ans[2] || *p == ans[3] || *p == CONTROL_D ) )
- {
- break ; /* back to the menu */
- }
- else if( !mode && (*p == ans[6] || *p == ans[7] ) )
- {
- break; /* skip */
- }
- else if( !mode && (*p == ans[4] || *p == ans[5] ) )
- {
- quit = 1;
- break ; /* back to the menu */
- }
- m_free(p); p = NULL;
- }
- m_free(p);
- return show? -2: quit? -1 : changed;
-}
-
-/*
- * Display a menu to change the ownertrust of the key PK (which should
- * be a primary key).
- * For mode values see do_edit_ownertrust ()
- */
-int
-edit_ownertrust (PKT_public_key *pk, int mode )
-{
- unsigned int trust;
- int no_help = 0;
-
- for(;;)
- {
- switch ( do_edit_ownertrust (pk, mode, &trust, no_help ) )
- {
- case -1: /* quit */
- return -1;
- case -2: /* show info */
- show_paths(pk, 1);
- no_help = 1;
- break;
- case 1: /* trust value set */
- trust &= ~TRUST_FLAG_DISABLED;
- trust |= get_ownertrust (pk) & TRUST_FLAG_DISABLED;
- update_ownertrust (pk, trust );
- return 1;
- default:
- return 0;
- }
- }
-}
-
-
-/****************
- * Check whether we can trust this pk which has a trustlevel of TRUSTLEVEL
- * Returns: true if we trust.
- */
-static int
-do_we_trust( PKT_public_key *pk, unsigned int *trustlevel )
-{
- unsigned int trustmask = 0;
-
- /* FIXME: get_pubkey_byname already checks the validity and won't
- * return keys which are either expired or revoked - so these
- * question here won't get triggered. We have to find a solution
- * for this. It might make sense to have a function in getkey.c
- * which does only the basic checks and returns even revoked and
- * expired keys. This fnction could then also returhn a list of
- * keys if the speicified name is ambiguous
- */
- if( (*trustlevel & TRUST_FLAG_REVOKED) ) {
- log_info(_("key %08lX: key has been revoked!\n"),
- (ulong)keyid_from_pk( pk, NULL) );
- show_revocation_reason( pk, 0 );
- if( opt.batch )
- return 0; /* no */
-
- if( !cpr_get_answer_is_yes("revoked_key.override",
- _("Use this key anyway? ")) )
- return 0; /* no */
- trustmask |= TRUST_FLAG_REVOKED;
- }
- if( (*trustlevel & TRUST_FLAG_SUB_REVOKED) ) {
- log_info(_("key %08lX: subkey has been revoked!\n"),
- (ulong)keyid_from_pk( pk, NULL) );
- show_revocation_reason( pk, 0 );
- if( opt.batch )
- return 0;
-
- if( !cpr_get_answer_is_yes("revoked_key.override",
- _("Use this key anyway? ")) )
- return 0;
- trustmask |= TRUST_FLAG_SUB_REVOKED;
- }
- *trustlevel &= ~trustmask;
-
- if( opt.always_trust) {
- if( opt.verbose )
- log_info("No trust check due to --always-trust option\n");
- return 1;
- }
-
- switch( (*trustlevel & TRUST_MASK) ) {
- case TRUST_EXPIRED:
- log_info(_("%08lX: key has expired\n"),
- (ulong)keyid_from_pk( pk, NULL) );
- return 0; /* no */
-
- default:
- log_error ("invalid trustlevel %u returned from validation layer\n",
- *trustlevel);
- /* fall thru */
- case TRUST_UNKNOWN:
- case TRUST_UNDEFINED:
- log_info(_("%08lX: There is no indication that this key "
- "really belongs to the owner\n"),
- (ulong)keyid_from_pk( pk, NULL) );
- return 0; /* no */
-
- case TRUST_NEVER:
- log_info(_("%08lX: We do NOT trust this key\n"),
- (ulong)keyid_from_pk( pk, NULL) );
- return 0; /* no */
-
- case TRUST_MARGINAL:
- log_info(
- _("%08lX: It is not sure that this key really belongs to the owner\n"
- "but it is accepted anyway\n"), (ulong)keyid_from_pk( pk, NULL) );
- return 1; /* yes */
-
- case TRUST_FULLY:
- if( opt.verbose )
- log_info(_("This key probably belongs to the owner\n"));
- return 1; /* yes */
-
- case TRUST_ULTIMATE:
- if( opt.verbose )
- log_info(_("This key belongs to us\n"));
- return 1; /* yes */
- }
-
- return 1; /* yes */
-}
-
-
-
-/****************
- * wrapper around do_we_trust, so we can ask whether to use the
- * key anyway.
- */
-static int
-do_we_trust_pre( PKT_public_key *pk, unsigned int trustlevel )
-{
- int rc;
-
- rc = do_we_trust( pk, &trustlevel );
-
- if( (trustlevel & TRUST_FLAG_REVOKED) && !rc )
- return 0;
- if( (trustlevel & TRUST_FLAG_SUB_REVOKED) && !rc )
- return 0;
-
- if( !opt.batch && !rc ) {
- char *p;
- u32 keyid[2];
- size_t n;
-
- keyid_from_pk( pk, keyid);
- tty_printf( "%4u%c/%08lX %s \"",
- nbits_from_pk( pk ), pubkey_letter( pk->pubkey_algo ),
- (ulong)keyid[1], datestr_from_pk( pk ) );
- p = get_user_id( keyid, &n );
- tty_print_utf8_string( p, n ),
- m_free(p);
- tty_printf("\"\n");
- print_fingerprint (pk, NULL, 2);
- tty_printf("\n");
-
- tty_printf(_(
-"It is NOT certain that the key belongs to the person named\n"
-"in the user ID. If you *really* know what you are doing,\n"
-"you may answer the next question with yes\n\n"));
-
- if( cpr_get_answer_is_yes("untrusted_key.override",
- _("Use this key anyway? ")) )
- rc = 1;
-
- /* Hmmm: Should we set a flag to tell the user about
- * his decision the next time he encrypts for this recipient?
- */
- }
- else if( opt.always_trust && !rc ) {
- if( !opt.quiet )
- log_info(_("WARNING: Using untrusted key!\n"));
- rc = 1;
- }
- return rc;
-}
-
-
-
-/****************
- * Check whether we can trust this signature.
- * Returns: Error if we shall not trust this signatures.
- */
-int
-check_signatures_trust( PKT_signature *sig )
-{
- PKT_public_key *pk = m_alloc_clear( sizeof *pk );
- unsigned int trustlevel;
- int rc=0;
-
- if ( opt.always_trust)
- {
- if( !opt.quiet )
- log_info(_("WARNING: Using untrusted key!\n"));
- if (opt.with_fingerprint)
- print_fingerprint (pk, NULL, 1);
- goto leave;
- }
-
- rc = get_pubkey( pk, sig->keyid );
- if (rc)
- { /* this should not happen */
- log_error("Ooops; the key vanished - can't check the trust\n");
- rc = G10ERR_NO_PUBKEY;
- goto leave;
- }
-
- trustlevel = get_validity (pk, NULL);
-
- if ( (trustlevel & TRUST_FLAG_REVOKED) )
- {
- write_status( STATUS_KEYREVOKED );
- log_info(_("WARNING: This key has been revoked by its owner!\n"));
- log_info(_(" This could mean that the signature is forgery.\n"));
- show_revocation_reason( pk, 0 );
- }
- else if ((trustlevel & TRUST_FLAG_SUB_REVOKED) )
- {
- write_status( STATUS_KEYREVOKED );
- log_info(_("WARNING: This subkey has been revoked by its owner!\n"));
- show_revocation_reason( pk, 0 );
- }
-
- if ((trustlevel & TRUST_FLAG_DISABLED))
- log_info (_("Note: This key has been disabled.\n"));
-
- switch ( (trustlevel & TRUST_MASK) )
- {
- case TRUST_EXPIRED:
- log_info(_("Note: This key has expired!\n"));
- print_fingerprint (pk, NULL, 1);
- break;
-
- default:
- log_error ("invalid trustlevel %u returned from validation layer\n",
- trustlevel);
- /* fall thru */
- case TRUST_UNKNOWN:
- case TRUST_UNDEFINED:
- write_status( STATUS_TRUST_UNDEFINED );
- log_info(_("WARNING: This key is not certified with"
- " a trusted signature!\n"));
- log_info(_(" There is no indication that the "
- "signature belongs to the owner.\n" ));
- print_fingerprint (pk, NULL, 1);
- break;
-
- case TRUST_NEVER:
- /* currently we won't get that status */
- write_status( STATUS_TRUST_NEVER );
- log_info(_("WARNING: We do NOT trust this key!\n"));
- log_info(_(" The signature is probably a FORGERY.\n"));
- if (opt.with_fingerprint)
- print_fingerprint (pk, NULL, 1);
- rc = G10ERR_BAD_SIGN;
- break;
-
- case TRUST_MARGINAL:
- write_status( STATUS_TRUST_MARGINAL );
- log_info(_("WARNING: This key is not certified with"
- " sufficiently trusted signatures!\n"));
- log_info(_(" It is not certain that the"
- " signature belongs to the owner.\n" ));
- print_fingerprint (pk, NULL, 1);
- break;
-
- case TRUST_FULLY:
- write_status( STATUS_TRUST_FULLY );
- if (opt.with_fingerprint)
- print_fingerprint (pk, NULL, 1);
- break;
-
- case TRUST_ULTIMATE:
- write_status( STATUS_TRUST_ULTIMATE );
- if (opt.with_fingerprint)
- print_fingerprint (pk, NULL, 1);
- break;
- }
-
- leave:
- free_public_key( pk );
- return rc;
-}
-
-
-void
-release_pk_list( PK_LIST pk_list )
-{
- PK_LIST pk_rover;
-
- for( ; pk_list; pk_list = pk_rover ) {
- pk_rover = pk_list->next;
- free_public_key( pk_list->pk );
- m_free( pk_list );
- }
-}
-
-
-static int
-key_present_in_pk_list(PK_LIST pk_list, PKT_public_key *pk)
-{
- for( ; pk_list; pk_list = pk_list->next)
- if (cmp_public_keys(pk_list->pk, pk) == 0)
- return 0;
-
- return -1;
-}
-
-
-/****************
- * Return a malloced string with a default reciepient if there is any
- */
-static char *
-default_recipient(void)
-{
- PKT_secret_key *sk;
- byte fpr[MAX_FINGERPRINT_LEN+1];
- size_t n;
- char *p;
- int i;
-
- if( opt.def_recipient )
- return m_strdup( opt.def_recipient );
- if( !opt.def_recipient_self )
- return NULL;
- sk = m_alloc_clear( sizeof *sk );
- i = get_seckey_byname( sk, NULL, 0 );
- if( i ) {
- free_secret_key( sk );
- return NULL;
- }
- n = MAX_FINGERPRINT_LEN;
- fingerprint_from_sk( sk, fpr, &n );
- free_secret_key( sk );
- p = m_alloc( 2*n+3 );
- *p++ = '0';
- *p++ = 'x';
- for(i=0; i < n; i++ )
- sprintf( p+2*i, "%02X", fpr[i] );
- p -= 2;
- return p;
-}
-
-static int
-expand_id(const char *id,STRLIST *into,unsigned int flags)
-{
- struct groupitem *groups;
- int count=0;
-
- for(groups=opt.grouplist;groups;groups=groups->next)
- {
- /* need strcasecmp() here, as this should be localized */
- if(strcasecmp(groups->name,id)==0)
- {
- STRLIST each,sl;
-
- /* this maintains the current utf8-ness */
- for(each=groups->values;each;each=each->next)
- {
- sl=add_to_strlist(into,each->d);
- sl->flags=flags;
- count++;
- }
-
- break;
- }
- }
-
- return count;
-}
-
-/* For simplicity, and to avoid potential loops, we only expand once -
- you can't make an alias that points to an alias. */
-static STRLIST
-expand_group(STRLIST input)
-{
- STRLIST sl,output=NULL,rover;
-
- for(rover=input;rover;rover=rover->next)
- if(expand_id(rover->d,&output,rover->flags)==0)
- {
- /* Didn't find any groups, so use the existing string */
- sl=add_to_strlist(&output,rover->d);
- sl->flags=rover->flags;
- }
-
- return output;
-}
-
-int
-build_pk_list( STRLIST rcpts, PK_LIST *ret_pk_list, unsigned use )
-{
- PK_LIST pk_list = NULL;
- PKT_public_key *pk=NULL;
- int rc=0;
- int any_recipients=0;
- STRLIST rov,remusr;
- char *def_rec = NULL;
-
- if(opt.grouplist)
- remusr=expand_group(rcpts);
- else
- remusr=rcpts;
-
- /* check whether there are any recipients in the list and build the
- * list of the encrypt-to ones (we always trust them) */
- for( rov = remusr; rov; rov = rov->next ) {
- if( !(rov->flags & 1) )
- any_recipients = 1;
- else if( (use & PUBKEY_USAGE_ENC) && !opt.no_encrypt_to ) {
- pk = m_alloc_clear( sizeof *pk );
- pk->req_usage = use;
- if( (rc = get_pubkey_byname( pk, rov->d, NULL, NULL )) ) {
- free_public_key( pk ); pk = NULL;
- log_error(_("%s: skipped: %s\n"), rov->d, g10_errstr(rc) );
- write_status_text_and_buffer (STATUS_INV_RECP, "0 ",
- rov->d, strlen (rov->d), -1);
- goto fail;
- }
- else if( !(rc=check_pubkey_algo2(pk->pubkey_algo, use )) ) {
- /* Skip the actual key if the key is already present
- * in the list */
- if (key_present_in_pk_list(pk_list, pk) == 0) {
- free_public_key(pk); pk = NULL;
- log_info(_("%s: skipped: public key already present\n"),
- rov->d);
- }
- else {
- PK_LIST r;
- r = m_alloc( sizeof *r );
- r->pk = pk; pk = NULL;
- r->next = pk_list;
- r->mark = 0;
- pk_list = r;
- }
- }
- else {
- free_public_key( pk ); pk = NULL;
- log_error(_("%s: skipped: %s\n"), rov->d, g10_errstr(rc) );
- write_status_text_and_buffer (STATUS_INV_RECP, "0 ",
- rov->d, strlen (rov->d), -1);
- goto fail;
- }
- }
- }
-
- if( !any_recipients && !opt.batch ) { /* ask */
- int have_def_rec;
- char *answer=NULL;
- STRLIST backlog=NULL;
-
- def_rec = default_recipient();
- have_def_rec = !!def_rec;
- if( !have_def_rec )
- tty_printf(_(
- "You did not specify a user ID. (you may use \"-r\")\n"));
- for(;;) {
- rc = 0;
- m_free(answer);
- if( have_def_rec ) {
- answer = def_rec;
- def_rec = NULL;
- }
- else if(backlog) {
- answer=pop_strlist(&backlog);
- }
- else {
- answer = cpr_get_utf8("pklist.user_id.enter",
- _("\nEnter the user ID. End with an empty line: "));
- trim_spaces(answer);
- cpr_kill_prompt();
- }
- if( !answer || !*answer ) {
- m_free(answer);
- break;
- }
- if(expand_id(answer,&backlog,0))
- continue;
- if( pk )
- free_public_key( pk );
- pk = m_alloc_clear( sizeof *pk );
- pk->req_usage = use;
- rc = get_pubkey_byname( pk, answer, NULL, NULL );
- if( rc )
- tty_printf(_("No such user ID.\n"));
- else if( !(rc=check_pubkey_algo2(pk->pubkey_algo, use)) ) {
- if( have_def_rec ) {
- if (key_present_in_pk_list(pk_list, pk) == 0) {
- free_public_key(pk); pk = NULL;
- log_info(_("skipped: public key "
- "already set as default recipient\n") );
- }
- else {
- PK_LIST r = m_alloc( sizeof *r );
- r->pk = pk; pk = NULL;
- r->next = pk_list;
- r->mark = 0;
- pk_list = r;
- }
- any_recipients = 1;
- continue;
- }
- else {
- int trustlevel;
-
- trustlevel = get_validity (pk, NULL);
- if( (trustlevel & TRUST_FLAG_DISABLED) ) {
- tty_printf(_("Public key is disabled.\n") );
- }
- else if( do_we_trust_pre( pk, trustlevel ) ) {
- /* Skip the actual key if the key is already present
- * in the list */
- if (key_present_in_pk_list(pk_list, pk) == 0) {
- free_public_key(pk); pk = NULL;
- log_info(_("skipped: public key already set\n") );
- }
- else {
- PK_LIST r;
- char *p;
- size_t n;
- u32 keyid[2];
-
- keyid_from_pk( pk, keyid);
- tty_printf("Added %4u%c/%08lX %s \"",
- nbits_from_pk( pk ),
- pubkey_letter( pk->pubkey_algo ),
- (ulong)keyid[1],
- datestr_from_pk( pk ) );
- p = get_user_id( keyid, &n );
- tty_print_utf8_string( p, n );
- m_free(p);
- tty_printf("\"\n");
-
- r = m_alloc( sizeof *r );
- r->pk = pk; pk = NULL;
- r->next = pk_list;
- r->mark = 0;
- pk_list = r;
- }
- any_recipients = 1;
- continue;
- }
- }
- }
- m_free(def_rec); def_rec = NULL;
- have_def_rec = 0;
- }
- if( pk ) {
- free_public_key( pk );
- pk = NULL;
- }
- }
- else if( !any_recipients && (def_rec = default_recipient()) ) {
- pk = m_alloc_clear( sizeof *pk );
- pk->req_usage = use;
- rc = get_pubkey_byname( pk, def_rec, NULL, NULL );
- if( rc )
- log_error(_("unknown default recipient `%s'\n"), def_rec );
- else if( !(rc=check_pubkey_algo2(pk->pubkey_algo, use)) ) {
- /* Mark any_recipients here since the default recipient
- would have been used if it wasn't already there. It
- doesn't really matter if we got this key from the default
- recipient or an encrypt-to. */
- any_recipients = 1;
- if (key_present_in_pk_list(pk_list, pk) == 0)
- log_info(_("skipped: public key already set as default recipient\n"));
- else {
- PK_LIST r = m_alloc( sizeof *r );
- r->pk = pk; pk = NULL;
- r->next = pk_list;
- r->mark = 0;
- pk_list = r;
- }
- }
- if( pk ) {
- free_public_key( pk );
- pk = NULL;
- }
- m_free(def_rec); def_rec = NULL;
- }
- else {
- any_recipients = 0;
- for(; remusr; remusr = remusr->next ) {
- if( (remusr->flags & 1) )
- continue; /* encrypt-to keys are already handled */
-
- pk = m_alloc_clear( sizeof *pk );
- pk->req_usage = use;
- if( (rc = get_pubkey_byname( pk, remusr->d, NULL, NULL )) ) {
- free_public_key( pk ); pk = NULL;
- log_error(_("%s: skipped: %s\n"), remusr->d, g10_errstr(rc) );
- write_status_text_and_buffer (STATUS_INV_RECP, "0 ",
- remusr->d, strlen (remusr->d),
- -1);
- goto fail;
- }
- else if( !(rc=check_pubkey_algo2(pk->pubkey_algo, use )) ) {
- int trustlevel;
-
- trustlevel = get_validity (pk, pk->namehash);
- if( (trustlevel & TRUST_FLAG_DISABLED) ) {
- free_public_key(pk); pk = NULL;
- log_info(_("%s: skipped: public key is disabled\n"),
- remusr->d);
- write_status_text_and_buffer (STATUS_INV_RECP, "0 ",
- remusr->d,
- strlen (remusr->d),
- -1);
- rc=G10ERR_UNU_PUBKEY;
- goto fail;
- }
- else if( do_we_trust_pre( pk, trustlevel ) ) {
- /* note: do_we_trust may have changed the trustlevel */
-
- /* We have at least one valid recipient. It doesn't matters
- * if this recipient is already present. */
- any_recipients = 1;
-
- /* Skip the actual key if the key is already present
- * in the list */
- if (key_present_in_pk_list(pk_list, pk) == 0) {
- free_public_key(pk); pk = NULL;
- log_info(_("%s: skipped: public key already present\n"),
- remusr->d);
- }
- else {
- PK_LIST r;
- r = m_alloc( sizeof *r );
- r->pk = pk; pk = NULL;
- r->next = pk_list;
- r->mark = 0;
- pk_list = r;
- }
- }
- else { /* we don't trust this pk */
- free_public_key( pk ); pk = NULL;
- write_status_text_and_buffer (STATUS_INV_RECP, "10 ",
- remusr->d,
- strlen (remusr->d),
- -1);
- rc=G10ERR_UNU_PUBKEY;
- goto fail;
- }
- }
- else {
- free_public_key( pk ); pk = NULL;
- write_status_text_and_buffer (STATUS_INV_RECP, "0 ",
- remusr->d,
- strlen (remusr->d),
- -1);
- log_error(_("%s: skipped: %s\n"), remusr->d, g10_errstr(rc) );
- goto fail;
- }
- }
- }
-
- if( !rc && !any_recipients ) {
- log_error(_("no valid addressees\n"));
- write_status_text (STATUS_NO_RECP, "0");
- rc = G10ERR_NO_USER_ID;
- }
-
- fail:
-
- if( rc )
- release_pk_list( pk_list );
- else
- *ret_pk_list = pk_list;
- if(opt.grouplist)
- free_strlist(remusr);
- return rc;
-}
-
-
-/* In pgp6 mode, disallow all ciphers except IDEA (1), 3DES (2), and
- CAST5 (3), all hashes except MD5 (1), SHA1 (2), and RIPEMD160 (3),
- and all compressions except none (0) and ZIP (1). pgp7 mode
- expands the cipher list to include AES128 (7), AES192 (8), AES256
- (9), and TWOFISH (10). For a true PGP key all of this is unneeded
- as they are the only items present in the preferences subpacket,
- but checking here covers the weird case of encrypting to a key that
- had preferences from a different implementation which was then used
- with PGP. I am not completely comfortable with this as the right
- thing to do, as it slightly alters the list of what the user is
- supposedly requesting. It is not against the RFC however, as the
- preference chosen will never be one that the user didn't specify
- somewhere ("The implementation may use any mechanism to pick an
- algorithm in the intersection"), and PGP has no mechanism to fix
- such a broken preference list, so I'm including it. -dms */
-
-static int
-algo_available( int preftype, int algo, void *hint )
-{
- if( preftype == PREFTYPE_SYM ) {
- if( opt.pgp6 && ( algo != 1 && algo != 2 && algo != 3) )
- return 0;
-
- if( opt.pgp7 && (algo != 1 && algo != 2 && algo != 3 &&
- algo != 7 && algo != 8 && algo != 9 && algo != 10) )
- return 0;
-
- return algo && !check_cipher_algo( algo );
- }
- else if( preftype == PREFTYPE_HASH ) {
- int bits=0;
-
- if(hint)
- bits=*(int *)hint;
-
- if(bits && (bits != md_digest_length(algo)))
- return 0;
-
- if( (opt.pgp6 || opt.pgp7 ) && ( algo != 1 && algo != 2 && algo != 3) )
- return 0;
-
- return algo && !check_digest_algo( algo );
- }
- else if( preftype == PREFTYPE_ZIP ) {
- if ( ( opt.pgp6 || opt.pgp7 ) && ( algo !=0 && algo != 1) )
- return 0;
-
- return !check_compress_algo( algo );
- }
- else
- return 0;
-}
-
-
-
-/****************
- * Return -1 if we could not find an algorithm.
- */
-int
-select_algo_from_prefs(PK_LIST pk_list, int preftype, int request, void *hint)
-{
- PK_LIST pkr;
- u32 bits[8];
- const prefitem_t *prefs;
- int i, j;
- int compr_hack=0;
- int any;
-
- if( !pk_list )
- return -1;
-
- memset( bits, ~0, 8 * sizeof *bits );
- for( pkr = pk_list; pkr; pkr = pkr->next ) {
- u32 mask[8];
-
- memset( mask, 0, 8 * sizeof *mask );
- if( preftype == PREFTYPE_SYM ) {
- if( opt.pgp2 &&
- pkr->pk->version < 4 &&
- pkr->pk->selfsigversion < 4 )
- mask[0] |= (1<<1); /* IDEA is implicitly there for v3 keys
- with v3 selfsigs (rfc2440:12.1) if
- --pgp2 mode is on. This doesn't
- mean it's actually available, of
- course. */
- else
- mask[0] |= (1<<2); /* 3DES is implicitly there for everyone else */
- }
- else if( preftype == PREFTYPE_HASH ) {
- /* While I am including this code for completeness, note
- that currently --pgp2 mode locks the hash at MD5, so this
- function will never even be called. Even if the hash
- wasn't locked at MD5, we don't support sign+encrypt in
- --pgp2 mode, and that's the only time PREFTYPE_HASH is
- used anyway. -dms */
- if( opt.pgp2 &&
- pkr->pk->version < 4 &&
- pkr->pk->selfsigversion < 4 )
- mask[0] |= (1<<1); /* MD5 is there for v3 keys with v3
- selfsigs when --pgp2 is on. */
- else
- mask[0] |= (1<<2); /* SHA1 is there for everyone else */
- }
- else if( preftype == PREFTYPE_ZIP )
- mask[0] |= (1<<0); /* Uncompressed is implicit */
-
- if (pkr->pk->user_id) /* selected by user ID */
- prefs = pkr->pk->user_id->prefs;
- else
- prefs = pkr->pk->prefs;
-
- any = 0;
- if( prefs ) {
- for (i=0; prefs[i].type; i++ ) {
- if( prefs[i].type == preftype ) {
- mask[prefs[i].value/32] |= 1 << (prefs[i].value%32);
- any = 1;
- }
- }
- }
-
- if( (!prefs || !any) && preftype == PREFTYPE_ZIP ) {
- mask[0] |= 3; /* asume no_compression and old pgp */
- compr_hack = 1;
- }
-
- #if 0
- log_debug("pref mask=%08lX%08lX%08lX%08lX%08lX%08lX%08lX%08lX\n",
- (ulong)mask[7], (ulong)mask[6], (ulong)mask[5], (ulong)mask[4],
- (ulong)mask[3], (ulong)mask[2], (ulong)mask[1], (ulong)mask[0]);
- #endif
- for(i=0; i < 8; i++ )
- bits[i] &= mask[i];
- #if 0
- log_debug("pref bits=%08lX%08lX%08lX%08lX%08lX%08lX%08lX%08lX\n",
- (ulong)bits[7], (ulong)bits[6], (ulong)bits[5], (ulong)bits[4],
- (ulong)bits[3], (ulong)bits[2], (ulong)bits[1], (ulong)bits[0]);
- #endif
- }
- /* usable algorithms are now in bits
- * We now use the last key from pk_list to select
- * the algorithm we want to use. there are no
- * preferences for the last key, we select the one
- * corresponding to first set bit.
- */
- i = -1;
- any = 0;
-
- /* Can we use the requested algorithm? */
- if(request>-1 && (bits[request/32] & (1<<(request%32))) &&
- algo_available(preftype,request,hint))
- return request;
-
- /* If we have personal prefs set, use them instead of the last key */
- if(preftype==PREFTYPE_SYM && opt.personal_cipher_prefs)
- prefs=opt.personal_cipher_prefs;
- else if(preftype==PREFTYPE_HASH && opt.personal_digest_prefs)
- prefs=opt.personal_digest_prefs;
- else if(preftype==PREFTYPE_ZIP && opt.personal_compress_prefs)
- prefs=opt.personal_compress_prefs;
-
- if( prefs ) {
- for(j=0; prefs[j].type; j++ ) {
- if( prefs[j].type == preftype ) {
- if( (bits[prefs[j].value/32] & (1<<(prefs[j].value%32))) ) {
- if( algo_available( preftype, prefs[j].value, hint ) ) {
- any = 1;
- i = prefs[j].value;
- break;
- }
- }
- }
- }
- }
- if( !prefs || !any ) {
- for(j=0; j < 256; j++ )
- if( (bits[j/32] & (1<<(j%32))) ) {
- if( algo_available( preftype, j, hint ) ) {
- i = j;
- break;
- }
- }
- }
-
- #if 0
- log_debug("prefs of type %d: selected %d\n", preftype, i );
- #endif
- if( compr_hack && !i ) {
- /* selected no compression, but we should check whether
- * algorithm 1 is also available (the ordering is not relevant
- * in this case). */
- if( bits[0] & (1<<1) )
- i = 1; /* yep; we can use compression algo 1 */
- }
-
- /* "If you are building an authentication system, the recipient
- may specify a preferred signing algorithm. However, the signer
- would be foolish to use a weak algorithm simply because the
- recipient requests it." RFC2440:13. If we settle on MD5, and
- SHA1 is also available, use SHA1 instead. Of course, if the
- user intentinally chose MD5 (by putting it in their personal
- prefs), then we should do what they say. */
-
- if(preftype==PREFTYPE_HASH &&
- i==DIGEST_ALGO_MD5 && (bits[0] & (1<<DIGEST_ALGO_SHA1)))
- {
- i=DIGEST_ALGO_SHA1;
-
- if(opt.personal_digest_prefs)
- for(j=0; prefs[j].type; j++ )
- if(opt.personal_digest_prefs[j].type==PREFTYPE_HASH &&
- opt.personal_digest_prefs[j].value==DIGEST_ALGO_MD5)
- {
- i=DIGEST_ALGO_MD5;
- break;
- }
- }
-
- return i;
-}
-
-/*
- * Select the MDC flag from the pk_list. We can only use MDC if all recipients
- * support this feature
- */
-int
-select_mdc_from_pklist (PK_LIST pk_list)
-{
- PK_LIST pkr;
-
- if( !pk_list )
- return 0;
-
- for (pkr = pk_list; pkr; pkr = pkr->next) {
- int mdc;
-
- if (pkr->pk->user_id) /* selected by user ID */
- mdc = pkr->pk->user_id->mdc_feature;
- else
- mdc = pkr->pk->mdc_feature;
- if (!mdc)
- return 0; /* at least one recipient does not support it */
- }
- return 1; /* can be used */
-}