/* Return a new DEK object using the string-to-key specifier S2K. Use KEYID and PUBKEY_ALGO to prompt the user. Returns NULL is the user selected to cancel the passphrase entry and if CANCELED is not NULL, sets it to true. MODE 0: Allow cached passphrase 1: Ignore cached passphrase 2: Ditto, but create a new key 3: Allow cached passphrase; use the S2K salt as the cache ID 4: Ditto, but create a new key */ DEK * passphrase_to_dek_ext (u32 *keyid, int pubkey_algo, int cipher_algo, STRING2KEY *s2k, int mode, const char *tryagain_text, const char *custdesc, const char *custprompt, int *canceled) { char *pw = NULL; DEK *dek; STRING2KEY help_s2k; int dummy_canceled; char s2k_cacheidbuf[1+16+1], *s2k_cacheid = NULL; if (!canceled) canceled = &dummy_canceled; *canceled = 0; if ( !s2k ) { log_assert (mode != 3 && mode != 4); /* This is used for the old rfc1991 mode * Note: This must match the code in encode.c with opt.rfc1991 set */ s2k = &help_s2k; s2k->mode = 0; s2k->hash_algo = S2K_DIGEST_ALGO; } /* Create a new salt or what else to be filled into the s2k for a new key. */ if ((mode == 2 || mode == 4) && (s2k->mode == 1 || s2k->mode == 3)) { gcry_randomize (s2k->salt, 8, GCRY_STRONG_RANDOM); if ( s2k->mode == 3 ) { /* We delay the encoding until it is really needed. This is if we are going to dynamically calibrate it, we need to call out to gpg-agent and that should not be done during option processing in main(). */ if (!opt.s2k_count) opt.s2k_count = encode_s2k_iterations (0); s2k->count = opt.s2k_count; } } /* If we do not have a passphrase available in NEXT_PW and status information are request, we print them now. */ if ( !next_pw && is_status_enabled() ) { char buf[50]; if ( keyid ) { emit_status_need_passphrase (keyid, keyid[2] && keyid[3]? keyid+2:NULL, pubkey_algo); } else { snprintf (buf, sizeof buf -1, "%d %d %d", cipher_algo, s2k->mode, s2k->hash_algo ); write_status_text ( STATUS_NEED_PASSPHRASE_SYM, buf ); } } /* If we do have a keyID, we do not have a passphrase available in NEXT_PW, we are not running in batch mode and we do not want to ignore the passphrase cache (mode!=1), print a prompt with information on that key. */ if ( keyid && !opt.batch && !next_pw && mode!=1 ) { PKT_public_key *pk = xmalloc_clear( sizeof *pk ); char *p; p = get_user_id_native(keyid); tty_printf ("\n"); tty_printf (_("You need a passphrase to unlock the secret key for\n" "user: \"%s\"\n"),p); xfree(p); if ( !get_pubkey( pk, keyid ) ) { const char *s = openpgp_pk_algo_name ( pk->pubkey_algo ); tty_printf (_("%u-bit %s key, ID %s, created %s"), nbits_from_pk( pk ), s?s:"?", keystr(keyid), strtimestamp(pk->timestamp) ); if ( keyid[2] && keyid[3] && keyid[0] != keyid[2] && keyid[1] != keyid[3] ) { if ( keystrlen () > 10 ) { tty_printf ("\n"); tty_printf (_(" (subkey on main key ID %s)"), keystr(&keyid[2]) ); } else tty_printf ( _(" (main key ID %s)"), keystr(&keyid[2]) ); } tty_printf("\n"); } tty_printf("\n"); free_public_key (pk); } if ( next_pw ) { /* Simply return the passphrase we already have in NEXT_PW. */ pw = next_pw; next_pw = NULL; } else if ( have_static_passphrase () ) { /* Return the passphrase we have stored in FD_PASSWD. */ pw = xmalloc_secure ( strlen(fd_passwd)+1 ); strcpy ( pw, fd_passwd ); } else { if ((mode == 3 || mode == 4) && (s2k->mode == 1 || s2k->mode == 3)) { memset (s2k_cacheidbuf, 0, sizeof s2k_cacheidbuf); *s2k_cacheidbuf = 'S'; bin2hex (s2k->salt, 8, s2k_cacheidbuf + 1); s2k_cacheid = s2k_cacheidbuf; } if (opt.pinentry_mode == PINENTRY_MODE_LOOPBACK) { char buf[32]; snprintf (buf, sizeof (buf), "%u", 100); write_status_text (STATUS_INQUIRE_MAXLEN, buf); } /* Divert to the gpg-agent. */ pw = passphrase_get (keyid, mode == 2, s2k_cacheid, (mode == 2 || mode == 4)? opt.passphrase_repeat : 0, tryagain_text, custdesc, custprompt, canceled); if (*canceled) { xfree (pw); write_status( STATUS_MISSING_PASSPHRASE ); return NULL; } } if ( !pw || !*pw ) write_status( STATUS_MISSING_PASSPHRASE ); /* Hash the passphrase and store it in a newly allocated DEK object. Keep a copy of the passphrase in LAST_PW for use by get_last_passphrase(). */ dek = xmalloc_secure_clear ( sizeof *dek ); dek->algo = cipher_algo; if ( (!pw || !*pw) && (mode == 2 || mode == 4)) dek->keylen = 0; else { gpg_error_t err; dek->keylen = openpgp_cipher_get_algo_keylen (dek->algo); if (!(dek->keylen > 0 && dek->keylen <= DIM(dek->key))) BUG (); err = gcry_kdf_derive (pw, strlen (pw), s2k->mode == 3? GCRY_KDF_ITERSALTED_S2K : s2k->mode == 1? GCRY_KDF_SALTED_S2K : /* */ GCRY_KDF_SIMPLE_S2K, s2k->hash_algo, s2k->salt, 8, S2K_DECODE_COUNT(s2k->count), dek->keylen, dek->key); if (err) { log_error ("gcry_kdf_derive failed: %s", gpg_strerror (err)); xfree (pw); xfree (dek); write_status( STATUS_MISSING_PASSPHRASE ); return NULL; } } if (s2k_cacheid) memcpy (dek->s2k_cacheid, s2k_cacheid, sizeof dek->s2k_cacheid); xfree(last_pw); last_pw = pw; return dek; }
/**************** * 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; u32 keyid[2]; int changed=0; int quit=0; int show=0; int min_num; int did_help=defer_help; unsigned int minimum=get_min_ownertrust(pk); switch(minimum) { default: case TRUST_UNDEFINED: min_num=1; break; case TRUST_NEVER: min_num=2; break; case TRUST_MARGINAL: min_num=3; break; case TRUST_FULLY: min_num=4; break; } keyid_from_pk (pk, keyid); for(;;) { /* A string with valid answers. Note to translators: These are the allowed answers in lower and uppercase. Below you will find the matching strings which should be translated accordingly and the letter changed to match the one in the answer string. i = please show me more information m = back to the main menu s = skip this key q = quit */ const char *ans = _("iImMqQsS"); if( !did_help ) { if( !mode ) { KBNODE keyblock, un; tty_printf(_("No trust value assigned to:\n")); tty_printf("%4u%c/%s %s\n",nbits_from_pk( pk ), pubkey_letter( pk->pubkey_algo ), keystr(keyid), datestr_from_pk( pk ) ); p=get_user_id_native(keyid); tty_printf(_(" \"%s\"\n"),p); xfree(p); 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.verify_options&VERIFY_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); p=utf8_to_native(un->pkt->pkt.user_id->name, un->pkt->pkt.user_id->len,0); tty_printf(_(" aka \"%s\"\n"),p); } print_fingerprint (pk, NULL, 2); tty_printf("\n"); release_kbnode (keyblock); } if(opt.trust_model==TM_DIRECT) { tty_printf(_("How much do you trust that this key actually " "belongs to the named user?\n")); tty_printf("\n"); } else { /* This string also used in keyedit.c:trustsig_prompt */ tty_printf(_("Please decide how far you trust this user to" " correctly verify other users' keys\n" "(by looking at passports, checking fingerprints from" " different sources, etc.)\n")); tty_printf("\n"); } if(min_num<=1) tty_printf (_(" %d = I don't know or won't say\n"), 1); if(min_num<=2) tty_printf (_(" %d = I do NOT trust\n"), 2); if(min_num<=3) tty_printf (_(" %d = I trust marginally\n"), 3); if(min_num<=4) 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"); if(minimum) tty_printf(_("The minimum trust level for this key is: %s\n\n"), trust_value_to_string(minimum)); 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 >= '0'+min_num) && *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? (y/N) "))) ; /* 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 */ } xfree(p); p = NULL; } xfree(p); return show? -2: quit? -1 : changed; }