diff options
Diffstat (limited to 'g10/pkclist.c')
-rw-r--r-- | g10/pkclist.c | 1100 |
1 files changed, 599 insertions, 501 deletions
diff --git a/g10/pkclist.c b/g10/pkclist.c index 1170c4088..671b56879 100644 --- a/g10/pkclist.c +++ b/g10/pkclist.c @@ -1,5 +1,5 @@ /* pkclist.c - * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -25,77 +25,21 @@ #include <errno.h> #include <assert.h> -#include <gcrypt.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 "i18n.h" -#include "main.h" #define CONTROL_D ('D' - 'A' + 1) -/* fixme: we have nearly the same code in keyedit.c */ -static void -print_fpr( PKT_public_key *pk ) -{ - byte array[MAX_FINGERPRINT_LEN], *p; - size_t i, n; - - fingerprint_from_pk( pk, array, &n ); - p = array; - /* Translators: this shoud fit into 24 bytes to that the fingerprint - * data is properly aligned with the user ID */ - tty_printf(_(" Fingerprint:")); - if( n == 20 ) { - for(i=0; i < n ; i++, i++, p += 2 ) { - if( i == 10 ) - tty_printf(" "); - tty_printf(" %02X%02X", *p, p[1] ); - } - } - else { - for(i=0; i < n ; i++, p++ ) { - if( i && !(i%8) ) - tty_printf(" "); - tty_printf(" %02X", *p ); - } - } - tty_printf("\n"); -} - -static void -fpr_info( PKT_public_key *pk ) -{ - byte array[MAX_FINGERPRINT_LEN], *p; - size_t i, n; - FILE *fp = log_stream(); - - fingerprint_from_pk( pk, array, &n ); - p = array; - log_info(_("Fingerprint:")); - if( n == 20 ) { - for(i=0; i < n ; i++, i++, p += 2 ) { - if( i == 10 ) - putc(' ', fp); - fprintf(fp, " %02X%02X", *p, p[1] ); - } - } - else { - for(i=0; i < n ; i++, p++ ) { - if( i && !(i%8) ) - putc(' ', fp); - fprintf(fp, " %02X", *p ); - } - } - putc('\n', fp ); -} - /**************** * Show the revocation reason as it is stored with the given signature @@ -108,15 +52,15 @@ do_show_revocation_reason( PKT_signature *sig ) int seq = 0; const char *text; - while( (p = enum_sig_subpkt( sig->hashed_data, SIGSUBPKT_REVOC_REASON, - &n, &seq )) ) { + 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 superseeded"); + text = _("Key is superseded"); else if( *p == 0x02 ) text = _("Key has been compromised"); else if( *p == 0x03 ) @@ -126,7 +70,7 @@ do_show_revocation_reason( PKT_signature *sig ) else text = NULL; - log_info( _("Reason for revocation: ") ); + log_info( _("reason for revocation: ") ); if( text ) fputs( text, log_stream() ); else @@ -143,7 +87,7 @@ do_show_revocation_reason( PKT_signature *sig ) if( n ) { pp = memchr( p, '\n', n ); nn = pp? pp - p : n; - log_info( _("Revocation comment: ") ); + log_info( _("revocation comment: ") ); print_string( log_stream(), p, nn, 0 ); putc( '\n', log_stream() ); p += nn; n -= nn; @@ -152,18 +96,20 @@ do_show_revocation_reason( PKT_signature *sig ) } } +/* 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 */ -static void -show_revocation_reason( PKT_public_key *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 toldus, taht we have a revoked key, we could - * simplylook 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. - */ + * 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; @@ -178,9 +124,10 @@ show_revocation_reason( PKT_public_key *pk ) } for( node=keyblock; node; node = node->next ) { - if( ( node->pkt->pkttype == PKT_PUBLIC_KEY + 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 ) ) + && !cmp_public_keys( node->pkt->pkt.public_key, pk ) ) ) break; } if( !node ) { @@ -197,16 +144,23 @@ show_revocation_reason( PKT_public_key *pk ) || 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( ulong lid, int only_first ) +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; @@ -224,16 +178,17 @@ show_paths( ulong lid, int only_first ) 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 = gcry_xcalloc( 1, sizeof *pk ); + 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], gpg_errstr(rc) ); + (ulong)keyid[1], g10_errstr(rc) ); return; } @@ -257,11 +212,12 @@ show_paths( ulong lid, int only_first ) p = get_user_id( keyid, &n ); tty_print_utf8_string( p, n ), - gcry_free(p); + m_free(p); tty_printf("\"\n"); free_public_key( pk ); } enum_cert_paths( &context, NULL, NULL, NULL ); /* release context */ +#endif tty_printf("\n"); } @@ -269,207 +225,192 @@ show_paths( ulong lid, int only_first ) /**************** - * Returns true if an ownertrust has changed. + * 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( ulong lid, int mode, unsigned *new_trust, int defer_help ) +do_edit_ownertrust (PKT_public_key *pk, int mode, + unsigned *new_trust, int defer_help ) { - char *p; - int rc; - size_t n; - u32 keyid[2]; - PKT_public_key *pk ; - int changed=0; - int quit=0; - int show=0; - int did_help=defer_help; - - rc = keyid_from_lid( lid, keyid ); - if( rc ) { - log_error("ooops: can't get keyid for lid %lu\n", lid); - return 0; - } - - pk = gcry_xcalloc( 1, sizeof *pk ); - rc = get_pubkey( pk, keyid ); - if( rc ) { - log_error("key %08lX: public key not found: %s\n", - (ulong)keyid[1], gpg_errstr(rc) ); - return 0; - } - - - for(;;) { - /* a string with valid answers */ - const char *ans = _("sSmMqQ"); - - if( !did_help ) { - if( !mode ) { - tty_printf(_("No trust value assigned to %lu:\n" - "%4u%c/%08lX %s \""), lid, - 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 ), - gcry_free(p); - tty_printf("\"\n"); - print_fpr( pk ); - 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" -" 1 = Don't know\n" -" 2 = I do NOT trust\n" -" 3 = I trust marginally\n" -" 4 = I trust fully\n" -" s = please show me more information\n") ); - if( mode ) - tty_printf(_(" m = back to the main menu\n")); - else - tty_printf(_(" q = quit\n")); - tty_printf("\n"); - did_help = 1; - } - if( strlen(ans) != 6 ) - 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 <= '4') ) { - unsigned 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; - default: BUG(); - } - *new_trust = trust; - changed = 1; - break; - } - else if( *p == ans[0] || *p == ans[1] ) { - tty_printf(_( - "Certificates leading to an ultimately trusted key:\n")); - show = 1; - break; - } - else if( mode && (*p == ans[2] || *p == ans[3] || *p == CONTROL_D ) ) { - break ; /* back to the menu */ - } - else if( !mode && (*p == ans[4] || *p == ans[5] ) ) { - quit = 1; - break ; /* back to the menu */ - } - gcry_free(p); p = NULL; - } - gcry_free(p); - gcry_free(pk); - return show? -2: quit? -1 : changed; + 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 ) + { + 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"); + 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); + tty_printf (_(" i = please show me more information\n") ); + 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; + } + } + else if( *p == ans[0] || *p == ans[1] ) + { + tty_printf(_("Certificates leading to an ultimately trusted key:\n")); + show = 1; + break; + } + 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( ulong lid, int mode ) +edit_ownertrust (PKT_public_key *pk, int mode ) { - unsigned int trust; - int no_help = 0; - - for(;;) { - switch( do_edit_ownertrust( lid, mode, &trust, no_help ) ) { - case -1: - return 0; - case -2: - show_paths( lid, 1 ); - no_help = 1; - break; - case 1: - trust &= ~TRUST_FLAG_DISABLED; - trust |= get_ownertrust( lid ) & TRUST_FLAG_DISABLED; - if( !update_ownertrust( lid, trust ) ) - return 1; - return 0; - default: - return 0; - } + 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; + } } } -static int -add_ownertrust_cb( ulong lid ) -{ - unsigned trust; - int rc = do_edit_ownertrust( lid, 0, &trust, 0 ); - - if( rc == 1 ) - return trust & TRUST_MASK; - return rc > 0? 0 : rc; -} - -/**************** - * Try to add some more owner trusts (interactive) - * This function presents all the signator in a certificate - * chain who have no ownertrust value assigned. - * Returns: -1 if no ownertrust were added. - */ -static int -add_ownertrust( PKT_public_key *pk, int *quit, unsigned *trustlevel ) -{ - int rc; - unsigned flags = 0; - - *quit = 0; - *trustlevel = 0; - tty_printf( -_("Could not find a valid trust path to the key. Let's see whether we\n" - "can assign some missing owner trust values.\n\n")); - - rc = check_trust( pk, trustlevel, NULL, add_ownertrust_cb, &flags ); - - if( !(flags & 1) ) - tty_printf(_("No path leading to one of our keys found.\n\n") ); - else if( !(flags & 2) ) - tty_printf(_("No certificates with undefined trust found.\n\n") ); - else if( !(flags & 4) ) - tty_printf(_("No trust values changed.\n\n") ); - - return (flags & 4)? 0:-1; -} /**************** * Check whether we can trust this pk which has a trustlevel of TRUSTLEVEL - * Returns: true if we trust. Might change the trustlevel + * Returns: true if we trust. */ static int -do_we_trust( PKT_public_key *pk, int *trustlevel ) +do_we_trust( PKT_public_key *pk, unsigned int *trustlevel ) { - int rc; - int did_add = 0; - int trustmask = 0; - - retry: + 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 ); + show_revocation_reason( pk, 0 ); if( opt.batch ) - return 0; + return 0; /* no */ if( !cpr_get_answer_is_yes("revoked_key.override", _("Use this key anyway? ")) ) - return 0; + return 0; /* no */ trustmask |= TRUST_FLAG_REVOKED; } - else if( (*trustlevel & TRUST_FLAG_SUB_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 ); + show_revocation_reason( pk, 0 ); if( opt.batch ) return 0; @@ -483,52 +424,25 @@ do_we_trust( PKT_public_key *pk, int *trustlevel ) if( opt.always_trust) { if( opt.verbose ) log_info("No trust check due to --always-trust option\n"); - /* The problem with this, is that EXPIRE can't be checked as - * this needs to insert a ne key into the trustdb first and - * we don't want that */ return 1; } - switch( (*trustlevel & TRUST_MASK) ) { - case TRUST_UNKNOWN: /* No pubkey in trustDB: Insert and check again */ - rc = insert_trust_record_by_pk( pk ); - if( rc ) { - log_error("failed to insert it into the trustdb: %s\n", - gpg_errstr(rc) ); - return 0; /* no */ - } - rc = check_trust( pk, trustlevel, NULL, NULL, NULL ); - *trustlevel &= ~trustmask; - if( rc ) - log_fatal("trust check after insert failed: %s\n", - gpg_errstr(rc) ); - if( *trustlevel == TRUST_UNKNOWN || *trustlevel == TRUST_EXPIRED ) { - log_debug("do_we_trust: oops at %d\n", __LINE__ ); - return 0; - } - return do_we_trust( pk, trustlevel ); - 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: - if( opt.batch || opt.answer_no ) - log_info(_("%08lX: no info to calculate a trust probability\n"), - (ulong)keyid_from_pk( pk, NULL) ); - else { - int quit; - - rc = add_ownertrust( pk, &quit, trustlevel ); - *trustlevel &= ~trustmask; - if( !rc && !did_add && !quit ) { - did_add = 1; - goto retry; - } - } - return 0; + 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"), @@ -550,8 +464,6 @@ do_we_trust( PKT_public_key *pk, int *trustlevel ) if( opt.verbose ) log_info(_("This key belongs to us\n")); return 1; /* yes */ - - default: BUG(); } return 1; /* yes */ @@ -564,7 +476,7 @@ do_we_trust( PKT_public_key *pk, int *trustlevel ) * key anyway. */ static int -do_we_trust_pre( PKT_public_key *pk, int trustlevel ) +do_we_trust_pre( PKT_public_key *pk, unsigned int trustlevel ) { int rc; @@ -574,7 +486,8 @@ do_we_trust_pre( PKT_public_key *pk, int trustlevel ) return 0; if( (trustlevel & TRUST_FLAG_SUB_REVOKED) && !rc ) return 0; - else if( !opt.batch && !rc ) { + + if( !opt.batch && !rc ) { char *p; u32 keyid[2]; size_t n; @@ -585,9 +498,9 @@ do_we_trust_pre( PKT_public_key *pk, int trustlevel ) (ulong)keyid[1], datestr_from_pk( pk ) ); p = get_user_id( keyid, &n ); tty_print_utf8_string( p, n ), - gcry_free(p); + m_free(p); tty_printf("\"\n"); - print_fpr( pk ); + print_fingerprint (pk, NULL, 2); tty_printf("\n"); tty_printf(_( @@ -599,7 +512,7 @@ do_we_trust_pre( PKT_public_key *pk, int trustlevel ) _("Use this key anyway? ")) ) rc = 1; - /* Hmmm: Should we set a flag to tell the user the user about + /* Hmmm: Should we set a flag to tell the user about * his decision the next time he encrypts for this recipient? */ } @@ -620,121 +533,102 @@ do_we_trust_pre( PKT_public_key *pk, int trustlevel ) int check_signatures_trust( PKT_signature *sig ) { - PKT_public_key *pk = gcry_xcalloc( 1, sizeof *pk ); - int trustlevel; - int did_add = 0; - int rc=0; - - - if( opt.always_trust ) { - if( !opt.quiet ) - log_info(_("WARNING: Using untrusted key!\n")); - return 0; + 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 = GPGERR_NO_PUBKEY; - 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; } - rc = check_trust( pk, &trustlevel, NULL, NULL, NULL ); - if( rc ) { - log_error("check trust failed: %s\n", gpg_errstr(rc)); - goto leave; - } + trustlevel = get_validity (pk, NULL); - retry: - 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 ); + 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 ); + 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 ); } - - - switch( (trustlevel & TRUST_MASK) ) { - case TRUST_UNKNOWN: /* No pubkey in trustDB: Insert and check again */ - rc = insert_trust_record_by_pk( pk ); - if( rc ) { - log_error("failed to insert it into the trustdb: %s\n", - gpg_errstr(rc) ); - goto leave; - } - rc = check_trust( pk, &trustlevel, NULL, NULL, NULL ); - if( rc ) - log_fatal("trust check after insert failed: %s\n", - gpg_errstr(rc) ); - if( trustlevel == TRUST_UNKNOWN || trustlevel == TRUST_EXPIRED ) - BUG(); - goto retry; - - case TRUST_EXPIRED: - log_info(_("Note: This key has expired!\n")); - fpr_info( pk ); - break; - - case TRUST_UNDEFINED: - if( did_add || opt.batch || opt.answer_no ) { - 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" )); - fpr_info( pk ); - } - else { - int quit; - rc = add_ownertrust( pk, &quit, &trustlevel ); - if( rc || quit ) { - did_add = 1; - rc = 0; - } - goto retry; - } - break; - - case TRUST_NEVER: - write_status( STATUS_TRUST_NEVER ); - log_info(_("WARNING: We do NOT trust this key!\n")); - log_info(_(" The signature is probably a FORGERY.\n")); - rc = GPGERR_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" - )); - fpr_info( pk ); - break; - - case TRUST_FULLY: - write_status( STATUS_TRUST_FULLY ); - break; - - case TRUST_ULTIMATE: - write_status( STATUS_TRUST_ULTIMATE ); - break; - - default: BUG(); + + 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; + leave: + free_public_key( pk ); + return rc; } @@ -746,7 +640,7 @@ release_pk_list( PK_LIST pk_list ) for( ; pk_list; pk_list = pk_rover ) { pk_rover = pk_list->next; free_public_key( pk_list->pk ); - gcry_free( pk_list ); + m_free( pk_list ); } } @@ -775,11 +669,11 @@ default_recipient(void) int i; if( opt.def_recipient ) - return gcry_xstrdup( opt.def_recipient ); + return m_strdup( opt.def_recipient ); if( !opt.def_recipient_self ) return NULL; - sk = gcry_xcalloc( 1, sizeof *sk ); - i = get_seckey_byname( NULL, sk, NULL, 0, NULL ); + sk = m_alloc_clear( sizeof *sk ); + i = get_seckey_byname( sk, NULL, 0 ); if( i ) { free_secret_key( sk ); return NULL; @@ -787,7 +681,7 @@ default_recipient(void) n = MAX_FINGERPRINT_LEN; fingerprint_from_sk( sk, fpr, &n ); free_secret_key( sk ); - p = gcry_xmalloc( 2*n+3 ); + p = m_alloc( 2*n+3 ); *p++ = '0'; *p++ = 'x'; for(i=0; i < n; i++ ) @@ -796,31 +690,82 @@ default_recipient(void) 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 remusr, PK_LIST *ret_pk_list, unsigned use ) +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; + 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 & GCRY_PK_USAGE_ENCR) && !opt.no_encrypt_to ) { - pk = gcry_xcalloc( 1, sizeof *pk ); + 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( NULL, pk, rov->d, NULL )) ) { + if( (rc = get_pubkey_byname( pk, rov->d, NULL, NULL )) ) { free_public_key( pk ); pk = NULL; - log_error(_("%s: skipped: %s\n"), rov->d, gpg_errstr(rc) ); - } - else if( !(rc=openpgp_pk_test_algo(pk->pubkey_algo, - pk->pubkey_usage)) ) { + 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); + } + 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) { @@ -830,7 +775,7 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use ) } else { PK_LIST r; - r = gcry_xmalloc( sizeof *r ); + r = m_alloc( sizeof *r ); r->pk = pk; pk = NULL; r->next = pk_list; r->mark = 0; @@ -839,44 +784,53 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use ) } else { free_public_key( pk ); pk = NULL; - log_error(_("%s: skipped: %s\n"), rov->d, gpg_errstr(rc) ); + 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); } } } if( !any_recipients && !opt.batch ) { /* ask */ - char *answer=NULL; 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\n")); + "You did not specify a user ID. (you may use \"-r\")\n")); for(;;) { rc = 0; - gcry_free(answer); + 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", - _("Enter the user ID: ")); + _("\nEnter the user ID. End with an empty line: ")); trim_spaces(answer); cpr_kill_prompt(); } - if( !*answer ) + if( !answer || !*answer ) { + m_free(answer); break; + } + if(expand_id(answer,&backlog,0)) + continue; if( pk ) free_public_key( pk ); - pk = gcry_xcalloc( 1, sizeof *pk ); + pk = m_alloc_clear( sizeof *pk ); pk->req_usage = use; - rc = get_pubkey_byname( NULL, pk, answer, NULL ); + rc = get_pubkey_byname( pk, answer, NULL, NULL ); if( rc ) tty_printf(_("No such user ID.\n")); - else if( !(rc=openpgp_pk_test_algo(pk->pubkey_algo, - pk->pubkey_usage)) ) { + 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; @@ -884,25 +838,20 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use ) "already set as default recipient\n") ); } else { - PK_LIST r = gcry_xmalloc( sizeof *r ); + 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; - break; + continue; } else { int trustlevel; - rc = check_trust( pk, &trustlevel, pk->namehash, - NULL, NULL ); - if( rc ) { - log_error("error checking pk of `%s': %s\n", - answer, gpg_errstr(rc) ); - } - else if( (trustlevel & TRUST_FLAG_DISABLED) ) { + 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 ) ) { @@ -910,52 +859,71 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use ) * 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 with --encrypt-to\n") ); + log_info(_("skipped: public key already set\n") ); } else { PK_LIST r; - - r = gcry_xmalloc( sizeof *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; - break; + continue; } } } - gcry_free(def_rec); def_rec = NULL; + m_free(def_rec); def_rec = NULL; have_def_rec = 0; } - gcry_free(answer); if( pk ) { free_public_key( pk ); pk = NULL; } } else if( !any_recipients && (def_rec = default_recipient()) ) { - pk = gcry_xcalloc( 1, sizeof *pk ); + pk = m_alloc_clear( sizeof *pk ); pk->req_usage = use; - rc = get_pubkey_byname( NULL, pk, def_rec, NULL ); + rc = get_pubkey_byname( pk, def_rec, NULL, NULL ); if( rc ) log_error(_("unknown default recipient `%s'\n"), def_rec ); - else if( !(rc=openpgp_pk_test_algo(pk->pubkey_algo, - pk->pubkey_usage)) ) { - PK_LIST r = gcry_xmalloc( sizeof *r ); + 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; - any_recipients = 1; + } } if( pk ) { free_public_key( pk ); pk = NULL; } - gcry_free(def_rec); def_rec = NULL; + m_free(def_rec); def_rec = NULL; } else { any_recipients = 0; @@ -963,26 +931,27 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use ) if( (remusr->flags & 1) ) continue; /* encrypt-to keys are already handled */ - pk = gcry_xcalloc( 1, sizeof *pk ); + pk = m_alloc_clear( sizeof *pk ); pk->req_usage = use; - if( (rc = get_pubkey_byname( NULL, pk, remusr->d, NULL )) ) { + if( (rc = get_pubkey_byname( pk, remusr->d, NULL, NULL )) ) { free_public_key( pk ); pk = NULL; - log_error(_("%s: skipped: %s\n"), remusr->d, gpg_errstr(rc) ); + 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); } - else if( !(rc=openpgp_pk_test_algo(pk->pubkey_algo, - pk->pubkey_usage)) ) { + else if( !(rc=check_pubkey_algo2(pk->pubkey_algo, use )) ) { int trustlevel; - rc = check_trust( pk, &trustlevel, pk->namehash, NULL, NULL ); - if( rc ) { - free_public_key( pk ); pk = NULL; - log_error(_("%s: error checking key: %s\n"), - remusr->d, gpg_errstr(rc) ); - } - else if( (trustlevel & TRUST_FLAG_DISABLED) ) { + 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); } else if( do_we_trust_pre( pk, trustlevel ) ) { /* note: do_we_trust may have changed the trustlevel */ @@ -1000,7 +969,7 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use ) } else { PK_LIST r; - r = gcry_xmalloc( sizeof *r ); + r = m_alloc( sizeof *r ); r->pk = pk; pk = NULL; r->next = pk_list; r->mark = 0; @@ -1009,55 +978,103 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use ) } else { /* we don't trust this pk */ free_public_key( pk ); pk = NULL; + write_status_text_and_buffer (STATUS_INV_RECP, "0 ", + remusr->d, + strlen (remusr->d), + -1); } } else { free_public_key( pk ); pk = NULL; - log_error(_("%s: skipped: %s\n"), remusr->d, gpg_errstr(rc) ); + 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) ); } } } if( !rc && !any_recipients ) { log_error(_("no valid addressees\n")); - rc = GPGERR_NO_USER_ID; + write_status_text (STATUS_NO_RECP, "0"); + rc = G10ERR_NO_USER_ID; } 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 ) +algo_available( int preftype, int algo, void *hint ) { if( preftype == PREFTYPE_SYM ) { - return algo && !openpgp_cipher_test_algo( algo ); + 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 ) { - return algo && !openpgp_md_test_algo( algo ); + 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_COMPR ) { - return !algo || algo == 1 || algo == 2; + 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 ) +select_algo_from_prefs(PK_LIST pk_list, int preftype, int request, void *hint) { PK_LIST pkr; u32 bits[8]; - byte *pref = NULL; - size_t npref; + const prefitem_t *prefs; int i, j; int compr_hack=0; int any; @@ -1070,43 +1087,65 @@ select_algo_from_prefs( PK_LIST pk_list, int preftype ) u32 mask[8]; memset( mask, 0, 8 * sizeof *mask ); - if( !pkr->pk->local_id ) { /* try to set the local id */ - query_trust_info( pkr->pk, NULL ); - if( !pkr->pk->local_id ) { - log_debug("select_algo_from_prefs: can't get LID\n"); - continue; - } + 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 */ } - if( preftype == PREFTYPE_SYM ) - mask[0] |= (1<<2); /* 3DES is implicitly there */ - gcry_free(pref); - pref = get_pref_data( pkr->pk->local_id, pkr->pk->namehash, &npref); + 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( pref ) { - #if 0 - log_hexdump("raw: ", pref, npref ); - #endif - for(i=0; i+1 < npref; i+=2 ) { - if( pref[i] == preftype ) { - mask[pref[i+1]/32] |= 1 << (pref[i+1]%32); + 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( (!pref || !any) && preftype == PREFTYPE_COMPR ) { + + if( (!prefs || !any) && preftype == PREFTYPE_ZIP ) { mask[0] |= 3; /* asume no_compression and old pgp */ compr_hack = 1; } #if 0 - log_debug("mask=%08lX%08lX%08lX%08lX%08lX%08lX%08lX%08lX\n", + 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("bits=%08lX%08lX%08lX%08lX%08lX%08lX%08lX%08lX\n", + 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 @@ -1119,28 +1158,42 @@ select_algo_from_prefs( PK_LIST pk_list, int preftype ) */ i = -1; any = 0; - if( pref ) { - for(j=0; j+1 < npref; j+=2 ) { - if( pref[j] == preftype ) { - if( (bits[pref[j+1]/32] & (1<<(pref[j+1]%32))) ) { - if( algo_available( preftype, pref[j+1] ) ) { + + /* 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 = pref[j+1]; + i = prefs[j].value; break; } } } } } - if( !pref || !any ) { + if( !prefs || !any ) { for(j=0; j < 256; j++ ) if( (bits[j/32] & (1<<(j%32))) ) { - if( algo_available( preftype, j ) ) { + if( algo_available( preftype, j, hint ) ) { i = j; break; } } } + + /* Can we use the requested algorithm? */ + if(request>-1 && request==i) + return i; + #if 0 log_debug("prefs of type %d: selected %d\n", preftype, i ); #endif @@ -1152,8 +1205,53 @@ select_algo_from_prefs( PK_LIST pk_list, int preftype ) i = 1; /* yep; we can use compression algo 1 */ } - gcry_free(pref); + /* "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 */ +} |