/* Gettext variant which temporary switches to utf-8 for string. */ const char * i18n_utf8 (const char *string) { char *saved = i18n_switchto_utf8 (); const char *result = _(string); i18n_switchback (saved); return result; }
/* Create a key description for the CERT, this may be passed to the pinentry. The caller must free the returned string. NULL may be returned on error. */ char * gpgsm_format_keydesc (ksba_cert_t cert) { char *name, *subject, *buffer; ksba_isotime_t t; char created[20]; char expires[20]; char *sn; ksba_sexp_t sexp; char *orig_codeset; name = ksba_cert_get_subject (cert, 0); subject = name? gpgsm_format_name2 (name, 0) : NULL; ksba_free (name); name = NULL; sexp = ksba_cert_get_serial (cert); sn = sexp? gpgsm_format_serial (sexp) : NULL; ksba_free (sexp); ksba_cert_get_validity (cert, 0, t); if (*t) sprintf (created, "%.4s-%.2s-%.2s", t, t+4, t+6); else *created = 0; ksba_cert_get_validity (cert, 1, t); if (*t) sprintf (expires, "%.4s-%.2s-%.2s", t, t+4, t+6); else *expires = 0; orig_codeset = i18n_switchto_utf8 (); name = xtryasprintf (_("Please enter the passphrase to unlock the" " secret key for the X.509 certificate:\n" "\"%s\"\n" "S/N %s, ID 0x%08lX,\n" "created %s, expires %s.\n" ), subject? subject:"?", sn? sn: "?", gpgsm_get_short_fingerprint (cert, NULL), created, expires); i18n_switchback (orig_codeset); if (!name) { xfree (subject); xfree (sn); return NULL; } xfree (subject); xfree (sn); buffer = percent_plus_escape (name); xfree (name); return buffer; }
/* Issue an SCD SERIALNO openpgp command and if SERIALNO is not NULL ask the user to insert the requested card. */ gpg_error_t select_openpgp (const char *serialno) { gpg_error_t err; /* Send the serialno command to initialize the connection. Without a given S/N we don't care about the data returned. If the card has already been initialized, this is a very fast command. We request the openpgp card because that is what we expect. Note that an opt.limit_card_insert_tries of 1 means: No tries at all whereas 0 means do not limit the number of tries. Due to the sue of a pinentry prompt with a cancel option we use it here in a boolean sense. */ if (!serialno || opt.limit_card_insert_tries == 1) err = assuan_transact (agent_ctx, "SCD SERIALNO openpgp", NULL, NULL, NULL, NULL, NULL, NULL); else { char *this_sn = NULL; char *desc; int ask; char *want_sn; char *p; want_sn = xtrystrdup (serialno); if (!want_sn) return gpg_error_from_syserror (); p = strchr (want_sn, '/'); if (p) *p = 0; do { ask = 0; err = assuan_transact (agent_ctx, "SCD SERIALNO openpgp", NULL, NULL, NULL, NULL, get_serialno_cb, &this_sn); if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT) ask = 1; else if (gpg_err_code (err) == GPG_ERR_NOT_SUPPORTED) ask = 2; else if (err) ; else if (this_sn) { if (strcmp (want_sn, this_sn)) ask = 2; } xfree (this_sn); this_sn = NULL; if (ask) { char *formatted = NULL; char *ocodeset = i18n_switchto_utf8 (); if (!strncmp (want_sn, "D27600012401", 12) && strlen (want_sn) == 32 ) formatted = xtryasprintf ("(%.4s) %.8s", want_sn + 16, want_sn + 20); err = 0; desc = xtryasprintf ("%s:\n\n" " \"%s\"", ask == 1 ? _("Please insert the card with serial number") : _("Please remove the current card and " "insert the one with serial number"), formatted? formatted : want_sn); if (!desc) err = gpg_error_from_syserror (); xfree (formatted); i18n_switchback (ocodeset); if (!err) err = gpg_agent_get_confirmation (desc); xfree (desc); } } while (ask && !err); xfree (want_sn); } return err; }
/* Return an allocated utf-8 string describing the key PK. If ESCAPED is true spaces and control characters are percent or plus escaped. MODE describes the use of the key description; use one of the FORMAT_KEYDESC_ macros. */ char * gpg_format_keydesc (PKT_public_key *pk, int mode, int escaped) { char *uid; size_t uidlen; const char *algo_name; const char *timestr; char *orig_codeset; char *maink; char *desc; const char *prompt; const char *trailer = ""; int is_subkey; is_subkey = (pk->main_keyid[0] && pk->main_keyid[1] && pk->keyid[0] != pk->main_keyid[0] && pk->keyid[1] != pk->main_keyid[1]); algo_name = openpgp_pk_algo_name (pk->pubkey_algo); timestr = strtimestamp (pk->timestamp); uid = get_user_id (is_subkey? pk->main_keyid:pk->keyid, &uidlen); orig_codeset = i18n_switchto_utf8 (); if (is_subkey) maink = xtryasprintf (_(" (main key ID %s)"), keystr (pk->main_keyid)); else maink = NULL; switch (mode) { case FORMAT_KEYDESC_NORMAL: prompt = _("Please enter the passphrase to unlock the" " OpenPGP secret key:"); break; case FORMAT_KEYDESC_IMPORT: prompt = _("Please enter the passphrase to import the" " OpenPGP secret key:"); break; case FORMAT_KEYDESC_EXPORT: if (is_subkey) prompt = _("Please enter the passphrase to export the" " OpenPGP secret subkey:"); else prompt = _("Please enter the passphrase to export the" " OpenPGP secret key:"); break; case FORMAT_KEYDESC_DELKEY: if (is_subkey) prompt = _("Do you really want to permanently delete the" " OpenPGP secret subkey key:"); else prompt = _("Do you really want to permanently delete the" " OpenPGP secret key:"); trailer = "?"; break; default: prompt = "?"; break; } desc = xtryasprintf (_("%s\n" "\"%.*s\"\n" "%u-bit %s key, ID %s,\n" "created %s%s.\n%s"), prompt, (int)uidlen, uid, nbits_from_pk (pk), algo_name, keystr (pk->keyid), timestr, maink?maink:"", trailer); xfree (maink); xfree (uid); i18n_switchback (orig_codeset); if (escaped) { char *tmp = percent_plus_escape (desc); xfree (desc); desc = tmp; } return desc; }
/* * 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; }
/* * Ask the GPG Agent for the passphrase. * If NOCACHE is set the symmetric passpharse caching will not be used. * * 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 (int nocache, const char *cacheid, int repeat, const char *tryagain_text, int *canceled) { int rc; char *pw = NULL; char *orig_codeset; const char *my_cacheid; if (canceled) *canceled = 0; orig_codeset = i18n_switchto_utf8 (); if (!nocache && cacheid) my_cacheid = cacheid; else my_cacheid = NULL; if (tryagain_text) tryagain_text = _(tryagain_text); rc = agent_get_passphrase (my_cacheid, tryagain_text, NULL, _("Enter passphrase\n"), repeat, nocache, &pw); 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); } if (rc) { xfree (pw); pw = NULL; } return pw; }