/**************** * Return a malloced string with a default recipient if there is any */ static char * default_recipient(void) { PKT_public_key *pk; byte fpr[MAX_FINGERPRINT_LEN+1]; size_t n; char *p; int i; if( opt.def_recipient ) return xstrdup( opt.def_recipient ); if( !opt.def_recipient_self ) return NULL; pk = xmalloc_clear( sizeof *pk ); i = get_seckey_byname (pk, NULL); if( i ) { free_public_key( pk ); return NULL; } n = MAX_FINGERPRINT_LEN; fingerprint_from_pk( pk, fpr, &n ); free_public_key( pk ); p = xmalloc( 2*n+3 ); *p++ = '0'; *p++ = 'x'; for(i=0; i < n; i++ ) sprintf( p+2*i, "%02X", fpr[i] ); p -= 2; return p; }
/* * Get the session key from a pubkey enc packet and return it in DEK, * which should have been allocated in secure memory by the caller. */ gpg_error_t get_session_key (PKT_pubkey_enc * k, DEK * dek) { PKT_public_key *sk = NULL; int rc; rc = openpgp_pk_test_algo2 (k->pubkey_algo, PUBKEY_USAGE_ENC); if (rc) goto leave; if ((k->keyid[0] || k->keyid[1]) && !opt.try_all_secrets) { sk = xmalloc_clear (sizeof *sk); sk->pubkey_algo = k->pubkey_algo; /* We want a pubkey with this algo. */ if (!(rc = get_seckey (sk, k->keyid))) rc = get_it (k, dek, sk, k->keyid); } else if (opt.skip_hidden_recipients) rc = gpg_error (GPG_ERR_NO_SECKEY); else /* Anonymous receiver: Try all available secret keys. */ { void *enum_context = NULL; u32 keyid[2]; for (;;) { if (sk) free_public_key (sk); sk = xmalloc_clear (sizeof *sk); rc = enum_secret_keys (&enum_context, sk); if (rc) { rc = G10ERR_NO_SECKEY; break; } if (sk->pubkey_algo != k->pubkey_algo) continue; if (!(sk->pubkey_usage & PUBKEY_USAGE_ENC)) continue; keyid_from_pk (sk, keyid); log_info (_("anonymous recipient; trying secret key %s ...\n"), keystr (keyid)); rc = get_it (k, dek, sk, keyid); if (!rc) { log_info (_("okay, we are the anonymous recipient.\n")); break; } else if (gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED) break; /* Don't try any more secret keys. */ } enum_secret_keys (&enum_context, NULL); /* free context */ } leave: if (sk) free_public_key (sk); return rc; }
/* when a X.509 certificate gets revoked, all instances of * the corresponding public key must be removed */ void remove_x509_public_key(/*const*/ x509cert_t *cert) { const cert_t c = {FALSE, CERT_X509_SIGNATURE, {cert}}; struct pubkey_list *p, **pp; struct pubkey *revoked_pk; revoked_pk = allocate_RSA_public_key(c); p = pluto_pubkeys; pp = &pluto_pubkeys; while(p != NULL) { if (same_RSA_public_key(&p->key->u.rsa, &revoked_pk->u.rsa)) { /* remove p from list and free memory */ *pp = free_public_keyentry(p); loglog(RC_LOG_SERIOUS, "invalid RSA public key deleted"); } else { pp = &p->next; } p =*pp; } free_public_key(revoked_pk); }
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 ); xfree( pk_list ); } }
void release_sk_list (SK_LIST sk_list) { SK_LIST sk_rover; for (; sk_list; sk_list = sk_rover) { sk_rover = sk_list->next; free_public_key (sk_list->pk); xfree (sk_list); } }
/* * Clear the cached passphrase. If CACHEID is not NULL, it will be * used instead of a cache ID derived from KEYID. */ void passphrase_clear_cache ( u32 *keyid, const char *cacheid, int algo ) { int rc; (void)algo; if (!cacheid) { PKT_public_key *pk; # if MAX_FINGERPRINT_LEN < 20 # error agent needs a 20 byte fingerprint # endif byte fpr[MAX_FINGERPRINT_LEN]; char hexfprbuf[2*20+1]; size_t dummy; pk = xcalloc (1, sizeof *pk); if ( !keyid || get_pubkey( pk, keyid ) ) { log_error ("key not found in passphrase_clear_cache\n"); free_public_key (pk); return; } memset (fpr, 0, MAX_FINGERPRINT_LEN ); fingerprint_from_pk ( pk, fpr, &dummy ); bin2hex (fpr, 20, hexfprbuf); rc = agent_clear_passphrase (hexfprbuf); free_public_key ( pk ); } else rc = agent_clear_passphrase (cacheid); if (rc) log_error (_("problem with the agent: %s\n"), gpg_strerror (rc)); }
void set_up_domain_manager(domain_manager* who, public_key parent) { // printf("[ SETUP_DM "); if (parent.level == 0) { printf(" if %s ]\n", who->name); public_key temp = init_public_key(&parent); who->pk.ID_tuple = temp.ID_tuple; who->pk.level = temp.level; who -> MK = create_DM(ROOT.MK, who->pk, *(ROOT.param)); param_copy_PP(&(who->param), ROOT.param); } else{ // printf(" else %s ]\n", who->name); domain_manager x; domain_manager* y = dm_from_publickey(parent); public_key temp1 = init_public_key(&parent); who->pk.ID_tuple = temp1.ID_tuple; who->pk.level = temp1.level; //x.MK who->MK= create_DM(y->MK, who->pk, *(ROOT.param) ); //who->MK = x.MK; param_copy_PP(&(who->param),ROOT.param); //updateparentchildren public_key* temp = (public_key* ) malloc(sizeof(public_key) * (y->number_of_children + 1) ); int i; for (i = 0; i < y->number_of_children; ++i) { public_key_copy(temp + i, y->children_dm + i); } y->children_dm += 1; public_key_copy(temp + i, &(who->pk)); for(i = 0; i < y->number_of_children - 1; ++i) { free_public_key(y->children_dm + i); } y->children_dm = temp; } }
/* * Ask the GPG Agent for the passphrase. * Mode 0: Allow cached passphrase * 1: No cached passphrase; that is we are asking for a new passphrase * FIXME: Only partially implemented * * Note that TRYAGAIN_TEXT must not be translated. If CANCELED is not * NULL, the function does set it to 1 if the user canceled the * operation. If CACHEID is not NULL, it will be used as the cacheID * for the gpg-agent; if is NULL and a key fingerprint can be * computed, this will be used as the cacheid. */ static char * passphrase_get ( u32 *keyid, int mode, const char *cacheid, int repeat, const char *tryagain_text, const char *custom_description, const char *custom_prompt, int *canceled) { int rc; char *atext = NULL; char *pw = NULL; PKT_public_key *pk = xmalloc_clear( sizeof *pk ); byte fpr[MAX_FINGERPRINT_LEN]; int have_fpr = 0; char *orig_codeset; char *my_prompt; char hexfprbuf[20*2+1]; const char *my_cacheid; int check = (mode == 1); if (canceled) *canceled = 0; #if MAX_FINGERPRINT_LEN < 20 #error agent needs a 20 byte fingerprint #endif memset (fpr, 0, MAX_FINGERPRINT_LEN ); if( keyid && get_pubkey( pk, keyid ) ) { free_public_key (pk); pk = NULL; /* oops: no key for some reason */ } orig_codeset = i18n_switchto_utf8 (); if (custom_description) atext = native_to_utf8 (custom_description); else if ( !mode && pk && keyid ) { char *uid; size_t uidlen; const char *algo_name = openpgp_pk_algo_name ( pk->pubkey_algo ); const char *timestr; char *maink; if ( !algo_name ) algo_name = "?"; if (keyid[2] && keyid[3] && keyid[0] != keyid[2] && keyid[1] != keyid[3] ) maink = xasprintf (_(" (main key ID %s)"), keystr (&keyid[2])); else maink = xstrdup (""); uid = get_user_id ( keyid, &uidlen ); timestr = strtimestamp (pk->timestamp); atext = xasprintf (_("Please enter the passphrase to unlock the" " secret key for the OpenPGP certificate:\n" "\"%.*s\"\n" "%u-bit %s key, ID %s,\n" "created %s%s.\n"), (int)uidlen, uid, nbits_from_pk (pk), algo_name, keystr(&keyid[0]), timestr, maink); xfree (uid); xfree (maink); { size_t dummy; fingerprint_from_pk( pk, fpr, &dummy ); have_fpr = 1; } } else atext = xstrdup ( _("Enter passphrase\n") ); if (!mode && cacheid) my_cacheid = cacheid; else if (!mode && have_fpr) my_cacheid = bin2hex (fpr, 20, hexfprbuf); else my_cacheid = NULL; if (tryagain_text) tryagain_text = _(tryagain_text); my_prompt = custom_prompt ? native_to_utf8 (custom_prompt): NULL; rc = agent_get_passphrase (my_cacheid, tryagain_text, my_prompt, atext, repeat, check, &pw); xfree (my_prompt); xfree (atext); atext = NULL; i18n_switchback (orig_codeset); if (!rc) ; else if (gpg_err_code (rc) == GPG_ERR_CANCELED || gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED) { log_info (_("cancelled by user\n") ); if (canceled) *canceled = 1; } else { log_error (_("problem with the agent: %s\n"), gpg_strerror (rc)); /* Due to limitations in the API of the upper layers they consider an error as no passphrase entered. This works in most cases but not during key creation where this should definitely not happen and let it continue without requiring a passphrase. Given that now all the upper layers handle a cancel correctly, we simply set the cancel flag now for all errors from the agent. */ if (canceled) *canceled = 1; write_status_errcode ("get_passphrase", rc); } free_public_key (pk); if (rc) { xfree (pw); return NULL; } return pw; }
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 ((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 = xmalloc (sizeof *r); r->pk = pk; pk = NULL; r->next = sk_list; r->mark = 0; sk_list = r; } } } 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 ((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 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; } } } } 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 (err) release_sk_list (sk_list); else *ret_sk_list = sk_list; return err; }
/* This is the central function to collect the keys for recipients. It is thus used to prepare a public key encryption. encrypt-to keys, default keys and the keys for the actual recipients are all collected here. When not in batch mode and no recipient has been passed on the commandline, the function will also ask for recipients. RCPTS is a string list with the recipients; NULL is an allowed value but not very useful. Group expansion is done on these names; they may be in any of the user Id formats we can handle. The flags bits for each string in the string list are used for: Bit 0: This is an encrypt-to recipient. Bit 1: This is a hidden recipient. USE is the desired use for the key - usually PUBKEY_USAGE_ENC. RET_PK_LIST. On success a list of keys is stored at the address RET_PK_LIST; the caller must free this list. On error the value at this address is not changed. */ int build_pk_list( STRLIST rcpts, PK_LIST *ret_pk_list, unsigned int 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; /* Try to expand groups if any have been defined. */ 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) ) { /* This is a regular recipient; i.e. not an encrypt-to one. */ any_recipients = 1; /* Hidden recipients are not allowed while in PGP mode, issue a warning and switch into GnuPG mode. */ if ((rov->flags&2) && (PGP2 || PGP6 || PGP7 || PGP8)) { log_info(_("you may not use %s while in %s mode\n"), "--hidden-recipient", compliance_option_string()); compliance_failure(); } } else if ( (use & PUBKEY_USAGE_ENC) && !opt.no_encrypt_to ) { /* Encryption has been requested and --encrypt-to has not been disabled. Check this encrypt-to key. */ pk = xmalloc_clear( sizeof *pk ); pk->req_usage = use; /* We explicitly allow encrypt-to to an disabled key; thus we pass 1 as last argument. */ if ( (rc = get_pubkey_byname ( pk, rov->d, NULL, NULL, 1 )) ) { 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. Add it to our list if not. */ 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 = xmalloc( sizeof *r ); r->pk = pk; pk = NULL; r->next = pk_list; r->flags = (rov->flags&2)?1:0; pk_list = r; /* Hidden encrypt-to recipients are not allowed while in PGP mode, issue a warning and switch into GnuPG mode. */ if ((r->flags&1) && (PGP2 || PGP6 || PGP7 || PGP8)) { log_info(_("you may not use %s while in %s mode\n"), "--hidden-encrypt-to", compliance_option_string()); compliance_failure(); } } } else { /* The public key is not usable for encryption or not available. */ 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 we don't have any recipients yet and we are not in batch mode drop into interactive selection mode. */ if ( !any_recipients && !opt.batch ) { int have_def_rec; char *answer = NULL; STRLIST backlog = NULL; if (pk_list) any_recipients = 1; 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; xfree(answer); if ( have_def_rec ) { /* A default recipient is taken as the first entry. */ answer = def_rec; def_rec = NULL; } else if (backlog) { /* This is part of our trick to expand and display groups. */ answer = pop_strlist (&backlog); } else { /* Show the list of already collected recipients and ask for more. */ PK_LIST iter; tty_printf("\n"); tty_printf(_("Current recipients:\n")); for (iter=pk_list;iter;iter=iter->next) { u32 keyid[2]; keyid_from_pk(iter->pk,keyid); tty_printf("%4u%c/%s %s \"", nbits_from_pk(iter->pk), pubkey_letter(iter->pk->pubkey_algo), keystr(keyid), datestr_from_pk(iter->pk)); if (iter->pk->user_id) tty_print_utf8_string(iter->pk->user_id->name, iter->pk->user_id->len); else { size_t n; char *p = get_user_id( keyid, &n ); tty_print_utf8_string( p, n ); xfree(p); } tty_printf("\"\n"); } 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 ) { xfree(answer); break; /* No more recipients entered - get out of loop. */ } /* Do group expand here too. The trick here is to continue the loop if any expansion occured. The code above will then list all expanded keys. */ if (expand_id(answer,&backlog,0)) continue; /* Get and check key for the current name. */ if (pk) free_public_key (pk); pk = xmalloc_clear( sizeof *pk ); pk->req_usage = use; rc = get_pubkey_byname( pk, answer, NULL, NULL, 0 ); if (rc) tty_printf(_("No such user ID.\n")); else if ( !(rc=check_pubkey_algo2(pk->pubkey_algo, use)) ) { if ( have_def_rec ) { /* No validation for a default recipient. */ if (!key_present_in_pk_list(pk_list, pk)) { free_public_key (pk); pk = NULL; log_info (_("skipped: public key " "already set as default recipient\n") ); } else { PK_LIST r = xmalloc (sizeof *r); r->pk = pk; pk = NULL; r->next = pk_list; r->flags = 0; /* No throwing default ids. */ pk_list = r; } any_recipients = 1; continue; } else { /* Check validity of this key. */ int trustlevel; trustlevel = get_validity (pk, pk->user_id); 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)) { free_public_key(pk); pk = NULL; log_info(_("skipped: public key already set\n") ); } else { PK_LIST r; r = xmalloc( sizeof *r ); r->pk = pk; pk = NULL; r->next = pk_list; r->flags = 0; /* No throwing interactive ids. */ pk_list = r; } any_recipients = 1; continue; } } } xfree(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()) ) { /* We are in batch mode and have only a default recipient. */ pk = xmalloc_clear( sizeof *pk ); pk->req_usage = use; /* The default recipient is allowed to be disabled; thus pass 1 as last argument. */ rc = get_pubkey_byname (pk, def_rec, NULL, NULL, 1); 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)) log_info (_("skipped: public key already set " "as default recipient\n")); else { PK_LIST r = xmalloc( sizeof *r ); r->pk = pk; pk = NULL; r->next = pk_list; r->flags = 0; /* No throwing default ids. */ pk_list = r; } } if ( pk ) { free_public_key( pk ); pk = NULL; } xfree(def_rec); def_rec = NULL; } else { /* General case: Check all keys. */ any_recipients = 0; for (; remusr; remusr = remusr->next ) { if ( (remusr->flags & 1) ) continue; /* encrypt-to keys are already handled. */ pk = xmalloc_clear( sizeof *pk ); pk->req_usage = use; if ( (rc = get_pubkey_byname( pk, remusr->d, NULL, NULL, 0 )) ) { /* Key not found or other error. */ 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 )) ) { /* Key found and usable. Check validity. */ int trustlevel; trustlevel = get_validity (pk, pk->user_id); if ( (trustlevel & TRUST_FLAG_DISABLED) ) { /*Key has been 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)) { free_public_key(pk); pk = NULL; log_info(_("%s: skipped: public key already present\n"), remusr->d); } else { PK_LIST r; r = xmalloc( sizeof *r ); r->pk = pk; pk = NULL; r->next = pk_list; r->flags = (remusr->flags&2)?1:0; pk_list = r; } } else { /* We don't trust this key. */ 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 { /* Key found but not usable for us (e.g. sign-only key). */ 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; }
/**************** * 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 = xmalloc_clear( sizeof *pk ); unsigned int trustlevel; int rc=0; 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; } if ( opt.trust_model==TM_ALWAYS ) { if( !opt.quiet ) log_info(_("WARNING: Using untrusted key!\n")); if (opt.with_fingerprint) print_fingerprint (pk, NULL, 1); goto leave; } if(pk->maybe_revoked && !pk->is_revoked) log_info(_("WARNING: this key might be revoked (revocation key" " not present)\n")); trustlevel = get_validity (pk, NULL); if ( (trustlevel & TRUST_FLAG_REVOKED) ) { write_status( STATUS_KEYREVOKED ); if(pk->is_revoked==2) log_info(_("WARNING: This key has been revoked by its" " designated revoker!\n")); else log_info(_("WARNING: This key has been revoked by its owner!\n")); log_info(_(" This could mean that the signature is forged.\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")); /* If we have PKA information adjust the trustlevel. */ if (sig->pka_info && sig->pka_info->valid) { unsigned char fpr[MAX_FINGERPRINT_LEN]; PKT_public_key *primary_pk; size_t fprlen; int okay; primary_pk = xmalloc_clear (sizeof *primary_pk); get_pubkey (primary_pk, pk->main_keyid); fingerprint_from_pk (primary_pk, fpr, &fprlen); free_public_key (primary_pk); if ( fprlen == 20 && !memcmp (sig->pka_info->fpr, fpr, 20) ) { okay = 1; write_status_text (STATUS_PKA_TRUST_GOOD, sig->pka_info->email); log_info (_("Note: Verified signer's address is `%s'\n"), sig->pka_info->email); } else { okay = 0; write_status_text (STATUS_PKA_TRUST_BAD, sig->pka_info->email); log_info (_("Note: Signer's address `%s' " "does not match DNS entry\n"), sig->pka_info->email); } switch ( (trustlevel & TRUST_MASK) ) { case TRUST_UNKNOWN: case TRUST_UNDEFINED: case TRUST_MARGINAL: if (okay && opt.verify_options&VERIFY_PKA_TRUST_INCREASE) { trustlevel = ((trustlevel & ~TRUST_MASK) | TRUST_FULLY); log_info (_("trustlevel adjusted to FULL" " due to valid PKA info\n")); } /* (fall through) */ case TRUST_FULLY: if (!okay) { trustlevel = ((trustlevel & ~TRUST_MASK) | TRUST_NEVER); log_info (_("trustlevel adjusted to NEVER" " due to bad PKA info\n")); } break; } } /* Now let the user know what up with the trustlevel. */ 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; }
int signature_check2( PKT_signature *sig, MD_HANDLE digest, u32 *r_expiredate, int *r_expired, int *r_revoked, PKT_public_key *ret_pk ) { PKT_public_key *pk = xmalloc_clear( sizeof *pk ); int rc=0; if( (rc=check_digest_algo(sig->digest_algo)) ) ; /* we don't have this digest */ else if((rc=check_pubkey_algo(sig->pubkey_algo))) ; /* we don't have this pubkey algo */ else if(!md_algo_present(digest,sig->digest_algo)) { /* Sanity check that the md has a context for the hash that the sig is expecting. This can happen if a onepass sig header does not match the actual sig, and also if the clearsign "Hash:" header is missing or does not match the actual sig. */ log_info(_("WARNING: signature digest conflict in message\n")); rc=G10ERR_GENERAL; } else if( get_pubkey( pk, sig->keyid ) ) rc = G10ERR_NO_PUBKEY; else if(!pk->is_valid && !pk->is_primary) rc=G10ERR_BAD_PUBKEY; /* you cannot have a good sig from an invalid subkey */ else { if(r_expiredate) *r_expiredate = pk->expiredate; rc = do_check( pk, sig, digest, r_expired, r_revoked, ret_pk ); /* Check the backsig. This is a 0x19 signature from the subkey on the primary key. The idea here is that it should not be possible for someone to "steal" subkeys and claim them as their own. The attacker couldn't actually use the subkey, but they could try and claim ownership of any signaures issued by it. */ if(rc==0 && !pk->is_primary && pk->backsig<2) { if(pk->backsig==0) { log_info(_("WARNING: signing subkey %s is not" " cross-certified\n"),keystr_from_pk(pk)); log_info(_("please see %s for more information\n"), "http://www.gnupg.org/faq/subkey-cross-certify.html"); /* --require-cross-certification makes this warning an error. TODO: change the default to require this after more keys have backsigs. */ if(opt.flags.require_cross_cert) rc=G10ERR_GENERAL; } else if(pk->backsig==1) { log_info(_("WARNING: signing subkey %s has an invalid" " cross-certification\n"),keystr_from_pk(pk)); rc=G10ERR_GENERAL; } } } free_public_key( pk ); if( !rc && sig->sig_class < 2 && is_status_enabled() ) { /* This signature id works best with DLP algorithms because * they use a random parameter for every signature. Instead of * this sig-id we could have also used the hash of the document * and the timestamp, but the drawback of this is, that it is * not possible to sign more than one identical document within * one second. Some remote batch processing applications might * like this feature here */ MD_HANDLE md; u32 a = sig->timestamp; int i, nsig = pubkey_get_nsig( sig->pubkey_algo ); byte *p, *buffer; md = md_open( DIGEST_ALGO_RMD160, 0); md_putc( digest, sig->pubkey_algo ); md_putc( digest, sig->digest_algo ); md_putc( digest, (a >> 24) & 0xff ); md_putc( digest, (a >> 16) & 0xff ); md_putc( digest, (a >> 8) & 0xff ); md_putc( digest, a & 0xff ); for(i=0; i < nsig; i++ ) { unsigned n = mpi_get_nbits( sig->data[i]); md_putc( md, n>>8); md_putc( md, n ); p = mpi_get_buffer( sig->data[i], &n, NULL ); md_write( md, p, n ); xfree(p); } md_final( md ); p = make_radix64_string( md_read( md, 0 ), 20 ); buffer = xmalloc( strlen(p) + 60 ); sprintf( buffer, "%s %s %lu", p, strtimestamp( sig->timestamp ), (ulong)sig->timestamp ); write_status_text( STATUS_SIG_ID, buffer ); xfree(buffer); xfree(p); md_close(md); }
int signature_check2 (PKT_signature *sig, gcry_md_hd_t digest, u32 *r_expiredate, int *r_expired, int *r_revoked, PKT_public_key *ret_pk ) { PKT_public_key *pk = xmalloc_clear( sizeof *pk ); int rc=0; if ( (rc=openpgp_md_test_algo(sig->digest_algo)) ) ; /* We don't have this digest. */ else if ((rc=openpgp_pk_test_algo(sig->pubkey_algo))) ; /* We don't have this pubkey algo. */ else if (!gcry_md_is_enabled (digest,sig->digest_algo)) { /* Sanity check that the md has a context for the hash that the sig is expecting. This can happen if a onepass sig header does not match the actual sig, and also if the clearsign "Hash:" header is missing or does not match the actual sig. */ log_info(_("WARNING: signature digest conflict in message\n")); rc=G10ERR_GENERAL; } else if( get_pubkey( pk, sig->keyid ) ) rc = G10ERR_NO_PUBKEY; else if(!pk->is_valid && !pk->is_primary) rc=G10ERR_BAD_PUBKEY; /* you cannot have a good sig from an invalid subkey */ else { if(r_expiredate) *r_expiredate = pk->expiredate; rc = do_check( pk, sig, digest, r_expired, r_revoked, ret_pk ); /* Check the backsig. This is a 0x19 signature from the subkey on the primary key. The idea here is that it should not be possible for someone to "steal" subkeys and claim them as their own. The attacker couldn't actually use the subkey, but they could try and claim ownership of any signaures issued by it. */ if(rc==0 && !pk->is_primary && pk->backsig<2) { if(pk->backsig==0) { log_info(_("WARNING: signing subkey %s is not" " cross-certified\n"),keystr_from_pk(pk)); log_info(_("please see %s for more information\n"), "http://www.gnupg.org/faq/subkey-cross-certify.html"); /* --require-cross-certification makes this warning an error. TODO: change the default to require this after more keys have backsigs. */ if(opt.flags.require_cross_cert) rc=G10ERR_GENERAL; } else if(pk->backsig==1) { log_info(_("WARNING: signing subkey %s has an invalid" " cross-certification\n"),keystr_from_pk(pk)); rc=G10ERR_GENERAL; } } } free_public_key( pk ); if( !rc && sig->sig_class < 2 && is_status_enabled() ) { /* This signature id works best with DLP algorithms because * they use a random parameter for every signature. Instead of * this sig-id we could have also used the hash of the document * and the timestamp, but the drawback of this is, that it is * not possible to sign more than one identical document within * one second. Some remote batch processing applications might * like this feature here. * * Note that before 2.0.10, we used RIPE-MD160 for the hash * and accidently didn't include the timestamp and algorithm * information in the hash. Given that this feature is not * commonly used and that a replay attacks detection should * not solely be based on this feature (because it does not * work with RSA), we take the freedom and switch to SHA-1 * with 2.0.10 to take advantage of hardware supported SHA-1 * implementations. We also include the missing information * in the hash. Note also the SIG_ID as computed by gpg 1.x * and gpg 2.x didn't matched either because 2.x used to print * MPIs not in PGP format. */ u32 a = sig->timestamp; int nsig = pubkey_get_nsig( sig->pubkey_algo ); unsigned char *p, *buffer; size_t n, nbytes; int i; char hashbuf[20]; nbytes = 6; for (i=0; i < nsig; i++ ) { if (gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &n, sig->data[i])) BUG(); nbytes += n; } /* Make buffer large enough to be later used as output buffer. */ if (nbytes < 100) nbytes = 100; nbytes += 10; /* Safety margin. */ /* Fill and hash buffer. */ buffer = p = xmalloc (nbytes); *p++ = sig->pubkey_algo; *p++ = sig->digest_algo; *p++ = (a >> 24) & 0xff; *p++ = (a >> 16) & 0xff; *p++ = (a >> 8) & 0xff; *p++ = a & 0xff; nbytes -= 6; for (i=0; i < nsig; i++ ) { if (gcry_mpi_print (GCRYMPI_FMT_PGP, p, nbytes, &n, sig->data[i])) BUG(); p += n; nbytes -= n; } gcry_md_hash_buffer (GCRY_MD_SHA1, hashbuf, buffer, p-buffer); p = make_radix64_string (hashbuf, 20); sprintf (buffer, "%s %s %lu", p, strtimestamp (sig->timestamp), (ulong)sig->timestamp); xfree (p); write_status_text (STATUS_SIG_ID, buffer); xfree (buffer); }
static int get_it( PKT_pubkey_enc *k, DEK *dek, PKT_secret_key *sk, u32 *keyid ) { int rc; MPI plain_dek = NULL; byte *frame = NULL; unsigned n, nframe; u16 csum, csum2; rc = pubkey_decrypt(sk->pubkey_algo, &plain_dek, k->data, sk->skey ); if( rc ) goto leave; frame = mpi_get_buffer( plain_dek, &nframe, NULL ); mpi_free( plain_dek ); plain_dek = NULL; /* Now get the DEK (data encryption key) from the frame * * Old versions encode the DEK in in this format (msb is left): * * 0 1 DEK(16 bytes) CSUM(2 bytes) 0 RND(n bytes) 2 * * Later versions encode the DEK like this: * * 0 2 RND(n bytes) 0 A DEK(k bytes) CSUM(2 bytes) * * (mpi_get_buffer already removed the leading zero). * * RND are non-zero randow bytes. * A is the cipher algorithm * DEK is the encryption key (session key) with length k * CSUM */ if( DBG_CIPHER ) log_hexdump("DEK frame:", frame, nframe ); n=0; if( n + 7 > nframe ) { rc = G10ERR_WRONG_SECKEY; goto leave; } if( frame[n] == 1 && frame[nframe-1] == 2 ) { log_info(_("old encoding of the DEK is not supported\n")); rc = G10ERR_CIPHER_ALGO; goto leave; } if( frame[n] != 2 ) /* somethink is wrong */ { rc = G10ERR_WRONG_SECKEY; goto leave; } for(n++; n < nframe && frame[n]; n++ ) /* skip the random bytes */ ; n++; /* and the zero byte */ if( n + 4 > nframe ) { rc = G10ERR_WRONG_SECKEY; goto leave; } dek->keylen = nframe - (n+1) - 2; dek->algo = frame[n++]; if( dek->algo == CIPHER_ALGO_IDEA ) write_status(STATUS_RSA_OR_IDEA); rc = check_cipher_algo( dek->algo ); if( rc ) { if( !opt.quiet && rc == G10ERR_CIPHER_ALGO ) { log_info(_("cipher algorithm %d is unknown or disabled\n"), dek->algo); } dek->algo = 0; goto leave; } if( (dek->keylen*8) != cipher_get_keylen( dek->algo ) ) { rc = G10ERR_WRONG_SECKEY; goto leave; } /* copy the key to DEK and compare the checksum */ csum = frame[nframe-2] << 8; csum |= frame[nframe-1]; memcpy( dek->key, frame+n, dek->keylen ); for( csum2=0, n=0; n < dek->keylen; n++ ) csum2 += dek->key[n]; if( csum != csum2 ) { rc = G10ERR_WRONG_SECKEY; goto leave; } if( DBG_CIPHER ) log_hexdump("DEK is:", dek->key, dek->keylen ); /* check that the algo is in the preferences and whether it has expired */ { PKT_public_key *pk = m_alloc_clear( sizeof *pk ); if( (rc = get_pubkey( pk, keyid )) ) log_error("public key problem: %s\n", g10_errstr(rc) ); else if( !pk->local_id && query_trust_record(pk) ) log_error("can't check algorithm against preferences\n"); else if( dek->algo != CIPHER_ALGO_3DES && !is_algo_in_prefs( pk->local_id, PREFTYPE_SYM, dek->algo ) ) { /* Don't print a note while we are not on verbose mode, * the cipher is blowfish and the preferences have twofish * listed */ if( opt.verbose || dek->algo != CIPHER_ALGO_BLOWFISH || !is_algo_in_prefs( pk->local_id, PREFTYPE_SYM, CIPHER_ALGO_TWOFISH ) ) log_info(_( "NOTE: cipher algorithm %d not found in preferences\n"), dek->algo ); } if( !rc && pk->expiredate && pk->expiredate <= make_timestamp() ) { log_info(_("NOTE: secret key %08lX expired at %s\n"), (ulong)keyid[1], asctimestamp( pk->expiredate) ); } /* FIXME: check wheter the key has been revoked and display * the revocation reason. Actually the user should know this himself, * but the sender might not know already and therefor the user * should get a notice that an revoked key has been used to decode * the message. The user can than watch out for snakes send by * one of those Eves outside his paradise :-) */ free_public_key( pk ); rc = 0; } leave: mpi_free(plain_dek); m_free(frame); return rc; }
/* Helper for build_pk_list to find and check one key. This helper is also used directly in server mode by the RECIPIENTS command. On success the new key is added to PK_LIST_ADDR. NAME is the user id of the key. USE the requested usage and a set MARK_HIDDEN will mark the key in the updated list as a hidden recipient. */ gpg_error_t find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use, int mark_hidden, pk_list_t *pk_list_addr) { int rc; PKT_public_key *pk; int trustlevel; if (!name || !*name) return gpg_error (GPG_ERR_INV_USER_ID); pk = xtrycalloc (1, sizeof *pk); if (!pk) return gpg_error_from_syserror (); pk->req_usage = use; rc = get_pubkey_byname (ctrl, NULL, pk, name, NULL, NULL, 0, 0); if (rc) { /* Key not found or other error. */ log_error (_("%s: skipped: %s\n"), name, g10_errstr(rc) ); send_status_inv_recp (0, name); free_public_key (pk); return rc; } rc = openpgp_pk_test_algo2 (pk->pubkey_algo, use); if (rc) { /* Key found but not usable for us (e.g. sign-only key). */ send_status_inv_recp (0, name); log_error (_("%s: skipped: %s\n"), name, g10_errstr(rc) ); free_public_key (pk); return rc; } /* Key found and usable. Check validity. */ trustlevel = get_validity (pk, pk->user_id); if ( (trustlevel & TRUST_FLAG_DISABLED) ) { /* Key has been disabled. */ send_status_inv_recp (0, name); log_info (_("%s: skipped: public key is disabled\n"), name); free_public_key (pk); return G10ERR_UNU_PUBKEY; } if ( !do_we_trust_pre (pk, trustlevel) ) { /* We don't trust this key. */ send_status_inv_recp (10, name); free_public_key (pk); return G10ERR_UNU_PUBKEY; } /* Note: do_we_trust may have changed the trustlevel. */ /* Skip the actual key if the key is already present in the list. */ if (!key_present_in_pk_list (*pk_list_addr, pk)) { log_info (_("%s: skipped: public key already present\n"), name); free_public_key (pk); } else { pk_list_t r; r = xtrymalloc (sizeof *r); if (!r) { rc = gpg_error_from_syserror (); free_public_key (pk); return rc; } r->pk = pk; r->next = *pk_list_addr; r->flags = mark_hidden? 1:0; *pk_list_addr = r; } return 0; }
/* * Get the session key from a pubkey enc packet and return it in DEK, * which should have been allocated in secure memory by the caller. */ gpg_error_t get_session_key (ctrl_t ctrl, PKT_pubkey_enc * k, DEK * dek) { PKT_public_key *sk = NULL; int rc; if (DBG_CLOCK) log_clock ("get_session_key enter"); rc = openpgp_pk_test_algo2 (k->pubkey_algo, PUBKEY_USAGE_ENC); if (rc) goto leave; if ((k->keyid[0] || k->keyid[1]) && !opt.try_all_secrets) { sk = xmalloc_clear (sizeof *sk); sk->pubkey_algo = k->pubkey_algo; /* We want a pubkey with this algo. */ if (!(rc = get_seckey (ctrl, sk, k->keyid))) { /* Check compliance. */ if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_DECRYPTION, sk->pubkey_algo, sk->pkey, nbits_from_pk (sk), NULL)) { log_info (_("key %s is not suitable for decryption" " in %s mode\n"), keystr_from_pk (sk), gnupg_compliance_option_string (opt.compliance)); rc = gpg_error (GPG_ERR_PUBKEY_ALGO); } else rc = get_it (ctrl, k, dek, sk, k->keyid); } } else if (opt.skip_hidden_recipients) rc = gpg_error (GPG_ERR_NO_SECKEY); else /* Anonymous receiver: Try all available secret keys. */ { void *enum_context = NULL; u32 keyid[2]; for (;;) { free_public_key (sk); sk = xmalloc_clear (sizeof *sk); rc = enum_secret_keys (ctrl, &enum_context, sk); if (rc) { rc = GPG_ERR_NO_SECKEY; break; } if (sk->pubkey_algo != k->pubkey_algo) continue; if (!(sk->pubkey_usage & PUBKEY_USAGE_ENC)) continue; keyid_from_pk (sk, keyid); if (!opt.quiet) log_info (_("anonymous recipient; trying secret key %s ...\n"), keystr (keyid)); /* Check compliance. */ if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_DECRYPTION, sk->pubkey_algo, sk->pkey, nbits_from_pk (sk), NULL)) { log_info (_("key %s is not suitable for decryption" " in %s mode\n"), keystr_from_pk (sk), gnupg_compliance_option_string (opt.compliance)); continue; } rc = get_it (ctrl, k, dek, sk, keyid); if (!rc) { if (!opt.quiet) log_info (_("okay, we are the anonymous recipient.\n")); break; } else if (gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED) break; /* Don't try any more secret keys. */ } enum_secret_keys (ctrl, &enum_context, NULL); /* free context */ } leave: free_public_key (sk); if (DBG_CLOCK) log_clock ("get_session_key leave"); return rc; }
/* 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; }
int signature_check2( PKT_signature *sig, MD_HANDLE digest, u32 *r_expiredate, int *r_expired ) { PKT_public_key *pk = m_alloc_clear( sizeof *pk ); int rc=0; *r_expiredate = 0; /* Sanity check that the md has a context for the hash that the sig is expecting. This can happen if a onepass sig header does not match the actual sig, and also if the clearsign "Hash:" header is missing or does not match the actual sig. */ if(!md_algo_present(digest,sig->digest_algo)) { log_info(_("WARNING: signature digest conflict in message\n")); rc=G10ERR_BAD_SIGN; } else if( get_pubkey( pk, sig->keyid ) ) rc = G10ERR_NO_PUBKEY; else if(!pk->is_valid && !pk->is_primary) rc=G10ERR_BAD_PUBKEY; /* you cannot have a good sig from an invalid subkey */ else { *r_expiredate = pk->expiredate; rc = do_check( pk, sig, digest, r_expired ); } free_public_key( pk ); if( !rc && sig->sig_class < 2 && is_status_enabled() ) { /* This signature id works best with DLP algorithms because * they use a random parameter for every signature. Instead of * this sig-id we could have also used the hash of the document * and the timestamp, but the drawback of this is, that it is * not possible to sign more than one identical document within * one second. Some remote batch processing applications might * like this feature here */ MD_HANDLE md; u32 a = sig->timestamp; int i, nsig = pubkey_get_nsig( sig->pubkey_algo ); byte *p, *buffer; md = md_open( DIGEST_ALGO_RMD160, 0); md_putc( digest, sig->pubkey_algo ); md_putc( digest, sig->digest_algo ); md_putc( digest, (a >> 24) & 0xff ); md_putc( digest, (a >> 16) & 0xff ); md_putc( digest, (a >> 8) & 0xff ); md_putc( digest, a & 0xff ); for(i=0; i < nsig; i++ ) { unsigned n = mpi_get_nbits( sig->data[i]); md_putc( md, n>>8); md_putc( md, n ); p = mpi_get_buffer( sig->data[i], &n, NULL ); md_write( md, p, n ); m_free(p); } md_final( md ); p = make_radix64_string( md_read( md, 0 ), 20 ); buffer = m_alloc( strlen(p) + 60 ); sprintf( buffer, "%s %s %lu", p, strtimestamp( sig->timestamp ), (ulong)sig->timestamp ); write_status_text( STATUS_SIG_ID, buffer ); m_free(buffer); m_free(p); md_close(md); }