diff options
110 files changed, 5964 insertions, 2265 deletions
@@ -1,3 +1,49 @@ +Noteworthy changes in version 2.2.21 (2020-07-09) +------------------------------------------------- + + * gpg: Improve symmetric decryption speed by about 25%. + See commit 144b95cc9d. + + * gpg: Support decryption of AEAD encrypted data packets. + + * gpg: Add option --no-include-key-block. [#4856] + + * gpg: Allow for extra padding in ECDH. [#4908] + + * gpg: Only a single pinentry is shown for symmetric encryption if + the pinentry supports this. [#4971] + + * gpg: Print a note if no keys are given to --delete-key. [#4959] + + * gpg,gpgsm: The ridiculous passphrase quality bar is not anymore + shown. [#2103] + + * gpgsm: Certificates without a CRL distribution point are now + considered valid without looking up a CRL. The new option + --enable-issuer-based-crl-check can be used to revert to the + former behaviour. + + * gpgsm: Support rsaPSS signature verification. [#4538] + + * gpgsm: Unless CRL checking is disabled lookup a missing issuer + certificate using the certificate's authorityInfoAccess. [#4898] + + * gpgsm: Print the certificate's serial number also in decimal + notation. + + * gpgsm: Fix possible NULL-deref in messages of --gen-key. [#4895] + + * scd: Support the CardOS 5 based D-Trust Card 3.1. + + * dirmngr: Allow http URLs with "LOOKUP --url". + + * wkd: Take name of sendmail from configure. Fixes an OpenBSD + specific bug. [#4886] + + Release-info: https://dev.gnupg.org/T4897 + See-also: gnupg-announce/2020q3/000446.html + + Noteworthy changes in version 2.2.20 (2020-03-20) ------------------------------------------------- diff --git a/agent/agent.h b/agent/agent.h index e10e02b..8b5ae60 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -447,7 +447,8 @@ gpg_error_t agent_askpin (ctrl_t ctrl, int agent_get_passphrase (ctrl_t ctrl, char **retpass, const char *desc, const char *prompt, const char *errtext, int with_qualitybar, - const char *keyinfo, cache_mode_t cache_mode); + const char *keyinfo, cache_mode_t cache_mode, + struct pin_entry_info_s *pininfo); int agent_get_confirmation (ctrl_t ctrl, const char *desc, const char *ok, const char *notokay, int with_cancel); int agent_show_message (ctrl_t ctrl, const char *desc, const char *ok_btn); @@ -484,7 +485,7 @@ int agent_pkdecrypt (ctrl_t ctrl, const char *desc_text, membuf_t *outbuf, int *r_padding); /*-- genkey.c --*/ -int check_passphrase_constraints (ctrl_t ctrl, const char *pw, +int check_passphrase_constraints (ctrl_t ctrl, const char *pw, int no_empty, char **failed_constraint); gpg_error_t agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt, char **r_passphrase); diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c index b0b5bcb..2af94c9 100644 --- a/agent/call-pinentry.c +++ b/agent/call-pinentry.c @@ -85,6 +85,7 @@ struct entry_parm_s int lines; size_t size; unsigned char *buffer; + int status; }; @@ -836,7 +837,7 @@ inq_quality (void *opaque, const char *line) else { percent = estimate_passphrase_quality (pin); - if (check_passphrase_constraints (NULL, pin, NULL)) + if (check_passphrase_constraints (NULL, pin, 0, NULL)) percent = -percent; snprintf (numbuf, sizeof numbuf, "%d", percent); rc = assuan_send_data (ctx, numbuf, strlen (numbuf)); @@ -953,6 +954,36 @@ build_cmd_setdesc (char *line, size_t linelen, const char *desc) } +/* Ask pinentry to get a pin by "GETPIN" command, spawning a thread + * detecting the socket's EOF. */ +static gpg_error_t +do_getpin (ctrl_t ctrl, struct entry_parm_s *parm) +{ + gpg_error_t rc; + int saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL); + + (void)ctrl; + + assuan_begin_confidential (entry_ctx); + rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, parm, + inq_quality, entry_ctx, + pinentry_status_cb, &parm->status); + assuan_set_flag (entry_ctx, ASSUAN_CONFIDENTIAL, saveflag); + /* Most pinentries out in the wild return the old Assuan error code + for canceled which gets translated to an assuan Cancel error and + not to the code for a user cancel. Fix this here. */ + if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED) + rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED); + /* Change error code in case the window close button was clicked + to cancel the operation. */ + if ((parm->status & PINENTRY_STATUS_CLOSE_BUTTON) + && gpg_err_code (rc) == GPG_ERR_CANCELED) + rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED); + + return rc; +} + + /* Call the Entry and ask for the PIN. We do check for a valid PIN number here and repeat it as long as we have invalid formed @@ -970,7 +1001,6 @@ agent_askpin (ctrl_t ctrl, struct entry_parm_s parm; const char *errtext = NULL; int is_pin = 0; - int saveflag; if (opt.batch) return 0; /* fixme: we should return BAD PIN */ @@ -1114,25 +1144,8 @@ agent_askpin (ctrl_t ctrl, return unlock_pinentry (ctrl, rc); } - saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL); - assuan_begin_confidential (entry_ctx); - rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, - inq_quality, entry_ctx, - pinentry_status_cb, &pininfo->status); - assuan_set_flag (entry_ctx, ASSUAN_CONFIDENTIAL, saveflag); - /* Most pinentries out in the wild return the old Assuan error code - for canceled which gets translated to an assuan Cancel error and - not to the code for a user cancel. Fix this here. */ - if (rc && gpg_err_source (rc) - && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED) - rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED); - - - /* Change error code in case the window close button was clicked - to cancel the operation. */ - if ((pininfo->status & PINENTRY_STATUS_CLOSE_BUTTON) - && gpg_err_code (rc) == GPG_ERR_CANCELED) - rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED); + rc = do_getpin (ctrl, &parm); + pininfo->status = parm.status; if (gpg_err_code (rc) == GPG_ERR_ASS_TOO_MUCH_DATA) errtext = is_pin? L_("PIN too long") @@ -1183,9 +1196,11 @@ agent_askpin (ctrl_t ctrl, } if ((pininfo->status & PINENTRY_STATUS_PASSWORD_FROM_CACHE)) - /* The password was read from the cache. Don't count this - against the retry count. */ - pininfo->failed_tries --; + { + /* The password was read from the cache. Don't count this + against the retry count. */ + pininfo->failed_tries --; + } } return unlock_pinentry (ctrl, gpg_error (pininfo->min_digits? GPG_ERR_BAD_PIN @@ -1195,19 +1210,22 @@ agent_askpin (ctrl_t ctrl, /* Ask for the passphrase using the supplied arguments. The returned - passphrase needs to be freed by the caller. */ + passphrase needs to be freed by the caller. PININFO is optional + and can be used to have constraints checinkg while the pinentry + dialog is open (like what we do in agent_askpin). This is very + similar to agent_akpin and we should eventually merge the two + functions. */ int agent_get_passphrase (ctrl_t ctrl, char **retpass, const char *desc, const char *prompt, const char *errtext, int with_qualitybar, - const char *keyinfo, cache_mode_t cache_mode) + const char *keyinfo, cache_mode_t cache_mode, + struct pin_entry_info_s *pininfo) { - int rc; + int is_pin; char line[ASSUAN_LINELENGTH]; struct entry_parm_s parm; - int saveflag; - unsigned int pinentry_status; *retpass = NULL; if (opt.batch) @@ -1215,17 +1233,42 @@ agent_get_passphrase (ctrl_t ctrl, if (ctrl->pinentry_mode != PINENTRY_MODE_ASK) { + unsigned char *passphrase; + size_t size; + if (ctrl->pinentry_mode == PINENTRY_MODE_CANCEL) return gpg_error (GPG_ERR_CANCELED); - if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK) + if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK && pininfo) { - size_t size; + *pininfo->pin = 0; /* Reset the PIN. */ + rc = pinentry_loopback (ctrl, "PASSPHRASE", + &passphrase, &size, + pininfo->max_length - 1); + if (rc) + return rc; + memcpy (&pininfo->pin, passphrase, size); + wipememory (passphrase, size); + xfree (passphrase); + pininfo->pin[size] = 0; + if (pininfo->check_cb) + { + /* More checks by utilizing the optional callback. */ + pininfo->cb_errtext = NULL; + rc = pininfo->check_cb (pininfo); + } + return rc; + + } + else if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK) + { + /* Legacy variant w/o PININFO. */ return pinentry_loopback (ctrl, "PASSPHRASE", (unsigned char **)retpass, &size, MAX_PASSPHRASE_LEN); } + return gpg_error (GPG_ERR_NO_PIN_ENTRY); } @@ -1233,9 +1276,14 @@ agent_get_passphrase (ctrl_t ctrl, if (rc) return rc; - if (!prompt) - prompt = desc && strstr (desc, "PIN")? L_("PIN:"): L_("Passphrase:"); - + /* Set IS_PIN and if needed a default prompt. */ + if (prompt) + is_pin = !!strstr (prompt, "PIN"); + else + { + is_pin = desc && strstr (desc, "PIN"); + prompt = is_pin? L_("PIN:"): L_("Passphrase:"); + } /* If we have a KEYINFO string and are normal, user, or ssh cache mode, we tell that the Pinentry so it may use it for own caching @@ -1256,7 +1304,6 @@ agent_get_passphrase (ctrl_t ctrl, if (rc && gpg_err_code (rc) != GPG_ERR_ASS_UNKNOWN_CMD) return unlock_pinentry (ctrl, rc); - if (desc) build_cmd_setdesc (line, DIM(line), desc); else @@ -1270,7 +1317,8 @@ agent_get_passphrase (ctrl_t ctrl, if (rc) return unlock_pinentry (ctrl, rc); - if (with_qualitybar && opt.min_passphrase_len) + if ((with_qualitybar || (pininfo && pininfo->with_qualitybar)) + && opt.min_passphrase_len) { rc = setup_qualitybar (ctrl); if (rc) @@ -1280,40 +1328,132 @@ agent_get_passphrase (ctrl_t ctrl, if (errtext) { snprintf (line, DIM(line), "SETERROR %s", errtext); - rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); + rc = assuan_transact (entry_ctx, line, + NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return unlock_pinentry (ctrl, rc); } - memset (&parm, 0, sizeof parm); - parm.size = ASSUAN_LINELENGTH/2 - 5; - parm.buffer = gcry_malloc_secure (parm.size+10); - if (!parm.buffer) - return unlock_pinentry (ctrl, out_of_core ()); + if (!pininfo) + { + /* Legacy method without PININFO. */ + memset (&parm, 0, sizeof parm); + parm.size = ASSUAN_LINELENGTH/2 - 5; + parm.buffer = gcry_malloc_secure (parm.size+10); + if (!parm.buffer) + return unlock_pinentry (ctrl, out_of_core ()); - saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL); - assuan_begin_confidential (entry_ctx); - pinentry_status = 0; - rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, - inq_quality, entry_ctx, - pinentry_status_cb, &pinentry_status); - assuan_set_flag (entry_ctx, ASSUAN_CONFIDENTIAL, saveflag); - /* Most pinentries out in the wild return the old Assuan error code - for canceled which gets translated to an assuan Cancel error and - not to the code for a user cancel. Fix this here. */ - if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED) - rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED); - /* Change error code in case the window close button was clicked - to cancel the operation. */ - if ((pinentry_status & PINENTRY_STATUS_CLOSE_BUTTON) - && gpg_err_code (rc) == GPG_ERR_CANCELED) - rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED); + rc = do_getpin (ctrl, &parm); + if (rc) + xfree (parm.buffer); + else + *retpass = parm.buffer; + return unlock_pinentry (ctrl, rc); + } - if (rc) - xfree (parm.buffer); - else - *retpass = parm.buffer; - return unlock_pinentry (ctrl, rc); + /* We got PININFO. */ + + if (pininfo->with_repeat) + { + snprintf (line, DIM(line), "SETREPEATERROR %s", + L_("does not match - try again")); + rc = assuan_transact (entry_ctx, line, + NULL, NULL, NULL, NULL, NULL, NULL); + if (rc) + pininfo->with_repeat = 0; /* Pinentry does not support it. */ + } + pininfo->repeat_okay = 0; + pininfo->status = 0; + + for (;pininfo->failed_tries < pininfo->max_tries; pininfo->failed_tries++) + { + memset (&parm, 0, sizeof parm); + parm.size = pininfo->max_length; + parm.buffer = (unsigned char*)pininfo->pin; + *pininfo->pin = 0; /* Reset the PIN. */ + + if (errtext) + { + /* TRANSLATORS: The string is appended to an error message in + the pinentry. The %s is the actual error message, the + two %d give the current and maximum number of tries. */ + snprintf (line, DIM(line), L_("SETERROR %s (try %d of %d)"), + errtext, pininfo->failed_tries+1, pininfo->max_tries); + rc = assuan_transact (entry_ctx, line, + NULL, NULL, NULL, NULL, NULL, NULL); + if (rc) + return unlock_pinentry (ctrl, rc); + errtext = NULL; + } + + if (pininfo->with_repeat) + { + snprintf (line, DIM(line), "SETREPEAT %s", L_("Repeat:")); + rc = assuan_transact (entry_ctx, line, + NULL, NULL, NULL, NULL, NULL, NULL); + if (rc) + return unlock_pinentry (ctrl, rc); + } + + rc = do_getpin (ctrl, &parm); + pininfo->status = parm.status; + if (gpg_err_code (rc) == GPG_ERR_ASS_TOO_MUCH_DATA) + errtext = is_pin? L_("PIN too long") + : L_("Passphrase too long"); + else if (rc) + return unlock_pinentry (ctrl, rc); + + if (!errtext && pininfo->min_digits) + { + /* do some basic checks on the entered PIN. */ + if (!all_digitsp (pininfo->pin)) + errtext = L_("Invalid characters in PIN"); + else if (pininfo->max_digits + && strlen (pininfo->pin) > pininfo->max_digits) + errtext = L_("PIN too long"); + else if (strlen (pininfo->pin) < pininfo->min_digits) + errtext = L_("PIN too short"); + } + + if (!errtext && pininfo->check_cb) + { + /* More checks by utilizing the optional callback. */ + pininfo->cb_errtext = NULL; + rc = pininfo->check_cb (pininfo); + /* When pinentry cache causes an error, return now. */ + if (rc && (pininfo->status & PINENTRY_STATUS_PASSWORD_FROM_CACHE)) + return unlock_pinentry (ctrl, rc); + + if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE) + { + if (pininfo->cb_errtext) + errtext = pininfo->cb_errtext; + else if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE + || gpg_err_code (rc) == GPG_ERR_BAD_PIN) + errtext = (is_pin? L_("Bad PIN") : L_("Bad Passphrase")); + } + else if (rc) + return unlock_pinentry (ctrl, rc); + } + + if (!errtext) + { + if (pininfo->with_repeat + && (pininfo->status & PINENTRY_STATUS_PIN_REPEATED)) + pininfo->repeat_okay = 1; + return unlock_pinentry (ctrl, 0); /* okay, got a PIN or passphrase */ + } + + if ((pininfo->status & PINENTRY_STATUS_PASSWORD_FROM_CACHE)) + { + /* The password was read from the Pinentry's own cache. + Don't count this against the retry count. */ + pininfo->failed_tries--; + } + } + + return unlock_pinentry (ctrl, gpg_error (pininfo->min_digits? GPG_ERR_BAD_PIN + : GPG_ERR_BAD_PASSPHRASE)); } diff --git a/agent/command.c b/agent/command.c index c24fc80..ebbb42c 100644 --- a/agent/command.c +++ b/agent/command.c @@ -1400,9 +1400,22 @@ send_back_passphrase (assuan_context_t ctx, int via_data, const char *pw) } +/* Callback function to compare the first entered PIN with the one + currently being entered. */ +static gpg_error_t +reenter_passphrase_cmp_cb (struct pin_entry_info_s *pi) +{ + const char *pin1 = pi->check_cb_arg; + + if (!strcmp (pin1, pi->pin)) + return 0; /* okay */ + return gpg_error (GPG_ERR_BAD_PASSPHRASE); +} + + static const char hlp_get_passphrase[] = "GET_PASSPHRASE [--data] [--check] [--no-ask] [--repeat[=N]]\n" - " [--qualitybar] <cache_id>\n" + " [--qualitybar] [--newsymkey] <cache_id>\n" " [<error_message> <prompt> <description>]\n" "\n" "This function is usually used to ask for a passphrase to be used\n" @@ -1424,6 +1437,9 @@ static const char hlp_get_passphrase[] = "cache the user will not be asked to enter a passphrase but the error\n" "code GPG_ERR_NO_DATA is returned. \n" "\n" + "If the option\"--newsymkey\" is used the agent asks for a new passphrase\n" + "to be used in symmetric-only encryption. This must not be empty.\n" + "\n" "If the option \"--qualitybar\" is used a visual indication of the\n" "entered passphrase quality is shown. (Unless no minimum passphrase\n" "length has been configured.)"; @@ -1433,13 +1449,19 @@ cmd_get_passphrase (assuan_context_t ctx, char *line) ctrl_t ctrl = assuan_get_pointer (ctx); int rc; char *pw; - char *response; - char *cacheid = NULL, *desc = NULL, *prompt = NULL, *errtext = NULL; + char *response = NULL; + char *response2 = NULL; + char *cacheid = NULL; /* May point into LINE. */ + char *desc = NULL; /* Ditto */ + char *prompt = NULL; /* Ditto */ + char *errtext = NULL; /* Ditto */ const char *desc2 = _("Please re-enter this passphrase"); char *p; - int opt_data, opt_check, opt_no_ask, opt_qualbar; + int opt_data, opt_check, opt_no_ask, opt_qualbar, opt_newsymkey; int opt_repeat = 0; char *entry_errtext = NULL; + struct pin_entry_info_s *pi = NULL; + struct pin_entry_info_s *pi2 = NULL; if (ctrl->restricted) return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN)); @@ -1456,6 +1478,7 @@ cmd_get_passphrase (assuan_context_t ctx, char *line) opt_repeat = 1; } opt_qualbar = has_option (line, "--qualitybar"); + opt_newsymkey = has_option (line, "--newsymkey"); line = skip_options (line); cacheid = line; @@ -1505,26 +1528,116 @@ cmd_get_passphrase (assuan_context_t ctx, char *line) { rc = send_back_passphrase (ctx, opt_data, pw); xfree (pw); + goto leave; } else if (opt_no_ask) - rc = gpg_error (GPG_ERR_NO_DATA); - else { - /* Note, that we only need to replace the + characters and - should leave the other escaping in place because the escaped - string is send verbatim to the pinentry which does the - unescaping (but not the + replacing) */ - if (errtext) - plus_to_blank (errtext); - if (prompt) - plus_to_blank (prompt); - if (desc) - plus_to_blank (desc); + rc = gpg_error (GPG_ERR_NO_DATA); + goto leave; + } + + /* Note, that we only need to replace the + characters and should + * leave the other escaping in place because the escaped string is + * send verbatim to the pinentry which does the unescaping (but not + * the + replacing) */ + if (errtext) + plus_to_blank (errtext); + if (prompt) + plus_to_blank (prompt); + if (desc) + plus_to_blank (desc); + if (opt_newsymkey) + { + /* We do not want to break any existing usage of this command + * and thus we introduced the option --newsymkey to make this + * command more useful to query the passphrase for symmetric + * encryption. */ + pi = gcry_calloc_secure (1, sizeof (*pi) + MAX_PASSPHRASE_LEN + 1); + if (!pi) + { + rc = gpg_error_from_syserror (); + goto leave; + } + pi2 = gcry_calloc_secure (1, sizeof (*pi2) + MAX_PASSPHRASE_LEN + 1); + if (!pi2) + { + rc = gpg_error_from_syserror (); + goto leave; + } + pi->max_length = MAX_PASSPHRASE_LEN + 1; + pi->max_tries = 3; + pi->with_qualitybar = opt_qualbar; + pi->with_repeat = opt_repeat; + pi2->max_length = MAX_PASSPHRASE_LEN + 1; + pi2->max_tries = 3; + pi2->check_cb = reenter_passphrase_cmp_cb; + pi2->check_cb_arg = pi->pin; + + for (;;) /* (degenerated for-loop) */ + { + xfree (response); + response = NULL; + rc = agent_get_passphrase (ctrl, &response, + desc, + prompt, + entry_errtext? entry_errtext:errtext, + opt_qualbar, cacheid, CACHE_MODE_USER, + pi); + if (rc) + goto leave; + xfree (entry_errtext); + entry_errtext = NULL; + /* We don't allow an empty passpharse in this mode. */ + if (check_passphrase_constraints (ctrl, pi->pin, 1, &entry_errtext)) + { + pi->failed_tries = 0; + pi2->failed_tries = 0; + continue; + } + if (*pi->pin && !pi->repeat_okay) + { + /* The passphrase is empty and the pinentry did not + * already run the repetition check, do it here. This + * is only called when using an old and simple pinentry. */ + xfree (response); + response = NULL; + rc = agent_get_passphrase (ctrl, &response, + L_("Please re-enter this passphrase"), + prompt, + entry_errtext? entry_errtext:errtext, + opt_qualbar, cacheid, CACHE_MODE_USER, + pi2); + if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE) + { /* The re-entered passphrase one did not match and + * the user did not hit cancel. */ + entry_errtext = xtrystrdup (L_("does not match - try again")); + if (!entry_errtext) + { + rc = gpg_error_from_syserror (); + goto leave; + } + continue; + } + } + break; + } + if (!rc && *pi->pin) + { + /* Return the passphrase. */ + if (cacheid) + agent_put_cache (ctrl, cacheid, CACHE_MODE_USER, pi->pin, 0); + rc = send_back_passphrase (ctx, opt_data, pi->pin); + } + } + else + { next_try: + xfree (response); + response = NULL; rc = agent_get_passphrase (ctrl, &response, desc, prompt, entry_errtext? entry_errtext:errtext, - opt_qualbar, cacheid, CACHE_MODE_USER); + opt_qualbar, cacheid, CACHE_MODE_USER, NULL); xfree (entry_errtext); entry_errtext = NULL; if (!rc) @@ -1532,27 +1645,24 @@ cmd_get_passphrase (assuan_context_t ctx, char *line) int i; if (opt_check - && check_passphrase_constraints (ctrl, response, &entry_errtext)) + && check_passphrase_constraints (ctrl, response,0,&entry_errtext)) { - xfree (response); goto next_try; } for (i = 0; i < opt_repeat; i++) { - char *response2; - if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK) break; + xfree (response2); + response2 = NULL; rc = agent_get_passphrase (ctrl, &response2, desc2, prompt, errtext, 0, - cacheid, CACHE_MODE_USER); + cacheid, CACHE_MODE_USER, NULL); if (rc) break; if (strcmp (response2, response)) { - xfree (response2); - xfree (response); entry_errtext = try_percent_escape (_("does not match - try again"), NULL); if (!entry_errtext) @@ -1562,7 +1672,6 @@ cmd_get_passphrase (assuan_context_t ctx, char *line) } goto next_try; } - xfree (response2); } if (!rc) { @@ -1570,10 +1679,15 @@ cmd_get_passphrase (assuan_context_t ctx, char *line) agent_put_cache (ctrl, cacheid, CACHE_MODE_USER, response, 0); rc = send_back_passphrase (ctx, opt_data, response); } - xfree (response); } } + leave: + xfree (response); + xfree (response2); + xfree (entry_errtext); + xfree (pi2); + xfree (pi); return leave_cmd (ctx, rc); } @@ -3233,7 +3347,9 @@ command_has_option (const char *cmd, const char *cmdopt) if (!strcmp (cmd, "GET_PASSPHRASE")) { if (!strcmp (cmdopt, "repeat")) - return 1; + return 1; + if (!strcmp (cmdopt, "newsymkey")) + return 1; } return 0; diff --git a/agent/cvt-openpgp.c b/agent/cvt-openpgp.c index bf05174..06cd1c8 100644 --- a/agent/cvt-openpgp.c +++ b/agent/cvt-openpgp.c @@ -878,11 +878,11 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp, int dontcare_exist, log_debug ("XXX pubkey_algo=%d\n", pubkey_algo); log_debug ("XXX is_protected=%d\n", is_protected); log_debug ("XXX protect_algo=%d\n", protect_algo); - log_printhex ("XXX iv", iv, ivlen); + log_printhex (iv, ivlen, "XXX iv"); log_debug ("XXX ivlen=%d\n", ivlen); log_debug ("XXX s2k_mode=%d\n", s2k_mode); log_debug ("XXX s2k_algo=%d\n", s2k_algo); - log_printhex ("XXX s2k_salt", s2k_salt, sizeof s2k_salt); + log_printhex (s2k_salt, sizeof s2k_salt, "XXX s2k_salt"); log_debug ("XXX s2k_count=%lu\n", (unsigned long)s2k_count); log_debug ("XXX curve='%s'\n", curve); for (idx=0; skey[idx]; idx++) diff --git a/agent/divert-scd.c b/agent/divert-scd.c index 191ed7f..b79f7a8 100644 --- a/agent/divert-scd.c +++ b/agent/divert-scd.c @@ -169,7 +169,7 @@ encode_md_for_card (const unsigned char *digest, size_t digestlen, int algo, memcpy (frame, asn, asnlen); memcpy (frame+asnlen, digest, digestlen); if (DBG_CRYPTO) - log_printhex ("encoded hash:", frame, asnlen+digestlen); + log_printhex (frame, asnlen+digestlen, "encoded hash:"); *r_val = frame; *r_len = asnlen+digestlen; diff --git a/agent/genkey.c b/agent/genkey.c index d5c80d0..cddd67d 100644 --- a/agent/genkey.c +++ b/agent/genkey.c @@ -179,7 +179,7 @@ take_this_one_anyway (ctrl_t ctrl, const char *desc) message describing the problem is returned in *FAILED_CONSTRAINT. */ int -check_passphrase_constraints (ctrl_t ctrl, const char *pw, +check_passphrase_constraints (ctrl_t ctrl, const char *pw, int no_empty, char **failed_constraint) { gpg_error_t err = 0; @@ -198,7 +198,7 @@ check_passphrase_constraints (ctrl_t ctrl, const char *pw, /* The first check is to warn about an empty passphrase. */ if (!*pw) { - const char *desc = (opt.enforce_passphrase_constraints? + const char *desc = (opt.enforce_passphrase_constraints || no_empty? L_("You have not entered a passphrase!%0A" "An empty passphrase is not allowed.") : L_("You have not entered a passphrase - " @@ -209,7 +209,7 @@ check_passphrase_constraints (ctrl_t ctrl, const char *pw, err = 1; if (failed_constraint) { - if (opt.enforce_passphrase_constraints) + if (opt.enforce_passphrase_constraints || no_empty) *failed_constraint = xstrdup (desc); else err = take_this_one_anyway2 (ctrl, desc, @@ -386,7 +386,7 @@ agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt, } pi->max_length = MAX_PASSPHRASE_LEN + 1; pi->max_tries = 3; - pi->with_qualitybar = 1; + pi->with_qualitybar = 0; pi->with_repeat = 1; pi2->max_length = MAX_PASSPHRASE_LEN + 1; pi2->max_tries = 3; @@ -399,7 +399,7 @@ agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt, initial_errtext = NULL; if (!err) { - if (check_passphrase_constraints (ctrl, pi->pin, &initial_errtext)) + if (check_passphrase_constraints (ctrl, pi->pin, 0, &initial_errtext)) { pi->failed_tries = 0; pi2->failed_tries = 0; diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c index 27cb70c..3dcbbf8 100644 --- a/agent/gpg-agent.c +++ b/agent/gpg-agent.c @@ -2618,7 +2618,7 @@ putty_message_proc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) if (!data) goto leave; - /* log_printhex ("request:", data, 20); */ + /* log_printhex (data, 20, "request:"); */ ctrl = xtrycalloc (1, sizeof *ctrl); if (!ctrl) @@ -2639,7 +2639,7 @@ putty_message_proc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) if (!serve_mmapped_ssh_request (ctrl, data, PUTTY_IPC_MAXLEN)) ret = 1; /* Valid ssh message has been constructed. */ agent_deinit_default_ctrl (ctrl); - /* log_printhex (" reply:", data, 20); */ + /* log_printhex (data, 20, " reply:"); */ leave: xfree (ctrl); diff --git a/agent/pkdecrypt.c b/agent/pkdecrypt.c index 46697ba..06a8e0b 100644 --- a/agent/pkdecrypt.c +++ b/agent/pkdecrypt.c @@ -64,8 +64,8 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text, if (DBG_CRYPTO) { - log_printhex ("keygrip:", ctrl->keygrip, 20); - log_printhex ("cipher: ", ciphertext, ciphertextlen); + log_printhex (ctrl->keygrip, 20, "keygrip:"); + log_printhex (ciphertext, ciphertextlen, "cipher: "); } rc = agent_key_from_file (ctrl, NULL, desc_text, ctrl->keygrip, &shadow_info, diff --git a/agent/protect-tool.c b/agent/protect-tool.c index 3bba5c6..00c0748 100644 --- a/agent/protect-tool.c +++ b/agent/protect-tool.c @@ -316,6 +316,11 @@ read_key (const char *fname) buf = read_file (fname, &buflen); if (!buf) return NULL; + if (buflen >= 4 && !memcmp (buf, "Key:", 4)) + { + log_error ("Extended key format is not supported by this tool\n"); + return NULL; + } key = make_canonical (fname, buf, buflen); xfree (buf); return key; diff --git a/common/audit.c b/common/audit.c index 179bf72..718f729 100644 --- a/common/audit.c +++ b/common/audit.c @@ -1105,6 +1105,7 @@ proc_type_verify (audit_ctx_t ctx) switch (gpg_err_code (item->err)) { case 0: ok = "good"; break; + case GPG_ERR_TRUE: ok = "n/a"; break; case GPG_ERR_CERT_REVOKED: ok = "bad"; break; case GPG_ERR_NOT_ENABLED: ok = "disabled"; break; case GPG_ERR_NO_CRL_KNOWN: diff --git a/common/compliance.c b/common/compliance.c index 49aada1..7dbbbd3 100644 --- a/common/compliance.c +++ b/common/compliance.c @@ -96,6 +96,7 @@ gnupg_initialize_compliance (int gnupg_module_name) * both are compatible from the point of view of this function. */ int gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo, + unsigned int algo_flags, gcry_mpi_t key[], unsigned int keylength, const char *curvename) { @@ -148,6 +149,10 @@ gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo, result = (keylength == 2048 || keylength == 3072 || keylength == 4096); + /* rsaPSS was not part of the evaluation and thus we don't + * claim compliance. */ + if ((algo_flags & PK_ALGO_FLAG_RSAPSS)) + result = 0; break; case is_dsa: @@ -197,7 +202,8 @@ gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo, * they produce, and liberal in what they accept. */ int gnupg_pk_is_allowed (enum gnupg_compliance_mode compliance, - enum pk_use_case use, int algo, gcry_mpi_t key[], + enum pk_use_case use, int algo, + unsigned int algo_flags, gcry_mpi_t key[], unsigned int keylength, const char *curvename) { int result = 0; @@ -228,6 +234,10 @@ gnupg_pk_is_allowed (enum gnupg_compliance_mode compliance, default: log_assert (!"reached"); } + /* rsaPSS was not part of the evaluation and thus we don't + * claim compliance. */ + if ((algo_flags & PK_ALGO_FLAG_RSAPSS)) + result = 0; break; case PUBKEY_ALGO_DSA: diff --git a/common/compliance.h b/common/compliance.h index 2076e79..21bd230 100644 --- a/common/compliance.h +++ b/common/compliance.h @@ -48,11 +48,17 @@ enum pk_use_case PK_USE_SIGNING, PK_USE_VERIFICATION, }; +/* Flags to distinguish public key algorithm variants. */ +#define PK_ALGO_FLAG_RSAPSS 1 /* Use rsaPSS padding. */ + + int gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo, + unsigned int algo_flags, gcry_mpi_t key[], unsigned int keylength, const char *curvename); int gnupg_pk_is_allowed (enum gnupg_compliance_mode compliance, - enum pk_use_case use, int algo, gcry_mpi_t key[], + enum pk_use_case use, int algo, + unsigned int algo_flags, gcry_mpi_t key[], unsigned int keylength, const char *curvename); int gnupg_cipher_is_compliant (enum gnupg_compliance_mode compliance, cipher_algo_t cipher, diff --git a/common/logging.c b/common/logging.c index df55e68..7fe8b74 100644 --- a/common/logging.c +++ b/common/logging.c @@ -1011,10 +1011,17 @@ log_flush (void) dump, with TEXT just an empty string, print a trailing linefeed, otherwise print an entire debug line. */ void -log_printhex (const char *text, const void *buffer, size_t length) +log_printhex (const void *buffer, size_t length, const char *fmt, ...) { - if (text && *text) - log_debug ("%s ", text); + if (fmt && *fmt) + { + va_list arg_ptr ; + + va_start (arg_ptr, fmt); + do_logv (GPGRT_LOG_DEBUG, 0, NULL, NULL, fmt, arg_ptr); + va_end (arg_ptr); + log_printf (" "); + } if (length) { const unsigned char *p = buffer; @@ -1022,7 +1029,7 @@ log_printhex (const char *text, const void *buffer, size_t length) for (length--, p++; length--; p++) log_printf (" %02X", *p); } - if (text) + if (fmt) log_printf ("\n"); } diff --git a/common/logging.h b/common/logging.h index 2225100..cb1ec11 100644 --- a/common/logging.h +++ b/common/logging.h @@ -103,11 +103,12 @@ void log_debug_with_string (const char *string, const char *fmt, void log_printf (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2); void log_flush (void); -/* Print a hexdump of BUFFER. With TEXT passes as NULL print just the - raw dump, with TEXT being an empty string, print a trailing - linefeed, otherwise print an entire debug line with TEXT followed - by the hexdump and a final LF. */ -void log_printhex (const char *text, const void *buffer, size_t length); +/* Print a hexdump of BUFFER. With FMT passed as NULL print just the + * raw dump, with FMT being an empty string, print a trailing + * linefeed, otherwise print an entire debug line with expanded FMT + * followed by the hexdump and a final LF. */ +void log_printhex (const void *buffer, size_t length, + const char *fmt, ...) GPGRT_ATTR_PRINTF(3,4); void log_clock (const char *string); diff --git a/common/openpgpdefs.h b/common/openpgpdefs.h index 4dcfc25..5cc437a 100644 --- a/common/openpgpdefs.h +++ b/common/openpgpdefs.h @@ -51,6 +51,7 @@ typedef enum PKT_ATTRIBUTE = 17, /* PGP's attribute packet. */ PKT_ENCRYPTED_MDC = 18, /* Integrity protected encrypted data. */ PKT_MDC = 19, /* Manipulation detection code packet. */ + PKT_ENCRYPTED_AEAD= 20, /* AEAD encrypted data packet. */ PKT_COMMENT = 61, /* new comment packet (GnuPG specific). */ PKT_GPG_CONTROL = 63 /* internal control packet (GnuPG specific). */ } @@ -125,6 +126,16 @@ typedef enum sigsubpkttype_t; +/* Note that we encode the AEAD algo in a 3 bit field at some places. */ +typedef enum + { + AEAD_ALGO_NONE = 0, + AEAD_ALGO_EAX = 1, + AEAD_ALGO_OCB = 2 + } +aead_algo_t; + + typedef enum { CIPHER_ALGO_NONE = 0, diff --git a/common/percent.c b/common/percent.c index 569c5fd..224de78 100644 --- a/common/percent.c +++ b/common/percent.c @@ -87,6 +87,89 @@ percent_plus_escape (const char *string) } +/* Create a newly malloced string from (DATA,DATALEN) with embedded + * nuls quoted as %00. The standard percent unescaping can be used to + * reverse this encoding. With PLUS_ESCAPE set plus-escaping (spaces + * are replaced by a '+') and escaping of characters with values less + * than 0x20 is used. If PREFIX is not NULL it will be prepended to + * the output in standard escape format; that is PLUS_ESCAPING is + * ignored for PREFIX. */ +char * +percent_data_escape (int plus_escape, const char *prefix, + const void *data, size_t datalen) +{ + char *buffer, *p; + const unsigned char *s; + size_t n; + size_t length = 1; + + if (prefix) + { + for (s = prefix; *s; s++) + { + if (*s == '%' || *s < 0x20) + length += 3; + else + length++; + } + } + + for (s=data, n=datalen; n; s++, n--) + { + if (!*s || *s == '%' || (plus_escape && (*s < ' ' || *s == '+'))) + length += 3; + else + length++; + } + + buffer = p = xtrymalloc (length); + if (!buffer) + return NULL; + + if (prefix) + { + for (s = prefix; *s; s++) + { + if (*s == '%' || *s < 0x20) + { + snprintf (p, 4, "%%%02X", *s); + p += 3; + } + else + *p++ = *s; + } + } + + for (s=data, n=datalen; n; s++, n--) + { + if (!*s) + { + memcpy (p, "%00", 3); + p += 3; + } + else if (*s == '%') + { + memcpy (p, "%25", 3); + p += 3; + } + else if (plus_escape && *s == ' ') + { + *p++ = '+'; + } + else if (plus_escape && (*s < ' ' || *s == '+')) + { + snprintf (p, 4, "%%%02X", *s); + p += 3; + } + else + *p++ = *s; + } + *p = 0; + + return buffer; +} + + /* Do the percent and plus/space unescaping from STRING to BUFFER and return the length of the valid buffer. Plus unescaping is only done if WITHPLUS is true. An escaped Nul character will be diff --git a/common/sexputil.c b/common/sexputil.c index e8c8a34..9a79c05 100644 --- a/common/sexputil.c +++ b/common/sexputil.c @@ -640,3 +640,61 @@ pubkey_algo_string (gcry_sexp_t s_pkey, enum gcry_pk_algos *r_algoid) xfree (algoname); return result; } + + +/* Map a pubkey algo id from gcrypt to a string. This is the same as + * gcry_pk_algo_name but makes sure that the ECC algo identifiers are + * not all mapped to "ECC". */ +const char * +pubkey_algo_to_string (int algo) +{ + if (algo == GCRY_PK_ECDSA) + return "ECDSA"; + else if (algo == GCRY_PK_ECDH) + return "ECDH"; + else if (algo == GCRY_PK_EDDSA) + return "EdDSA"; + else + return gcry_pk_algo_name (algo); +} + + +/* Map a hash algo id from gcrypt to a string. This is the same as + * gcry_md_algo_name but the returned string is lower case, as + * expected by libksba and it avoids some overhead. */ +const char * +hash_algo_to_string (int algo) +{ + static const struct + { + const char *name; + int algo; + } hashnames[] = + { + { "sha256", GCRY_MD_SHA256 }, + { "sha512", GCRY_MD_SHA512 }, + { "sha1", GCRY_MD_SHA1 }, + { "sha384", GCRY_MD_SHA384 }, + { "sha224", GCRY_MD_SHA224 }, + { "sha3-224", GCRY_MD_SHA3_224 }, + { "sha3-256", GCRY_MD_SHA3_256 }, + { "sha3-384", GCRY_MD_SHA3_384 }, + { "sha3-512", GCRY_MD_SHA3_512 }, + { "ripemd160", GCRY_MD_RMD160 }, + { "rmd160", GCRY_MD_RMD160 }, + { "md2", GCRY_MD_MD2 }, + { "md4", GCRY_MD_MD4 }, + { "tiger", GCRY_MD_TIGER }, + { "haval", GCRY_MD_HAVAL }, +#if GCRYPT_VERSION_NUMBER >= 0x010900 + { "sm3", GCRY_MD_SM3 }, +#endif + { "md5", GCRY_MD_MD5 } + }; + int i; + + for (i=0; i < DIM (hashnames); i++) + if (algo == hashnames[i].algo) + return hashnames[i].name; + return "?"; +} diff --git a/common/util.h b/common/util.h index 4d763f0..fd8a7dc 100644 --- a/common/util.h +++ b/common/util.h @@ -35,10 +35,19 @@ #include <errno.h> /* We need errno. */ #include <gpg-error.h> /* We need gpg_error_t and estream. */ -/* These error codes are used but not defined in the required +/* These error codes might be used but not defined in the required * libgpg-error version. Define them here. * Example: (#if GPG_ERROR_VERSION_NUMBER < 0x011500 // 1.21) */ +#if GPG_ERROR_VERSION_NUMBER < 0x012400 /* 1.36 */ +# define GPG_ERR_NO_AUTH 314 +# define GPG_ERR_BAD_AUTH 315 +#endif + +#if GPG_ERROR_VERSION_NUMBER < 0x011b00 /* 1.27 */ +# define GPG_ERR_WRONG_NAME 313 +#endif + #if GPG_ERROR_VERSION_NUMBER < 0x011a00 /* 1.26 */ # define GPG_ERR_UNKNOWN_FLAG 309 # define GPG_ERR_INV_ORDER 310 @@ -66,6 +75,11 @@ /* Hash function used with libksba. */ #define HASH_FNC ((void (*)(void *, const void*,size_t))gcry_md_write) +/* The length of the keygrip. This is a SHA-1 hash of the key + * parameters as generated by gcry_pk_get_keygrip. */ +#define KEYGRIP_LEN 20 + + /* Get all the stuff from jnlib. */ #include "../common/logging.h" #include "../common/argparse.h" @@ -207,6 +221,8 @@ int get_pk_algo_from_key (gcry_sexp_t key); int get_pk_algo_from_canon_sexp (const unsigned char *keydata, size_t keydatalen); char *pubkey_algo_string (gcry_sexp_t s_pkey, enum gcry_pk_algos *r_algoid); +const char *pubkey_algo_to_string (int algo); +const char *hash_algo_to_string (int algo); /*-- convert.c --*/ int hex2bin (const char *string, void *buffer, size_t length); @@ -219,6 +235,8 @@ char *hex2str_alloc (const char *hexstring, size_t *r_count); /*-- percent.c --*/ char *percent_plus_escape (const char *string); +char *percent_data_escape (int plus_escape, const char *prefix, + const void *data, size_t datalen); char *percent_plus_unescape (const char *string, int nulrepl); char *percent_unescape (const char *string, int nulrepl); diff --git a/configure.ac b/configure.ac index f3c9863..1d05d39 100644 --- a/configure.ac +++ b/configure.ac @@ -29,7 +29,7 @@ min_automake_version="1.14" m4_define([mym4_package],[gnupg]) m4_define([mym4_major], [2]) m4_define([mym4_minor], [2]) -m4_define([mym4_micro], [20]) +m4_define([mym4_micro], [21]) # To start a new development series, i.e a new major or minor number # you need to mark an arbitrary commit before the first beta release @@ -54,7 +54,7 @@ AC_INIT([mym4_package],[mym4_version], [https://bugs.gnupg.org]) # build-aux/speedo.mk and Makefile.am AC_DEFINE_UNQUOTED(GNUPG_SWDB_TAG, "gnupg22", [swdb tag for this branch]) -NEED_GPG_ERROR_VERSION=1.24 +NEED_GPG_ERROR_VERSION=1.25 NEED_LIBGCRYPT_API=1 NEED_LIBGCRYPT_VERSION=1.7.0 @@ -1220,6 +1220,8 @@ elif test x"$with_mailprog" != xno ; then AC_SUBST(SENDMAIL,$with_mailprog) AC_MSG_RESULT($with_mailprog) fi +AC_DEFINE_UNQUOTED(NAME_OF_SENDMAIL,"$SENDMAIL", + [Tool with sendmail -t interface]) # @@ -1638,7 +1640,7 @@ if test "$GCC" = yes; then AC_MSG_RESULT($_gcc_wopt) fi if test x"$_gcc_wopt" = xyes ; then - mycflags="$mycflags -W -Wno-sign-compare" + mycflags="$mycflags -W -Wno-sign-compare -Wno-format-zero-length" mycflags="$mycflags -Wno-missing-field-initializers" fi diff --git a/dirmngr/crlcache.c b/dirmngr/crlcache.c index 52f49c0..cd35335 100644 --- a/dirmngr/crlcache.c +++ b/dirmngr/crlcache.c @@ -1351,7 +1351,7 @@ cache_isvalid (ctrl_t ctrl, const char *issuer_hash, { log_error (_("WARNING: invalid cache record length for S/N ")); log_printf ("0x"); - log_printhex ("", sn, snlen); + log_printhex (sn, snlen, ""); } else if (opt.verbose) { @@ -1531,17 +1531,104 @@ crl_cache_cert_isvalid (ctrl_t ctrl, ksba_cert_t cert, } +/* Return the hash algorithm's algo id from its name given in the + * non-null termnated string in (buffer,buflen). Returns 0 on failure + * or if the algo is not known. */ +static int +hash_algo_from_buffer (const void *buffer, size_t buflen) +{ + char *string; + int algo; + + string = xtrymalloc (buflen + 1); + if (!string) + { + log_error (_("out of core\n")); + return 0; + } + memcpy (string, buffer, buflen); + string[buflen] = 0; + algo = gcry_md_map_name (string); + if (!algo) + log_error ("unknown digest algorithm '%s' used in certificate\n", string); + xfree (string); + return algo; +} + + +/* Return an unsigned integer from the non-null termnated string + * (buffer,buflen). Returns 0 on failure. */ +static unsigned int +uint_from_buffer (const void *buffer, size_t buflen) +{ + char *string; + unsigned int val; + + string = xtrymalloc (buflen + 1); + if (!string) + { + log_error (_("out of core\n")); + return 0; + } + memcpy (string, buffer, buflen); + string[buflen] = 0; + val = strtoul (string, NULL, 10); + xfree (string); + return val; +} + + /* Prepare a hash context for the signature verification. Input is the CRL and the output is the hash context MD as well as the uses algorithm identifier ALGO. */ static gpg_error_t -start_sig_check (ksba_crl_t crl, gcry_md_hd_t *md, int *algo) +start_sig_check (ksba_crl_t crl, gcry_md_hd_t *md, int *algo, int *use_pss) { gpg_error_t err; const char *algoid; + *use_pss = 0; algoid = ksba_crl_get_digest_algo (crl); - *algo = gcry_md_map_name (algoid); + if (algoid && !strcmp (algoid, "1.2.840.113549.1.1.10")) + { + /* Parse rsaPSS parameter. */ + gcry_buffer_t ioarray[1] = { {0} }; + ksba_sexp_t pssparam; + size_t n; + gcry_sexp_t psssexp; + + pssparam = ksba_crl_get_sig_val (crl); + n = gcry_sexp_canon_len (pssparam, 0, NULL, NULL); + if (!n) + { + ksba_free (pssparam); + log_error (_("got an invalid S-expression from libksba\n")); + return gpg_error (GPG_ERR_INV_SEXP); + } + err = gcry_sexp_sscan (&psssexp, NULL, pssparam, n); + ksba_free (pssparam); + if (err) + { + log_error (_("converting S-expression failed: %s\n"), + gcry_strerror (err)); + return err; + } + + err = gcry_sexp_extract_param (psssexp, "sig-val", + "&'hash-algo'", ioarray, NULL); + gcry_sexp_release (psssexp); + if (err) + { + log_error ("extracting params from PSS failed: %s\n", + gpg_strerror (err)); + return err; + } + *algo = hash_algo_from_buffer (ioarray[0].data, ioarray[0].len); + xfree (ioarray[0].data); + *use_pss = 1; + } + else + *algo = gcry_md_map_name (algoid); if (!*algo) { log_error (_("unknown hash algorithm '%s'\n"), algoid? algoid:"?"); @@ -1570,15 +1657,13 @@ start_sig_check (ksba_crl_t crl, gcry_md_hd_t *md, int *algo) certificate of the CRL issuer. This function takes ownership of MD. */ static gpg_error_t finish_sig_check (ksba_crl_t crl, gcry_md_hd_t md, int algo, - ksba_cert_t issuer_cert) + ksba_cert_t issuer_cert, int use_pss) { gpg_error_t err; ksba_sexp_t sigval = NULL, pubkey = NULL; - const char *s; - char algoname[50]; size_t n; gcry_sexp_t s_sig = NULL, s_hash = NULL, s_pkey = NULL; - unsigned int i; + unsigned int saltlen = 0; /* (used only with use_pss) */ /* This also stops debugging on the MD. */ gcry_md_final (md); @@ -1600,6 +1685,78 @@ finish_sig_check (ksba_crl_t crl, gcry_md_hd_t md, int algo, goto leave; } + if (use_pss) + { + /* Parse rsaPSS parameter which we should find in S_SIG. */ + gcry_buffer_t ioarray[2] = { {0}, {0} }; + ksba_sexp_t pssparam; + gcry_sexp_t psssexp; + int hashalgo; + + pssparam = ksba_crl_get_sig_val (crl); + n = gcry_sexp_canon_len (pssparam, 0, NULL, NULL); + if (!n) + { + ksba_free (pssparam); + log_error (_("got an invalid S-expression from libksba\n")); + err = gpg_error (GPG_ERR_INV_SEXP); + goto leave; + } + err = gcry_sexp_sscan (&psssexp, NULL, pssparam, n); + ksba_free (pssparam); + if (err) + { + log_error (_("converting S-expression failed: %s\n"), + gcry_strerror (err)); + goto leave; + } + + err = gcry_sexp_extract_param (psssexp, "sig-val", + "&'hash-algo''salt-length'", + ioarray+0, ioarray+1, NULL); + gcry_sexp_release (psssexp); + if (err) + { + log_error ("extracting params from PSS failed: %s\n", + gpg_strerror (err)); + goto leave; + } + hashalgo = hash_algo_from_buffer (ioarray[0].data, ioarray[0].len); + saltlen = uint_from_buffer (ioarray[1].data, ioarray[1].len); + xfree (ioarray[0].data); + xfree (ioarray[1].data); + if (hashalgo != algo) + { + log_error ("hash algo mismatch: %d announced but %d used\n", + algo, hashalgo); + return gpg_error (GPG_ERR_INV_CRL); + } + /* Add some restrictions; see ../sm/certcheck.c for details. */ + switch (algo) + { + case GCRY_MD_SHA1: + case GCRY_MD_SHA256: + case GCRY_MD_SHA384: + case GCRY_MD_SHA512: + case GCRY_MD_SHA3_256: + case GCRY_MD_SHA3_384: + case GCRY_MD_SHA3_512: + break; + default: + log_error ("PSS hash algorithm '%s' rejected\n", + gcry_md_algo_name (algo)); + return gpg_error (GPG_ERR_DIGEST_ALGO); + } + + if (gcry_md_get_algo_dlen (algo) != saltlen) + { + log_error ("PSS hash algorithm '%s' rejected due to salt length %u\n", + gcry_md_algo_name (algo), saltlen); + return gpg_error (GPG_ERR_DIGEST_ALGO); + } + } + + /* Get and convert the public key for the issuer certificate. */ if (DBG_X509) dump_cert ("crl_issuer_cert", issuer_cert); @@ -1620,13 +1777,25 @@ finish_sig_check (ksba_crl_t crl, gcry_md_hd_t md, int algo, } /* Create an S-expression with the actual hash value. */ - s = gcry_md_algo_name (algo); - for (i = 0; *s && i < sizeof(algoname) - 1; s++, i++) - algoname[i] = ascii_tolower (*s); - algoname[i] = 0; - err = gcry_sexp_build (&s_hash, NULL, "(data(flags pkcs1)(hash %s %b))", - algoname, - gcry_md_get_algo_dlen (algo), gcry_md_read (md, algo)); + if (use_pss) + { + err = gcry_sexp_build (&s_hash, NULL, + "(data (flags pss)" + "(hash %s %b)" + "(salt-length %u))", + hash_algo_to_string (algo), + (int)gcry_md_get_algo_dlen (algo), + gcry_md_read (md, algo), + saltlen); + } + else + { + err = gcry_sexp_build (&s_hash, NULL, + "(data(flags pkcs1)(hash %s %b))", + hash_algo_to_string (algo), + (int)gcry_md_get_algo_dlen (algo), + gcry_md_read (md, algo)); + } if (err) { log_error (_("creating S-expression failed: %s\n"), gcry_strerror (err)); @@ -1688,6 +1857,7 @@ crl_parse_insert (ctrl_t ctrl, ksba_crl_t crl, ksba_cert_t crlissuer_cert = NULL; gcry_md_hd_t md = NULL; int algo = 0; + int use_pss = 0; size_t n; (void)fname; @@ -1710,7 +1880,7 @@ crl_parse_insert (ctrl_t ctrl, ksba_crl_t crl, { case KSBA_SR_BEGIN_ITEMS: { - err = start_sig_check (crl, &md, &algo); + err = start_sig_check (crl, &md, &algo, &use_pss); if (err) goto failure; @@ -1847,7 +2017,7 @@ crl_parse_insert (ctrl_t ctrl, ksba_crl_t crl, goto failure; } - err = finish_sig_check (crl, md, algo, crlissuer_cert); + err = finish_sig_check (crl, md, algo, crlissuer_cert, use_pss); md = NULL; /* Closed. */ if (err) { diff --git a/dirmngr/crlfetch.c b/dirmngr/crlfetch.c index 57ac51b..7da3d8b 100644 --- a/dirmngr/crlfetch.c +++ b/dirmngr/crlfetch.c @@ -408,40 +408,124 @@ end_cert_fetch (cert_fetch_context_t context) } +/* Read a certificate from an HTTP URL and return it as an estream + * memory buffer at R_FP. */ +static gpg_error_t +read_cert_via_http (ctrl_t ctrl, const char *url, estream_t *r_fp) +{ + gpg_error_t err; + estream_t fp = NULL; + estream_t httpfp = NULL; + size_t nread, nwritten; + char buffer[1024]; + + if ((err = ks_http_fetch (ctrl, url, KS_HTTP_FETCH_TRUST_CFG, &httpfp))) + goto leave; + + /* We now read the data from the web server into a memory buffer. + * To DOS we limit the certificate length to 32k. */ + fp = es_fopenmem (32*1024, "rw"); + if (!fp) + { + err = gpg_error_from_syserror (); + log_error ("error allocating memory buffer: %s\n", gpg_strerror (err)); + goto leave; + } + + for (;;) + { + if (es_read (httpfp, buffer, sizeof buffer, &nread)) + { + err = gpg_error_from_syserror (); + log_error ("error reading '%s': %s\n", + es_fname_get (httpfp), gpg_strerror (err)); + goto leave; + } + + if (!nread) + break; /* Ready. */ + if (es_write (fp, buffer, nread, &nwritten)) + { + err = gpg_error_from_syserror (); + log_error ("error writing '%s': %s\n", + es_fname_get (fp), gpg_strerror (err)); + goto leave; + } + else if (nread != nwritten) + { + err = gpg_error (GPG_ERR_EIO); + log_error ("error writing '%s': %s\n", + es_fname_get (fp), "short write"); + goto leave; + } + } + + es_rewind (fp); + *r_fp = fp; + fp = NULL; + + leave: + es_fclose (httpfp); + es_fclose (fp); + return err; +} + + /* Lookup a cert by it's URL. */ gpg_error_t fetch_cert_by_url (ctrl_t ctrl, const char *url, unsigned char **value, size_t *valuelen) { - const unsigned char *cert_image; + const unsigned char *cert_image = NULL; size_t cert_image_n; - ksba_reader_t reader; - ksba_cert_t cert; + ksba_reader_t reader = NULL; + ksba_cert_t cert = NULL; gpg_error_t err; *value = NULL; *valuelen = 0; - cert_image = NULL; - reader = NULL; - cert = NULL; - -#if USE_LDAP - err = url_fetch_ldap (ctrl, url, NULL, 0, &reader); -#else - (void)ctrl; - (void)url; - err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); -#endif /*USE_LDAP*/ - if (err) - goto leave; err = ksba_cert_new (&cert); if (err) goto leave; - err = ksba_cert_read_der (cert, reader); - if (err) - goto leave; + if (url && (!strncmp (url, "http:", 5) || !strncmp (url, "https:", 6))) + { + estream_t stream; + void *der; + size_t derlen; + + err = read_cert_via_http (ctrl, url, &stream); + if (err) + goto leave; + + if (es_fclose_snatch (stream, &der, &derlen)) + { + err = gpg_error_from_syserror (); + goto leave; + } + + err = ksba_cert_init_from_mem (cert, der, derlen); + xfree (der); + if (err) + goto leave; + } + else /* Assume LDAP. */ + { +#if USE_LDAP + err = url_fetch_ldap (ctrl, url, NULL, 0, &reader); +#else + (void)ctrl; + (void)url; + err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); +#endif /*USE_LDAP*/ + if (err) + goto leave; + + err = ksba_cert_read_der (cert, reader); + if (err) + goto leave; + } cert_image = ksba_cert_get_image (cert, &cert_image_n); if (!cert_image || !cert_image_n) @@ -461,7 +545,6 @@ fetch_cert_by_url (ctrl_t ctrl, const char *url, *valuelen = cert_image_n; leave: - ksba_cert_release (cert); #if USE_LDAP ldap_wrapper_release_context (reader); diff --git a/dirmngr/dirmngr.c b/dirmngr/dirmngr.c index 3ec6139..3beaab8 100644 --- a/dirmngr/dirmngr.c +++ b/dirmngr/dirmngr.c @@ -373,7 +373,7 @@ static npth_key_t my_tlskey_current_fd; /* Prototypes. */ static void cleanup (void); #if USE_LDAP -static ldap_server_t parse_ldapserver_file (const char* filename); +static ldap_server_t parse_ldapserver_file (const char* filename, int ienoent); #endif /*USE_LDAP*/ static fingerprint_list_t parse_ocsp_signer (const char *string); static void netactivity_action (void); @@ -1100,11 +1100,11 @@ main (int argc, char **argv) ldapfile = make_filename (gnupg_homedir (), "dirmngr_ldapservers.conf", NULL); - opt.ldapservers = parse_ldapserver_file (ldapfile); + opt.ldapservers = parse_ldapserver_file (ldapfile, 1); xfree (ldapfile); } else - opt.ldapservers = parse_ldapserver_file (ldapfile); + opt.ldapservers = parse_ldapserver_file (ldapfile, 0); #endif /*USE_LDAP*/ #ifndef HAVE_W32_SYSTEM @@ -1618,7 +1618,7 @@ dirmngr_deinit_default_ctrl (ctrl_t ctrl) */ #if USE_LDAP static ldap_server_t -parse_ldapserver_file (const char* filename) +parse_ldapserver_file (const char* filename, int ignore_enoent) { char buffer[1024]; char *p; @@ -1631,7 +1631,10 @@ parse_ldapserver_file (const char* filename) if (!fp) { if (errno == ENOENT) - log_info ("No ldapserver file at: '%s'\n", filename); + { + if (!ignore_enoent) + log_info ("No ldapserver file at: '%s'\n", filename); + } else log_error (_("error opening '%s': %s\n"), filename, strerror (errno)); diff --git a/dirmngr/dns.c b/dirmngr/dns.c index 4c3b559..43845eb 100644 --- a/dirmngr/dns.c +++ b/dirmngr/dns.c @@ -2150,6 +2150,7 @@ static size_t dns_p_lines_fmt(void *dst, size_t lim, dns_error_t *_error, const static size_t dns_p_lines(void *dst, size_t lim, dns_error_t *_error, struct dns_packet *P, struct dns_rr_i *I, struct dns_p_lines_i *state) { int error, pc; size_t len; + char __dst[DNS_STRMAXLEN + 1] = { 0 }; *_error = 0; @@ -2168,7 +2169,7 @@ static size_t dns_p_lines(void *dst, size_t lim, dns_error_t *_error, struct dns while (dns_rr_grep(&state->rr, 1, I, P, &error)) { if (state->section != state->rr.section) { DNS_P_LINE("\n"); - DNS_P_LINE(";; [%s:%d]\n", dns_strsection(state->rr.section), dns_p_count(P, state->rr.section)); + DNS_P_LINE(";; [%s:%d]\n", dns_strsection(state->rr.section, __dst), dns_p_count(P, state->rr.section)); } if (!(len = dns_rr_print(dst, lim, &state->rr, P, &error))) @@ -3274,6 +3275,7 @@ size_t dns_rr_print(void *_dst, size_t lim, struct dns_rr *rr, struct dns_packet union dns_any any; size_t n; int error; + char __dst[DNS_STRMAXLEN + 1] = { 0 }; if (rr->section == DNS_S_QD) dns_b_putc(&dst, ';'); @@ -3288,9 +3290,9 @@ size_t dns_rr_print(void *_dst, size_t lim, struct dns_rr *rr, struct dns_packet } dns_b_putc(&dst, ' '); - dns_b_puts(&dst, dns_strclass(rr->class)); + dns_b_puts(&dst, dns_strclass(rr->class, __dst)); dns_b_putc(&dst, ' '); - dns_b_puts(&dst, dns_strtype(rr->type)); + dns_b_puts(&dst, dns_strtype(rr->type, __dst)); if (rr->section == DNS_S_QD) goto epilog; @@ -4864,6 +4866,7 @@ dns_error_t dns_trace_dump(struct dns_trace *trace, FILE *fp) { dns_microseconds_t begin, elapsed; } state = { 0 }; int error; + char __dst[DNS_STRMAXLEN + 1] = { 0 }; if (!trace || !trace->fp) return EINVAL; @@ -4886,8 +4889,8 @@ dns_error_t dns_trace_dump(struct dns_trace *trace, FILE *fp) { fprintf(fp, "dns_res_submit:\n"); dns_trace_dump_meta(trace, " ", te, state.elapsed, fp); fprintf(fp, " qname: %s\n", te->res_submit.qname); - fprintf(fp, " qtype: %s\n", dns_strtype(te->res_submit.qtype)); - fprintf(fp, " qclass: %s\n", dns_strclass(te->res_submit.qclass)); + fprintf(fp, " qtype: %s\n", dns_strtype(te->res_submit.qtype, __dst)); + fprintf(fp, " qclass: %s\n", dns_strclass(te->res_submit.qclass, __dst)); dns_trace_dump_error(trace, " error: ", te->res_submit.error, fp); break; case DNS_TE_RES_FETCH: @@ -10010,16 +10013,17 @@ int dns_ai_poll(struct dns_addrinfo *ai, int timeout) { size_t dns_ai_print(void *_dst, size_t lim, struct addrinfo *ent, struct dns_addrinfo *ai) { struct dns_buf dst = DNS_B_INTO(_dst, lim); char addr[DNS_PP_MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) + 1]; + char __dst[DNS_STRMAXLEN + 1] = { 0 }; dns_b_puts(&dst, "[ "); dns_b_puts(&dst, ai->qname); dns_b_puts(&dst, " IN "); if (ai->qtype) { - dns_b_puts(&dst, dns_strtype(ai->qtype)); + dns_b_puts(&dst, dns_strtype(ai->qtype, __dst)); } else if (ent->ai_family == AF_INET) { - dns_b_puts(&dst, dns_strtype(DNS_T_A)); + dns_b_puts(&dst, dns_strtype(DNS_T_A, __dst)); } else if (ent->ai_family == AF_INET6) { - dns_b_puts(&dst, dns_strtype(DNS_T_AAAA)); + dns_b_puts(&dst, dns_strtype(DNS_T_AAAA, __dst)); } else { dns_b_puts(&dst, "0"); } @@ -10106,9 +10110,8 @@ static const struct { { "AR", DNS_S_ADDITIONAL }, }; -const char *(dns_strsection)(enum dns_section section) { - char _dst[DNS_STRMAXLEN + 1] = { 0 }; - struct dns_buf dst = DNS_B_INTO(_dst, sizeof _dst); +const char *(dns_strsection)(enum dns_section section, char *_dst) { + struct dns_buf dst = DNS_B_INTO(_dst, DNS_STRMAXLEN + 1); unsigned i; for (i = 0; i < lengthof(dns_sections); i++) { @@ -10156,9 +10159,8 @@ static const struct { { "IN", DNS_C_IN }, }; -const char *(dns_strclass)(enum dns_class type) { - char _dst[DNS_STRMAXLEN + 1] = { 0 }; - struct dns_buf dst = DNS_B_INTO(_dst, sizeof _dst); +const char *(dns_strclass)(enum dns_class type, char *_dst) { + struct dns_buf dst = DNS_B_INTO(_dst, DNS_STRMAXLEN + 1); unsigned i; for (i = 0; i < lengthof(dns_classes); i++) { @@ -10193,9 +10195,8 @@ enum dns_class dns_iclass(const char *name) { } /* dns_iclass() */ -const char *(dns_strtype)(enum dns_type type) { - char _dst[DNS_STRMAXLEN + 1] = { 0 }; - struct dns_buf dst = DNS_B_INTO(_dst, sizeof _dst); +const char *(dns_strtype)(enum dns_type type, char *_dst) { + struct dns_buf dst = DNS_B_INTO(_dst, DNS_STRMAXLEN + 1); unsigned i; for (i = 0; i < lengthof(dns_rrtypes); i++) { @@ -10618,6 +10619,7 @@ static int parse_packet(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) { union dns_any any; char pretty[sizeof any * 2]; size_t len; + char __dst[DNS_STRMAXLEN + 1] = { 0 }; P->end = fread(P->data, 1, P->size, stdin); @@ -10634,7 +10636,7 @@ static int parse_packet(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) { dns_rr_foreach(&rr, P, .sort = MAIN.sort) { if (section != rr.section) - fprintf(stdout, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(P, rr.section)); + fprintf(stdout, "\n;; [%s:%d]\n", dns_strsection(rr.section, __dst), dns_p_count(P, rr.section)); if ((len = dns_rr_print(pretty, sizeof pretty, &rr, P, &error))) fprintf(stdout, "%s\n", pretty); @@ -10665,7 +10667,7 @@ static int parse_packet(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) { rr = rrset[i]; #endif if (section != rr.section) - fprintf(stdout, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(Q, rr.section)); + fprintf(stdout, "\n;; [%s:%d]\n", dns_strsection(rr.section, __dst), dns_p_count(Q, rr.section)); if ((len = dns_rr_print(pretty, sizeof pretty, &rr, Q, &error))) fprintf(stdout, "%s\n", pretty); @@ -10944,6 +10946,7 @@ static int send_query(int argc, char *argv[]) { struct dns_socket *so; int error, type; struct dns_options opts = { 0 }; + char __dst[DNS_STRMAXLEN + 1] = { 0 }; memset(&ss, 0, sizeof ss); if (argc > 1) { @@ -10976,7 +10979,7 @@ static int send_query(int argc, char *argv[]) { else type = dns_res_tcp2type(resconf()->options.tcp); - fprintf(stderr, "querying %s for %s IN %s\n", host, MAIN.qname, dns_strtype(MAIN.qtype)); + fprintf(stderr, "querying %s for %s IN %s\n", host, MAIN.qname, dns_strtype(MAIN.qtype, __dst)); if (!(so = dns_so_open((struct sockaddr *)&resconf()->iface, type, &opts, &error))) panic("dns_so_open: %s", dns_strerror(error)); @@ -11227,11 +11230,12 @@ static int echo_port(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) { static int isection(int argc, char *argv[]) { + char __dst[DNS_STRMAXLEN + 1] = { 0 }; const char *name = (argc > 1)? argv[1] : ""; int type; type = dns_isection(name); - name = dns_strsection(type); + name = dns_strsection(type, __dst); printf("%s (%d)\n", name, type); @@ -11240,11 +11244,12 @@ static int isection(int argc, char *argv[]) { static int iclass(int argc, char *argv[]) { + char __dst[DNS_STRMAXLEN + 1] = { 0 }; const char *name = (argc > 1)? argv[1] : ""; int type; type = dns_iclass(name); - name = dns_strclass(type); + name = dns_strclass(type, __dst); printf("%s (%d)\n", name, type); @@ -11253,11 +11258,12 @@ static int iclass(int argc, char *argv[]) { static int itype(int argc, char *argv[]) { + char __dst[DNS_STRMAXLEN + 1] = { 0 }; const char *name = (argc > 1)? argv[1] : ""; int type; type = dns_itype(name); - name = dns_strtype(type); + name = dns_strtype(type, __dst); printf("%s (%d)\n", name, type); diff --git a/dirmngr/dns.h b/dirmngr/dns.h index 024d6dc..1f647e1 100644 --- a/dirmngr/dns.h +++ b/dirmngr/dns.h @@ -272,15 +272,15 @@ enum dns_rcode { */ #define DNS_STRMAXLEN 47 /* "QUESTION|ANSWER|AUTHORITY|ADDITIONAL" */ -DNS_PUBLIC const char *dns_strsection(enum dns_section); +DNS_PUBLIC const char *dns_strsection(enum dns_section, char *); DNS_PUBLIC enum dns_section dns_isection(const char *); -DNS_PUBLIC const char *dns_strclass(enum dns_class); +DNS_PUBLIC const char *dns_strclass(enum dns_class, char *); DNS_PUBLIC enum dns_class dns_iclass(const char *); -DNS_PUBLIC const char *dns_strtype(enum dns_type); +DNS_PUBLIC const char *dns_strtype(enum dns_type, char *); DNS_PUBLIC enum dns_type dns_itype(const char *); diff --git a/dirmngr/ldap-parse-uri.c b/dirmngr/ldap-parse-uri.c index 94d4efd..cae0351 100644 --- a/dirmngr/ldap-parse-uri.c +++ b/dirmngr/ldap-parse-uri.c @@ -54,7 +54,7 @@ ldap_uri_p (const char *url) && (url[3] == 'p' || url[3] == 'P') && (url[4] == ':' || ((url[4] == 's' || url[4] == 'S' - || url[4] == 'i' || url[4] == 'i') + || url[4] == 'i' || url[4] == 'I') && url[5] == ':')))) return 1; return 0; diff --git a/dirmngr/misc.c b/dirmngr/misc.c index eef04ed..ba47c99 100644 --- a/dirmngr/misc.c +++ b/dirmngr/misc.c @@ -284,7 +284,7 @@ dump_string (const char *string) else { log_printf ( "[ "); - log_printhex (NULL, string, strlen (string)); + log_printhex (string, strlen (string), NULL); log_printf ( " ]"); } } diff --git a/dirmngr/ocsp.c b/dirmngr/ocsp.c index 13e6120..eaa6ca2 100644 --- a/dirmngr/ocsp.c +++ b/dirmngr/ocsp.c @@ -305,7 +305,7 @@ do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, if (opt.verbose) log_info (_("OCSP responder at '%s' status: %s\n"), url, t); - /* Get the signature value now because we can all this fucntion + /* Get the signature value now because we can call this function * only once. */ *r_sigval = ksba_ocsp_get_sig_val (ocsp, r_produced_at); diff --git a/dirmngr/validate.c b/dirmngr/validate.c index 371852b..901c165 100644 --- a/dirmngr/validate.c +++ b/dirmngr/validate.c @@ -888,6 +888,53 @@ pk_algo_from_sexp (gcry_sexp_t pkey) } +/* Return the hash algorithm's algo id from its name given in the + * non-null termnated string in (buffer,buflen). Returns 0 on failure + * or if the algo is not known. */ +static int +hash_algo_from_buffer (const void *buffer, size_t buflen) +{ + char *string; + int algo; + + string = xtrymalloc (buflen + 1); + if (!string) + { + log_error (_("out of core\n")); + return 0; + } + memcpy (string, buffer, buflen); + string[buflen] = 0; + algo = gcry_md_map_name (string); + if (!algo) + log_error ("unknown digest algorithm '%s' used in certificate\n", string); + xfree (string); + return algo; +} + + +/* Return an unsigned integer from the non-null termnated string + * (buffer,buflen). Returns 0 on failure. */ +static unsigned int +uint_from_buffer (const void *buffer, size_t buflen) +{ + char *string; + unsigned int val; + + string = xtrymalloc (buflen + 1); + if (!string) + { + log_error (_("out of core\n")); + return 0; + } + memcpy (string, buffer, buflen); + string[buflen] = 0; + val = strtoul (string, NULL, 10); + xfree (string); + return val; +} + + /* Check the signature on CERT using the ISSUER_CERT. This function * does only test the cryptographic signature and nothing else. It is * assumed that the ISSUER_CERT is valid. */ @@ -897,45 +944,26 @@ check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert) gpg_error_t err; const char *algoid; gcry_md_hd_t md; - int i, algo; + int algo; ksba_sexp_t p; size_t n; gcry_sexp_t s_sig, s_hash, s_pkey; - const char *s; - char algo_name[16+1]; /* hash algorithm name converted to lower case. */ + const char *algo_name; /* hash algorithm name converted to lower case. */ int digestlen; unsigned char *digest; + int use_pss = 0; + unsigned int saltlen; /* Hash the target certificate using the algorithm from that certificate. */ algoid = ksba_cert_get_digest_algo (cert); algo = gcry_md_map_name (algoid); - if (!algo) + if (!algo && algoid && !strcmp (algoid, "1.2.840.113549.1.1.10")) + use_pss = 1; + else if (!algo) { log_error (_("unknown hash algorithm '%s'\n"), algoid? algoid:"?"); return gpg_error (GPG_ERR_GENERAL); } - s = gcry_md_algo_name (algo); - for (i=0; *s && i < sizeof algo_name - 1; s++, i++) - algo_name[i] = tolower (*s); - algo_name[i] = 0; - - err = gcry_md_open (&md, algo, 0); - if (err) - { - log_error ("md_open failed: %s\n", gpg_strerror (err)); - return err; - } - if (DBG_HASHING) - gcry_md_debug (md, "hash.cert"); - - err = ksba_cert_hash (cert, 1, HASH_FNC, md); - if (err) - { - log_error ("ksba_cert_hash failed: %s\n", gpg_strerror (err)); - gcry_md_close (md); - return err; - } - gcry_md_final (md); /* Get the signature value out of the target certificate. */ p = ksba_cert_get_sig_val (cert); @@ -943,27 +971,96 @@ check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert) if (!n) { log_error ("libksba did not return a proper S-Exp\n"); - gcry_md_close (md); ksba_free (p); return gpg_error (GPG_ERR_BUG); } + err = gcry_sexp_sscan ( &s_sig, NULL, p, n); + ksba_free (p); + if (err) + { + log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (err)); + return err; + } if (DBG_CRYPTO) + gcry_log_debugsxp ("sigval", s_sig); + + if (use_pss) { - int j; - log_debug ("signature value:"); - for (j=0; j < n; j++) - log_printf (" %02X", p[j]); - log_printf ("\n"); + /* Extract the hash algorithm and the salt length from the sigval. */ + gcry_buffer_t ioarray[2] = { {0}, {0} }; + + err = gcry_sexp_extract_param (s_sig, "sig-val", + "&'hash-algo''salt-length'", + ioarray+0, ioarray+1, NULL); + if (err) + { + gcry_sexp_release (s_sig); + log_error ("extracting params from PSS failed: %s\n", + gpg_strerror (err)); + return err; + } + algo = hash_algo_from_buffer (ioarray[0].data, ioarray[0].len); + saltlen = uint_from_buffer (ioarray[1].data, ioarray[1].len); + xfree (ioarray[0].data); + xfree (ioarray[1].data); + if (saltlen < 20) + { + log_error ("length of PSS salt too short\n"); + gcry_sexp_release (s_sig); + return gpg_error (GPG_ERR_DIGEST_ALGO); + } + if (!algo) + { + gcry_sexp_release (s_sig); + return gpg_error (GPG_ERR_DIGEST_ALGO); + } + /* Add some restrictions; see ../sm/certcheck.c for details. */ + switch (algo) + { + case GCRY_MD_SHA1: + case GCRY_MD_SHA256: + case GCRY_MD_SHA384: + case GCRY_MD_SHA512: + case GCRY_MD_SHA3_256: + case GCRY_MD_SHA3_384: + case GCRY_MD_SHA3_512: + break; + default: + log_error ("PSS hash algorithm '%s' rejected\n", + gcry_md_algo_name (algo)); + gcry_sexp_release (s_sig); + return gpg_error (GPG_ERR_DIGEST_ALGO); + } + + if (gcry_md_get_algo_dlen (algo) != saltlen) + { + log_error ("PSS hash algorithm '%s' rejected due to salt length %u\n", + gcry_md_algo_name (algo), saltlen); + gcry_sexp_release (s_sig); + return gpg_error (GPG_ERR_DIGEST_ALGO); + } } - err = gcry_sexp_sscan ( &s_sig, NULL, p, n); - ksba_free (p); + algo_name = hash_algo_to_string (algo); + err = gcry_md_open (&md, algo, 0); if (err) { - log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (err)); + log_error ("md_open failed: %s\n", gpg_strerror (err)); + gcry_sexp_release (s_sig); + return err; + } + if (DBG_HASHING) + gcry_md_debug (md, "hash.cert"); + + err = ksba_cert_hash (cert, 1, HASH_FNC, md); + if (err) + { + log_error ("ksba_cert_hash failed: %s\n", gpg_strerror (err)); gcry_md_close (md); + gcry_sexp_release (s_sig); return err; } + gcry_md_final (md); /* Get the public key from the issuer certificate. */ p = ksba_cert_get_public_key (issuer_cert); @@ -994,10 +1091,22 @@ check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert) * S_SIG - Signature value as given in the certificate. * MD - Finalized hash context with hash of the certificate. * ALGO_NAME - Lowercase hash algorithm name + * SALTLEN - Salt length for rsaPSS. */ digestlen = gcry_md_get_algo_dlen (algo); digest = gcry_md_read (md, algo); - if (pk_algo_from_sexp (s_pkey) == GCRY_PK_DSA) + if (use_pss) + { + err = gcry_sexp_build (&s_hash, NULL, + "(data (flags pss)" + "(hash %s %b)" + "(salt-length %u))", + algo_name, + (int)digestlen, + digest, + saltlen); + } + else if (pk_algo_from_sexp (s_pkey) == GCRY_PK_DSA) { /* NB.: We support only SHA-1 here because we had problems back * then to get test data for DSA-2. Meanwhile DSA has been @@ -1010,19 +1119,17 @@ check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert) gcry_sexp_release (s_pkey); return gpg_error (GPG_ERR_INTERNAL); } - if ( gcry_sexp_build (&s_hash, NULL, "(data(flags raw)(value %b))", - (int)digestlen, digest) ) - BUG (); + err = gcry_sexp_build (&s_hash, NULL, "(data(flags raw)(value %b))", + (int)digestlen, digest); } else /* Not DSA - we assume RSA */ { - if ( gcry_sexp_build (&s_hash, NULL, "(data(flags pkcs1)(hash %s %b))", - algo_name, (int)digestlen, digest) ) - BUG (); - + err = gcry_sexp_build (&s_hash, NULL, "(data(flags pkcs1)(hash %s %b))", + algo_name, (int)digestlen, digest); } - err = gcry_pk_verify (s_sig, s_hash, s_pkey); + if (!err) + err = gcry_pk_verify (s_sig, s_hash, s_pkey); if (DBG_X509) log_debug ("gcry_pk_verify: %s\n", gpg_strerror (err)); gcry_md_close (md); diff --git a/doc/DETAILS b/doc/DETAILS index 883fe03..acca242 100644 --- a/doc/DETAILS +++ b/doc/DETAILS @@ -545,9 +545,10 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB: actual key used for descryption. <fpr2> is the fingerprint of the primary key. <otrust> is the letter with the ownertrust; this is in general a 'u' which stands for ultimately trusted. -*** DECRYPTION_INFO <mdc_method> <sym_algo> +*** DECRYPTION_INFO <mdc_method> <sym_algo> [<aead_algo>] Print information about the symmetric encryption algorithm and the MDC method. This will be emitted even if the decryption fails. + For an AEAD algorithm AEAD_ALGO is not 0. *** DECRYPTION_FAILED The symmetric decryption failed - one reason could be a wrong @@ -1138,6 +1139,38 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB: *** BEGIN_STREAM, END_STREAM Used to issued by the experimental pipemode. +** Inter-component codes + Status codes are also used between the components of the GnuPG + system via the Assuan S lines. Some of them are documented here: + +*** PUBKEY_INFO <n> <ubid> + The type of the public key in the following D-lines or + communicated via a pipe. <n> is the value of =enum pubkey_types= + and <ubid> the Unique Blob ID (UBID) which is the fingerprint of + the primary key truncated to 20 octets and formatted in hex. Note + that the keyboxd SEARCH command can be used to lookup the public + key using the <ubid> prefixed with a caret (^). + +*** KEYPAIRINFO <grip> <keyref> [<usage>] [<keytime>] + + This status is emitted by scdaemon and gpg-agent to convey brief + information about keypairs stored on tokens. <grip> is the + hexified keygrip of the key or, if no key is stored, an "X". + <keyref> is the ID of a card's key; for example "OPENPGP.2" for + the second key slot of an OpenPGP card. <usage> is optional and + returns technically possible key usages, this is a string of + single letters describing the usage ('c' for certify, 'e' for + encryption, 's' for signing, 'a' for authentication). A '-' can be + used to tell that usage flags are not conveyed. <keytime> is used + by OpenPGP cards for the stored key creation time. A '-' means no + info available. The format is the usual ISO string are a number + with the seconds since Epoch. +*** MANUFACTURER <n> [<string>] + + This status returns the Manufactorer ID as the unsigned number N. + For OpenPGP this is weel defined; for other cards this is 0. The + name of the manufacturer is also given as <string>; spaces are not + escaped. For PKCS#15 cards <string> is TokenInfo.manufactorerID. * Format of the --attribute-fd output diff --git a/doc/Makefile.am b/doc/Makefile.am index d47d83e..ca13bcf 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -182,6 +182,8 @@ defsincdate: $(gnupg_TEXINFOS) if test -e $(top_srcdir)/.git; then \ (cd $(srcdir) && git log -1 --format='%ct' \ -- $(gnupg_TEXINFOS) 2>/dev/null) >>defsincdate; \ + elif test x"$SOURCE_DATE_EPOCH" != x; then \ + echo "$SOURCE_DATE_EPOCH" >>defsincdate ; \ fi defs.inc : defsincdate Makefile mkdefsinc diff --git a/doc/gpgsm.texi b/doc/gpgsm.texi index eb30368..1c329a7 100644 --- a/doc/gpgsm.texi +++ b/doc/gpgsm.texi @@ -409,9 +409,14 @@ change it. @itemx --disable-crl-checks @opindex enable-crl-checks @opindex disable-crl-checks -By default the @acronym{CRL} checks are enabled and the DirMngr is used -to check for revoked certificates. The disable option is most useful -with an off-line network connection to suppress this check. +By default the @acronym{CRL} checks are enabled and the DirMngr is +used to check for revoked certificates. The disable option is most +useful with an off-line network connection to suppress this check and +also to avoid that new certificates introduce a web bug by including a +certificate specific CRL DP. The disable option also disables an +issuer certificate lookup via the authorityInfoAccess property of the +certificate; the @option{--enable-issuer-key-retrieve} can be used +to make use of that property anyway. @item --enable-trusted-cert-crl-check @itemx --disable-trusted-cert-crl-check @@ -438,6 +443,14 @@ hold in the keybox. The suggested way of doing this is by using it along with the option @option{--with-validation} for a key listing command. This option should not be used in a configuration file. +@item --enable-issuer-based-crl-check +@opindex enable-issuer-based-crl-check +Run a CRL check even for certificates which do not have any CRL +distribution point. This requires that a suitable LDAP server has +been configured in Dirmngr and that the CRL can be found using the +issuer. This option reverts to what GnuPG did up to version 2.2.20. +This option is in general not useful. + @item --enable-ocsp @itemx --disable-ocsp @opindex enable-ocsp diff --git a/g10/call-agent.c b/g10/call-agent.c index 574f6ca..7c08c9b 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -484,6 +484,7 @@ agent_release_card_info (struct agent_card_info_s *info) return; xfree (info->reader); info->reader = NULL; + xfree (info->manufacturer_name); info->manufacturer_name = NULL; xfree (info->serialno); info->serialno = NULL; xfree (info->apptype); info->apptype = NULL; xfree (info->disp_name); info->disp_name = NULL; @@ -507,6 +508,7 @@ learn_status_cb (void *opaque, const char *line) const char *keyword = line; int keywordlen; int i; + char *endp; for (keywordlen=0; *line && !spacep (line); line++, keywordlen++) ; @@ -706,6 +708,16 @@ learn_status_cb (void *opaque, const char *line) xfree (parm->private_do[no]); parm->private_do[no] = unescape_status_string (line); } + else if (keywordlen == 12 && !memcmp (keyword, "MANUFACTURER", 12)) + { + xfree (parm->manufacturer_name); + parm->manufacturer_name = NULL; + parm->manufacturer_id = strtoul (line, &endp, 0); + while (endp && spacep (endp)) + endp++; + if (endp && *endp) + parm->manufacturer_name = xstrdup (endp); + } else if (keywordlen == 3 && !memcmp (keyword, "KDF", 3)) { unsigned char *data = unescape_status_string (line); @@ -1518,13 +1530,15 @@ agent_scd_checkpin (const char *serialno) /* Note: All strings shall be UTF-8. On success the caller needs to free the string stored at R_PASSPHRASE. On error NULL will be - stored at R_PASSPHRASE and an appropriate fpf error code - returned. */ + stored at R_PASSPHRASE and an appropriate error code returned. + Only called from passphrase.c:passphrase_get - see there for more + comments on this ugly API. */ gpg_error_t agent_get_passphrase (const char *cache_id, const char *err_msg, const char *prompt, const char *desc_msg, + int newsymkey, int repeat, int check, char **r_passphrase) @@ -1537,6 +1551,7 @@ agent_get_passphrase (const char *cache_id, char *arg4 = NULL; membuf_t data; struct default_inq_parm_s dfltparm; + int have_newsymkey; memset (&dfltparm, 0, sizeof dfltparm); @@ -1552,6 +1567,10 @@ agent_get_passphrase (const char *cache_id, "GETINFO cmd_has_option GET_PASSPHRASE repeat", NULL, NULL, NULL, NULL, NULL, NULL)) return gpg_error (GPG_ERR_NOT_SUPPORTED); + have_newsymkey = !(assuan_transact + (agent_ctx, + "GETINFO cmd_has_option GET_PASSPHRASE newsymkey", + NULL, NULL, NULL, NULL, NULL, NULL)); if (cache_id && *cache_id) if (!(arg1 = percent_plus_escape (cache_id))) @@ -1566,10 +1585,14 @@ agent_get_passphrase (const char *cache_id, if (!(arg4 = percent_plus_escape (desc_msg))) goto no_mem; + /* CHECK && REPEAT or NEWSYMKEY is here an indication that a new + * passphrase for symmetric encryption is requested; if the agent + * supports this we enable the modern API by also passing --newsymkey. */ snprintf (line, DIM(line), - "GET_PASSPHRASE --data --repeat=%d%s -- %s %s %s %s", + "GET_PASSPHRASE --data --repeat=%d%s%s -- %s %s %s %s", repeat, - check? " --check --qualitybar":"", + ((repeat && check) || newsymkey)? " --check":"", + (have_newsymkey && newsymkey)? " --newsymkey":"", arg1? arg1:"X", arg2? arg2:"X", arg3? arg3:"X", diff --git a/g10/call-agent.h b/g10/call-agent.h index 94ca154..784ed5c 100644 --- a/g10/call-agent.h +++ b/g10/call-agent.h @@ -32,6 +32,8 @@ struct agent_card_info_s int error; /* private. */ char *reader; /* Reader information. */ char *apptype; /* Malloced application type string. */ + unsigned int manufacturer_id; + char *manufacturer_name; /* malloced. */ char *serialno; /* malloced hex string. */ char *disp_name; /* malloced. */ char *disp_lang; /* malloced. */ @@ -133,6 +135,7 @@ gpg_error_t agent_get_passphrase (const char *cache_id, const char *err_msg, const char *prompt, const char *desc_msg, + int newsymkey, int repeat, int check, char **r_passphrase); diff --git a/g10/card-util.c b/g10/card-util.c index 3aaea84..00b64b3 100644 --- a/g10/card-util.c +++ b/g10/card-util.c @@ -192,46 +192,6 @@ change_pin (int unblock_v2, int allow_admin) agent_release_card_info (&info); } -static const char * -get_manufacturer (unsigned int no) -{ - /* Note: Make sure that there is no colon or linefeed in the string. */ - switch (no) - { - case 0x0001: return "PPC Card Systems"; - case 0x0002: return "Prism"; - case 0x0003: return "OpenFortress"; - case 0x0004: return "Wewid"; - case 0x0005: return "ZeitControl"; - case 0x0006: return "Yubico"; - case 0x0007: return "OpenKMS"; - case 0x0008: return "LogoEmail"; - case 0x0009: return "Fidesmo"; - case 0x000A: return "Dangerous Things"; - case 0x000B: return "Feitian Technologies"; - - case 0x002A: return "Magrathea"; - case 0x0042: return "GnuPG e.V."; - - case 0x1337: return "Warsaw Hackerspace"; - case 0x2342: return "warpzone"; /* hackerspace Muenster. */ - case 0x4354: return "Confidential Technologies"; /* cotech.de */ - case 0x5443: return "TIF-IT e.V."; - case 0x63AF: return "Trustica"; - case 0xBA53: return "c-base e.V."; - case 0xBD0E: return "Paranoidlabs"; - case 0xF517: return "FSIJ"; - case 0xF5EC: return "F-Secure"; - - /* 0x0000 and 0xFFFF are defined as test cards per spec, - 0xFF00 to 0xFFFE are assigned for use with randomly created - serial numbers. */ - case 0x0000: - case 0xffff: return "test card"; - default: return (no & 0xff00) == 0xff00? "unmanaged S/N range":"unknown"; - } -} - static void print_sha1_fpr (estream_t fp, const unsigned char *fpr) @@ -393,6 +353,7 @@ current_card_status (ctrl_t ctrl, estream_t fp, unsigned int uval; const unsigned char *thefpr; int i; + char *pesc; if (serialno && serialnobuflen) *serialno = 0; @@ -479,7 +440,10 @@ current_card_status (ctrl_t ctrl, estream_t fp, { es_fprintf (fp, "version:%.4s:\n", info.serialno+12); uval = xtoi_2(info.serialno+16)*256 + xtoi_2 (info.serialno+18); - es_fprintf (fp, "vendor:%04x:%s:\n", uval, get_manufacturer (uval)); + pesc = (info.manufacturer_name + ? percent_escape (info.manufacturer_name, NULL) : NULL); + es_fprintf (fp, "vendor:%04x:%s:\n", uval, pesc? pesc:""); + xfree (pesc); es_fprintf (fp, "serial:%.8s:\n", info.serialno+20); print_isoname (fp, "Name of cardholder: ", "name", info.disp_name); @@ -572,8 +536,7 @@ current_card_status (ctrl_t ctrl, estream_t fp, info.serialno[14] == '0'?"":info.serialno+14, info.serialno[15]); tty_fprintf (fp, "Manufacturer .....: %s\n", - get_manufacturer (xtoi_2(info.serialno+16)*256 - + xtoi_2 (info.serialno+18))); + info.manufacturer_name? info.manufacturer_name : "?"); tty_fprintf (fp, "Serial number ....: %.8s\n", info.serialno+20); print_isoname (fp, "Name of cardholder: ", "name", info.disp_name); diff --git a/g10/decrypt-data.c b/g10/decrypt-data.c index 736534d..2793885 100644 --- a/g10/decrypt-data.c +++ b/g10/decrypt-data.c @@ -1,6 +1,7 @@ /* decrypt-data.c - Decrypt an encrypted data packet - * Copyright (C) 1998, 1999, 2000, 2001, 2005, - * 2006, 2009 Free Software Foundation, Inc. + * Copyright (C) 1998-2001, 2005-2006, 2009 Free Software Foundation, Inc. + * Copyright (C) 1998-2001, 2005-2006, 2009, 2018 Werner Koch + * Copyright (C) 2020 g10 Code GmbH * * This file is part of GnuPG. * @@ -16,6 +17,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, see <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-3.0-or-later */ #include <config.h> @@ -32,22 +34,71 @@ #include "../common/compliance.h" +static int aead_decode_filter (void *opaque, int control, iobuf_t a, + byte *buf, size_t *ret_len); static int mdc_decode_filter ( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len); static int decode_filter ( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len); -typedef struct decode_filter_context_s +/* Our context object. */ +struct decode_filter_context_s { + /* Recounter (max value is 2). We need it because we do not know + * whether the iobuf or the outer control code frees this object + * first. */ + int refcount; + + /* The cipher handle. */ gcry_cipher_hd_t cipher_hd; + + /* The hash handle for use in MDC mode. */ gcry_md_hd_t mdc_hash; - char defer[22]; - int defer_filled; - int eof_seen; - int refcount; - int partial; /* Working on a partial length packet. */ - size_t length; /* If !partial: Remaining bytes in the packet. */ -} *decode_filter_ctx_t; + + /* The start IV for AEAD encryption. */ + byte startiv[16]; + + /* The holdback buffer and its used length. For AEAD we need 32+1 + * bytes but we use 48 byte. For MDC we need 22 bytes; here + * holdbacklen will either 0 or 22. */ + char holdback[48]; + unsigned int holdbacklen; + + /* Working on a partial length packet. */ + unsigned int partial : 1; + + /* EOF indicator with these true values: + * 1 = normal EOF + * 2 = premature EOF (tag or hash incomplete) + * 3 = premature EOF (general) */ + unsigned int eof_seen : 2; + + /* The actually used cipher algo for AEAD. */ + byte cipher_algo; + + /* The AEAD algo. */ + byte aead_algo; + + /* The encoded chunk byte for AEAD. */ + byte chunkbyte; + + /* The decoded CHUNKBYTE. */ + uint64_t chunksize; + + /* The chunk index for AEAD. */ + uint64_t chunkindex; + + /* The number of bytes in the current chunk. */ + uint64_t chunklen; + + /* The total count of decrypted plaintext octets. */ + uint64_t total; + + /* Remaining bytes in the packet according to the packet header. + * Not used if PARTIAL is true. */ + size_t length; +}; +typedef struct decode_filter_context_s *decode_filter_ctx_t; /* Helper to release the decode context. */ @@ -69,6 +120,99 @@ release_dfx_context (decode_filter_ctx_t dfx) } +/* Set the nonce and the additional data for the current chunk. This + * also reset the decryption machinery so that the handle can be + * used for a new chunk. If FINAL is set the final AEAD chunk is + * processed. */ +static gpg_error_t +aead_set_nonce_and_ad (decode_filter_ctx_t dfx, int final) +{ + gpg_error_t err; + unsigned char ad[21]; + unsigned char nonce[16]; + int i; + + switch (dfx->aead_algo) + { + case AEAD_ALGO_OCB: + memcpy (nonce, dfx->startiv, 15); + i = 7; + break; + + case AEAD_ALGO_EAX: + memcpy (nonce, dfx->startiv, 16); + i = 8; + break; + + default: + BUG (); + } + nonce[i++] ^= dfx->chunkindex >> 56; + nonce[i++] ^= dfx->chunkindex >> 48; + nonce[i++] ^= dfx->chunkindex >> 40; + nonce[i++] ^= dfx->chunkindex >> 32; + nonce[i++] ^= dfx->chunkindex >> 24; + nonce[i++] ^= dfx->chunkindex >> 16; + nonce[i++] ^= dfx->chunkindex >> 8; + nonce[i++] ^= dfx->chunkindex; + + if (DBG_CRYPTO) + log_printhex (nonce, i, "nonce:"); + err = gcry_cipher_setiv (dfx->cipher_hd, nonce, i); + if (err) + return err; + + ad[0] = (0xc0 | PKT_ENCRYPTED_AEAD); + ad[1] = 1; + ad[2] = dfx->cipher_algo; + ad[3] = dfx->aead_algo; + ad[4] = dfx->chunkbyte; + ad[5] = dfx->chunkindex >> 56; + ad[6] = dfx->chunkindex >> 48; + ad[7] = dfx->chunkindex >> 40; + ad[8] = dfx->chunkindex >> 32; + ad[9] = dfx->chunkindex >> 24; + ad[10]= dfx->chunkindex >> 16; + ad[11]= dfx->chunkindex >> 8; + ad[12]= dfx->chunkindex; + if (final) + { + ad[13] = dfx->total >> 56; + ad[14] = dfx->total >> 48; + ad[15] = dfx->total >> 40; + ad[16] = dfx->total >> 32; + ad[17] = dfx->total >> 24; + ad[18] = dfx->total >> 16; + ad[19] = dfx->total >> 8; + ad[20] = dfx->total; + } + if (DBG_CRYPTO) + log_printhex (ad, final? 21 : 13, "authdata:"); + return gcry_cipher_authenticate (dfx->cipher_hd, ad, final? 21 : 13); +} + + +/* Helper to check the 16 byte tag in TAGBUF. The FINAL flag is only + * for debug messages. */ +static gpg_error_t +aead_checktag (decode_filter_ctx_t dfx, int final, const void *tagbuf) +{ + gpg_error_t err; + + if (DBG_FILTER) + log_printhex (tagbuf, 16, "tag:"); + err = gcry_cipher_checktag (dfx->cipher_hd, tagbuf, 16); + if (err) + { + log_error ("gcry_cipher_checktag%s failed: %s\n", + final? " (final)":"", gpg_strerror (err)); + return err; + } + if (DBG_FILTER) + log_debug ("%stag is valid\n", final?"final ":""); + return 0; +} + /**************** * Decrypt the data, specified by ED with the key DEK. @@ -77,6 +221,8 @@ int decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek) { decode_filter_ctx_t dfx; + enum gcry_cipher_modes ciphermode; + unsigned int startivlen; byte *p; int rc=0, c, i; byte temp[32]; @@ -98,9 +244,18 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek) dek->algo_info_printed = 1; } + if (ed->aead_algo) + { + rc = openpgp_aead_algo_info (ed->aead_algo, &ciphermode, &startivlen); + if (rc) + goto leave; + log_assert (startivlen <= sizeof dfx->startiv); + } + else + ciphermode = GCRY_CIPHER_MODE_CFB; + /* Check compliance. */ - if (! gnupg_cipher_is_allowed (opt.compliance, 0, dek->algo, - GCRY_CIPHER_MODE_CFB)) + if (!gnupg_cipher_is_allowed (opt.compliance, 0, dek->algo, ciphermode)) { log_error (_("cipher algorithm '%s' may not be used in %s mode\n"), openpgp_cipher_algo_name (dek->algo), @@ -109,12 +264,8 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek) goto leave; } - { - char buf[20]; - - snprintf (buf, sizeof buf, "%d %d", ed->mdc_method, dek->algo); - write_status_text (STATUS_DECRYPTION_INFO, buf); - } + write_status_printf (STATUS_DECRYPTION_INFO, "%d %d %d", + ed->mdc_method, dek->algo, 0); if (opt.show_session_key) { @@ -139,95 +290,181 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek) blocksize = openpgp_cipher_get_algo_blklen (dek->algo); if ( !blocksize || blocksize > 16 ) log_fatal ("unsupported blocksize %u\n", blocksize ); - nprefix = blocksize; - if ( ed->len && ed->len < (nprefix+2) ) - { - /* An invalid message. We can't check that during parsing - because we may not know the used cipher then. */ - rc = gpg_error (GPG_ERR_INV_PACKET); - goto leave; - } - if ( ed->mdc_method ) + if (ed->aead_algo) { - if (gcry_md_open (&dfx->mdc_hash, ed->mdc_method, 0 )) - BUG (); - if ( DBG_HASHING ) - gcry_md_debug (dfx->mdc_hash, "checkmdc"); - } + if (blocksize != 16) + { + rc = gpg_error (GPG_ERR_CIPHER_ALGO); + goto leave; + } - rc = openpgp_cipher_open (&dfx->cipher_hd, dek->algo, - GCRY_CIPHER_MODE_CFB, - (GCRY_CIPHER_SECURE - | ((ed->mdc_method || dek->algo >= 100)? - 0 : GCRY_CIPHER_ENABLE_SYNC))); - if (rc) - { - /* We should never get an error here cause we already checked - * that the algorithm is available. */ - BUG(); - } + if (ed->chunkbyte > 56) + { + log_error ("invalid AEAD chunkbyte %u\n", ed->chunkbyte); + rc = gpg_error (GPG_ERR_INV_PACKET); + goto leave; + } + /* Read the Start-IV. */ + if (ed->len) + { + for (i=0; i < startivlen && ed->len; i++, ed->len--) + { + if ((c=iobuf_get (ed->buf)) == -1) + break; + dfx->startiv[i] = c; + } + } + else + { + for (i=0; i < startivlen; i++ ) + if ( (c=iobuf_get (ed->buf)) == -1 ) + break; + else + dfx->startiv[i] = c; + } + if (i != startivlen) + { + log_error ("Start-IV in AEAD packet too short (%d/%u)\n", + i, startivlen); + rc = gpg_error (GPG_ERR_TOO_SHORT); + goto leave; + } + + dfx->cipher_algo = ed->cipher_algo; + dfx->aead_algo = ed->aead_algo; + dfx->chunkbyte = ed->chunkbyte; + dfx->chunksize = (uint64_t)1 << (dfx->chunkbyte + 6); + + if (dek->algo != dfx->cipher_algo) + log_info ("Note: different cipher algorithms used (%s/%s)\n", + openpgp_cipher_algo_name (dek->algo), + openpgp_cipher_algo_name (dfx->cipher_algo)); + + rc = openpgp_cipher_open (&dfx->cipher_hd, + dfx->cipher_algo, + ciphermode, + GCRY_CIPHER_SECURE); + if (rc) + goto leave; /* Should never happen. */ + + if (DBG_CRYPTO) + log_printhex (dek->key, dek->keylen, "thekey:"); + rc = gcry_cipher_setkey (dfx->cipher_hd, dek->key, dek->keylen); + if (gpg_err_code (rc) == GPG_ERR_WEAK_KEY) + { + log_info (_("WARNING: message was encrypted with" + " a weak key in the symmetric cipher.\n")); + rc = 0; + } + else if (rc) + { + log_error("key setup failed: %s\n", gpg_strerror (rc)); + goto leave; + } + + if (!ed->buf) + { + log_error(_("problem handling encrypted packet\n")); + goto leave; + } - /* log_hexdump( "thekey", dek->key, dek->keylen );*/ - rc = gcry_cipher_setkey (dfx->cipher_hd, dek->key, dek->keylen); - if ( gpg_err_code (rc) == GPG_ERR_WEAK_KEY ) - { - log_info(_("WARNING: message was encrypted with" - " a weak key in the symmetric cipher.\n")); - rc=0; } - else if( rc ) + else /* CFB encryption. */ { - log_error("key setup failed: %s\n", gpg_strerror (rc) ); - goto leave; - } + nprefix = blocksize; + if ( ed->len && ed->len < (nprefix+2) ) + { + /* An invalid message. We can't check that during parsing + * because we may not know the used cipher then. */ + rc = gpg_error (GPG_ERR_INV_PACKET); + goto leave; + } - if (!ed->buf) - { - log_error(_("problem handling encrypted packet\n")); - goto leave; - } + if ( ed->mdc_method ) + { + if (gcry_md_open (&dfx->mdc_hash, ed->mdc_method, 0 )) + BUG (); + if ( DBG_HASHING ) + gcry_md_debug (dfx->mdc_hash, "checkmdc"); + } + + rc = openpgp_cipher_open (&dfx->cipher_hd, dek->algo, + GCRY_CIPHER_MODE_CFB, + (GCRY_CIPHER_SECURE + | ((ed->mdc_method || dek->algo >= 100)? + 0 : GCRY_CIPHER_ENABLE_SYNC))); + if (rc) + { + /* We should never get an error here cause we already checked + * that the algorithm is available. */ + BUG(); + } - gcry_cipher_setiv (dfx->cipher_hd, NULL, 0); - if ( ed->len ) - { - for (i=0; i < (nprefix+2) && ed->len; i++, ed->len-- ) + /* log_hexdump( "thekey", dek->key, dek->keylen );*/ + rc = gcry_cipher_setkey (dfx->cipher_hd, dek->key, dek->keylen); + if ( gpg_err_code (rc) == GPG_ERR_WEAK_KEY ) { - if ( (c=iobuf_get(ed->buf)) == -1 ) - break; - else - temp[i] = c; + log_info (_("WARNING: message was encrypted with" + " a weak key in the symmetric cipher.\n")); + rc = 0; + } + else if (rc) + { + log_error("key setup failed: %s\n", gpg_strerror (rc) ); + goto leave; } - } - else - { - for (i=0; i < (nprefix+2); i++ ) - if ( (c=iobuf_get(ed->buf)) == -1 ) - break; - else - temp[i] = c; - } - gcry_cipher_decrypt (dfx->cipher_hd, temp, nprefix+2, NULL, 0); - gcry_cipher_sync (dfx->cipher_hd); - p = temp; - /* log_hexdump( "prefix", temp, nprefix+2 ); */ - if (dek->symmetric - && (p[nprefix-2] != p[nprefix] || p[nprefix-1] != p[nprefix+1]) ) - { - rc = gpg_error (GPG_ERR_BAD_KEY); - goto leave; - } + if (!ed->buf) + { + log_error (_("problem handling encrypted packet\n")); + goto leave; + } - if ( dfx->mdc_hash ) - gcry_md_write (dfx->mdc_hash, temp, nprefix+2); + gcry_cipher_setiv (dfx->cipher_hd, NULL, 0); + + if ( ed->len ) + { + for (i=0; i < (nprefix+2) && ed->len; i++, ed->len-- ) + { + if ( (c=iobuf_get(ed->buf)) == -1 ) + break; + else + temp[i] = c; + } + } + else + { + for (i=0; i < (nprefix+2); i++ ) + if ( (c=iobuf_get(ed->buf)) == -1 ) + break; + else + temp[i] = c; + } + + gcry_cipher_decrypt (dfx->cipher_hd, temp, nprefix+2, NULL, 0); + gcry_cipher_sync (dfx->cipher_hd); + p = temp; + /* log_hexdump( "prefix", temp, nprefix+2 ); */ + if (dek->symmetric + && (p[nprefix-2] != p[nprefix] || p[nprefix-1] != p[nprefix+1]) ) + { + rc = gpg_error (GPG_ERR_BAD_KEY); + goto leave; + } + + if ( dfx->mdc_hash ) + gcry_md_write (dfx->mdc_hash, temp, nprefix+2); + } dfx->refcount++; - dfx->partial = ed->is_partial; + dfx->partial = !!ed->is_partial; dfx->length = ed->len; - if ( ed->mdc_method ) + if (ed->aead_algo) + iobuf_push_filter ( ed->buf, aead_decode_filter, dfx ); + else if (ed->mdc_method) iobuf_push_filter ( ed->buf, mdc_decode_filter, dfx ); else iobuf_push_filter ( ed->buf, decode_filter, dfx ); @@ -287,26 +524,359 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek) log_assert (dfx->cipher_hd); log_assert (dfx->mdc_hash); - gcry_cipher_decrypt (dfx->cipher_hd, dfx->defer, 22, NULL, 0); - gcry_md_write (dfx->mdc_hash, dfx->defer, 2); + gcry_cipher_decrypt (dfx->cipher_hd, dfx->holdback, 22, NULL, 0); + gcry_md_write (dfx->mdc_hash, dfx->holdback, 2); gcry_md_final (dfx->mdc_hash); - if ( dfx->defer[0] != '\xd3' - || dfx->defer[1] != '\x14' + if ( dfx->holdback[0] != '\xd3' + || dfx->holdback[1] != '\x14' || datalen != 20 - || memcmp (gcry_md_read (dfx->mdc_hash, 0), dfx->defer+2, datalen)) + || memcmp (gcry_md_read (dfx->mdc_hash, 0), dfx->holdback+2, datalen)) rc = gpg_error (GPG_ERR_BAD_SIGNATURE); - /* log_printhex("MDC message:", dfx->defer, 22); */ - /* log_printhex("MDC calc:", gcry_md_read (dfx->mdc_hash,0), datalen); */ + /* log_printhex(dfx->holdback, 22, "MDC message:"); */ + /* log_printhex(gcry_md_read (dfx->mdc_hash,0), datalen, "MDC calc:"); */ } - leave: release_dfx_context (dfx); return rc; } +/* Fill BUFFER with up to NBYTES-OFFSET from STREAM utilizing + * information from the context DFX. Returns the new offset which is + * the number of bytes read plus the original offset. On EOF the + * respective flag in DFX is set. */ +static size_t +fill_buffer (decode_filter_ctx_t dfx, iobuf_t stream, + byte *buffer, size_t nbytes, size_t offset) +{ + size_t nread = offset; + size_t curr; + int ret; + + if (dfx->partial) + { + while (nread < nbytes) + { + curr = nbytes - nread; + + ret = iobuf_read (stream, &buffer[nread], curr); + if (ret == -1) + { + dfx->eof_seen = 1; /* Normal EOF. */ + break; + } + + nread += ret; + } + } + else + { + while (nread < nbytes && dfx->length) + { + curr = nbytes - nread; + if (curr > dfx->length) + curr = dfx->length; + + ret = iobuf_read (stream, &buffer[nread], curr); + if (ret == -1) + { + dfx->eof_seen = 3; /* Premature EOF. */ + break; + } + + nread += ret; + dfx->length -= ret; + } + if (!dfx->length) + dfx->eof_seen = 1; /* Normal EOF. */ + } + + return nread; +} + + +/* The core of the AEAD decryption. This is the underflow function of + * the aead_decode_filter. */ +static gpg_error_t +aead_underflow (decode_filter_ctx_t dfx, iobuf_t a, byte *buf, size_t *ret_len) +{ + const size_t size = *ret_len; /* The allocated size of BUF. */ + gpg_error_t err; + size_t totallen = 0; /* The number of bytes to return on success or EOF. */ + size_t off = 0; /* The offset into the buffer. */ + size_t len; /* The current number of bytes in BUF+OFF. */ + + log_assert (size > 48); /* Our code requires at least this size. */ + + /* Copy the rest from the last call of this function into BUF. */ + len = dfx->holdbacklen; + dfx->holdbacklen = 0; + memcpy (buf, dfx->holdback, len); + + if (DBG_FILTER) + log_debug ("aead_underflow: size=%zu len=%zu%s%s\n", size, len, + dfx->partial? " partial":"", dfx->eof_seen? " eof":""); + + /* Read and fill up BUF. We need to watch out for an EOF so that we + * can detect the last chunk which is commonly shorter than the + * chunksize. After the last data byte from the last chunk 32 more + * bytes are expected for the last chunk's tag and the following + * final chunk's tag. To detect the EOF we need to try reading at least + * one further byte; however we try to read 16 extra bytes to avoid + * single byte reads in some lower layers. The outcome is that we + * have up to 48 extra extra octets which we will later put into the + * holdback buffer for the next invocation (which handles the EOF + * case). */ + len = fill_buffer (dfx, a, buf, size, len); + if (len < 32) + { + /* Not enough data for the last two tags. */ + err = gpg_error (GPG_ERR_TRUNCATED); + goto leave; + } + if (dfx->eof_seen) + { + /* If have seen an EOF we copy only the last two auth tags into + * the holdback buffer. */ + dfx->holdbacklen = 32; + memcpy (dfx->holdback, buf+len-32, 32); + len -= 32; + } + else + { + /* If have not seen an EOF we copy the entire extra 48 bytes + * into the holdback buffer for processing at the next call of + * this function. */ + dfx->holdbacklen = len > 48? 48 : len; + memcpy (dfx->holdback, buf+len-dfx->holdbacklen, dfx->holdbacklen); + len -= dfx->holdbacklen; + } + /* log_printhex (dfx->holdback, dfx->holdbacklen, "holdback:"); */ + + /* Decrypt the buffer. This first requires a loop to handle the + * case when a chunk ends within the buffer. */ + if (DBG_FILTER) + log_debug ("decrypt: chunklen=%ju total=%ju size=%zu len=%zu%s\n", + dfx->chunklen, dfx->total, size, len, + dfx->eof_seen? " eof":""); + + while (len && dfx->chunklen + len >= dfx->chunksize) + { + size_t n = dfx->chunksize - dfx->chunklen; + byte tagbuf[16]; + + if (DBG_FILTER) + log_debug ("chunksize will be reached: n=%zu\n", n); + + if (!dfx->chunklen) + { + /* First data for this chunk - prepare. */ + err = aead_set_nonce_and_ad (dfx, 0); + if (err) + goto leave; + } + + /* log_printhex (buf, n, "ciph:"); */ + gcry_cipher_final (dfx->cipher_hd); + err = gcry_cipher_decrypt (dfx->cipher_hd, buf+off, n, NULL, 0); + if (err) + { + log_error ("gcry_cipher_decrypt failed (1): %s\n", + gpg_strerror (err)); + goto leave; + } + /* log_printhex (buf, n, "plai:"); */ + totallen += n; + dfx->chunklen += n; + dfx->total += n; + off += n; + len -= n; + + if (DBG_FILTER) + log_debug ("ndecrypted: %zu (nchunk=%ju) bytes left: %zu at off=%zu\n", + totallen, dfx->chunklen, len, off); + + /* Check the tag. */ + if (len < 16) + { + /* The tag is not entirely in the buffer. Read the rest of + * the tag from the holdback buffer. Then shift the holdback + * buffer and fill it up again. */ + memcpy (tagbuf, buf+off, len); + memcpy (tagbuf + len, dfx->holdback, 16 - len); + dfx->holdbacklen -= 16-len; + memmove (dfx->holdback, dfx->holdback + (16-len), dfx->holdbacklen); + + if (dfx->eof_seen) + { + /* We should have the last chunk's tag in TAGBUF and the + * final tag in HOLDBACKBUF. */ + if (len || dfx->holdbacklen != 16) + { + /* Not enough data for the last two tags. */ + err = gpg_error (GPG_ERR_TRUNCATED); + goto leave; + } + } + else + { + len = 0; + dfx->holdbacklen = fill_buffer (dfx, a, dfx->holdback, 48, + dfx->holdbacklen); + if (dfx->holdbacklen < 32) + { + /* Not enough data for the last two tags. */ + err = gpg_error (GPG_ERR_TRUNCATED); + goto leave; + } + } + } + else /* We already have the full tag. */ + { + memcpy (tagbuf, buf+off, 16); + /* Remove that tag from the output. */ + memmove (buf + off, buf + off + 16, len - 16); + len -= 16; + } + err = aead_checktag (dfx, 0, tagbuf); + if (err) + goto leave; + dfx->chunklen = 0; + dfx->chunkindex++; + + continue; + } + + /* The bulk decryption of our buffer. */ + if (len) + { + if (!dfx->chunklen) + { + /* First data for this chunk - prepare. */ + err = aead_set_nonce_and_ad (dfx, 0); + if (err) + goto leave; + } + + if (dfx->eof_seen) + { + /* This is the last block of the last chunk. Its length may + * not be a multiple of the block length. */ + gcry_cipher_final (dfx->cipher_hd); + } + err = gcry_cipher_decrypt (dfx->cipher_hd, buf + off, len, NULL, 0); + if (err) + { + log_error ("gcry_cipher_decrypt failed (2): %s\n", + gpg_strerror (err)); + goto leave; + } + totallen += len; + dfx->chunklen += len; + dfx->total += len; + if (DBG_FILTER) + log_debug ("ndecrypted: %zu (nchunk=%ju)\n", totallen, dfx->chunklen); + } + + if (dfx->eof_seen) + { + + if (dfx->chunklen) + { + if (DBG_FILTER) + log_debug ("eof seen: holdback has the last and final tag\n"); + log_assert (dfx->holdbacklen >= 32); + err = aead_checktag (dfx, 0, dfx->holdback); + if (err) + goto leave; + dfx->chunklen = 0; + dfx->chunkindex++; + off = 16; + } + else + { + if (DBG_FILTER) + log_debug ("eof seen: holdback has the final tag\n"); + log_assert (dfx->holdbacklen >= 16); + off = 0; + } + + /* Check the final chunk. */ + err = aead_set_nonce_and_ad (dfx, 1); + if (err) + goto leave; + gcry_cipher_final (dfx->cipher_hd); + /* Decrypt an empty string (using HOLDBACK as a dummy). */ + err = gcry_cipher_decrypt (dfx->cipher_hd, dfx->holdback, 0, NULL, 0); + if (err) + { + log_error ("gcry_cipher_decrypt failed (final): %s\n", + gpg_strerror (err)); + goto leave; + } + err = aead_checktag (dfx, 1, dfx->holdback+off); + if (err) + goto leave; + err = gpg_error (GPG_ERR_EOF); + } + + leave: + if (DBG_FILTER) + log_debug ("aead_underflow: returning %zu (%s)\n", + totallen, gpg_strerror (err)); + + /* In case of an auth error we map the error code to the same as + * used by the MDC decryption. */ + if (gpg_err_code (err) == GPG_ERR_CHECKSUM) + err = gpg_error (GPG_ERR_BAD_SIGNATURE); + + /* In case of an error we better wipe out the buffer than to convey + * partly decrypted data. */ + if (err && gpg_err_code (err) != GPG_ERR_EOF) + memset (buf, 0, size); + + *ret_len = totallen; + + return err; +} + + +/* The IOBUF filter used to decrypt AEAD encrypted data. */ +static int +aead_decode_filter (void *opaque, int control, IOBUF a, + byte *buf, size_t *ret_len) +{ + decode_filter_ctx_t dfx = opaque; + int rc = 0; + + if ( control == IOBUFCTRL_UNDERFLOW && dfx->eof_seen ) + { + *ret_len = 0; + rc = -1; + } + else if ( control == IOBUFCTRL_UNDERFLOW ) + { + log_assert (a); + + rc = aead_underflow (dfx, a, buf, ret_len); + if (gpg_err_code (rc) == GPG_ERR_EOF) + rc = -1; /* We need to use the old convention in the filter. */ + + } + else if ( control == IOBUFCTRL_FREE ) + { + release_dfx_context (dfx); + } + else if ( control == IOBUFCTRL_DESC ) + { + mem2str (buf, "aead_decode_filter", *ret_len); + } + + return rc; +} + static int mdc_decode_filter (void *opaque, int control, IOBUF a, @@ -315,7 +885,6 @@ mdc_decode_filter (void *opaque, int control, IOBUF a, decode_filter_ctx_t dfx = opaque; size_t n, size = *ret_len; int rc = 0; - int c; /* Note: We need to distinguish between a partial and a fixed length packet. The first is the usual case as created by GPG. However @@ -336,73 +905,29 @@ mdc_decode_filter (void *opaque, int control, IOBUF a, log_assert (size > 44); /* Our code requires at least this size. */ /* Get at least 22 bytes and put it ahead in the buffer. */ - if (dfx->partial) - { - for (n=22; n < 44; n++) - { - if ( (c = iobuf_get(a)) == -1 ) - break; - buf[n] = c; - } - } - else - { - for (n=22; n < 44 && dfx->length; n++, dfx->length--) - { - c = iobuf_get (a); - if (c == -1) - break; /* Premature EOF. */ - buf[n] = c; - } - } + n = fill_buffer (dfx, a, buf, 44, 22); if (n == 44) { /* We have enough stuff - flush the deferred stuff. */ - if ( !dfx->defer_filled ) /* First time. */ + if ( !dfx->holdbacklen ) /* First time. */ { memcpy (buf, buf+22, 22); n = 22; } else { - memcpy (buf, dfx->defer, 22); + memcpy (buf, dfx->holdback, 22); } /* Fill up the buffer. */ - if (dfx->partial) - { - for (; n < size; n++ ) - { - if ( (c = iobuf_get(a)) == -1 ) - { - dfx->eof_seen = 1; /* Normal EOF. */ - break; - } - buf[n] = c; - } - } - else - { - for (; n < size && dfx->length; n++, dfx->length--) - { - c = iobuf_get(a); - if (c == -1) - { - dfx->eof_seen = 3; /* Premature EOF. */ - break; - } - buf[n] = c; - } - if (!dfx->length) - dfx->eof_seen = 1; /* Normal EOF. */ - } + n = fill_buffer (dfx, a, buf, size, n); - /* Move the trailing 22 bytes back to the defer buffer. We + /* Move the trailing 22 bytes back to the holdback buffer. We have at least 44 bytes thus a memmove is not needed. */ n -= 22; - memcpy (dfx->defer, buf+n, 22 ); - dfx->defer_filled = 1; + memcpy (dfx->holdback, buf+n, 22 ); + dfx->holdbacklen = 22; } - else if ( !dfx->defer_filled ) /* EOF seen but empty defer buffer. */ + else if ( !dfx->holdbacklen ) /* EOF seen but empty holdback buffer. */ { /* This is bad because it means an incomplete hash. */ n -= 22; @@ -411,9 +936,9 @@ mdc_decode_filter (void *opaque, int control, IOBUF a, } else /* EOF seen (i.e. read less than 22 bytes). */ { - memcpy (buf, dfx->defer, 22 ); + memcpy (buf, dfx->holdback, 22 ); n -= 22; - memcpy (dfx->defer, buf+n, 22 ); + memcpy (dfx->holdback, buf+n, 22 ); dfx->eof_seen = 1; /* Normal EOF. */ } @@ -449,7 +974,7 @@ decode_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len) decode_filter_ctx_t fc = opaque; size_t size = *ret_len; size_t n; - int c, rc = 0; + int rc = 0; if ( control == IOBUFCTRL_UNDERFLOW && fc->eof_seen ) @@ -461,34 +986,7 @@ decode_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len) { log_assert (a); - if (fc->partial) - { - for (n=0; n < size; n++ ) - { - c = iobuf_get(a); - if (c == -1) - { - fc->eof_seen = 1; /* Normal EOF. */ - break; - } - buf[n] = c; - } - } - else - { - for (n=0; n < size && fc->length; n++, fc->length--) - { - c = iobuf_get(a); - if (c == -1) - { - fc->eof_seen = 3; /* Premature EOF. */ - break; - } - buf[n] = c; - } - if (!fc->length) - fc->eof_seen = 1; /* Normal EOF. */ - } + n = fill_buffer (fc, a, buf, size, 0); if (n) { if (fc->cipher_hd) @@ -19,21 +19,31 @@ #ifndef G10_DEK_H #define G10_DEK_H - typedef struct { /* The algorithm (e.g., CIPHER_ALGO_AES). */ int algo; /* The length of the key (in bytes). */ int keylen; + /* Whether we've already printed information about this key. This - is currently only used in decrypt_data() and only if we are in - verbose mode. */ - int algo_info_printed; - int use_mdc; + * is currently only used in decrypt_data() and only if we are in + * verbose mode. */ + unsigned int algo_info_printed : 1; + + /* AEAD shall be used. The value is the AEAD algo. */ + int use_aead : 4; + + /* MDC shall be used. */ + unsigned int use_mdc : 1; + /* This key was read from a SK-ESK packet (see proc_symkey_enc). */ - int symmetric; - byte key[32]; /* This is the largest used keylen (256 bit). */ + unsigned int symmetric : 1; + + /* This is the largest used keylen (256 bit). */ + byte key[32]; + + /* The cacheid for the S2K. */ char s2k_cacheid[1+16+1]; } DEK; @@ -76,7 +76,7 @@ pk_ecdh_default_params (unsigned int qbits) } log_assert (i < DIM (kek_params_table)); if (DBG_CRYPTO) - log_printhex ("ECDH KEK params are", kek_params, sizeof(kek_params) ); + log_printhex (kek_params, sizeof(kek_params), "ECDH KEK params are"); return gcry_mpi_set_opaque (NULL, kek_params, 4 * 8); } @@ -159,7 +159,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, memset (secret_x+secret_x_size, 0, nbytes-secret_x_size); if (DBG_CRYPTO) - log_printhex ("ECDH shared secret X is:", secret_x, secret_x_size ); + log_printhex (secret_x, secret_x_size, "ECDH shared secret X is:"); } /*** We have now the shared secret bytes in secret_x. ***/ @@ -179,7 +179,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, kek_params_size = (nbits+7)/8; if (DBG_CRYPTO) - log_printhex ("ecdh KDF params:", kek_params, kek_params_size); + log_printhex (kek_params, kek_params_size, "ecdh KDF params:"); /* Expect 4 bytes 03 01 hash_alg symm_alg. */ if (kek_params_size != 4 || kek_params[0] != 3 || kek_params[1] != 1) @@ -236,7 +236,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, } if(DBG_CRYPTO) - log_printhex ("ecdh KDF message params are:", message, message_size); + log_printhex (message, message_size, "ecdh KDF message params are:"); } /* Derive a KEK (key wrapping key) using MESSAGE and SECRET_X. */ @@ -272,7 +272,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, /* We could have allocated more, so clean the tail before returning. */ memset (secret_x+secret_x_size, 0, old_size - secret_x_size); if (DBG_CRYPTO) - log_printhex ("ecdh KEK is:", secret_x, secret_x_size ); + log_printhex (secret_x, secret_x_size, "ecdh KEK is:"); } /* And, finally, aeswrap with key secret_x. */ @@ -338,7 +338,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, } if (DBG_CRYPTO) - log_printhex ("ecdh encrypting :", in, data_buf_size ); + log_printhex (in, data_buf_size, "ecdh encrypting :"); err = gcry_cipher_encrypt (hd, data_buf+1, data_buf_size+8, in, data_buf_size); @@ -354,7 +354,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, data_buf[0] = data_buf_size+8; if (DBG_CRYPTO) - log_printhex ("ecdh encrypted to:", data_buf+1, data_buf[0] ); + log_printhex (data_buf+1, data_buf[0], "ecdh encrypted to:"); result = gcry_mpi_set_opaque (NULL, data_buf, 8 * (1+data_buf[0])); if (!result) @@ -391,7 +391,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, data_buf_size = data_buf[0]; if (DBG_CRYPTO) - log_printhex ("ecdh decrypting :", data_buf+1, data_buf_size); + log_printhex (data_buf+1, data_buf_size, "ecdh decrypting :"); err = gcry_cipher_decrypt (hd, in, data_buf_size, data_buf+1, data_buf_size); @@ -407,7 +407,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi, data_buf_size -= 8; if (DBG_CRYPTO) - log_printhex ("ecdh decrypted to :", in, data_buf_size); + log_printhex (in, data_buf_size, "ecdh decrypted to :"); /* Padding is removed later. */ /* if (in[data_buf_size-1] > 8 ) */ diff --git a/g10/encrypt.c b/g10/encrypt.c index 543f1a7..42cad2b 100644 --- a/g10/encrypt.c +++ b/g10/encrypt.c @@ -110,7 +110,7 @@ encrypt_seskey (DEK *dek, DEK **seskey, byte *enckey) /* Shall we use the MDC? Yes - unless rfc-2440 compatibility is - * requested. */ + * requested. Must return 1 or 0. */ int use_mdc (pk_list_t pk_list,int algo) { @@ -191,18 +191,9 @@ encrypt_simple (const char *filename, int mode, int use_seskey) cfx.dek = NULL; if ( mode ) { - int canceled; - - s2k = xmalloc_clear( sizeof *s2k ); - s2k->mode = opt.s2k_mode; - s2k->hash_algo = S2K_DIGEST_ALGO; - cfx.dek = passphrase_to_dek (default_cipher_algo (), s2k, 1, 0, - NULL, &canceled); - if ( !cfx.dek || !cfx.dek->keylen ) + rc = setup_symkey (&s2k, &cfx.dek); + if (rc) { - rc = gpg_error (canceled? GPG_ERR_CANCELED:GPG_ERR_INV_PASSPHRASE); - xfree (cfx.dek); - xfree (s2k); iobuf_close (inp); log_error (_("error creating passphrase: %s\n"), gpg_strerror (rc)); release_progress_context (pfx); @@ -378,22 +369,22 @@ encrypt_simple (const char *filename, int mode, int use_seskey) } -int -setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek) +gpg_error_t +setup_symkey (STRING2KEY **symkey_s2k, DEK **symkey_dek) { int canceled; - *symkey_s2k=xmalloc_clear(sizeof(STRING2KEY)); + *symkey_s2k = xmalloc_clear (sizeof **symkey_s2k); (*symkey_s2k)->mode = opt.s2k_mode; (*symkey_s2k)->hash_algo = S2K_DIGEST_ALGO; - *symkey_dek = passphrase_to_dek (opt.s2k_cipher_algo, + *symkey_dek = passphrase_to_dek (default_cipher_algo (), *symkey_s2k, 1, 0, NULL, &canceled); - if(!*symkey_dek || !(*symkey_dek)->keylen) + if (!*symkey_dek || !(*symkey_dek)->keylen) { xfree(*symkey_dek); xfree(*symkey_s2k); - return gpg_error (canceled?GPG_ERR_CANCELED:GPG_ERR_BAD_PASSPHRASE); + return gpg_error (canceled?GPG_ERR_CANCELED:GPG_ERR_INV_PASSPHRASE); } return 0; @@ -619,15 +610,15 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename, PKT_public_key *pk = pkr->pk; unsigned int nbits = nbits_from_pk (pk); - if (!gnupg_pk_is_compliant (opt.compliance, - pk->pubkey_algo, pk->pkey, nbits, NULL)) + if (!gnupg_pk_is_compliant (opt.compliance, pk->pubkey_algo, 0, + pk->pkey, nbits, NULL)) log_info (_("WARNING: key %s is not suitable for encryption" " in %s mode\n"), keystr_from_pk (pk), gnupg_compliance_option_string (opt.compliance)); if (compliant - && !gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, pk->pkey, + && !gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, 0, pk->pkey, nbits, NULL)) compliant = 0; } @@ -660,7 +651,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename, make_session_key (cfx.dek); if (DBG_CRYPTO) - log_printhex ("DEK is: ", cfx.dek->key, cfx.dek->keylen ); + log_printhex (cfx.dek->key, cfx.dek->keylen, "DEK is: "); rc = write_pubkey_enc_from_list (ctrl, pk_list, cfx.dek, out); if (rc) @@ -854,7 +845,7 @@ encrypt_filter (void *opaque, int control, make_session_key ( efx->cfx.dek ); if (DBG_CRYPTO) - log_printhex ("DEK is: ", efx->cfx.dek->key, efx->cfx.dek->keylen); + log_printhex (efx->cfx.dek->key, efx->cfx.dek->keylen, "DEK is: "); rc = write_pubkey_enc_from_list (efx->ctrl, efx->pk_list, efx->cfx.dek, a); diff --git a/g10/export.c b/g10/export.c index 3f4b565..5149277 100644 --- a/g10/export.c +++ b/g10/export.c @@ -1028,11 +1028,11 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk) /* log_debug ("XXX pubkey_algo=%d\n", pubkey_algo); */ /* log_debug ("XXX is_protected=%d\n", is_protected); */ /* log_debug ("XXX protect_algo=%d\n", protect_algo); */ - /* log_printhex ("XXX iv", iv, ivlen); */ + /* log_printhex (iv, ivlen, "XXX iv"); */ /* log_debug ("XXX ivlen=%d\n", ivlen); */ /* log_debug ("XXX s2k_mode=%d\n", s2k_mode); */ /* log_debug ("XXX s2k_algo=%d\n", s2k_algo); */ - /* log_printhex ("XXX s2k_salt", s2k_salt, sizeof s2k_salt); */ + /* log_printhex (s2k_salt, sizeof s2k_salt, "XXX s2k_salt"); */ /* log_debug ("XXX s2k_count=%lu\n", (unsigned long)s2k_count); */ /* for (idx=0; skey[idx]; idx++) */ /* { */ @@ -1043,7 +1043,7 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk) /* void *p; */ /* unsigned int nbits; */ /* p = gcry_mpi_get_opaque (skey[idx], &nbits); */ - /* log_printhex (NULL, p, (nbits+7)/8); */ + /* log_printhex ( p, (nbits+7)/8, NULL); */ /* } */ /* else */ /* gcry_mpi_dump (skey[idx]); */ @@ -1110,7 +1110,7 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk) /* void *p; */ /* unsigned int nbits; */ /* p = gcry_mpi_get_opaque (skey[idx], &nbits); */ - /* log_printhex (NULL, p, (nbits+7)/8); */ + /* log_printhex (p, (nbits+7)/8, NULL); */ /* } */ /* else */ /* gcry_mpi_dump (skey[idx]); */ diff --git a/g10/getkey.c b/g10/getkey.c index cafed3a..3d0dd0b 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -2414,8 +2414,8 @@ fixup_uidnode (KBNODE uidnode, KBNODE signode, u32 keycreated) { PKT_user_id *uid = uidnode->pkt->pkt.user_id; PKT_signature *sig = signode->pkt->pkt.signature; - const byte *p, *sym, *hash, *zip; - size_t n, nsym, nhash, nzip; + const byte *p, *sym, *aead, *hash, *zip; + size_t n, nsym, naead, nhash, nzip; sig->flags.chosen_selfsig = 1;/* We chose this one. */ uid->created = 0; /* Not created == invalid. */ @@ -2470,6 +2470,9 @@ fixup_uidnode (KBNODE uidnode, KBNODE signode, u32 keycreated) p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_SYM, &n); sym = p; nsym = p ? n : 0; + p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_AEAD, &n); + aead = p; + naead = p ? n : 0; p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_HASH, &n); hash = p; nhash = p ? n : 0; @@ -2490,6 +2493,11 @@ fixup_uidnode (KBNODE uidnode, KBNODE signode, u32 keycreated) uid->prefs[n].type = PREFTYPE_SYM; uid->prefs[n].value = *sym++; } + for (; naead; naead--, n++) + { + uid->prefs[n].type = PREFTYPE_AEAD; + uid->prefs[n].value = *aead++; + } for (; nhash; nhash--, n++) { uid->prefs[n].type = PREFTYPE_HASH; @@ -2510,6 +2518,12 @@ fixup_uidnode (KBNODE uidnode, KBNODE signode, u32 keycreated) if (p && n && (p[0] & 0x01)) uid->flags.mdc = 1; + /* See whether we have the AEAD feature. */ + uid->flags.aead = 0; + p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n); + if (p && n && (p[0] & 0x02)) + uid->flags.aead = 1; + /* And the keyserver modify flag. */ uid->flags.ks_modify = 1; p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KS_FLAGS, &n); @@ -3332,6 +3346,7 @@ merge_selfsigs (ctrl_t ctrl, kbnode_t keyblock) PKT_public_key *main_pk; prefitem_t *prefs; unsigned int mdc_feature; + unsigned int aead_feature; if (keyblock->pkt->pkttype != PKT_PUBLIC_KEY) { @@ -3393,7 +3408,7 @@ merge_selfsigs (ctrl_t ctrl, kbnode_t keyblock) * all preferences. * Do a similar thing for the MDC feature flag. */ prefs = NULL; - mdc_feature = 0; + mdc_feature = aead_feature = 0; for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next) { if (k->pkt->pkttype == PKT_USER_ID @@ -3402,6 +3417,7 @@ merge_selfsigs (ctrl_t ctrl, kbnode_t keyblock) { prefs = k->pkt->pkt.user_id->prefs; mdc_feature = k->pkt->pkt.user_id->flags.mdc; + aead_feature = k->pkt->pkt.user_id->flags.aead; break; } } @@ -3415,6 +3431,7 @@ merge_selfsigs (ctrl_t ctrl, kbnode_t keyblock) xfree (pk->prefs); pk->prefs = copy_prefs (prefs); pk->flags.mdc = mdc_feature; + pk->flags.aead = aead_feature; } } } @@ -893,6 +893,7 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_n (oNoAutostart, "no-autostart", "@"), ARGPARSE_s_n (oNoSymkeyCache, "no-symkey-cache", "@"), ARGPARSE_s_n (oIncludeKeyBlock, "include-key-block", "@"), + ARGPARSE_s_n (oNoIncludeKeyBlock, "no-include-key-block", "@"), ARGPARSE_s_n (oAutoKeyImport, "auto-key-import", "@"), ARGPARSE_s_n (oNoAutoKeyImport, "no-auto-key-import", "@"), @@ -4436,7 +4437,10 @@ main (int argc, char **argv) case aDeleteSecretKeys: case aDeleteSecretAndPublicKeys: sl = NULL; - /* I'm adding these in reverse order as add_to_strlist2 + /* Print a note if the user did not specify any key. */ + if (!argc && !opt.quiet) + log_info (_("Note: %s\n"), gpg_strerror (GPG_ERR_NO_KEY)); + /* I'm adding these in reverse order as add_to_strlist2 reverses them again, and it's easier to understand in the proper order :) */ for( ; argc; argc-- ) diff --git a/g10/keyedit.c b/g10/keyedit.c index 7ed997a..a7932ce 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -3069,6 +3069,23 @@ show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose) tty_printf ("%s", openpgp_cipher_algo_name (CIPHER_ALGO_3DES)); } tty_printf ("\n "); + tty_printf (_("AEAD: ")); + for (i = any = 0; prefs[i].type; i++) + { + if (prefs[i].type == PREFTYPE_AEAD) + { + if (any) + tty_printf (", "); + any = 1; + /* We don't want to display strings for experimental algos */ + if (!openpgp_aead_test_algo (prefs[i].value) + && prefs[i].value < 100) + tty_printf ("%s", openpgp_aead_algo_name (prefs[i].value)); + else + tty_printf ("[%d]", prefs[i].value); + } + } + tty_printf ("\n "); tty_printf (_("Digest: ")); for (i = any = 0; prefs[i].type; i++) { @@ -3123,7 +3140,7 @@ show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose) } tty_printf ("%s", compress_algo_to_string (COMPRESS_ALGO_NONE)); } - if (uid->flags.mdc || !uid->flags.ks_modify) + if (uid->flags.mdc || uid->flags.aead || !uid->flags.ks_modify) { tty_printf ("\n "); tty_printf (_("Features: ")); @@ -3133,6 +3150,12 @@ show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose) tty_printf ("MDC"); any = 1; } + if (!uid->flags.aead) + { + if (any) + tty_printf (", "); + tty_printf ("AEAD"); + } if (!uid->flags.ks_modify) { if (any) @@ -3171,12 +3194,15 @@ show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose) for (i = 0; prefs[i].type; i++) { tty_printf (" %c%d", prefs[i].type == PREFTYPE_SYM ? 'S' : + prefs[i].type == PREFTYPE_AEAD ? 'A' : prefs[i].type == PREFTYPE_HASH ? 'H' : prefs[i].type == PREFTYPE_ZIP ? 'Z' : '?', prefs[i].value); } if (uid->flags.mdc) tty_printf (" [mdc]"); + if (uid->flags.aead) + tty_printf (" [aead]"); if (!uid->flags.ks_modify) tty_printf (" [no-ks-modify]"); tty_printf ("\n"); diff --git a/g10/keyid.c b/g10/keyid.c index 5b868cd..69d85da 100644 --- a/g10/keyid.c +++ b/g10/keyid.c @@ -953,7 +953,7 @@ keygrip_from_pk (PKT_public_key *pk, unsigned char *array) else { if (DBG_PACKET) - log_printhex ("keygrip=", array, 20); + log_printhex (array, 20, "keygrip="); /* FIXME: Save the keygrip in PK. */ } gcry_sexp_release (s_pkey); diff --git a/g10/keylist.c b/g10/keylist.c index 8ff4085..5b0f7ba 100644 --- a/g10/keylist.c +++ b/g10/keylist.c @@ -1340,7 +1340,7 @@ print_compliance_flags (PKT_public_key *pk, es_fputs (gnupg_status_compliance_flag (CO_GNUPG), es_stdout); any++; } - if (gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, pk->pkey, + if (gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, 0, pk->pkey, keylength, curvename)) { es_fprintf (es_stdout, any ? " %s" : "%s", @@ -122,6 +122,12 @@ int openpgp_cipher_blocklen (cipher_algo_t algo); int openpgp_cipher_test_algo(cipher_algo_t algo); const char *openpgp_cipher_algo_name (cipher_algo_t algo); +gpg_error_t openpgp_aead_test_algo (aead_algo_t algo); +const char *openpgp_aead_algo_name (aead_algo_t algo); +gpg_error_t openpgp_aead_algo_info (aead_algo_t algo, + enum gcry_cipher_modes *r_mode, + unsigned int *r_noncelen); + pubkey_algo_t map_pk_gcry_to_openpgp (enum gcry_pk_algos algo); int openpgp_pk_test_algo (pubkey_algo_t algo); int openpgp_pk_test_algo2 (pubkey_algo_t algo, unsigned int use); @@ -223,7 +229,7 @@ int cpr_get_answer_okay_cancel (const char *keyword, void display_online_help( const char *keyword ); /*-- encode.c --*/ -int setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek); +gpg_error_t setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek); void encrypt_seskey (DEK *dek, DEK **seskey, byte *enckey); int use_mdc (pk_list_t pk_list,int algo); int encrypt_symmetric (const char *filename ); diff --git a/g10/mainproc.c b/g10/mainproc.c index d278c2d..79ff211 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -97,6 +97,7 @@ struct mainproc_context int trustletter; /* Temporary usage in list_node. */ ulong symkeys; /* Number of symmetrically encrypted session keys. */ struct kidlist_item *pkenc_list; /* List of encryption packets. */ + int seen_pkt_encrypted_aead; /* PKT_ENCRYPTED_AEAD packet seen. */ struct { unsigned int sig_seen:1; /* Set to true if a signature packet has been seen. */ @@ -145,6 +146,7 @@ release_list( CTX c ) c->any.data = 0; c->any.uncompress_failed = 0; c->last_was_session_key = 0; + c->seen_pkt_encrypted_aead = 0; xfree (c->dek); c->dek = NULL; } @@ -252,47 +254,111 @@ add_signature (CTX c, PACKET *pkt) return 1; } -static int + +static gpg_error_t symkey_decrypt_seskey (DEK *dek, byte *seskey, size_t slen) { + gpg_error_t err; gcry_cipher_hd_t hd; + enum gcry_cipher_modes ciphermode; + unsigned int noncelen, keylen; - if(slen < 17 || slen > 33) + if (dek->use_aead) + { + err = openpgp_aead_algo_info (dek->use_aead, &ciphermode, &noncelen); + if (err) + return err; + } + else + { + ciphermode = GCRY_CIPHER_MODE_CFB; + noncelen = 0; + } + + /* Check that the session key has a size of 16 to 32 bytes. */ + if ((dek->use_aead && (slen < (noncelen + 16 + 16) + || slen > (noncelen + 32 + 16))) + || (!dek->use_aead && (slen < 17 || slen > 33))) { log_error ( _("weird size for an encrypted session key (%d)\n"), (int)slen); - return GPG_ERR_BAD_KEY; + return gpg_error (GPG_ERR_BAD_KEY); } - if (openpgp_cipher_open (&hd, dek->algo, GCRY_CIPHER_MODE_CFB, 1)) - BUG (); - if (gcry_cipher_setkey ( hd, dek->key, dek->keylen )) - BUG (); - gcry_cipher_setiv ( hd, NULL, 0 ); - gcry_cipher_decrypt ( hd, seskey, slen, NULL, 0 ); - gcry_cipher_close ( hd ); - - /* Here we can only test whether the algo given in decrypted - * session key is a valid OpenPGP algo. With 11 defined - * symmetric algorithms we will miss 4.3% of wrong passphrases - * here. The actual checking is done later during bulk - * decryption; we can't bring this check forward easily. */ - if (openpgp_cipher_test_algo (seskey[0])) - return gpg_error (GPG_ERR_BAD_KEY); - - /* Now we replace the dek components with the real session key to - decrypt the contents of the sequencing packet. */ + err = openpgp_cipher_open (&hd, dek->algo, ciphermode, 1); + if (!err) + err = gcry_cipher_setkey (hd, dek->key, dek->keylen); + if (!err) + err = gcry_cipher_setiv (hd, noncelen? seskey : NULL, noncelen); + if (err) + goto leave; - dek->keylen=slen-1; - dek->algo=seskey[0]; - - if(dek->keylen > DIM(dek->key)) - BUG (); + if (dek->use_aead) + { + byte ad[4]; + + ad[0] = (0xc0 | PKT_SYMKEY_ENC); + ad[1] = 5; + ad[2] = dek->algo; + ad[3] = dek->use_aead; + err = gcry_cipher_authenticate (hd, ad, 4); + if (err) + goto leave; + gcry_cipher_final (hd); + keylen = slen - noncelen - 16; + err = gcry_cipher_decrypt (hd, seskey+noncelen, keylen, NULL, 0); + if (err) + goto leave; + err = gcry_cipher_checktag (hd, seskey+noncelen+keylen, 16); + if (err) + goto leave; + /* Now we replace the dek components with the real session key to + * decrypt the contents of the sequencing packet. */ + if (keylen > DIM(dek->key)) + { + err = gpg_error (GPG_ERR_TOO_LARGE); + goto leave; + } + dek->keylen = keylen; + memcpy (dek->key, seskey + noncelen, dek->keylen); + } + else + { + gcry_cipher_decrypt (hd, seskey, slen, NULL, 0); + + /* Here we can only test whether the algo given in decrypted + * session key is a valid OpenPGP algo. With 11 defined + * symmetric algorithms we will miss 4.3% of wrong passphrases + * here. The actual checking is done later during bulk + * decryption; we can't bring this check forward easily. We + * need to use the GPG_ERR_CHECKSUM so that we won't run into + * the gnupg < 2.2 bug compatible case which would terminate the + * process on GPG_ERR_CIPHER_ALGO. Note that with AEAD (above) + * we will have a reliable test here. */ + if (openpgp_cipher_test_algo (seskey[0]) + || openpgp_cipher_get_algo_keylen (seskey[0]) != slen - 1) + { + err = gpg_error (GPG_ERR_CHECKSUM); + goto leave; + } - memcpy(dek->key, seskey + 1, dek->keylen); + /* Now we replace the dek components with the real session key to + * decrypt the contents of the sequencing packet. */ + keylen = slen-1; + if (keylen > DIM(dek->key)) + { + err = gpg_error (GPG_ERR_TOO_LARGE); + goto leave; + } + dek->algo = seskey[0]; + dek->keylen = slen-1; + memcpy (dek->key, seskey + 1, dek->keylen); + } /*log_hexdump( "thekey", dek->key, dek->keylen );*/ + leave: + gcry_cipher_close (hd); return 0; } @@ -300,6 +366,7 @@ symkey_decrypt_seskey (DEK *dek, byte *seskey, size_t slen) static void proc_symkey_enc (CTX c, PACKET *pkt) { + gpg_error_t err; PKT_symkey_enc *enc; enc = pkt->pkt.symkey_enc; @@ -309,15 +376,20 @@ proc_symkey_enc (CTX c, PACKET *pkt) { int algo = enc->cipher_algo; const char *s = openpgp_cipher_algo_name (algo); + const char *a = (enc->aead_algo ? openpgp_aead_algo_name (enc->aead_algo) + /**/ : "CFB"); if (!openpgp_cipher_test_algo (algo)) { if (!opt.quiet) { + /* Note: TMPSTR is only used to avoid i18n changes. */ + char *tmpstr = xstrconcat (s, ".", a, NULL); if (enc->seskeylen) - log_info (_("%s encrypted session key\n"), s ); + log_info (_("%s encrypted session key\n"), tmpstr); else - log_info (_("%s encrypted data\n"), s ); + log_info (_("%s encrypted data\n"), tmpstr); + xfree (tmpstr); } } else @@ -349,6 +421,7 @@ proc_symkey_enc (CTX c, PACKET *pkt) if (c->dek) { c->dek->symmetric = 1; + c->dek->use_aead = enc->aead_algo; /* FIXME: This doesn't work perfectly if a symmetric key comes before a public key in the message - if the @@ -359,9 +432,16 @@ proc_symkey_enc (CTX c, PACKET *pkt) come later. */ if (enc->seskeylen) { - if (symkey_decrypt_seskey (c->dek, - enc->seskey, enc->seskeylen)) + err = symkey_decrypt_seskey (c->dek, + enc->seskey, enc->seskeylen); + if (err) { + log_info ("decryption of the symmetrically encrypted" + " session key failed: %s\n", + gpg_strerror (err)); + if (gpg_err_code (err) != GPG_ERR_BAD_KEY + && gpg_err_code (err) != GPG_ERR_CHECKSUM) + log_fatal ("process terminated to be bug compatible\n"); if (c->dek->s2k_cacheid[0]) { if (opt.debug) @@ -550,6 +630,9 @@ proc_encrypted (CTX c, PACKET *pkt) int result = 0; int early_plaintext = literals_seen; + if (pkt->pkttype == PKT_ENCRYPTED_AEAD) + c->seen_pkt_encrypted_aead = 1; + if (early_plaintext) { log_info (_("WARNING: multiple plaintexts seen\n")); @@ -656,8 +739,8 @@ proc_encrypted (CTX c, PACKET *pkt) memset (pk, 0, sizeof *pk); pk->pubkey_algo = i->pubkey_algo; if (get_pubkey (c->ctrl, pk, i->kid) != 0 - || ! gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, pk->pkey, - nbits_from_pk (pk), NULL)) + || ! gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, 0, + pk->pkey, nbits_from_pk (pk), NULL)) compliant = 0; release_public_key_parts (pk); } @@ -683,7 +766,8 @@ proc_encrypted (CTX c, PACKET *pkt) ; else if (!result && !opt.ignore_mdc_error - && !pkt->pkt.encrypted->mdc_method) + && !pkt->pkt.encrypted->mdc_method + && !pkt->pkt.encrypted->aead_algo) { /* The message has been decrypted but does not carry an MDC. * The option --ignore-mdc-error has also not been used. To @@ -712,17 +796,25 @@ proc_encrypted (CTX c, PACKET *pkt) write_status (STATUS_DECRYPTION_FAILED); } else if (!result || (gpg_err_code (result) == GPG_ERR_BAD_SIGNATURE + && !pkt->pkt.encrypted->aead_algo && opt.ignore_mdc_error)) { + /* All is fine or for an MDC message the MDC failed but the + * --ignore-mdc-error option is active. For compatibility + * reasons we issue GOODMDC also for AEAD messages. */ write_status (STATUS_DECRYPTION_OKAY); if (opt.verbose > 1) log_info(_("decryption okay\n")); - if (pkt->pkt.encrypted->mdc_method && !result) + + if (pkt->pkt.encrypted->aead_algo) + write_status (STATUS_GOODMDC); + else if (pkt->pkt.encrypted->mdc_method && !result) write_status (STATUS_GOODMDC); else log_info (_("WARNING: message was not integrity protected\n")); } - else if (gpg_err_code (result) == GPG_ERR_BAD_SIGNATURE) + else if (gpg_err_code (result) == GPG_ERR_BAD_SIGNATURE + || gpg_err_code (result) == GPG_ERR_TRUNCATED) { glo_ctrl.lasterr = result; log_error (_("WARNING: encrypted message has been manipulated!\n")); @@ -732,6 +824,7 @@ proc_encrypted (CTX c, PACKET *pkt) else { if ((gpg_err_code (result) == GPG_ERR_BAD_KEY + || gpg_err_code (result) == GPG_ERR_CHECKSUM || gpg_err_code (result) == GPG_ERR_CIPHER_ALGO) && *c->dek->s2k_cacheid != '\0') { @@ -761,6 +854,21 @@ proc_encrypted (CTX c, PACKET *pkt) } +static int +have_seen_pkt_encrypted_aead( CTX c ) +{ + CTX cc; + + for (cc = c; cc; cc = cc->anchor) + { + if (cc->seen_pkt_encrypted_aead) + return 1; + } + + return 0; +} + + static void proc_plaintext( CTX c, PACKET *pkt ) { @@ -836,7 +944,7 @@ proc_plaintext( CTX c, PACKET *pkt ) } } - if (!any && !opt.skip_verify) + if (!any && !opt.skip_verify && !have_seen_pkt_encrypted_aead(c)) { /* This is for the old GPG LITERAL+SIG case. It's not legal according to 2440, so hopefully it won't come up that often. @@ -1467,7 +1575,8 @@ do_proc_packets (ctrl_t ctrl, CTX c, iobuf_t a) case PKT_PUBKEY_ENC: proc_pubkey_enc (ctrl, c, pkt); break; case PKT_SYMKEY_ENC: proc_symkey_enc (c, pkt); break; case PKT_ENCRYPTED: - case PKT_ENCRYPTED_MDC: proc_encrypted (c, pkt); break; + case PKT_ENCRYPTED_MDC: + case PKT_ENCRYPTED_AEAD:proc_encrypted (c, pkt); break; case PKT_COMPRESSED: rc = proc_compressed (c, pkt); break; default: newpkt = 0; break; } @@ -1483,6 +1592,7 @@ do_proc_packets (ctrl_t ctrl, CTX c, iobuf_t a) case PKT_PUBKEY_ENC: case PKT_ENCRYPTED: case PKT_ENCRYPTED_MDC: + case PKT_ENCRYPTED_AEAD: write_status_text( STATUS_UNEXPECTED, "0" ); rc = GPG_ERR_UNEXPECTED; goto leave; @@ -1510,7 +1620,8 @@ do_proc_packets (ctrl_t ctrl, CTX c, iobuf_t a) case PKT_SYMKEY_ENC: proc_symkey_enc (c, pkt); break; case PKT_PUBKEY_ENC: proc_pubkey_enc (ctrl, c, pkt); break; case PKT_ENCRYPTED: - case PKT_ENCRYPTED_MDC: proc_encrypted (c, pkt); break; + case PKT_ENCRYPTED_MDC: + case PKT_ENCRYPTED_AEAD: proc_encrypted (c, pkt); break; case PKT_PLAINTEXT: proc_plaintext (c, pkt); break; case PKT_COMPRESSED: rc = proc_compressed (c, pkt); break; case PKT_ONEPASS_SIG: newpkt = add_onepass_sig (c, pkt); break; @@ -1537,7 +1648,8 @@ do_proc_packets (ctrl_t ctrl, CTX c, iobuf_t a) case PKT_PUBKEY_ENC: proc_pubkey_enc (ctrl, c, pkt); break; case PKT_SYMKEY_ENC: proc_symkey_enc (c, pkt); break; case PKT_ENCRYPTED: - case PKT_ENCRYPTED_MDC: proc_encrypted (c, pkt); break; + case PKT_ENCRYPTED_MDC: + case PKT_ENCRYPTED_AEAD: proc_encrypted (c, pkt); break; case PKT_PLAINTEXT: proc_plaintext (c, pkt); break; case PKT_COMPRESSED: rc = proc_compressed (c, pkt); break; case PKT_ONEPASS_SIG: newpkt = add_onepass_sig (c, pkt); break; @@ -2317,7 +2429,7 @@ check_sig_and_print (CTX c, kbnode_t node) /* Print compliance warning for Good signatures. */ if (!rc && pk && !opt.quiet - && !gnupg_pk_is_compliant (opt.compliance, pk->pubkey_algo, + && !gnupg_pk_is_compliant (opt.compliance, pk->pubkey_algo, 0, pk->pkey, nbits_from_pk (pk), NULL)) { log_info (_("WARNING: This key is not suitable for signing" @@ -2401,7 +2513,7 @@ check_sig_and_print (CTX c, kbnode_t node) /* Compute compliance with CO_DE_VS. */ if (pk && is_status_enabled () - && gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, pk->pkey, + && gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, 0, pk->pkey, nbits_from_pk (pk), NULL) && gnupg_digest_is_compliant (CO_DE_VS, sig->digest_algo)) write_status_strings (STATUS_VERIFICATION_COMPLIANCE_MODE, @@ -70,6 +70,10 @@ #include "../common/i18n.h" #include "../common/zb32.h" +/* FIXME: Libgcrypt 1.9 will support EAX. Until we name this a + * requirement we hardwire the enum used for EAX. */ +#define MY_GCRY_CIPHER_MODE_EAX 14 + #ifdef ENABLE_SELINUX_HACKS /* A object and a global variable to keep track of files marked as @@ -602,6 +606,80 @@ openpgp_cipher_algo_name (cipher_algo_t algo) } +/* Return 0 if ALGO is supported. Return an error if not. */ +gpg_error_t +openpgp_aead_test_algo (aead_algo_t algo) +{ + /* FIXME: We currently have no easy way to test whether libgcrypt + * implements a mode. The only way we can do this is to open a + * cipher context with that mode and close it immediately. That is + * a bit costly. So we look at the libgcrypt version and assume + * nothing has been patched out. */ + switch (algo) + { + case AEAD_ALGO_NONE: + break; + + case AEAD_ALGO_EAX: +#if GCRYPT_VERSION_NUMBER < 0x010900 + break; +#else + return 0; +#endif + + case AEAD_ALGO_OCB: + return 0; + } + + return gpg_error (GPG_ERR_INV_CIPHER_MODE); +} + + +/* Map the OpenPGP AEAD algorithm with ID ALGO to a string + * representation of the algorithm name. For unknown algorithm IDs + * this function returns "?". */ +const char * +openpgp_aead_algo_name (aead_algo_t algo) +{ + switch (algo) + { + case AEAD_ALGO_NONE: break; + case AEAD_ALGO_EAX: return "EAX"; + case AEAD_ALGO_OCB: return "OCB"; + } + + return "?"; +} + + +/* Return information for the AEAD algorithm ALGO. The corresponding + * Libgcrypt ciphermode is stored at R_MODE and the required number of + * octets for the nonce at R_NONCELEN. On error and error code is + * returned. Note that the taglen is always 128 bits. */ +gpg_error_t +openpgp_aead_algo_info (aead_algo_t algo, enum gcry_cipher_modes *r_mode, + unsigned int *r_noncelen) +{ + switch (algo) + { + case AEAD_ALGO_OCB: + *r_mode = GCRY_CIPHER_MODE_OCB; + *r_noncelen = 15; + break; + + case AEAD_ALGO_EAX: + *r_mode = MY_GCRY_CIPHER_MODE_EAX; + *r_noncelen = 16; + break; + + default: + log_error ("unsupported AEAD algo %d\n", algo); + return gpg_error (GPG_ERR_INV_CIPHER_MODE); + } + return 0; +} + + /* Return 0 if ALGO is a supported OpenPGP public key algorithm. */ int openpgp_pk_test_algo (pubkey_algo_t algo) diff --git a/g10/packet.h b/g10/packet.h index 4c0655c..187fffc 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -77,7 +77,8 @@ typedef enum { PREFTYPE_NONE = 0, PREFTYPE_SYM = 1, PREFTYPE_HASH = 2, - PREFTYPE_ZIP = 3 + PREFTYPE_ZIP = 3, + PREFTYPE_AEAD = 4 } preftype_t; typedef struct { @@ -104,6 +105,8 @@ typedef struct { be different from the algorithm that is used to encrypt the SED packet.) */ byte cipher_algo; + /* The AEAD algorithm or 0 for CFB encryption. */ + byte aead_algo; /* The string-to-key specifier. */ STRING2KEY s2k; /* The length of SESKEY in bytes or 0 if this packet does not @@ -111,7 +114,8 @@ typedef struct { S2K function on the password is the session key. See RFC 4880, Section 5.3.) */ byte seskeylen; - /* The session key as encrypted by the S2K specifier. */ + /* The session key as encrypted by the S2K specifier. For AEAD this + * includes the nonce and the authentication tag. */ byte seskey[1]; } PKT_symkey_enc; @@ -297,6 +301,7 @@ typedef struct struct { unsigned int mdc:1; + unsigned int aead:1; unsigned int ks_modify:1; unsigned int compacted:1; unsigned int primary:2; /* 2 if set via the primary flag, 1 if calculated */ @@ -393,6 +398,7 @@ typedef struct struct { unsigned int mdc:1; /* MDC feature set. */ + unsigned int aead:1; /* AEAD feature set. */ unsigned int disabled_valid:1;/* The next flag is valid. */ unsigned int disabled:1; /* The key has been disabled. */ unsigned int primary:1; /* This is a primary key. */ @@ -463,12 +469,13 @@ typedef struct { typedef struct { /* Remaining length of encrypted data. */ u32 len; - /* When encrypting, the first block size bytes of data are random - data and the following 2 bytes are copies of the last two bytes - of the random data (RFC 4880, Section 5.7). This provides a - simple check that the key is correct. extralen is the size of - this extra data. This is used by build_packet when writing out - the packet's header. */ + /* When encrypting in CFB mode, the first block size bytes of data + * are random data and the following 2 bytes are copies of the last + * two bytes of the random data (RFC 4880, Section 5.7). This + * provides a simple check that the key is correct. EXTRALEN is the + * size of this extra data or, in AEAD mode, the length of the + * headers and the tags. This is used by build_packet when writing + * out the packet's header. */ int extralen; /* Whether the serialized version of the packet used / should use the new format. */ @@ -480,6 +487,15 @@ typedef struct { /* If 0, MDC is disabled. Otherwise, the MDC method that was used (currently, only DIGEST_ALGO_SHA1 is supported). */ byte mdc_method; + /* If 0, AEAD is not used. Otherwise, the used AEAD algorithm. + * MDC_METHOD (above) shall be zero if AEAD is used. */ + byte aead_algo; + /* The cipher algo for/from the AEAD packet. 0 for other encryption + * packets. */ + byte cipher_algo; + /* The chunk byte from the AEAD packet. */ + byte chunkbyte; + /* An iobuf holding the data to be decrypted. (This is not used for encryption!) */ iobuf_t buf; diff --git a/g10/parse-packet.c b/g10/parse-packet.c index 6646bec..9cb254e 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -81,6 +81,9 @@ static int parse_compressed (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet, int new_ctb); static int parse_encrypted (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet, int new_ctb, int partial); +static gpg_error_t parse_encrypted_aead (IOBUF inp, int pkttype, + unsigned long pktlen, PACKET *packet, + int partial); static int parse_mdc (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet, int new_ctb); static int parse_gpg_control (IOBUF inp, int pkttype, unsigned long pktlen, @@ -665,6 +668,7 @@ parse (parse_packet_ctx_t ctx, PACKET *pkt, int onlykeypkts, off_t * retpos, case PKT_PLAINTEXT: case PKT_ENCRYPTED: case PKT_ENCRYPTED_MDC: + case PKT_ENCRYPTED_AEAD: case PKT_COMPRESSED: iobuf_set_partial_body_length_mode (inp, c & 0xff); pktlen = 0; /* To indicate partial length. */ @@ -852,6 +856,9 @@ parse (parse_packet_ctx_t ctx, PACKET *pkt, int onlykeypkts, off_t * retpos, case PKT_MDC: rc = parse_mdc (inp, pkttype, pktlen, pkt, new_ctb); break; + case PKT_ENCRYPTED_AEAD: + rc = parse_encrypted_aead (inp, pkttype, pktlen, pkt, partial); + break; case PKT_GPG_CONTROL: rc = parse_gpg_control (inp, pkttype, pktlen, pkt, partial); break; @@ -1127,19 +1134,17 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen, { PKT_symkey_enc *k; int rc = 0; - int i, version, s2kmode, cipher_algo, hash_algo, seskeylen, minlen; + int i, version, s2kmode, cipher_algo, aead_algo, hash_algo, seskeylen, minlen; if (pktlen < 4) - { - log_error ("packet(%d) too short\n", pkttype); - if (list_mode) - es_fprintf (listfp, ":symkey enc packet: [too short]\n"); - rc = gpg_error (GPG_ERR_INV_PACKET); - goto leave; - } + goto too_short; version = iobuf_get_noeof (inp); pktlen--; - if (version != 4) + if (version == 4) + ; + else if (version == 5) + ; + else { log_error ("packet(%d) with unknown version %d\n", pkttype, version); if (list_mode) @@ -1157,6 +1162,15 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen, } cipher_algo = iobuf_get_noeof (inp); pktlen--; + if (version == 5) + { + aead_algo = iobuf_get_noeof (inp); + pktlen--; + } + else + aead_algo = 0; + if (pktlen < 2) + goto too_short; s2kmode = iobuf_get_noeof (inp); pktlen--; hash_algo = iobuf_get_noeof (inp); @@ -1191,6 +1205,7 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen, + seskeylen - 1); k->version = version; k->cipher_algo = cipher_algo; + k->aead_algo = aead_algo; k->s2k.mode = s2kmode; k->s2k.hash_algo = hash_algo; if (s2kmode == 1 || s2kmode == 3) @@ -1221,10 +1236,20 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen, if (list_mode) { es_fprintf (listfp, - ":symkey enc packet: version %d, cipher %d, s2k %d, hash %d", - version, cipher_algo, s2kmode, hash_algo); + ":symkey enc packet: version %d, cipher %d, aead %d," + "s2k %d, hash %d", + version, cipher_algo, aead_algo, s2kmode, hash_algo); if (seskeylen) - es_fprintf (listfp, ", seskey %d bits", (seskeylen - 1) * 8); + { + /* To compute the size of the session key we need to know + * the size of the AEAD nonce which we may not know. Thus + * we show only the size of the entire encrypted session + * key. */ + if (aead_algo) + es_fprintf (listfp, ", encrypted seskey %d bytes", seskeylen); + else + es_fprintf (listfp, ", seskey %d bits", (seskeylen - 1) * 8); + } es_fprintf (listfp, "\n"); if (s2kmode == 1 || s2kmode == 3) { @@ -1241,6 +1266,13 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen, leave: iobuf_skip_rest (inp, pktlen, 0); return rc; + + too_short: + log_error ("packet(%d) too short\n", pkttype); + if (list_mode) + es_fprintf (listfp, ":symkey enc packet: [too short]\n"); + rc = gpg_error (GPG_ERR_INV_PACKET); + goto leave; } @@ -1421,6 +1453,11 @@ dump_sig_subpkt (int hashed, int type, int critical, for (i = 0; i < length; i++) es_fprintf (listfp, " %d", buffer[i]); break; + case SIGSUBPKT_PREF_AEAD: + es_fputs ("pref-aead-algos:", listfp); + for (i = 0; i < length; i++) + es_fprintf (listfp, " %d", buffer[i]); + break; case SIGSUBPKT_REV_KEY: es_fputs ("revocation key: ", listfp); if (length < 22) @@ -1601,6 +1638,7 @@ parse_one_sig_subpkt (const byte * buffer, size_t n, int type) case SIGSUBPKT_KEY_FLAGS: case SIGSUBPKT_KS_FLAGS: case SIGSUBPKT_PREF_SYM: + case SIGSUBPKT_PREF_AEAD: case SIGSUBPKT_PREF_HASH: case SIGSUBPKT_PREF_COMPR: case SIGSUBPKT_POLICY: @@ -3253,6 +3291,9 @@ parse_encrypted (IOBUF inp, int pkttype, unsigned long pktlen, ed->buf = NULL; ed->new_ctb = new_ctb; ed->is_partial = partial; + ed->aead_algo = 0; + ed->cipher_algo = 0; /* Only used with AEAD. */ + ed->chunkbyte = 0; /* Only used with AEAD. */ if (pkttype == PKT_ENCRYPTED_MDC) { /* Fixme: add some pktlen sanity checks. */ @@ -3344,6 +3385,81 @@ parse_mdc (IOBUF inp, int pkttype, unsigned long pktlen, } +static gpg_error_t +parse_encrypted_aead (iobuf_t inp, int pkttype, unsigned long pktlen, + PACKET *pkt, int partial) +{ + int rc = 0; + PKT_encrypted *ed; + unsigned long orig_pktlen = pktlen; + int version; + + ed = pkt->pkt.encrypted = xtrymalloc (sizeof *pkt->pkt.encrypted); + if (!ed) + return gpg_error_from_syserror (); + ed->len = 0; + ed->extralen = 0; /* (only used in build_packet.) */ + ed->buf = NULL; + ed->new_ctb = 1; /* (packet number requires a new CTB anyway.) */ + ed->is_partial = partial; + ed->mdc_method = 0; + /* A basic sanity check. We need one version byte, one algo byte, + * one aead algo byte, one chunkbyte, at least 15 byte IV. */ + if (orig_pktlen && pktlen < 19) + { + log_error ("packet(%d) too short\n", pkttype); + if (list_mode) + es_fputs (":aead encrypted packet: [too short]\n", listfp); + rc = gpg_error (GPG_ERR_INV_PACKET); + iobuf_skip_rest (inp, pktlen, partial); + goto leave; + } + + version = iobuf_get_noeof (inp); + if (orig_pktlen) + pktlen--; + if (version != 1) + { + log_error ("aead encrypted packet with unknown version %d\n", + version); + if (list_mode) + es_fputs (":aead encrypted packet: [unknown version]\n", listfp); + /*skip_rest(inp, pktlen); should we really do this? */ + rc = gpg_error (GPG_ERR_INV_PACKET); + goto leave; + } + + ed->cipher_algo = iobuf_get_noeof (inp); + if (orig_pktlen) + pktlen--; + ed->aead_algo = iobuf_get_noeof (inp); + if (orig_pktlen) + pktlen--; + ed->chunkbyte = iobuf_get_noeof (inp); + if (orig_pktlen) + pktlen--; + + /* Store the remaining length of the encrypted data. We read the + * rest during decryption. */ + ed->len = pktlen; + + if (list_mode) + { + es_fprintf (listfp, ":aead encrypted packet: cipher=%u aead=%u cb=%u\n", + ed->cipher_algo, ed->aead_algo, ed->chunkbyte); + if (orig_pktlen) + es_fprintf (listfp, "\tlength: %lu\n", orig_pktlen); + else + es_fprintf (listfp, "\tlength: unknown\n"); + } + + ed->buf = inp; + + leave: + return rc; +} + + /* * This packet is internally generated by us (in armor.c) to transfer * some information to the lower layer. To make sure that this packet diff --git a/g10/passphrase.c b/g10/passphrase.c index 10574ec..df80af8 100644 --- a/g10/passphrase.c +++ b/g10/passphrase.c @@ -212,6 +212,10 @@ read_passphrase_from_fd( int fd ) * Ask the GPG Agent for the passphrase. * If NOCACHE is set the symmetric passpharse caching will not be used. * + * If REPEAT is positive, a new passphrase is requested and the agent + * shall require REPEAT times repetitions of the entered passphrase. + * This is used for symmetric encryption. + * * 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 @@ -219,7 +223,7 @@ read_passphrase_from_fd( int fd ) * computed, this will be used as the cacheid. */ static char * -passphrase_get (int nocache, const char *cacheid, int repeat, +passphrase_get (int newsymkey, int nocache, const char *cacheid, int repeat, const char *tryagain_text, int *canceled) { int rc; @@ -240,9 +244,19 @@ passphrase_get (int nocache, const char *cacheid, int repeat, if (tryagain_text) tryagain_text = _(tryagain_text); + /* Here we have: + * REPEAT is set in create mode and if opt.passphrase_repeat is set. + * (Thus it is not a clean indication that we want a new passphrase). + * NOCACHE is set in create mode or if --no-symkey-cache is used. + * CACHEID is only set if caching shall be used. + * NEWSYMKEY has been added latter to make it clear that a new key + * is requested. The whole chain of API is a bit too complex since + * we we stripped things out over time; however, there is no time + * for a full state analysis and thus this new parameter. + */ rc = agent_get_passphrase (my_cacheid, tryagain_text, NULL, _("Enter passphrase\n"), - repeat, nocache, &pw); + newsymkey, repeat, nocache, &pw); i18n_switchback (orig_codeset); @@ -318,7 +332,7 @@ passphrase_to_dek (int cipher_algo, STRING2KEY *s2k, *canceled = 0; if (opt.no_symkey_cache) - nocache = 1; /* Force no symmtric key caching. */ + nocache = 1; /* Force no symmetric key caching. */ if ( !s2k ) { @@ -389,7 +403,7 @@ passphrase_to_dek (int cipher_algo, STRING2KEY *s2k, } /* Divert to the gpg-agent. */ - pw = passphrase_get (create && nocache, s2k_cacheid, + pw = passphrase_get (create, create && nocache, s2k_cacheid, create? opt.passphrase_repeat : 0, tryagain_text, canceled); if (*canceled) diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c index 4e6f893..30a4bc0 100644 --- a/g10/pubkey-enc.c +++ b/g10/pubkey-enc.c @@ -92,7 +92,7 @@ get_session_key (ctrl_t ctrl, PKT_pubkey_enc * k, DEK * dek) { /* Check compliance. */ if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_DECRYPTION, - sk->pubkey_algo, + sk->pubkey_algo, 0, sk->pkey, nbits_from_pk (sk), NULL)) { log_info (_("key %s is not suitable for decryption" @@ -133,7 +133,7 @@ get_session_key (ctrl_t ctrl, PKT_pubkey_enc * k, DEK * dek) /* Check compliance. */ if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_DECRYPTION, - sk->pubkey_algo, + sk->pubkey_algo, 0, sk->pkey, nbits_from_pk (sk), NULL)) { log_info (_("key %s is not suitable for decryption" @@ -259,7 +259,7 @@ get_it (ctrl_t ctrl, * CSUM */ if (DBG_CRYPTO) - log_printhex ("DEK frame:", frame, nframe); + log_printhex (frame, nframe, "DEK frame:"); n = 0; if (sk->pubkey_algo == PUBKEY_ALGO_ECDH) @@ -288,10 +288,7 @@ get_it (ctrl_t ctrl, goto leave; /* Now the frame are the bytes decrypted but padded session key. */ - - /* Allow double padding for the benefit of DEK size concealment. - Higher than this is wasteful. */ - if (!nframe || frame[nframe-1] > 8*2 || nframe <= 8 + if (!nframe || nframe <= 8 || frame[nframe-1] > nframe) { err = gpg_error (GPG_ERR_WRONG_SECKEY); @@ -375,7 +372,7 @@ get_it (ctrl_t ctrl, if (DBG_CLOCK) log_clock ("decryption ready"); if (DBG_CRYPTO) - log_printhex ("DEK is:", dek->key, dek->keylen); + log_printhex (dek->key, dek->keylen, "DEK is:"); /* Check that the algo is in the preferences and whether it has * expired. Also print a status line with the key's fingerprint. */ diff --git a/g10/sig-check.c b/g10/sig-check.c index 44e7871..e71e662 100644 --- a/g10/sig-check.c +++ b/g10/sig-check.c @@ -164,7 +164,7 @@ check_signature2 (ctrl_t ctrl, else if (get_pubkey_for_sig (ctrl, pk, sig, forced_pk)) rc = gpg_error (GPG_ERR_NO_PUBKEY); else if (!gnupg_pk_is_allowed (opt.compliance, PK_USE_VERIFICATION, - pk->pubkey_algo, pk->pkey, + pk->pubkey_algo, 0, pk->pkey, nbits_from_pk (pk), NULL)) { @@ -395,7 +395,8 @@ do_sign (ctrl_t ctrl, PKT_public_key *pksk, PKT_signature *sig, goto leave; } - if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_SIGNING, pksk->pubkey_algo, + if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_SIGNING, + pksk->pubkey_algo, 0, pksk->pkey, nbits_from_pk (pksk), NULL)) { log_error (_("key %s may not be used for signing in %s mode\n"), diff --git a/g13/call-syshelp.c b/g13/call-syshelp.c index 8a50c3f..b160ba3 100644 --- a/g13/call-syshelp.c +++ b/g13/call-syshelp.c @@ -366,7 +366,7 @@ create_inq_cb (void *opaque, const char *line) void *ciphertext; size_t ciphertextlen; - log_printhex ("plain", plaintext, plaintextlen); + log_printhex (plaintext, plaintextlen, "plain"); err = g13_encrypt_keyblob (parm->ctrl, plaintext, plaintextlen, &ciphertext, &ciphertextlen); diff --git a/g13/g13tuple.c b/g13/g13tuple.c index b10ebbc..6693826 100644 --- a/g13/g13tuple.c +++ b/g13/g13tuple.c @@ -318,7 +318,7 @@ dump_tupledesc (tupledesc_t tuples) if (n < 100 && all_printable (value, n)) log_printf ("%.*s\n", (int)n, (const char*)value); else - log_printhex ("", value, n); + log_printhex (value, n, ""); break; case KEYBLOB_TAG_CONT_NSEC: @@ -327,11 +327,11 @@ dump_tupledesc (tupledesc_t tuples) if (!convert_uint (value, n, &uint)) log_printf ("%llu\n", uint); else - log_printhex ("", value, n); + log_printhex (value, n, ""); break; default: - log_printhex ("", value, n); + log_printhex (value, n, ""); break; } } diff --git a/po/POTFILES.in b/po/POTFILES.in index 15f7485..bd90a6c 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -79,6 +79,7 @@ g10/verify.c kbx/kbxutil.c +scd/app-p15.c scd/app-nks.c scd/app-openpgp.c scd/app-dinsig.c @@ -115,6 +115,9 @@ msgstr "" #. the pinentry. The %s is the actual error message, the #. two %d give the current and maximum number of tries. #. Do not translate the "SETERROR" keyword. +#. TRANSLATORS: The string is appended to an error message in +#. the pinentry. The %s is the actual error message, the +#. two %d give the current and maximum number of tries. #, c-format msgid "SETERROR %s (try %d of %d)" msgstr "" @@ -3811,6 +3814,9 @@ msgstr "error: l'empremta digital és invà lida\n" msgid "subkey \"%s\" not found\n" msgstr "no s'ha trobat la clau «%s»: %s\n" +msgid "AEAD: " +msgstr "" + msgid "Digest: " msgstr "Resum: " @@ -6607,6 +6613,26 @@ msgid "" "List, export, import Keybox data\n" msgstr "Forma d'ús: gpg [opcions] [fitxers] (-h per a veure l'ajuda)" +#. TRANSLATORS: Put a \x1f right before a colon. This can be +#. * used by pinentry to nicely align the names and values. Keep +#. * the %s at the start and end of the string. +#, c-format +msgid "%sNumber: %s%%0AHolder: %s%s" +msgstr "" + +#. TRANSLATORS: This is the number of remaining attempts to +#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. +#, c-format +msgid "Remaining attempts: %d" +msgstr "" + +msgid "||Please enter the PIN for the key to create qualified signatures." +msgstr "" + +#, fuzzy +msgid "||Please enter the PIN for the standard keys." +msgstr "canvia la contrasenya" + #, c-format msgid "RSA modulus missing or not of size %d bits\n" msgstr "" @@ -6628,10 +6654,6 @@ msgid "|N|Please enter a new PIN for the standard keys." msgstr "canvia la contrasenya" #, fuzzy -msgid "||Please enter the PIN for the standard keys." -msgstr "canvia la contrasenya" - -#, fuzzy msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys." msgstr "Seleccioneu la raó de la revocació:\n" @@ -6642,9 +6664,6 @@ msgstr "Seleccioneu la raó de la revocació:\n" msgid "|N|Please enter a new PIN for the key to create qualified signatures." msgstr "" -msgid "||Please enter the PIN for the key to create qualified signatures." -msgstr "" - msgid "" "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create " "qualified signatures." @@ -6700,16 +6719,6 @@ msgid "%sNumber: %s%%0AHolder: %s%%0ACounter: %lu%s" msgstr "" #, c-format -msgid "%sNumber: %s%%0AHolder: %s%s" -msgstr "" - -#. TRANSLATORS: This is the number of remaining attempts to -#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. -#, c-format -msgid "Remaining attempts: %d" -msgstr "" - -#, c-format msgid "using default PIN as %s\n" msgstr "" @@ -6967,6 +6976,10 @@ msgstr "s'està escrivint la clau secreta a «%s»\n" msgid "certificate policy not allowed" msgstr "s'està escrivint la clau secreta a «%s»\n" +#, fuzzy, c-format +msgid "failed to get the fingerprint\n" +msgstr "no s'ha pogut emmagatzemar l'empremta digital: %s\n" + #, c-format msgid "looking up issuer at external location\n" msgstr "" @@ -6975,6 +6988,11 @@ msgstr "" msgid "number of issuers matching: %d\n" msgstr "" +#, fuzzy, c-format +#| msgid "%s: can't access: %s\n" +msgid "can't get authorityInfoAccess: %s\n" +msgstr "%s: no s'ha pogut accedir: %s\n" + #, c-format msgid "looking up issuer from the Dirmngr cache\n" msgstr "" @@ -7603,10 +7621,6 @@ msgstr "error en la creació de la contrasenya: %s\n" msgid "error reading input: %s\n" msgstr "error en la lectura de «%s»: %s\n" -#, fuzzy, c-format -msgid "failed to get the fingerprint\n" -msgstr "no s'ha pogut emmagatzemar l'empremta digital: %s\n" - #, c-format msgid "problem looking for existing certificate: %s\n" msgstr "" @@ -7686,8 +7700,8 @@ msgid "[date not given]" msgstr "" #, fuzzy, c-format -msgid " using certificate ID 0x%08lX\n" -msgstr "error en la creació de la contrasenya: %s\n" +msgid "algorithm:" +msgstr "armadura: %s\n" #, c-format msgid "" @@ -8019,15 +8033,6 @@ msgid "error getting data from cache file: %s\n" msgstr "error en crear «%s»: %s\n" #, fuzzy, c-format -#| msgid "invalid hash algorithm `%s'\n" -msgid "unknown hash algorithm '%s'\n" -msgstr "l'algoritme de dispersió és invà lid «%s»\n" - -#, c-format -msgid "gcry_md_open for algorithm %d failed: %s\n" -msgstr "" - -#, fuzzy, c-format #| msgid "invalid response from agent\n" msgid "got an invalid S-expression from libksba\n" msgstr "la resposta de l'agent és invà lida\n" @@ -8038,6 +8043,15 @@ msgid "converting S-expression failed: %s\n" msgstr "no s'han pogut canviar els permissos de «%s»: %s\n" #, fuzzy, c-format +#| msgid "invalid hash algorithm `%s'\n" +msgid "unknown hash algorithm '%s'\n" +msgstr "l'algoritme de dispersió és invà lid «%s»\n" + +#, c-format +msgid "gcry_md_open for algorithm %d failed: %s\n" +msgstr "" + +#, fuzzy, c-format #| msgid "changing permission of `%s' failed: %s\n" msgid "creating S-expression failed: %s\n" msgstr "no s'han pogut canviar els permissos de «%s»: %s\n" @@ -8834,11 +8848,6 @@ msgstr "Certificat correcte" msgid "failed to allocate OCSP context: %s\n" msgstr "no s'ha pogut inicialitzar la base de dades de confiança: %s\n" -#, fuzzy, c-format -#| msgid "%s: can't access: %s\n" -msgid "can't get authorityInfoAccess: %s\n" -msgstr "%s: no s'ha pogut accedir: %s\n" - #, c-format msgid "no default OCSP responder defined\n" msgstr "" @@ -9433,6 +9442,10 @@ msgid "" msgstr "" #, fuzzy +#~ msgid " using certificate ID 0x%08lX\n" +#~ msgstr "error en la creació de la contrasenya: %s\n" + +#, fuzzy #~| msgid "you may not use %s while in %s mode\n" #~ msgid "" #~ "keyserver option \"honor-keyserver-url\" may not be used in Tor mode\n" @@ -125,6 +125,9 @@ msgstr "neshodujà se – zkuste to znovu" #. the pinentry. The %s is the actual error message, the #. two %d give the current and maximum number of tries. #. Do not translate the "SETERROR" keyword. +#. TRANSLATORS: The string is appended to an error message in +#. the pinentry. The %s is the actual error message, the +#. two %d give the current and maximum number of tries. #, c-format msgid "SETERROR %s (try %d of %d)" msgstr "SETERROR %s (pokus %d z %d)" @@ -3510,6 +3513,9 @@ msgstr "„%s“ nenà řádný otisk\n" msgid "subkey \"%s\" not found\n" msgstr "podklÃÄ â€ž%s“ nenalezen\n" +msgid "AEAD: " +msgstr "" + msgid "Digest: " msgstr "Hash: " @@ -6214,6 +6220,26 @@ msgstr "" "Syntaxe: kbxutil [volby] [soubory]\n" "Vypisuje, exportuje, importuje schránku na klÃÄe (keybox).\n" +#. TRANSLATORS: Put a \x1f right before a colon. This can be +#. * used by pinentry to nicely align the names and values. Keep +#. * the %s at the start and end of the string. +#, c-format +msgid "%sNumber: %s%%0AHolder: %s%s" +msgstr "%sÄŒÃslo: %s%%0ADržitel: %s%s" + +#. TRANSLATORS: This is the number of remaining attempts to +#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. +#, c-format +msgid "Remaining attempts: %d" +msgstr "Zbývá pokusů: %d" + +msgid "||Please enter the PIN for the key to create qualified signatures." +msgstr "" +"||ProsÃm, zadejte PIN klÃÄe urÄeného na tvorbu kvalifikovaných podpisů." + +msgid "||Please enter the PIN for the standard keys." +msgstr "||ProsÃm, zadejte PIN pro standardnà klÃÄe." + #, c-format msgid "RSA modulus missing or not of size %d bits\n" msgstr "scházà RSA modulus nebo nemá velikost %d bitů\n" @@ -6235,9 +6261,6 @@ msgstr "NullPIN jeÅ¡tÄ› nebyl zmÄ›nÄ›n\n" msgid "|N|Please enter a new PIN for the standard keys." msgstr "|N|ProsÃm, zadejte nový PIN pro standardnà klÃÄe." -msgid "||Please enter the PIN for the standard keys." -msgstr "||ProsÃm, zadejte PIN pro standardnà klÃÄe." - msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys." msgstr "|NP|ProsÃm, zadejte nový kód pro odblokovánà (PUK) standardnÃch klÃÄů." @@ -6248,10 +6271,6 @@ msgid "|N|Please enter a new PIN for the key to create qualified signatures." msgstr "" "|N|ProsÃm, zadejte nový PIN klÃÄe urÄeného na tvorbu kvalifikovaných podpisů." -msgid "||Please enter the PIN for the key to create qualified signatures." -msgstr "" -"||ProsÃm, zadejte PIN klÃÄe urÄeného na tvorbu kvalifikovaných podpisů." - msgid "" "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create " "qualified signatures." @@ -6310,16 +6329,6 @@ msgid "%sNumber: %s%%0AHolder: %s%%0ACounter: %lu%s" msgstr "%sÄŒÃslo: %s%%0ADržitel: %s%%0APoÄÃtadlo: %lu%s" #, c-format -msgid "%sNumber: %s%%0AHolder: %s%s" -msgstr "%sÄŒÃslo: %s%%0ADržitel: %s%s" - -#. TRANSLATORS: This is the number of remaining attempts to -#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. -#, c-format -msgid "Remaining attempts: %d" -msgstr "Zbývá pokusů: %d" - -#, c-format msgid "using default PIN as %s\n" msgstr "použije se výchozà PIN jako %s\n" @@ -6570,6 +6579,10 @@ msgid "certificate policy not allowed" msgstr "certifikaÄnà politika nenà dovolena" #, c-format +msgid "failed to get the fingerprint\n" +msgstr "otisk se nepodaÅ™ilo zÃskat\n" + +#, c-format msgid "looking up issuer at external location\n" msgstr "hledám vydavatele na jiném mÃstÄ›\n" @@ -6578,6 +6591,10 @@ msgid "number of issuers matching: %d\n" msgstr "poÄet odpovÃdajÃcÃch vydavatelů: %d\n" #, c-format +msgid "can't get authorityInfoAccess: %s\n" +msgstr "authorityInfoAccess nelze zÃskat: %s\n" + +#, c-format msgid "looking up issuer from the Dirmngr cache\n" msgstr "hledám vydavatele ve vyrovnávacà pamÄ›ti Dirmngr\n" @@ -7162,10 +7179,6 @@ msgid "error reading input: %s\n" msgstr "chyba pÅ™i Ätenà vstupu: %s\n" #, c-format -msgid "failed to get the fingerprint\n" -msgstr "otisk se nepodaÅ™ilo zÃskat\n" - -#, c-format msgid "problem looking for existing certificate: %s\n" msgstr "problém pÅ™i hledánà existujÃcÃho certifikátu: %s\n" @@ -7255,9 +7268,10 @@ msgstr "Podpis vytvoÅ™en " msgid "[date not given]" msgstr "[datum neudáno]" -#, c-format -msgid " using certificate ID 0x%08lX\n" -msgstr " pomocà certifikátu s ID 0x%08lX\n" +#, fuzzy, c-format +#| msgid "algorithm: %s" +msgid "algorithm:" +msgstr "algoritmus: %s" #, c-format msgid "" @@ -7594,14 +7608,6 @@ msgid "error getting data from cache file: %s\n" msgstr "chyba pÅ™i zÃskávánà dat ze souboru keÅ¡e: %s\n" #, c-format -msgid "unknown hash algorithm '%s'\n" -msgstr "neznámý haÅ¡ovacà algoritmus „%s“\n" - -#, c-format -msgid "gcry_md_open for algorithm %d failed: %s\n" -msgstr "gcry_md_open selhalo na algoritmu %d: %s\n" - -#, c-format msgid "got an invalid S-expression from libksba\n" msgstr "z libksba obdržen neplatný S-výraz\n" @@ -7610,6 +7616,14 @@ msgid "converting S-expression failed: %s\n" msgstr "pÅ™evod S-výrazu se nezdaÅ™il: %s\n" #, c-format +msgid "unknown hash algorithm '%s'\n" +msgstr "neznámý haÅ¡ovacà algoritmus „%s“\n" + +#, c-format +msgid "gcry_md_open for algorithm %d failed: %s\n" +msgstr "gcry_md_open selhalo na algoritmu %d: %s\n" + +#, c-format msgid "creating S-expression failed: %s\n" msgstr "výroba S-výrazu selhala: %s\n" @@ -8363,10 +8377,6 @@ msgid "failed to allocate OCSP context: %s\n" msgstr "alokace OCSP kontextu selhala: %s\n" #, c-format -msgid "can't get authorityInfoAccess: %s\n" -msgstr "authorityInfoAccess nelze zÃskat: %s\n" - -#, c-format msgid "no default OCSP responder defined\n" msgstr "žádný výchozà OCSP odpovÃdaÄ nedefinován\n" @@ -8939,6 +8949,9 @@ msgstr "" "Syntaxe: gpg-check-pattern [volby] soubor_se_vzorem\n" "Prověřà heslo zadané na vstupu proti souboru se vzory\n" +#~ msgid " using certificate ID 0x%08lX\n" +#~ msgstr " pomocà certifikátu s ID 0x%08lX\n" + #, fuzzy #~| msgid "option '%s' may not be used in %s mode\n" #~ msgid "" @@ -116,6 +116,9 @@ msgstr "matcher ikke - prøv igen" #. the pinentry. The %s is the actual error message, the #. two %d give the current and maximum number of tries. #. Do not translate the "SETERROR" keyword. +#. TRANSLATORS: The string is appended to an error message in +#. the pinentry. The %s is the actual error message, the +#. two %d give the current and maximum number of tries. #, c-format msgid "SETERROR %s (try %d of %d)" msgstr "SETERROR %s (forsøg %d af %d)" @@ -3767,6 +3770,9 @@ msgstr "ugyldig fingeraftryk" msgid "subkey \"%s\" not found\n" msgstr "nøglen »%s« blev ikke fundet: %s\n" +msgid "AEAD: " +msgstr "" + msgid "Digest: " msgstr "Sammendrag: " @@ -6555,6 +6561,27 @@ msgstr "" "Syntaks: kbxutil [tilvalg] [filer]\n" "Vis, eksporter, importer Keybox-data\n" +#. TRANSLATORS: Put a \x1f right before a colon. This can be +#. * used by pinentry to nicely align the names and values. Keep +#. * the %s at the start and end of the string. +#, c-format +msgid "%sNumber: %s%%0AHolder: %s%s" +msgstr "" + +#. TRANSLATORS: This is the number of remaining attempts to +#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. +#, c-format +msgid "Remaining attempts: %d" +msgstr "" + +msgid "||Please enter the PIN for the key to create qualified signatures." +msgstr "" +"||Indtast venligst PIN'en for nøglen til at oprette kvalificerede " +"underskrifter." + +msgid "||Please enter the PIN for the standard keys." +msgstr "||Indtast venligst PIn'en for standardnøglerne." + #, c-format msgid "RSA modulus missing or not of size %d bits\n" msgstr "RSA-modulus mangler eller har ikke størrelsen %d bit\n" @@ -6574,9 +6601,6 @@ msgstr "NullPIN'en er endnu ikke ændret\n" msgid "|N|Please enter a new PIN for the standard keys." msgstr "|N|Indtast venligst en ny PIN for standardnøglerne." -msgid "||Please enter the PIN for the standard keys." -msgstr "||Indtast venligst PIn'en for standardnøglerne." - msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys." msgstr "" "|NP|Indtast venligst en ny PIN Unblocking Code (PUK) for standardnøglerne." @@ -6589,11 +6613,6 @@ msgstr "" "|N|Indtast venligst en ny PIN for nøglen til at oprette kvalificerede " "underskrifter." -msgid "||Please enter the PIN for the key to create qualified signatures." -msgstr "" -"||Indtast venligst PIN'en for nøglen til at oprette kvalificerede " -"underskrifter." - msgid "" "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create " "qualified signatures." @@ -6653,16 +6672,6 @@ msgid "%sNumber: %s%%0AHolder: %s%%0ACounter: %lu%s" msgstr "" #, c-format -msgid "%sNumber: %s%%0AHolder: %s%s" -msgstr "" - -#. TRANSLATORS: This is the number of remaining attempts to -#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. -#, c-format -msgid "Remaining attempts: %d" -msgstr "" - -#, c-format msgid "using default PIN as %s\n" msgstr "bruger standard-PIN som %s\n" @@ -6926,6 +6935,10 @@ msgid "certificate policy not allowed" msgstr "certifikatpolitik er ikke tilladt" #, c-format +msgid "failed to get the fingerprint\n" +msgstr "kunne ikke indhente fingeraftrykket\n" + +#, c-format msgid "looking up issuer at external location\n" msgstr "slÃ¥r udsteder op pÃ¥ ekstern placering\n" @@ -6933,6 +6946,11 @@ msgstr "slÃ¥r udsteder op pÃ¥ ekstern placering\n" msgid "number of issuers matching: %d\n" msgstr "antallet af udstedere der matcher: %d\n" +#, fuzzy, c-format +#| msgid "can't access `%s': %s\n" +msgid "can't get authorityInfoAccess: %s\n" +msgstr "kan ikke tilgÃ¥ »%s«: %s\n" + #, c-format msgid "looking up issuer from the Dirmngr cache\n" msgstr "slÃ¥r udsteder op fra Dirmngr-mellemlageret\n" @@ -7551,10 +7569,6 @@ msgid "error reading input: %s\n" msgstr "fejl ved læsning af inddata: %s\n" #, c-format -msgid "failed to get the fingerprint\n" -msgstr "kunne ikke indhente fingeraftrykket\n" - -#, c-format msgid "problem looking for existing certificate: %s\n" msgstr "problem under udkig efter eksisterende certifikat: %s\n" @@ -7646,9 +7660,10 @@ msgstr "Underskrift lavet " msgid "[date not given]" msgstr "[dato ikke angivet]" -#, c-format -msgid " using certificate ID 0x%08lX\n" -msgstr " bruger certifikat-id 0x%08lX\n" +#, fuzzy, c-format +#| msgid "algorithm: %s" +msgid "algorithm:" +msgstr "algoritme: %s" #, c-format msgid "" @@ -8021,15 +8036,6 @@ msgstr "" msgid "error getting data from cache file: %s\n" msgstr "fejl ved indhentelse af gemte flag: %s\n" -#, fuzzy, c-format -#| msgid "invalid hash algorithm `%s'\n" -msgid "unknown hash algorithm '%s'\n" -msgstr "ugyldig hash-algoritme »%s«\n" - -#, c-format -msgid "gcry_md_open for algorithm %d failed: %s\n" -msgstr "" - #, c-format msgid "got an invalid S-expression from libksba\n" msgstr "" @@ -8040,6 +8046,15 @@ msgid "converting S-expression failed: %s\n" msgstr "iconv_open mislykkedes: %s:\n" #, fuzzy, c-format +#| msgid "invalid hash algorithm `%s'\n" +msgid "unknown hash algorithm '%s'\n" +msgstr "ugyldig hash-algoritme »%s«\n" + +#, c-format +msgid "gcry_md_open for algorithm %d failed: %s\n" +msgstr "" + +#, fuzzy, c-format #| msgid "receiving line failed: %s\n" msgid "creating S-expression failed: %s\n" msgstr "modtagelse af linje mislykkedes: %s\n" @@ -8917,11 +8932,6 @@ msgstr "fejl ved lagring af certifikat\n" msgid "failed to allocate OCSP context: %s\n" msgstr "kunne ikke allokere keyDB-hÃ¥ndtag\n" -#, fuzzy, c-format -#| msgid "can't access `%s': %s\n" -msgid "can't get authorityInfoAccess: %s\n" -msgstr "kan ikke tilgÃ¥ »%s«: %s\n" - #, c-format msgid "no default OCSP responder defined\n" msgstr "" @@ -9560,6 +9570,9 @@ msgstr "" "Syntaks: gpg-check-pattern [tilvalg] mønsterfil\n" "Kontroller en adgangsfrase angivet pÃ¥ stdin mod mønsterfilen\n" +#~ msgid " using certificate ID 0x%08lX\n" +#~ msgstr " bruger certifikat-id 0x%08lX\n" + #, fuzzy #~| msgid "you may not use %s while in %s mode\n" #~ msgid "" @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: gnupg-2.1.0\n" "Report-Msgid-Bugs-To: translations@gnupg.org\n" -"PO-Revision-Date: 2020-03-19 14:27+0100\n" +"PO-Revision-Date: 2020-07-09 11:31+0200\n" "Last-Translator: Werner Koch <wk@gnupg.org>\n" "Language-Team: German <de@li.org>\n" "Language: de\n" @@ -101,6 +101,9 @@ msgstr "Keine Ãœbereinstimmung - bitte nochmal versuchen." #. the pinentry. The %s is the actual error message, the #. two %d give the current and maximum number of tries. #. Do not translate the "SETERROR" keyword. +#. TRANSLATORS: The string is appended to an error message in +#. the pinentry. The %s is the actual error message, the +#. two %d give the current and maximum number of tries. #, c-format msgid "SETERROR %s (try %d of %d)" msgstr "SETERROR %s (Versuch %d von %d)" @@ -3544,6 +3547,9 @@ msgstr "\"%s\" ist kein gültiger Fingerabdruck\n" msgid "subkey \"%s\" not found\n" msgstr "Unterschlüssel \"%s\" nicht gefunden\n" +msgid "AEAD: " +msgstr "AEAD: " + msgid "Digest: " msgstr "Digest: " @@ -6300,6 +6306,27 @@ msgstr "" "Syntax: kbxutil [Optionen] [Dateien]\n" "Anlisten exportieren und Importieren von KeyBox Dateien\n" +#. TRANSLATORS: Put a \x1f right before a colon. This can be +#. * used by pinentry to nicely align the names and values. Keep +#. * the %s at the start and end of the string. +#, c-format +msgid "%sNumber: %s%%0AHolder: %s%s" +msgstr "%sNummer: %s%%0ABesitzer: %s%s" + +#. TRANSLATORS: This is the number of remaining attempts to +#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. +#, c-format +msgid "Remaining attempts: %d" +msgstr "Verbliebene Versuche: %d" + +msgid "||Please enter the PIN for the key to create qualified signatures." +msgstr "" +"||Bitte geben Sie die PIN für den Schlüssel zur Erstellung qualifizierter " +"Signaturen ein." + +msgid "||Please enter the PIN for the standard keys." +msgstr "||Bitte die PIN für den Standard-Schlüssel eingeben." + #, c-format msgid "RSA modulus missing or not of size %d bits\n" msgstr "Der RSA Modulus fehlt oder ist nicht %d Bits lang\n" @@ -6319,9 +6346,6 @@ msgstr "Die Nullpin wurde noch nicht geändert\n" msgid "|N|Please enter a new PIN for the standard keys." msgstr "|N|Bitte eine neue PIN für den Standard-Schlüssel eingeben." -msgid "||Please enter the PIN for the standard keys." -msgstr "||Bitte die PIN für den Standard-Schlüssel eingeben." - msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys." msgstr "" "|NP|Bitte geben Sie einen neuen PIN Entsperrcode (PUK) für den Standard-" @@ -6336,11 +6360,6 @@ msgstr "" "|N|Bitte geben Sie eine neue PIN für den Schlüssel zur Erstellung " "qualifizierter Signaturen ein." -msgid "||Please enter the PIN for the key to create qualified signatures." -msgstr "" -"||Bitte geben Sie die PIN für den Schlüssel zur Erstellung qualifizierter " -"Signaturen ein." - msgid "" "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create " "qualified signatures." @@ -6399,16 +6418,6 @@ msgid "%sNumber: %s%%0AHolder: %s%%0ACounter: %lu%s" msgstr "%sNummer: %s%%0ABesitzer: %s%%0AAnzahl: %lu%s" #, c-format -msgid "%sNumber: %s%%0AHolder: %s%s" -msgstr "%sNummer: %s%%0ABesitzer: %s%s" - -#. TRANSLATORS: This is the number of remaining attempts to -#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. -#, c-format -msgid "Remaining attempts: %d" -msgstr "Verbliebene Versuche: %d" - -#, c-format msgid "using default PIN as %s\n" msgstr "Die Standard PIN wird für %s benutzt\n" @@ -6658,6 +6667,10 @@ msgid "certificate policy not allowed" msgstr "Die Zertifikatsrichtlinie ist nicht erlaubt" #, c-format +msgid "failed to get the fingerprint\n" +msgstr "Kann den Fingerprint nicht ermitteln\n" + +#, c-format msgid "looking up issuer at external location\n" msgstr "Der Herausgeber wird von einer externen Stelle gesucht\n" @@ -6666,6 +6679,10 @@ msgid "number of issuers matching: %d\n" msgstr "Anzahl der übereinstimmenden Herausgeber: %d\n" #, c-format +msgid "can't get authorityInfoAccess: %s\n" +msgstr "authorityInfoAccess kann nicht geholt werden: %s\n" + +#, c-format msgid "looking up issuer from the Dirmngr cache\n" msgstr "Der Herausgeber wird im Cache des Dirmngr gesucht\n" @@ -7261,10 +7278,6 @@ msgid "error reading input: %s\n" msgstr "Fehler beim Lesen der Eingabe: %s\n" #, c-format -msgid "failed to get the fingerprint\n" -msgstr "Kann den Fingerprint nicht ermitteln\n" - -#, c-format msgid "problem looking for existing certificate: %s\n" msgstr "Problem bei der Suche nach vorhandenem Zertifikat: %s\n" @@ -7359,8 +7372,8 @@ msgid "[date not given]" msgstr "[Datum nicht vorhanden]" #, c-format -msgid " using certificate ID 0x%08lX\n" -msgstr " mittels Zertifikat ID 0x%08lX\n" +msgid "algorithm:" +msgstr "Verfahren:" #, c-format msgid "" @@ -7708,14 +7721,6 @@ msgid "error getting data from cache file: %s\n" msgstr "Fehler beim Holen der Daten aus der Zwischenspeicherdatei: %s\n" #, c-format -msgid "unknown hash algorithm '%s'\n" -msgstr "Ungültige Hashmethode `%s'\n" - -#, c-format -msgid "gcry_md_open for algorithm %d failed: %s\n" -msgstr "gcry_md_open für Methode %d fehlgeschlagen: %s\n" - -#, c-format msgid "got an invalid S-expression from libksba\n" msgstr "Ungültige S-Expression von Libksba erhalten\n" @@ -7724,6 +7729,14 @@ msgid "converting S-expression failed: %s\n" msgstr "Konvertierung der S-Expression fehlgeschlagen: %s\n" #, c-format +msgid "unknown hash algorithm '%s'\n" +msgstr "Ungültige Hashmethode `%s'\n" + +#, c-format +msgid "gcry_md_open for algorithm %d failed: %s\n" +msgstr "gcry_md_open für Methode %d fehlgeschlagen: %s\n" + +#, c-format msgid "creating S-expression failed: %s\n" msgstr "Erzeugen der S-Expression fehlgeschlagen: %s\n" @@ -8488,10 +8501,6 @@ msgid "failed to allocate OCSP context: %s\n" msgstr "Fehler beim Bereitstellen eines OCSP Kontext: %s\n" #, c-format -msgid "can't get authorityInfoAccess: %s\n" -msgstr "authorityInfoAccess kann nicht geholt werden: %s\n" - -#, c-format msgid "no default OCSP responder defined\n" msgstr "Kein voreingestellter OCSP Responder definiert\n" @@ -9064,6 +9073,9 @@ msgstr "" "Syntax: gpg-check-pattern [optionen] Musterdatei\n" "Die von stdin gelesene Passphrase gegen die Musterdatei prüfen\n" +#~ msgid " using certificate ID 0x%08lX\n" +#~ msgstr " mittels Zertifikat ID 0x%08lX\n" + #, fuzzy #~ msgid "" #~ "keyserver option \"honor-keyserver-url\" may not be used in Tor mode\n" @@ -96,6 +96,9 @@ msgstr "" #. the pinentry. The %s is the actual error message, the #. two %d give the current and maximum number of tries. #. Do not translate the "SETERROR" keyword. +#. TRANSLATORS: The string is appended to an error message in +#. the pinentry. The %s is the actual error message, the +#. two %d give the current and maximum number of tries. #, c-format msgid "SETERROR %s (try %d of %d)" msgstr "" @@ -3715,6 +3718,9 @@ msgstr "σφάλμα: μη ÎγκυÏο αποτÏπωμα\n" msgid "subkey \"%s\" not found\n" msgstr "το κλειδί '%s' δε βÏÎθηκε: %s\n" +msgid "AEAD: " +msgstr "" + msgid "Digest: " msgstr "ΠεÏίληψη: " @@ -6474,6 +6480,26 @@ msgid "" "List, export, import Keybox data\n" msgstr "ΧÏήση: gpg [επιλογÎÏ‚] [αÏχεία] (-h για βοήθεια)" +#. TRANSLATORS: Put a \x1f right before a colon. This can be +#. * used by pinentry to nicely align the names and values. Keep +#. * the %s at the start and end of the string. +#, c-format +msgid "%sNumber: %s%%0AHolder: %s%s" +msgstr "" + +#. TRANSLATORS: This is the number of remaining attempts to +#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. +#, c-format +msgid "Remaining attempts: %d" +msgstr "" + +msgid "||Please enter the PIN for the key to create qualified signatures." +msgstr "" + +#, fuzzy +msgid "||Please enter the PIN for the standard keys." +msgstr "αλλαγή της φÏάσης κλειδί" + #, c-format msgid "RSA modulus missing or not of size %d bits\n" msgstr "" @@ -6495,10 +6521,6 @@ msgid "|N|Please enter a new PIN for the standard keys." msgstr "αλλαγή της φÏάσης κλειδί" #, fuzzy -msgid "||Please enter the PIN for the standard keys." -msgstr "αλλαγή της φÏάσης κλειδί" - -#, fuzzy msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys." msgstr "ΠαÏακαλώ επιλÎξτε την αιτία για την ανάκληση:\n" @@ -6509,9 +6531,6 @@ msgstr "ΠαÏακαλώ επιλÎξτε την αιτία για την ανά msgid "|N|Please enter a new PIN for the key to create qualified signatures." msgstr "" -msgid "||Please enter the PIN for the key to create qualified signatures." -msgstr "" - msgid "" "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create " "qualified signatures." @@ -6567,16 +6586,6 @@ msgid "%sNumber: %s%%0AHolder: %s%%0ACounter: %lu%s" msgstr "" #, c-format -msgid "%sNumber: %s%%0AHolder: %s%s" -msgstr "" - -#. TRANSLATORS: This is the number of remaining attempts to -#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. -#, c-format -msgid "Remaining attempts: %d" -msgstr "" - -#, c-format msgid "using default PIN as %s\n" msgstr "" @@ -6832,6 +6841,10 @@ msgstr "εγγÏαφή του Î¼Ï…ÏƒÏ„Î¹ÎºÎ¿Ï ÎºÎ»ÎµÎ¹Î´Î¹Î¿Ï ÏƒÏ„Î¿ `%s'\n" msgid "certificate policy not allowed" msgstr "εγγÏαφή του Î¼Ï…ÏƒÏ„Î¹ÎºÎ¿Ï ÎºÎ»ÎµÎ¹Î´Î¹Î¿Ï ÏƒÏ„Î¿ `%s'\n" +#, fuzzy, c-format +msgid "failed to get the fingerprint\n" +msgstr "αποτυχία αÏχικοποίησης της TrustDB: %s\n" + #, c-format msgid "looking up issuer at external location\n" msgstr "" @@ -6840,6 +6853,11 @@ msgstr "" msgid "number of issuers matching: %d\n" msgstr "" +#, fuzzy, c-format +#| msgid "%s: can't access: %s\n" +msgid "can't get authorityInfoAccess: %s\n" +msgstr "%s: αδυναμία Ï€Ïόσβασης: %s\n" + #, c-format msgid "looking up issuer from the Dirmngr cache\n" msgstr "" @@ -7447,10 +7465,6 @@ msgstr "σφάλμα στη δημιουÏγία της φÏάσης κλειδΠmsgid "error reading input: %s\n" msgstr "σφάλμα κατά την ανάγνωση του `%s': %s\n" -#, fuzzy, c-format -msgid "failed to get the fingerprint\n" -msgstr "αποτυχία αÏχικοποίησης της TrustDB: %s\n" - #, c-format msgid "problem looking for existing certificate: %s\n" msgstr "" @@ -7530,8 +7544,8 @@ msgid "[date not given]" msgstr "" #, fuzzy, c-format -msgid " using certificate ID 0x%08lX\n" -msgstr "σφάλμα στη δημιουÏγία της φÏάσης κλειδί: %s\n" +msgid "algorithm:" +msgstr "θωÏάκιση: %s\n" #, c-format msgid "" @@ -7863,15 +7877,6 @@ msgid "error getting data from cache file: %s\n" msgstr "σφάλμα στη δημιουÏγία της φÏάσης κλειδί: %s\n" #, fuzzy, c-format -#| msgid "invalid hash algorithm `%s'\n" -msgid "unknown hash algorithm '%s'\n" -msgstr "μη ÎγκυÏος αλγόÏιθμος hash `%s'\n" - -#, c-format -msgid "gcry_md_open for algorithm %d failed: %s\n" -msgstr "" - -#, fuzzy, c-format #| msgid "invalid response from agent\n" msgid "got an invalid S-expression from libksba\n" msgstr "μη ÎγκυÏη απάντηση από τον agent\n" @@ -7881,6 +7886,15 @@ msgid "converting S-expression failed: %s\n" msgstr "αδυναμία Ï€Ïόσβασης του αÏχείου: %s\n" #, fuzzy, c-format +#| msgid "invalid hash algorithm `%s'\n" +msgid "unknown hash algorithm '%s'\n" +msgstr "μη ÎγκυÏος αλγόÏιθμος hash `%s'\n" + +#, c-format +msgid "gcry_md_open for algorithm %d failed: %s\n" +msgstr "" + +#, fuzzy, c-format msgid "creating S-expression failed: %s\n" msgstr "διαγÏαφή block κλειδιών απÎτυχε: %s\n" @@ -8663,11 +8677,6 @@ msgstr "δημιουÏγία ενός Ï€Î¹ÏƒÏ„Î¿Ï€Î¿Î¹Î·Ï„Î¹ÎºÎ¿Ï Î±Î½Î¬ÎºÎ»Î·Ï msgid "failed to allocate OCSP context: %s\n" msgstr "αποτυχία αÏχικοποίησης της TrustDB: %s\n" -#, fuzzy, c-format -#| msgid "%s: can't access: %s\n" -msgid "can't get authorityInfoAccess: %s\n" -msgstr "%s: αδυναμία Ï€Ïόσβασης: %s\n" - #, c-format msgid "no default OCSP responder defined\n" msgstr "" @@ -9262,6 +9271,10 @@ msgid "" msgstr "" #, fuzzy +#~ msgid " using certificate ID 0x%08lX\n" +#~ msgstr "σφάλμα στη δημιουÏγία της φÏάσης κλειδί: %s\n" + +#, fuzzy #~| msgid "you may not use %s while in %s mode\n" #~ msgid "" #~ "keyserver option \"honor-keyserver-url\" may not be used in Tor mode\n" @@ -96,6 +96,9 @@ msgstr "" #. the pinentry. The %s is the actual error message, the #. two %d give the current and maximum number of tries. #. Do not translate the "SETERROR" keyword. +#. TRANSLATORS: The string is appended to an error message in +#. the pinentry. The %s is the actual error message, the +#. two %d give the current and maximum number of tries. #, c-format msgid "SETERROR %s (try %d of %d)" msgstr "" @@ -3687,6 +3690,9 @@ msgstr "%s: nevalida dosiero-versio %d\n" msgid "subkey \"%s\" not found\n" msgstr "Ålosilo '%s' ne trovita: %s\n" +msgid "AEAD: " +msgstr "" + msgid "Digest: " msgstr "" @@ -6389,6 +6395,26 @@ msgid "" "List, export, import Keybox data\n" msgstr "Uzado: gpg [opcioj] [dosieroj] (-h por helpo)" +#. TRANSLATORS: Put a \x1f right before a colon. This can be +#. * used by pinentry to nicely align the names and values. Keep +#. * the %s at the start and end of the string. +#, c-format +msgid "%sNumber: %s%%0AHolder: %s%s" +msgstr "" + +#. TRANSLATORS: This is the number of remaining attempts to +#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. +#, c-format +msgid "Remaining attempts: %d" +msgstr "" + +msgid "||Please enter the PIN for the key to create qualified signatures." +msgstr "" + +#, fuzzy +msgid "||Please enter the PIN for the standard keys." +msgstr "ÅanÄi la pasfrazon" + #, c-format msgid "RSA modulus missing or not of size %d bits\n" msgstr "" @@ -6410,10 +6436,6 @@ msgid "|N|Please enter a new PIN for the standard keys." msgstr "ÅanÄi la pasfrazon" #, fuzzy -msgid "||Please enter the PIN for the standard keys." -msgstr "ÅanÄi la pasfrazon" - -#, fuzzy msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys." msgstr "Kialo por revoko: " @@ -6424,9 +6446,6 @@ msgstr "Kialo por revoko: " msgid "|N|Please enter a new PIN for the key to create qualified signatures." msgstr "" -msgid "||Please enter the PIN for the key to create qualified signatures." -msgstr "" - msgid "" "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create " "qualified signatures." @@ -6482,16 +6501,6 @@ msgid "%sNumber: %s%%0AHolder: %s%%0ACounter: %lu%s" msgstr "" #, c-format -msgid "%sNumber: %s%%0AHolder: %s%s" -msgstr "" - -#. TRANSLATORS: This is the number of remaining attempts to -#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. -#, c-format -msgid "Remaining attempts: %d" -msgstr "" - -#, c-format msgid "using default PIN as %s\n" msgstr "" @@ -6748,6 +6757,10 @@ msgstr "skribas sekretan Ålosilon al '%s'\n" msgid "certificate policy not allowed" msgstr "skribas sekretan Ålosilon al '%s'\n" +#, fuzzy, c-format +msgid "failed to get the fingerprint\n" +msgstr "malsukcesis doni komencajn valorojn al fido-datenaro: %s\n" + #, c-format msgid "looking up issuer at external location\n" msgstr "" @@ -6756,6 +6769,11 @@ msgstr "" msgid "number of issuers matching: %d\n" msgstr "" +#, fuzzy, c-format +#| msgid "%s: can't access: %s\n" +msgid "can't get authorityInfoAccess: %s\n" +msgstr "%s: ne povas aliri: %s\n" + #, c-format msgid "looking up issuer from the Dirmngr cache\n" msgstr "" @@ -7370,10 +7388,6 @@ msgstr "eraro dum kreado de pasfrazo: %s\n" msgid "error reading input: %s\n" msgstr "eraro dum legado de '%s': %s\n" -#, fuzzy, c-format -msgid "failed to get the fingerprint\n" -msgstr "malsukcesis doni komencajn valorojn al fido-datenaro: %s\n" - #, c-format msgid "problem looking for existing certificate: %s\n" msgstr "" @@ -7453,8 +7467,8 @@ msgid "[date not given]" msgstr "" #, fuzzy, c-format -msgid " using certificate ID 0x%08lX\n" -msgstr "eraro dum kreado de pasfrazo: %s\n" +msgid "algorithm:" +msgstr "kiraso: %s\n" #, c-format msgid "" @@ -7779,15 +7793,6 @@ msgstr "" msgid "error getting data from cache file: %s\n" msgstr "eraro dum kreado de pasfrazo: %s\n" -#, fuzzy, c-format -#| msgid "invalid hash algorithm `%s'\n" -msgid "unknown hash algorithm '%s'\n" -msgstr "nevalida kompendi-metodo '%s'\n" - -#, c-format -msgid "gcry_md_open for algorithm %d failed: %s\n" -msgstr "" - #, c-format msgid "got an invalid S-expression from libksba\n" msgstr "" @@ -7798,6 +7803,15 @@ msgid "converting S-expression failed: %s\n" msgstr "ÅanÄo de permesoj de '%s' malsukcesis: %s\n" #, fuzzy, c-format +#| msgid "invalid hash algorithm `%s'\n" +msgid "unknown hash algorithm '%s'\n" +msgstr "nevalida kompendi-metodo '%s'\n" + +#, c-format +msgid "gcry_md_open for algorithm %d failed: %s\n" +msgstr "" + +#, fuzzy, c-format #| msgid "changing permission of `%s' failed: %s\n" msgid "creating S-expression failed: %s\n" msgstr "ÅanÄo de permesoj de '%s' malsukcesis: %s\n" @@ -8578,11 +8592,6 @@ msgstr "Bona atestilo" msgid "failed to allocate OCSP context: %s\n" msgstr "malsukcesis doni komencajn valorojn al fido-datenaro: %s\n" -#, fuzzy, c-format -#| msgid "%s: can't access: %s\n" -msgid "can't get authorityInfoAccess: %s\n" -msgstr "%s: ne povas aliri: %s\n" - #, c-format msgid "no default OCSP responder defined\n" msgstr "" @@ -9176,6 +9185,10 @@ msgid "" msgstr "" #, fuzzy +#~ msgid " using certificate ID 0x%08lX\n" +#~ msgstr "eraro dum kreado de pasfrazo: %s\n" + +#, fuzzy #~ msgid "" #~ "keyserver option \"honor-keyserver-url\" may not be used in Tor mode\n" #~ msgstr "Tiu komando ne eblas en la reÄimo %s.\n" @@ -106,6 +106,9 @@ msgstr "no coincide - reinténtelo" #. the pinentry. The %s is the actual error message, the #. two %d give the current and maximum number of tries. #. Do not translate the "SETERROR" keyword. +#. TRANSLATORS: The string is appended to an error message in +#. the pinentry. The %s is the actual error message, the +#. two %d give the current and maximum number of tries. #, c-format msgid "SETERROR %s (try %d of %d)" msgstr "SETERROR %s (intento %d de %d)" @@ -3509,6 +3512,9 @@ msgstr "\"%s\" no es una huella digital válida\n" msgid "subkey \"%s\" not found\n" msgstr "subclave \"%s\" no encontrada\n" +msgid "AEAD: " +msgstr "" + msgid "Digest: " msgstr "Resumen: " @@ -6202,6 +6208,25 @@ msgstr "" "Sintaxis: kbxutil [opciones] [ficheros]\n" "Listar, exportar, importar datos Keybox\n" +#. TRANSLATORS: Put a \x1f right before a colon. This can be +#. * used by pinentry to nicely align the names and values. Keep +#. * the %s at the start and end of the string. +#, c-format +msgid "%sNumber: %s%%0AHolder: %s%s" +msgstr "%sNúmero: %s%%0ATitular: %s%s" + +#. TRANSLATORS: This is the number of remaining attempts to +#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. +#, c-format +msgid "Remaining attempts: %d" +msgstr "Intentos disponibles: %d" + +msgid "||Please enter the PIN for the key to create qualified signatures." +msgstr "||Introduzca un PIN para la clave que crea firmas cualificadas." + +msgid "||Please enter the PIN for the standard keys." +msgstr "||Por favor, introduzca PIN para claves estándar." + #, c-format msgid "RSA modulus missing or not of size %d bits\n" msgstr "falta el módulo RSA o no es de %d bits\n" @@ -6221,9 +6246,6 @@ msgstr "el PIN-Nulo no ha sido cambiado\n" msgid "|N|Please enter a new PIN for the standard keys." msgstr "|N|Por favor introduzca un nuevo PIN para las claves estándar." -msgid "||Please enter the PIN for the standard keys." -msgstr "||Por favor, introduzca PIN para claves estándar." - msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys." msgstr "|NP|Introduzca nuevo PIN Unblocking Code (PUK) para claves estándar." @@ -6234,9 +6256,6 @@ msgstr "" msgid "|N|Please enter a new PIN for the key to create qualified signatures." msgstr "|N|Entre un nuevo PIN para la clave que crea firmas cualificadas." -msgid "||Please enter the PIN for the key to create qualified signatures." -msgstr "||Introduzca un PIN para la clave que crea firmas cualificadas." - msgid "" "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create " "qualified signatures." @@ -6295,16 +6314,6 @@ msgid "%sNumber: %s%%0AHolder: %s%%0ACounter: %lu%s" msgstr "%sNumber: %s%%0AHolder: %s%%0ACounter: %lu%s" #, c-format -msgid "%sNumber: %s%%0AHolder: %s%s" -msgstr "%sNúmero: %s%%0ATitular: %s%s" - -#. TRANSLATORS: This is the number of remaining attempts to -#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. -#, c-format -msgid "Remaining attempts: %d" -msgstr "Intentos disponibles: %d" - -#, c-format msgid "using default PIN as %s\n" msgstr "usando PIN por defecto %s\n" @@ -6553,6 +6562,10 @@ msgid "certificate policy not allowed" msgstr "no se permite polÃtica de certificado" #, c-format +msgid "failed to get the fingerprint\n" +msgstr "fallo obteniendo huella digital\n" + +#, c-format msgid "looking up issuer at external location\n" msgstr "buscando al emisor en una localización externa\n" @@ -6561,6 +6574,10 @@ msgid "number of issuers matching: %d\n" msgstr "numero de emisores coincidentes: %d\n" #, c-format +msgid "can't get authorityInfoAccess: %s\n" +msgstr "no se ha podido obtener authorityInfoAccess: %s\n" + +#, c-format msgid "looking up issuer from the Dirmngr cache\n" msgstr "buscando emisor en el caché de Dirmngr\n" @@ -7149,10 +7166,6 @@ msgid "error reading input: %s\n" msgstr "error al leer la entrada: %s\n" #, c-format -msgid "failed to get the fingerprint\n" -msgstr "fallo obteniendo huella digital\n" - -#, c-format msgid "problem looking for existing certificate: %s\n" msgstr "problema buscando el certificado existente: %s\n" @@ -7240,9 +7253,10 @@ msgstr "Firmado el " msgid "[date not given]" msgstr "[no hay fecha]" -#, c-format -msgid " using certificate ID 0x%08lX\n" -msgstr " usando el certificado ID 0x%08lX\n" +#, fuzzy, c-format +#| msgid "algorithm: %s" +msgid "algorithm:" +msgstr "algoritmo: %s" #, c-format msgid "" @@ -7573,14 +7587,6 @@ msgid "error getting data from cache file: %s\n" msgstr "error al obtener datos del archivo de cache: %s\n" #, c-format -msgid "unknown hash algorithm '%s'\n" -msgstr "algoritmo hash inválido '%s'\n" - -#, c-format -msgid "gcry_md_open for algorithm %d failed: %s\n" -msgstr "gcry_md_open para algoritmo %d ha fallado: %s\n" - -#, c-format msgid "got an invalid S-expression from libksba\n" msgstr "respuesta S-expression de libksba no válida\n" @@ -7589,6 +7595,14 @@ msgid "converting S-expression failed: %s\n" msgstr "he fallado al convertir la expresión S-expression: %s\n" #, c-format +msgid "unknown hash algorithm '%s'\n" +msgstr "algoritmo hash inválido '%s'\n" + +#, c-format +msgid "gcry_md_open for algorithm %d failed: %s\n" +msgstr "gcry_md_open para algoritmo %d ha fallado: %s\n" + +#, c-format msgid "creating S-expression failed: %s\n" msgstr "fallo al crear S-expression: %s\n" @@ -8356,10 +8370,6 @@ msgid "failed to allocate OCSP context: %s\n" msgstr "fallo al asignar el contexto OCSP: %s\n" #, c-format -msgid "can't get authorityInfoAccess: %s\n" -msgstr "no se ha podido obtener authorityInfoAccess: %s\n" - -#, c-format msgid "no default OCSP responder defined\n" msgstr "no hay un OCSP responder predeterminado\n" @@ -8948,6 +8958,9 @@ msgstr "" "Compara frase contraseña dada en entrada estándar con un fichero de " "patrones\n" +#~ msgid " using certificate ID 0x%08lX\n" +#~ msgstr " usando el certificado ID 0x%08lX\n" + #, fuzzy #~| msgid "option '%s' may not be used in %s mode\n" #~ msgid "" @@ -93,6 +93,9 @@ msgstr "" #. the pinentry. The %s is the actual error message, the #. two %d give the current and maximum number of tries. #. Do not translate the "SETERROR" keyword. +#. TRANSLATORS: The string is appended to an error message in +#. the pinentry. The %s is the actual error message, the +#. two %d give the current and maximum number of tries. #, c-format msgid "SETERROR %s (try %d of %d)" msgstr "" @@ -3687,6 +3690,9 @@ msgstr "viga: vigane sõrmejälg\n" msgid "subkey \"%s\" not found\n" msgstr "võtit '%s' ei leitud: %s\n" +msgid "AEAD: " +msgstr "" + msgid "Digest: " msgstr "Teatelühend: " @@ -6395,6 +6401,26 @@ msgid "" "List, export, import Keybox data\n" msgstr "Kasuta: gpg [võtmed] [failid] (-h näitab abiinfot)" +#. TRANSLATORS: Put a \x1f right before a colon. This can be +#. * used by pinentry to nicely align the names and values. Keep +#. * the %s at the start and end of the string. +#, c-format +msgid "%sNumber: %s%%0AHolder: %s%s" +msgstr "" + +#. TRANSLATORS: This is the number of remaining attempts to +#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. +#, c-format +msgid "Remaining attempts: %d" +msgstr "" + +msgid "||Please enter the PIN for the key to create qualified signatures." +msgstr "" + +#, fuzzy +msgid "||Please enter the PIN for the standard keys." +msgstr "muuda parooli" + #, c-format msgid "RSA modulus missing or not of size %d bits\n" msgstr "" @@ -6416,10 +6442,6 @@ msgid "|N|Please enter a new PIN for the standard keys." msgstr "muuda parooli" #, fuzzy -msgid "||Please enter the PIN for the standard keys." -msgstr "muuda parooli" - -#, fuzzy msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys." msgstr "Palun valige tühistamise põhjus:\n" @@ -6430,9 +6452,6 @@ msgstr "Palun valige tühistamise põhjus:\n" msgid "|N|Please enter a new PIN for the key to create qualified signatures." msgstr "" -msgid "||Please enter the PIN for the key to create qualified signatures." -msgstr "" - msgid "" "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create " "qualified signatures." @@ -6488,16 +6507,6 @@ msgid "%sNumber: %s%%0AHolder: %s%%0ACounter: %lu%s" msgstr "" #, c-format -msgid "%sNumber: %s%%0AHolder: %s%s" -msgstr "" - -#. TRANSLATORS: This is the number of remaining attempts to -#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. -#, c-format -msgid "Remaining attempts: %d" -msgstr "" - -#, c-format msgid "using default PIN as %s\n" msgstr "" @@ -6753,6 +6762,10 @@ msgstr "kirjutan salajase võtme faili `%s'\n" msgid "certificate policy not allowed" msgstr "kirjutan salajase võtme faili `%s'\n" +#, fuzzy, c-format +msgid "failed to get the fingerprint\n" +msgstr "TrustDB initsialiseerimine ebaõnnestus: %s\n" + #, c-format msgid "looking up issuer at external location\n" msgstr "" @@ -6761,6 +6774,11 @@ msgstr "" msgid "number of issuers matching: %d\n" msgstr "" +#, fuzzy, c-format +#| msgid "%s: can't access: %s\n" +msgid "can't get authorityInfoAccess: %s\n" +msgstr "%s: ei õnnestu kasutada: %s\n" + #, c-format msgid "looking up issuer from the Dirmngr cache\n" msgstr "" @@ -7367,10 +7385,6 @@ msgstr "viga parooli loomisel: %s\n" msgid "error reading input: %s\n" msgstr "viga `%s' lugemisel: %s\n" -#, fuzzy, c-format -msgid "failed to get the fingerprint\n" -msgstr "TrustDB initsialiseerimine ebaõnnestus: %s\n" - #, c-format msgid "problem looking for existing certificate: %s\n" msgstr "" @@ -7450,8 +7464,8 @@ msgid "[date not given]" msgstr "" #, fuzzy, c-format -msgid " using certificate ID 0x%08lX\n" -msgstr "viga parooli loomisel: %s\n" +msgid "algorithm:" +msgstr "pakend: %s\n" #, c-format msgid "" @@ -7781,15 +7795,6 @@ msgid "error getting data from cache file: %s\n" msgstr "viga parooli loomisel: %s\n" #, fuzzy, c-format -#| msgid "invalid hash algorithm `%s'\n" -msgid "unknown hash algorithm '%s'\n" -msgstr "vigane räsialgoritm `%s'\n" - -#, c-format -msgid "gcry_md_open for algorithm %d failed: %s\n" -msgstr "" - -#, fuzzy, c-format #| msgid "invalid response from agent\n" msgid "got an invalid S-expression from libksba\n" msgstr "vigane vastus agendilt\n" @@ -7799,6 +7804,15 @@ msgid "converting S-expression failed: %s\n" msgstr "faili ei õnnestu avada: %s\n" #, fuzzy, c-format +#| msgid "invalid hash algorithm `%s'\n" +msgid "unknown hash algorithm '%s'\n" +msgstr "vigane räsialgoritm `%s'\n" + +#, c-format +msgid "gcry_md_open for algorithm %d failed: %s\n" +msgstr "" + +#, fuzzy, c-format msgid "creating S-expression failed: %s\n" msgstr "võtmebloki kustutamine ebaõnnestus: %s\n" @@ -8579,11 +8593,6 @@ msgstr "genereeri tühistamise sertifikaat" msgid "failed to allocate OCSP context: %s\n" msgstr "TrustDB initsialiseerimine ebaõnnestus: %s\n" -#, fuzzy, c-format -#| msgid "%s: can't access: %s\n" -msgid "can't get authorityInfoAccess: %s\n" -msgstr "%s: ei õnnestu kasutada: %s\n" - #, c-format msgid "no default OCSP responder defined\n" msgstr "" @@ -9178,6 +9187,10 @@ msgid "" msgstr "" #, fuzzy +#~ msgid " using certificate ID 0x%08lX\n" +#~ msgstr "viga parooli loomisel: %s\n" + +#, fuzzy #~| msgid "you may not use %s while in %s mode\n" #~ msgid "" #~ "keyserver option \"honor-keyserver-url\" may not be used in Tor mode\n" @@ -109,6 +109,9 @@ msgstr "" #. the pinentry. The %s is the actual error message, the #. two %d give the current and maximum number of tries. #. Do not translate the "SETERROR" keyword. +#. TRANSLATORS: The string is appended to an error message in +#. the pinentry. The %s is the actual error message, the +#. two %d give the current and maximum number of tries. #, c-format msgid "SETERROR %s (try %d of %d)" msgstr "" @@ -3707,6 +3710,9 @@ msgstr "virhe: sormenjälki on väärä\n" msgid "subkey \"%s\" not found\n" msgstr "avainta \"%s\" ei löydy: %s\n" +msgid "AEAD: " +msgstr "" + msgid "Digest: " msgstr "Tiiviste: " @@ -6454,6 +6460,26 @@ msgid "" "List, export, import Keybox data\n" msgstr "Käyttö: gpg [valitsimet] [tiedostot] (-h näyttää ohjeen)" +#. TRANSLATORS: Put a \x1f right before a colon. This can be +#. * used by pinentry to nicely align the names and values. Keep +#. * the %s at the start and end of the string. +#, c-format +msgid "%sNumber: %s%%0AHolder: %s%s" +msgstr "" + +#. TRANSLATORS: This is the number of remaining attempts to +#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. +#, c-format +msgid "Remaining attempts: %d" +msgstr "" + +msgid "||Please enter the PIN for the key to create qualified signatures." +msgstr "" + +#, fuzzy +msgid "||Please enter the PIN for the standard keys." +msgstr "muuta salasanaa" + #, c-format msgid "RSA modulus missing or not of size %d bits\n" msgstr "" @@ -6475,10 +6501,6 @@ msgid "|N|Please enter a new PIN for the standard keys." msgstr "muuta salasanaa" #, fuzzy -msgid "||Please enter the PIN for the standard keys." -msgstr "muuta salasanaa" - -#, fuzzy msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys." msgstr "Valitse mitätöinnin syy:\n" @@ -6489,9 +6511,6 @@ msgstr "Valitse mitätöinnin syy:\n" msgid "|N|Please enter a new PIN for the key to create qualified signatures." msgstr "" -msgid "||Please enter the PIN for the key to create qualified signatures." -msgstr "" - msgid "" "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create " "qualified signatures." @@ -6547,16 +6566,6 @@ msgid "%sNumber: %s%%0AHolder: %s%%0ACounter: %lu%s" msgstr "" #, c-format -msgid "%sNumber: %s%%0AHolder: %s%s" -msgstr "" - -#. TRANSLATORS: This is the number of remaining attempts to -#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. -#, c-format -msgid "Remaining attempts: %d" -msgstr "" - -#, c-format msgid "using default PIN as %s\n" msgstr "" @@ -6813,6 +6822,10 @@ msgstr "kirjoitan salaisen avaimen kohteeseen \"%s\"\n" msgid "certificate policy not allowed" msgstr "kirjoitan salaisen avaimen kohteeseen \"%s\"\n" +#, fuzzy, c-format +msgid "failed to get the fingerprint\n" +msgstr "TrustDB:n alustaminen ei onnistu: %s\n" + #, c-format msgid "looking up issuer at external location\n" msgstr "" @@ -6821,6 +6834,11 @@ msgstr "" msgid "number of issuers matching: %d\n" msgstr "" +#, fuzzy, c-format +#| msgid "%s: can't access: %s\n" +msgid "can't get authorityInfoAccess: %s\n" +msgstr "%s: kohteeseen ei päästä: %s\n" + #, c-format msgid "looking up issuer from the Dirmngr cache\n" msgstr "" @@ -7427,10 +7445,6 @@ msgstr "virhe luotaessa salasanaa: %s\n" msgid "error reading input: %s\n" msgstr "virhe luettaessa tiedostoa \"%s\": %s\n" -#, fuzzy, c-format -msgid "failed to get the fingerprint\n" -msgstr "TrustDB:n alustaminen ei onnistu: %s\n" - #, c-format msgid "problem looking for existing certificate: %s\n" msgstr "" @@ -7510,8 +7524,8 @@ msgid "[date not given]" msgstr "" #, fuzzy, c-format -msgid " using certificate ID 0x%08lX\n" -msgstr "virhe luotaessa salasanaa: %s\n" +msgid "algorithm:" +msgstr "ascii-koodaus: %s\n" #, c-format msgid "" @@ -7842,15 +7856,6 @@ msgid "error getting data from cache file: %s\n" msgstr "virhe luotaessa salasanaa: %s\n" #, fuzzy, c-format -#| msgid "invalid hash algorithm `%s'\n" -msgid "unknown hash algorithm '%s'\n" -msgstr "virheellinen tiivistealgoritmi \"%s\"\n" - -#, c-format -msgid "gcry_md_open for algorithm %d failed: %s\n" -msgstr "" - -#, fuzzy, c-format #| msgid "invalid response from agent\n" msgid "got an invalid S-expression from libksba\n" msgstr "agentin lähettämä vastaus ei kelpaa\n" @@ -7860,6 +7865,15 @@ msgid "converting S-expression failed: %s\n" msgstr "ei voi avata tiedostoa: %s\n" #, fuzzy, c-format +#| msgid "invalid hash algorithm `%s'\n" +msgid "unknown hash algorithm '%s'\n" +msgstr "virheellinen tiivistealgoritmi \"%s\"\n" + +#, c-format +msgid "gcry_md_open for algorithm %d failed: %s\n" +msgstr "" + +#, fuzzy, c-format msgid "creating S-expression failed: %s\n" msgstr "avainlohkojen poisto epäonnistui: %s\n" @@ -8642,11 +8656,6 @@ msgstr "luo mitätöintivarmenne" msgid "failed to allocate OCSP context: %s\n" msgstr "TrustDB:n alustaminen ei onnistu: %s\n" -#, fuzzy, c-format -#| msgid "%s: can't access: %s\n" -msgid "can't get authorityInfoAccess: %s\n" -msgstr "%s: kohteeseen ei päästä: %s\n" - #, c-format msgid "no default OCSP responder defined\n" msgstr "" @@ -9241,6 +9250,10 @@ msgid "" msgstr "" #, fuzzy +#~ msgid " using certificate ID 0x%08lX\n" +#~ msgstr "virhe luotaessa salasanaa: %s\n" + +#, fuzzy #~| msgid "you may not use %s while in %s mode\n" #~ msgid "" #~ "keyserver option \"honor-keyserver-url\" may not be used in Tor mode\n" @@ -108,6 +108,9 @@ msgstr "ne correspond pas — veuillez réessayer" #. the pinentry. The %s is the actual error message, the #. two %d give the current and maximum number of tries. #. Do not translate the "SETERROR" keyword. +#. TRANSLATORS: The string is appended to an error message in +#. the pinentry. The %s is the actual error message, the +#. two %d give the current and maximum number of tries. #, c-format msgid "SETERROR %s (try %d of %d)" msgstr "SETERROR %s (essai %d sur %d)" @@ -3650,6 +3653,9 @@ msgstr "« %s » n’est pas une empreinte\n" msgid "subkey \"%s\" not found\n" msgstr "clef « %s » introuvable : %s\n" +msgid "AEAD: " +msgstr "" + msgid "Digest: " msgstr "Hachage : " @@ -6469,6 +6475,27 @@ msgstr "" "Syntaxe : kbxutil [options] [fichiers]\n" "Afficher, exporter, importer les données de trousseau local\n" +#. TRANSLATORS: Put a \x1f right before a colon. This can be +#. * used by pinentry to nicely align the names and values. Keep +#. * the %s at the start and end of the string. +#, c-format +msgid "%sNumber: %s%%0AHolder: %s%s" +msgstr "" + +#. TRANSLATORS: This is the number of remaining attempts to +#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. +#, c-format +msgid "Remaining attempts: %d" +msgstr "" + +msgid "||Please enter the PIN for the key to create qualified signatures." +msgstr "" +"||Veuillez entrer le code personnel pour permettre à la clef de créer des " +"signatures qualifiées." + +msgid "||Please enter the PIN for the standard keys." +msgstr "||Veuillez entrer le code personnel pour les clefs standards." + #, c-format msgid "RSA modulus missing or not of size %d bits\n" msgstr "le module RSA est manquant ou sa taille n'est pas de %d bits\n" @@ -6488,9 +6515,6 @@ msgstr "le code personnel nul n'a pas encore été modifié\n" msgid "|N|Please enter a new PIN for the standard keys." msgstr "|N|Veuillez entrer un nouveau code personnel pour les clefs standards." -msgid "||Please enter the PIN for the standard keys." -msgstr "||Veuillez entrer le code personnel pour les clefs standards." - msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys." msgstr "" "|NP|Veuillez entrer un nouveau code de déblocage personnel (CDP) pour les " @@ -6506,11 +6530,6 @@ msgstr "" "|N|Veuillez entrer un nouveau code personnel pour permettre à la clef de " "créer des signatures qualifiées." -msgid "||Please enter the PIN for the key to create qualified signatures." -msgstr "" -"||Veuillez entrer le code personnel pour permettre à la clef de créer des " -"signatures qualifiées." - msgid "" "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create " "qualified signatures." @@ -6570,16 +6589,6 @@ msgid "%sNumber: %s%%0AHolder: %s%%0ACounter: %lu%s" msgstr "" #, c-format -msgid "%sNumber: %s%%0AHolder: %s%s" -msgstr "" - -#. TRANSLATORS: This is the number of remaining attempts to -#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. -#, c-format -msgid "Remaining attempts: %d" -msgstr "" - -#, c-format msgid "using default PIN as %s\n" msgstr "utilisation du code personnel par défaut en tant que %s\n" @@ -6849,6 +6858,10 @@ msgid "certificate policy not allowed" msgstr "politique de certificat non autorisée" #, c-format +msgid "failed to get the fingerprint\n" +msgstr "impossible d'obtenir l'empreinte\n" + +#, c-format msgid "looking up issuer at external location\n" msgstr "recherche d'émetteur à l'extérieur\n" @@ -6857,6 +6870,10 @@ msgid "number of issuers matching: %d\n" msgstr "nombre d'émetteurs correspondants : %d\n" #, c-format +msgid "can't get authorityInfoAccess: %s\n" +msgstr "impossible d'obtenir authorityInfoAccess : %s\n" + +#, c-format msgid "looking up issuer from the Dirmngr cache\n" msgstr "recherche d'émetteur dans le cache du Dirmngr\n" @@ -7452,10 +7469,6 @@ msgid "error reading input: %s\n" msgstr "erreur de lecture de l'entrée : %s\n" #, c-format -msgid "failed to get the fingerprint\n" -msgstr "impossible d'obtenir l'empreinte\n" - -#, c-format msgid "problem looking for existing certificate: %s\n" msgstr "problème de recherche de certificat existant : %s\n" @@ -7550,9 +7563,10 @@ msgstr "Signature faite le " msgid "[date not given]" msgstr "[date non donnée]" -#, c-format -msgid " using certificate ID 0x%08lX\n" -msgstr " en utilisant le certificat d'identifiant 0x%08lX\n" +#, fuzzy, c-format +#| msgid "algorithm: %s" +msgid "algorithm:" +msgstr "algorithme : %s" #, c-format msgid "" @@ -7898,14 +7912,6 @@ msgid "error getting data from cache file: %s\n" msgstr "erreur de lecture des données du fichier de cache : %s\n" #, c-format -msgid "unknown hash algorithm '%s'\n" -msgstr "algorithme de hachage « %s » inconnu\n" - -#, c-format -msgid "gcry_md_open for algorithm %d failed: %s\n" -msgstr "échec de gcry_md_open pour l'algorithme %d : %s\n" - -#, c-format msgid "got an invalid S-expression from libksba\n" msgstr "expression symbolique incorrecte obtenue de libksba\n" @@ -7914,6 +7920,14 @@ msgid "converting S-expression failed: %s\n" msgstr "échec de conversion d'expression symbolique : %s\n" #, c-format +msgid "unknown hash algorithm '%s'\n" +msgstr "algorithme de hachage « %s » inconnu\n" + +#, c-format +msgid "gcry_md_open for algorithm %d failed: %s\n" +msgstr "échec de gcry_md_open pour l'algorithme %d : %s\n" + +#, c-format msgid "creating S-expression failed: %s\n" msgstr "échec de création d'expression symbolique : %s\n" @@ -8712,10 +8726,6 @@ msgid "failed to allocate OCSP context: %s\n" msgstr "échec d'allocation du contexte OCSP : %s\n" #, c-format -msgid "can't get authorityInfoAccess: %s\n" -msgstr "impossible d'obtenir authorityInfoAccess : %s\n" - -#, c-format msgid "no default OCSP responder defined\n" msgstr "aucun répondeur OCSP par défaut défini\n" @@ -9321,6 +9331,9 @@ msgstr "" "Vérifier une phrase secrète donnée sur l'entrée standard par rapport à " "ficmotif\n" +#~ msgid " using certificate ID 0x%08lX\n" +#~ msgstr " en utilisant le certificat d'identifiant 0x%08lX\n" + #, fuzzy #~| msgid "you may not use %s while in %s mode\n" #~ msgid "" @@ -94,6 +94,9 @@ msgstr "" #. the pinentry. The %s is the actual error message, the #. two %d give the current and maximum number of tries. #. Do not translate the "SETERROR" keyword. +#. TRANSLATORS: The string is appended to an error message in +#. the pinentry. The %s is the actual error message, the +#. two %d give the current and maximum number of tries. #, c-format msgid "SETERROR %s (try %d of %d)" msgstr "" @@ -3711,6 +3714,9 @@ msgstr "erro: pegada dactilar non válida\n" msgid "subkey \"%s\" not found\n" msgstr "non se atopou a chave `%s': %s\n" +msgid "AEAD: " +msgstr "" + msgid "Digest: " msgstr "Resumo: " @@ -6458,6 +6464,26 @@ msgid "" "List, export, import Keybox data\n" msgstr "Uso: gpg [opcións] [ficheiros] (-h para ve-la axuda)" +#. TRANSLATORS: Put a \x1f right before a colon. This can be +#. * used by pinentry to nicely align the names and values. Keep +#. * the %s at the start and end of the string. +#, c-format +msgid "%sNumber: %s%%0AHolder: %s%s" +msgstr "" + +#. TRANSLATORS: This is the number of remaining attempts to +#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. +#, c-format +msgid "Remaining attempts: %d" +msgstr "" + +msgid "||Please enter the PIN for the key to create qualified signatures." +msgstr "" + +#, fuzzy +msgid "||Please enter the PIN for the standard keys." +msgstr "cambia-lo contrasinal" + #, c-format msgid "RSA modulus missing or not of size %d bits\n" msgstr "" @@ -6479,10 +6505,6 @@ msgid "|N|Please enter a new PIN for the standard keys." msgstr "cambia-lo contrasinal" #, fuzzy -msgid "||Please enter the PIN for the standard keys." -msgstr "cambia-lo contrasinal" - -#, fuzzy msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys." msgstr "Por favor, escolla o motivo da revocación:\n" @@ -6493,9 +6515,6 @@ msgstr "Por favor, escolla o motivo da revocación:\n" msgid "|N|Please enter a new PIN for the key to create qualified signatures." msgstr "" -msgid "||Please enter the PIN for the key to create qualified signatures." -msgstr "" - msgid "" "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create " "qualified signatures." @@ -6551,16 +6570,6 @@ msgid "%sNumber: %s%%0AHolder: %s%%0ACounter: %lu%s" msgstr "" #, c-format -msgid "%sNumber: %s%%0AHolder: %s%s" -msgstr "" - -#. TRANSLATORS: This is the number of remaining attempts to -#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. -#, c-format -msgid "Remaining attempts: %d" -msgstr "" - -#, c-format msgid "using default PIN as %s\n" msgstr "" @@ -6817,6 +6826,10 @@ msgstr "gravando a chave secreta en `%s'\n" msgid "certificate policy not allowed" msgstr "gravando a chave secreta en `%s'\n" +#, fuzzy, c-format +msgid "failed to get the fingerprint\n" +msgstr "non se puido inicializa-la base de datos de confianzas: %s\n" + #, c-format msgid "looking up issuer at external location\n" msgstr "" @@ -6825,6 +6838,11 @@ msgstr "" msgid "number of issuers matching: %d\n" msgstr "" +#, fuzzy, c-format +#| msgid "%s: can't access: %s\n" +msgid "can't get authorityInfoAccess: %s\n" +msgstr "%s: non é posible acceder: %s\n" + #, c-format msgid "looking up issuer from the Dirmngr cache\n" msgstr "" @@ -7439,10 +7457,6 @@ msgstr "erro ao crea-lo contrasinal: %s\n" msgid "error reading input: %s\n" msgstr "erro lendo `%s': %s\n" -#, fuzzy, c-format -msgid "failed to get the fingerprint\n" -msgstr "non se puido inicializa-la base de datos de confianzas: %s\n" - #, c-format msgid "problem looking for existing certificate: %s\n" msgstr "" @@ -7522,8 +7536,8 @@ msgid "[date not given]" msgstr "" #, fuzzy, c-format -msgid " using certificate ID 0x%08lX\n" -msgstr "erro ao crea-lo contrasinal: %s\n" +msgid "algorithm:" +msgstr "armadura: %s\n" #, c-format msgid "" @@ -7854,15 +7868,6 @@ msgid "error getting data from cache file: %s\n" msgstr "erro ao crea-lo contrasinal: %s\n" #, fuzzy, c-format -#| msgid "invalid hash algorithm `%s'\n" -msgid "unknown hash algorithm '%s'\n" -msgstr "algoritmo de hash non válido `%s'\n" - -#, c-format -msgid "gcry_md_open for algorithm %d failed: %s\n" -msgstr "" - -#, fuzzy, c-format #| msgid "invalid response from agent\n" msgid "got an invalid S-expression from libksba\n" msgstr "resposta do axente non válida\n" @@ -7873,6 +7878,15 @@ msgid "converting S-expression failed: %s\n" msgstr "o cambio de permisos de `%s' fallou: %s\n" #, fuzzy, c-format +#| msgid "invalid hash algorithm `%s'\n" +msgid "unknown hash algorithm '%s'\n" +msgstr "algoritmo de hash non válido `%s'\n" + +#, c-format +msgid "gcry_md_open for algorithm %d failed: %s\n" +msgstr "" + +#, fuzzy, c-format #| msgid "changing permission of `%s' failed: %s\n" msgid "creating S-expression failed: %s\n" msgstr "o cambio de permisos de `%s' fallou: %s\n" @@ -8658,11 +8672,6 @@ msgstr "Certificado correcto" msgid "failed to allocate OCSP context: %s\n" msgstr "non se puido inicializa-la base de datos de confianzas: %s\n" -#, fuzzy, c-format -#| msgid "%s: can't access: %s\n" -msgid "can't get authorityInfoAccess: %s\n" -msgstr "%s: non é posible acceder: %s\n" - #, c-format msgid "no default OCSP responder defined\n" msgstr "" @@ -9259,6 +9268,10 @@ msgid "" msgstr "" #, fuzzy +#~ msgid " using certificate ID 0x%08lX\n" +#~ msgstr "erro ao crea-lo contrasinal: %s\n" + +#, fuzzy #~| msgid "you may not use %s while in %s mode\n" #~ msgid "" #~ "keyserver option \"honor-keyserver-url\" may not be used in Tor mode\n" @@ -1,12 +1,12 @@ # GnuPG Hungarian translation. -# Copyright (C) 2003, 2004 Free Software Foundation, Inc. -# Nagy Ferenc László <nfl@nfllab.com>, 2003, 2004. +# Copyright (C) 2003, 2004, 2020 Free Software Foundation, Inc. +# Nagy Ferenc László <nfl@nfllab.com>, 2003, 2004, 2020. # msgid "" msgstr "" -"Project-Id-Version: gnupg 1.2.5\n" +"Project-Id-Version: gnupg 2.2.20\n" "Report-Msgid-Bugs-To: translations@gnupg.org\n" -"PO-Revision-Date: 2004-06-19 21:53+0200\n" +"PO-Revision-Date: 2020-06-09 23:10+0200\n" "Last-Translator: Nagy Ferenc László <nfl@nfllab.com>\n" "Language-Team: Hungarian <translation-team-hu@lists.sourceforge.net>\n" "Language: hu\n" @@ -93,6 +93,9 @@ msgstr "" #. the pinentry. The %s is the actual error message, the #. two %d give the current and maximum number of tries. #. Do not translate the "SETERROR" keyword. +#. TRANSLATORS: The string is appended to an error message in +#. the pinentry. The %s is the actual error message, the +#. two %d give the current and maximum number of tries. #, c-format msgid "SETERROR %s (try %d of %d)" msgstr "" @@ -3686,6 +3689,9 @@ msgstr "Hiba: Érvénytelen ujjlenyomat.\n" msgid "subkey \"%s\" not found\n" msgstr "\"%s\" kulcs nem található: %s\n" +msgid "AEAD: " +msgstr "" + msgid "Digest: " msgstr "Kivonat: " @@ -4397,16 +4403,11 @@ msgid "Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? " msgstr "" "(N)év, (M)egjegyzés, (E)-mail megváltoztatása vagy (R)endben/(K)ilépés? " -#, fuzzy -#| msgid "Change (N)ame, (C)omment, (E)mail or (Q)uit? " msgid "Change (N)ame, (E)mail, or (Q)uit? " -msgstr "(N)év, (M)egjegyzés, (E)-mail megváltoztatása vagy (K)ilépés? " +msgstr "(N)év, (E)-mail megváltoztatása vagy (K)ilépés? " -#, fuzzy -#| msgid "Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? " msgid "Change (N)ame, (E)mail, or (O)kay/(Q)uit? " -msgstr "" -"(N)év, (M)egjegyzés, (E)-mail megváltoztatása vagy (R)endben/(K)ilépés? " +msgstr "(N)év, (E)-mail megváltoztatása vagy (R)endben/(K)ilépés? " msgid "Please correct the error first\n" msgstr "Kérem, elÅ‘bb javÃtsa ki a hibát!\n" @@ -6424,6 +6425,26 @@ msgid "" "List, export, import Keybox data\n" msgstr "Használat: gpg [opciók] [fájlok] (-h a súgóhoz)" +#. TRANSLATORS: Put a \x1f right before a colon. This can be +#. * used by pinentry to nicely align the names and values. Keep +#. * the %s at the start and end of the string. +#, c-format +msgid "%sNumber: %s%%0AHolder: %s%s" +msgstr "" + +#. TRANSLATORS: This is the number of remaining attempts to +#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. +#, c-format +msgid "Remaining attempts: %d" +msgstr "" + +msgid "||Please enter the PIN for the key to create qualified signatures." +msgstr "" + +#, fuzzy +msgid "||Please enter the PIN for the standard keys." +msgstr "jelszóváltoztatás" + #, c-format msgid "RSA modulus missing or not of size %d bits\n" msgstr "" @@ -6445,10 +6466,6 @@ msgid "|N|Please enter a new PIN for the standard keys." msgstr "jelszóváltoztatás" #, fuzzy -msgid "||Please enter the PIN for the standard keys." -msgstr "jelszóváltoztatás" - -#, fuzzy msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys." msgstr "Kérem, válassza ki a visszavonás okát:\n" @@ -6459,9 +6476,6 @@ msgstr "Kérem, válassza ki a visszavonás okát:\n" msgid "|N|Please enter a new PIN for the key to create qualified signatures." msgstr "" -msgid "||Please enter the PIN for the key to create qualified signatures." -msgstr "" - msgid "" "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create " "qualified signatures." @@ -6517,16 +6531,6 @@ msgid "%sNumber: %s%%0AHolder: %s%%0ACounter: %lu%s" msgstr "" #, c-format -msgid "%sNumber: %s%%0AHolder: %s%s" -msgstr "" - -#. TRANSLATORS: This is the number of remaining attempts to -#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. -#, c-format -msgid "Remaining attempts: %d" -msgstr "" - -#, c-format msgid "using default PIN as %s\n" msgstr "" @@ -6782,6 +6786,10 @@ msgstr "Ãrom a titkos kulcsot a %s állományba.\n" msgid "certificate policy not allowed" msgstr "Ãrom a titkos kulcsot a %s állományba.\n" +#, fuzzy, c-format +msgid "failed to get the fingerprint\n" +msgstr "Bizalmi adatbázis (%s) inicializálása sikertelen!\n" + #, c-format msgid "looking up issuer at external location\n" msgstr "" @@ -6790,6 +6798,11 @@ msgstr "" msgid "number of issuers matching: %d\n" msgstr "" +#, fuzzy, c-format +#| msgid "%s: can't access: %s\n" +msgid "can't get authorityInfoAccess: %s\n" +msgstr "%s: Nem tudom elérni: %s.\n" + #, c-format msgid "looking up issuer from the Dirmngr cache\n" msgstr "" @@ -7397,10 +7410,6 @@ msgstr "Hiba a jelszó létrehozásakor: %s.\n" msgid "error reading input: %s\n" msgstr "Hiba \"%s\" olvasásakor: %s\n" -#, fuzzy, c-format -msgid "failed to get the fingerprint\n" -msgstr "Bizalmi adatbázis (%s) inicializálása sikertelen!\n" - #, c-format msgid "problem looking for existing certificate: %s\n" msgstr "" @@ -7480,8 +7489,8 @@ msgid "[date not given]" msgstr "" #, fuzzy, c-format -msgid " using certificate ID 0x%08lX\n" -msgstr "Hiba a jelszó létrehozásakor: %s.\n" +msgid "algorithm:" +msgstr "Páncél: %s\n" #, c-format msgid "" @@ -7811,15 +7820,6 @@ msgid "error getting data from cache file: %s\n" msgstr "Hiba a jelszó létrehozásakor: %s.\n" #, fuzzy, c-format -#| msgid "invalid hash algorithm `%s'\n" -msgid "unknown hash algorithm '%s'\n" -msgstr "Érvénytelen kivonatoló algoritmus: %s\n" - -#, c-format -msgid "gcry_md_open for algorithm %d failed: %s\n" -msgstr "" - -#, fuzzy, c-format #| msgid "invalid response from agent\n" msgid "got an invalid S-expression from libksba\n" msgstr "Érvénytelen válasz az ügynöktÅ‘l!\n" @@ -7829,6 +7829,15 @@ msgid "converting S-expression failed: %s\n" msgstr "Nem tudom megnyitni az állományt: %s.\n" #, fuzzy, c-format +#| msgid "invalid hash algorithm `%s'\n" +msgid "unknown hash algorithm '%s'\n" +msgstr "Érvénytelen kivonatoló algoritmus: %s\n" + +#, c-format +msgid "gcry_md_open for algorithm %d failed: %s\n" +msgstr "" + +#, fuzzy, c-format msgid "creating S-expression failed: %s\n" msgstr "A kulcsblokk törlése sikertelen: %s.\n" @@ -8609,11 +8618,6 @@ msgstr "visszavonási igazolás készÃtése" msgid "failed to allocate OCSP context: %s\n" msgstr "Bizalmi adatbázis (%s) inicializálása sikertelen!\n" -#, fuzzy, c-format -#| msgid "%s: can't access: %s\n" -msgid "can't get authorityInfoAccess: %s\n" -msgstr "%s: Nem tudom elérni: %s.\n" - #, c-format msgid "no default OCSP responder defined\n" msgstr "" @@ -9208,6 +9212,10 @@ msgid "" msgstr "" #, fuzzy +#~ msgid " using certificate ID 0x%08lX\n" +#~ msgstr "Hiba a jelszó létrehozásakor: %s.\n" + +#, fuzzy #~| msgid "you may not use %s while in %s mode\n" #~ msgid "" #~ "keyserver option \"honor-keyserver-url\" may not be used in Tor mode\n" @@ -98,6 +98,9 @@ msgstr "" #. the pinentry. The %s is the actual error message, the #. two %d give the current and maximum number of tries. #. Do not translate the "SETERROR" keyword. +#. TRANSLATORS: The string is appended to an error message in +#. the pinentry. The %s is the actual error message, the +#. two %d give the current and maximum number of tries. #, c-format msgid "SETERROR %s (try %d of %d)" msgstr "" @@ -3691,6 +3694,9 @@ msgstr "kesalahan: fingerprint tidak valid\n" msgid "subkey \"%s\" not found\n" msgstr "kunci '%s' tidak ditemukan: %s\n" +msgid "AEAD: " +msgstr "" + msgid "Digest: " msgstr "Digest: " @@ -6417,6 +6423,26 @@ msgid "" "List, export, import Keybox data\n" msgstr "Pemakaian: gpg [pilihan] [file] (-h untuk bantuan)" +#. TRANSLATORS: Put a \x1f right before a colon. This can be +#. * used by pinentry to nicely align the names and values. Keep +#. * the %s at the start and end of the string. +#, c-format +msgid "%sNumber: %s%%0AHolder: %s%s" +msgstr "" + +#. TRANSLATORS: This is the number of remaining attempts to +#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. +#, c-format +msgid "Remaining attempts: %d" +msgstr "" + +msgid "||Please enter the PIN for the key to create qualified signatures." +msgstr "" + +#, fuzzy +msgid "||Please enter the PIN for the standard keys." +msgstr "ubah passphrase" + #, c-format msgid "RSA modulus missing or not of size %d bits\n" msgstr "" @@ -6438,10 +6464,6 @@ msgid "|N|Please enter a new PIN for the standard keys." msgstr "ubah passphrase" #, fuzzy -msgid "||Please enter the PIN for the standard keys." -msgstr "ubah passphrase" - -#, fuzzy msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys." msgstr "Silakan pilih alasan untuk pembatalan:\n" @@ -6452,9 +6474,6 @@ msgstr "Silakan pilih alasan untuk pembatalan:\n" msgid "|N|Please enter a new PIN for the key to create qualified signatures." msgstr "" -msgid "||Please enter the PIN for the key to create qualified signatures." -msgstr "" - msgid "" "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create " "qualified signatures." @@ -6510,16 +6529,6 @@ msgid "%sNumber: %s%%0AHolder: %s%%0ACounter: %lu%s" msgstr "" #, c-format -msgid "%sNumber: %s%%0AHolder: %s%s" -msgstr "" - -#. TRANSLATORS: This is the number of remaining attempts to -#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. -#, c-format -msgid "Remaining attempts: %d" -msgstr "" - -#, c-format msgid "using default PIN as %s\n" msgstr "" @@ -6775,6 +6784,10 @@ msgstr "menulis kunci rahasia ke `%s'\n" msgid "certificate policy not allowed" msgstr "menulis kunci rahasia ke `%s'\n" +#, fuzzy, c-format +msgid "failed to get the fingerprint\n" +msgstr "gagal inisialisasi TrustDB: %s\n" + #, c-format msgid "looking up issuer at external location\n" msgstr "" @@ -6783,6 +6796,11 @@ msgstr "" msgid "number of issuers matching: %d\n" msgstr "" +#, fuzzy, c-format +#| msgid "%s: can't access: %s\n" +msgid "can't get authorityInfoAccess: %s\n" +msgstr "%s: tidak dapat mengakses: %s\n" + #, c-format msgid "looking up issuer from the Dirmngr cache\n" msgstr "" @@ -7390,10 +7408,6 @@ msgstr "kesalahan penciptaan passphrase: %s\n" msgid "error reading input: %s\n" msgstr "kesalahan membaca `%s': %s\n" -#, fuzzy, c-format -msgid "failed to get the fingerprint\n" -msgstr "gagal inisialisasi TrustDB: %s\n" - #, c-format msgid "problem looking for existing certificate: %s\n" msgstr "" @@ -7473,8 +7487,8 @@ msgid "[date not given]" msgstr "" #, fuzzy, c-format -msgid " using certificate ID 0x%08lX\n" -msgstr "kesalahan penciptaan passphrase: %s\n" +msgid "algorithm:" +msgstr "armor: %s\n" #, c-format msgid "" @@ -7804,15 +7818,6 @@ msgid "error getting data from cache file: %s\n" msgstr "kesalahan penciptaan passphrase: %s\n" #, fuzzy, c-format -#| msgid "invalid hash algorithm `%s'\n" -msgid "unknown hash algorithm '%s'\n" -msgstr "algoritma hash tidak valid `%s'\n" - -#, c-format -msgid "gcry_md_open for algorithm %d failed: %s\n" -msgstr "" - -#, fuzzy, c-format #| msgid "invalid response from agent\n" msgid "got an invalid S-expression from libksba\n" msgstr "respon tidak valid dari agen\n" @@ -7822,6 +7827,15 @@ msgid "converting S-expression failed: %s\n" msgstr "tidak dapat membuka file: %s\n" #, fuzzy, c-format +#| msgid "invalid hash algorithm `%s'\n" +msgid "unknown hash algorithm '%s'\n" +msgstr "algoritma hash tidak valid `%s'\n" + +#, c-format +msgid "gcry_md_open for algorithm %d failed: %s\n" +msgstr "" + +#, fuzzy, c-format msgid "creating S-expression failed: %s\n" msgstr "gagal menghapus keyblok: %s\n" @@ -8602,11 +8616,6 @@ msgstr "buat sertifikat revokasi" msgid "failed to allocate OCSP context: %s\n" msgstr "gagal inisialisasi TrustDB: %s\n" -#, fuzzy, c-format -#| msgid "%s: can't access: %s\n" -msgid "can't get authorityInfoAccess: %s\n" -msgstr "%s: tidak dapat mengakses: %s\n" - #, c-format msgid "no default OCSP responder defined\n" msgstr "" @@ -9201,6 +9210,10 @@ msgid "" msgstr "" #, fuzzy +#~ msgid " using certificate ID 0x%08lX\n" +#~ msgstr "kesalahan penciptaan passphrase: %s\n" + +#, fuzzy #~| msgid "you may not use %s while in %s mode\n" #~ msgid "" #~ "keyserver option \"honor-keyserver-url\" may not be used in Tor mode\n" @@ -93,6 +93,9 @@ msgstr "" #. the pinentry. The %s is the actual error message, the #. two %d give the current and maximum number of tries. #. Do not translate the "SETERROR" keyword. +#. TRANSLATORS: The string is appended to an error message in +#. the pinentry. The %s is the actual error message, the +#. two %d give the current and maximum number of tries. #, c-format msgid "SETERROR %s (try %d of %d)" msgstr "" @@ -3698,6 +3701,9 @@ msgstr "errore: impronta digitale non valida\n" msgid "subkey \"%s\" not found\n" msgstr "chiave `%s' non trovata: %s\n" +msgid "AEAD: " +msgstr "" + msgid "Digest: " msgstr "Digest: " @@ -6456,6 +6462,26 @@ msgid "" "List, export, import Keybox data\n" msgstr "Uso: gpg [opzioni] [files] (-h per l'aiuto)" +#. TRANSLATORS: Put a \x1f right before a colon. This can be +#. * used by pinentry to nicely align the names and values. Keep +#. * the %s at the start and end of the string. +#, c-format +msgid "%sNumber: %s%%0AHolder: %s%s" +msgstr "" + +#. TRANSLATORS: This is the number of remaining attempts to +#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. +#, c-format +msgid "Remaining attempts: %d" +msgstr "" + +msgid "||Please enter the PIN for the key to create qualified signatures." +msgstr "" + +#, fuzzy +msgid "||Please enter the PIN for the standard keys." +msgstr "cambia la passphrase" + #, c-format msgid "RSA modulus missing or not of size %d bits\n" msgstr "" @@ -6477,10 +6503,6 @@ msgid "|N|Please enter a new PIN for the standard keys." msgstr "cambia la passphrase" #, fuzzy -msgid "||Please enter the PIN for the standard keys." -msgstr "cambia la passphrase" - -#, fuzzy msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys." msgstr "Per favore scegli il motivo della revoca:\n" @@ -6491,9 +6513,6 @@ msgstr "Per favore scegli il motivo della revoca:\n" msgid "|N|Please enter a new PIN for the key to create qualified signatures." msgstr "" -msgid "||Please enter the PIN for the key to create qualified signatures." -msgstr "" - msgid "" "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create " "qualified signatures." @@ -6549,16 +6568,6 @@ msgid "%sNumber: %s%%0AHolder: %s%%0ACounter: %lu%s" msgstr "" #, c-format -msgid "%sNumber: %s%%0AHolder: %s%s" -msgstr "" - -#. TRANSLATORS: This is the number of remaining attempts to -#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. -#, c-format -msgid "Remaining attempts: %d" -msgstr "" - -#, c-format msgid "using default PIN as %s\n" msgstr "" @@ -6814,6 +6823,10 @@ msgstr "scrittura della chiave segreta in `%s'\n" msgid "certificate policy not allowed" msgstr "scrittura della chiave segreta in `%s'\n" +#, fuzzy, c-format +msgid "failed to get the fingerprint\n" +msgstr "inizializzazione del trustdb fallita: %s\n" + #, c-format msgid "looking up issuer at external location\n" msgstr "" @@ -6822,6 +6835,11 @@ msgstr "" msgid "number of issuers matching: %d\n" msgstr "" +#, fuzzy, c-format +#| msgid "%s: can't access: %s\n" +msgid "can't get authorityInfoAccess: %s\n" +msgstr "%s: impossibile acedere a: %s\n" + #, c-format msgid "looking up issuer from the Dirmngr cache\n" msgstr "" @@ -7428,10 +7446,6 @@ msgstr "errore nella creazione della passhprase: %s\n" msgid "error reading input: %s\n" msgstr "errore leggendo `%s': %s\n" -#, fuzzy, c-format -msgid "failed to get the fingerprint\n" -msgstr "inizializzazione del trustdb fallita: %s\n" - #, c-format msgid "problem looking for existing certificate: %s\n" msgstr "" @@ -7511,8 +7525,8 @@ msgid "[date not given]" msgstr "" #, fuzzy, c-format -msgid " using certificate ID 0x%08lX\n" -msgstr "errore nella creazione della passhprase: %s\n" +msgid "algorithm:" +msgstr "armatura: %s\n" #, c-format msgid "" @@ -7843,15 +7857,6 @@ msgid "error getting data from cache file: %s\n" msgstr "errore nella creazione della passhprase: %s\n" #, fuzzy, c-format -#| msgid "invalid hash algorithm `%s'\n" -msgid "unknown hash algorithm '%s'\n" -msgstr "algoritmo di hash non valido `%s'\n" - -#, c-format -msgid "gcry_md_open for algorithm %d failed: %s\n" -msgstr "" - -#, fuzzy, c-format #| msgid "invalid response from agent\n" msgid "got an invalid S-expression from libksba\n" msgstr "risposta non valida dall'agent\n" @@ -7861,6 +7866,15 @@ msgid "converting S-expression failed: %s\n" msgstr "impossibile aprire il file: %s\n" #, fuzzy, c-format +#| msgid "invalid hash algorithm `%s'\n" +msgid "unknown hash algorithm '%s'\n" +msgstr "algoritmo di hash non valido `%s'\n" + +#, c-format +msgid "gcry_md_open for algorithm %d failed: %s\n" +msgstr "" + +#, fuzzy, c-format msgid "creating S-expression failed: %s\n" msgstr "cancellazione del keyblock fallita: %s\n" @@ -8643,11 +8657,6 @@ msgstr "genera un certificato di revoca" msgid "failed to allocate OCSP context: %s\n" msgstr "inizializzazione del trustdb fallita: %s\n" -#, fuzzy, c-format -#| msgid "%s: can't access: %s\n" -msgid "can't get authorityInfoAccess: %s\n" -msgstr "%s: impossibile acedere a: %s\n" - #, c-format msgid "no default OCSP responder defined\n" msgstr "" @@ -9242,6 +9251,10 @@ msgid "" msgstr "" #, fuzzy +#~ msgid " using certificate ID 0x%08lX\n" +#~ msgstr "errore nella creazione della passhprase: %s\n" + +#, fuzzy #~| msgid "you may not use %s while in %s mode\n" #~ msgid "" #~ "keyserver option \"honor-keyserver-url\" may not be used in Tor mode\n" @@ -10,7 +10,7 @@ msgid "" msgstr "" "Project-Id-Version: gnupg 2.2.20\n" "Report-Msgid-Bugs-To: translations@gnupg.org\n" -"PO-Revision-Date: 2020-03-19 09:27+0900\n" +"PO-Revision-Date: 2020-07-07 09:37+0900\n" "Last-Translator: NIIBE Yutaka <gniibe@fsij.org>\n" "Language-Team: none\n" "Language: ja\n" @@ -97,6 +97,9 @@ msgstr "一致ã—ã¾ã›ã‚“ - ã‚‚ã†ä¸€åº¦" #. the pinentry. The %s is the actual error message, the #. two %d give the current and maximum number of tries. #. Do not translate the "SETERROR" keyword. +#. TRANSLATORS: The string is appended to an error message in +#. the pinentry. The %s is the actual error message, the +#. two %d give the current and maximum number of tries. #, c-format msgid "SETERROR %s (try %d of %d)" msgstr "SETERROR %s (ç¾åœ¨ %d / 最大 %d)" @@ -3423,6 +3426,9 @@ msgstr "\"%s\"ã¯æ£ã—ã„フィンガープリントã§ã¯ã‚ã‚Šã¾ã›ã‚“\n" msgid "subkey \"%s\" not found\n" msgstr "副éµ\"%s\"ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“\n" +msgid "AEAD: " +msgstr "AEAD: " + msgid "Digest: " msgstr "ダイジェスト: " @@ -5998,6 +6004,25 @@ msgstr "" "å½¢å¼: kbxutil [オプション] [ファイル]\n" "Keyboxデータを一覧ã€ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã€ã‚¤ãƒ³ãƒãƒ¼ãƒˆ\n" +#. TRANSLATORS: Put a \x1f right before a colon. This can be +#. * used by pinentry to nicely align the names and values. Keep +#. * the %s at the start and end of the string. +#, c-format +msgid "%sNumber: %s%%0AHolder: %s%s" +msgstr "%s番å·: %s%%0Aä¿æŒè€…: %s%s" + +#. TRANSLATORS: This is the number of remaining attempts to +#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. +#, c-format +msgid "Remaining attempts: %d" +msgstr "残ã•ã‚ŒãŸè©¦è¡Œå›žæ•°: %d" + +msgid "||Please enter the PIN for the key to create qualified signatures." +msgstr "||æ–°ã—ã„PINã‚’èªå®šç½²åを生æˆã™ã‚‹éµã®ãŸã‚ã«å…¥åŠ›ã—ã¦ãã ã•ã„。" + +msgid "||Please enter the PIN for the standard keys." +msgstr "||PINを標準ã®éµã®ãŸã‚ã«å…¥åŠ›ã—ã¦ãã ã•ã„。" + #, c-format msgid "RSA modulus missing or not of size %d bits\n" msgstr "RSAã®ãƒ¢ã‚¸ãƒ¥ãƒ©ã‚¹ãŒãªã„ã‹ã€%dビットã®ã‚‚ã®ã§ã¯ã‚ã‚Šã¾ã›ã‚“\n" @@ -6017,9 +6042,6 @@ msgstr "NullPINãŒå¤‰æ›´ã•ã‚Œã¦ã„ã¾ã›ã‚“\n" msgid "|N|Please enter a new PIN for the standard keys." msgstr "|N|æ–°ã—ã„PINを標準ã®éµã®ãŸã‚ã«å…¥åŠ›ã—ã¦ãã ã•ã„。" -msgid "||Please enter the PIN for the standard keys." -msgstr "||PINを標準ã®éµã®ãŸã‚ã«å…¥åŠ›ã—ã¦ãã ã•ã„。" - msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys." msgstr "|NP|標準ã®éµã®æ–°ã—ã„PIN Unblocking Code (PUK)を入力ã—ã¦ãã ã•ã„。" @@ -6029,9 +6051,6 @@ msgstr "|P|標準ã®éµã®PIN Unblocking Code (PUK)を入力ã—ã¦ãã ã•ã„〠msgid "|N|Please enter a new PIN for the key to create qualified signatures." msgstr "|N|æ–°ã—ã„PINã‚’èªå®šç½²åを生æˆã™ã‚‹éµã®ãŸã‚ã«å…¥åŠ›ã—ã¦ãã ã•ã„。" -msgid "||Please enter the PIN for the key to create qualified signatures." -msgstr "||æ–°ã—ã„PINã‚’èªå®šç½²åを生æˆã™ã‚‹éµã®ãŸã‚ã«å…¥åŠ›ã—ã¦ãã ã•ã„。" - msgid "" "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create " "qualified signatures." @@ -6088,16 +6107,6 @@ msgid "%sNumber: %s%%0AHolder: %s%%0ACounter: %lu%s" msgstr "%s番å·: %s%%0Aä¿æŒè€…: %s%%0Aカウンタ: %lu%s" #, c-format -msgid "%sNumber: %s%%0AHolder: %s%s" -msgstr "%s番å·: %s%%0Aä¿æŒè€…: %s%s" - -#. TRANSLATORS: This is the number of remaining attempts to -#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. -#, c-format -msgid "Remaining attempts: %d" -msgstr "残ã•ã‚ŒãŸè©¦è¡Œå›žæ•°: %d" - -#, c-format msgid "using default PIN as %s\n" msgstr "デフォルトPINã‚’%sã¨ã—ã¦ä½¿ã„ã¾ã™\n" @@ -6343,6 +6352,10 @@ msgid "certificate policy not allowed" msgstr "証明書ãƒãƒªã‚·ãƒ¼ã¯èªã‚られã¾ã›ã‚“" #, c-format +msgid "failed to get the fingerprint\n" +msgstr "フィンガープリントã®å–å¾—ã«å¤±æ•—ã—ã¾ã—ãŸ\n" + +#, c-format msgid "looking up issuer at external location\n" msgstr "発行者ã®å¤–部ãƒã‚±ãƒ¼ã‚·ãƒ§ãƒ³ã‚’調ã¹ã¦ã„ã¾ã™\n" @@ -6351,6 +6364,10 @@ msgid "number of issuers matching: %d\n" msgstr "マッãƒã™ã‚‹ç™ºè¡Œè€…ã®æ•°: %d\n" #, c-format +msgid "can't get authorityInfoAccess: %s\n" +msgstr "authorityInfoAccessã‚’å–å¾—ã§ãã¾ã›ã‚“: %s\n" + +#, c-format msgid "looking up issuer from the Dirmngr cache\n" msgstr "Dirmngrã‚ャッシュã‹ã‚‰ç™ºè¡Œè€…を調ã¹ã¦ã„ã¾ã™\n" @@ -6933,10 +6950,6 @@ msgid "error reading input: %s\n" msgstr "入力èªã¿è¾¼ã¿ã‚¨ãƒ©ãƒ¼: %s\n" #, c-format -msgid "failed to get the fingerprint\n" -msgstr "フィンガープリントã®å–å¾—ã«å¤±æ•—ã—ã¾ã—ãŸ\n" - -#, c-format msgid "problem looking for existing certificate: %s\n" msgstr "æ—¢å˜ã®è¨¼æ˜Žæ›¸ã®æ¤œç´¢ã®å•é¡Œ: %s\n" @@ -7028,8 +7041,8 @@ msgid "[date not given]" msgstr "[日時指定ãªã—]" #, c-format -msgid " using certificate ID 0x%08lX\n" -msgstr " 証明書 ID 0x%08lXを用ã„ã¾ã™\n" +msgid "algorithm:" +msgstr "アルゴリズム:" #, c-format msgid "" @@ -7353,14 +7366,6 @@ msgid "error getting data from cache file: %s\n" msgstr "ã‚ャッシュ・ファイルã‹ã‚‰ãƒ‡ãƒ¼ã‚¿ã®å–得エラー: %s\n" #, c-format -msgid "unknown hash algorithm '%s'\n" -msgstr "ä¸æ˜Žãªãƒãƒƒã‚·ãƒ¥ãƒ»ã‚¢ãƒ«ã‚´ãƒªã‚ºãƒ '%s'\n" - -#, c-format -msgid "gcry_md_open for algorithm %d failed: %s\n" -msgstr "アルゴリズム%dã®gcry_md_openãŒå¤±æ•—: %s\n" - -#, c-format msgid "got an invalid S-expression from libksba\n" msgstr "libksbaã‹ã‚‰ç„¡åŠ¹ãªS-å¼ã‚’å–å¾—ã—ã¾ã—ãŸ\n" @@ -7369,6 +7374,14 @@ msgid "converting S-expression failed: %s\n" msgstr "Så¼ã®å¤‰æ›ã«å¤±æ•—ã—ã¾ã—ãŸ: %s\n" #, c-format +msgid "unknown hash algorithm '%s'\n" +msgstr "ä¸æ˜Žãªãƒãƒƒã‚·ãƒ¥ãƒ»ã‚¢ãƒ«ã‚´ãƒªã‚ºãƒ '%s'\n" + +#, c-format +msgid "gcry_md_open for algorithm %d failed: %s\n" +msgstr "アルゴリズム%dã®gcry_md_openãŒå¤±æ•—: %s\n" + +#, c-format msgid "creating S-expression failed: %s\n" msgstr "Så¼ã®ä½œæˆã«å¤±æ•—ã—ã¾ã—ãŸ: %s\n" @@ -8119,10 +8132,6 @@ msgid "failed to allocate OCSP context: %s\n" msgstr "OCSPコンテクストã®ç¢ºä¿ã«å¤±æ•—ã—ã¾ã—ãŸ: %s\n" #, c-format -msgid "can't get authorityInfoAccess: %s\n" -msgstr "authorityInfoAccessã‚’å–å¾—ã§ãã¾ã›ã‚“: %s\n" - -#, c-format msgid "no default OCSP responder defined\n" msgstr "デフォルトOCSPレスãƒãƒ³ãƒ€ãŒå®šç¾©ã•ã‚Œã¦ã„ã¾ã›ã‚“\n" @@ -8691,6 +8700,9 @@ msgstr "" "å½¢å¼: gpg-check-pattern [オプション] パターンファイル\n" "パターンファイルã«å¯¾ã—ã¦æ¨™æº–入力ã®ãƒ‘スフレーズを確èªã™ã‚‹\n" +#~ msgid " using certificate ID 0x%08lX\n" +#~ msgstr " 証明書 ID 0x%08lXを用ã„ã¾ã™\n" + #~ msgid "male" #~ msgstr "ç”·" @@ -101,6 +101,9 @@ msgstr "feil. Prøv igjen" #. the pinentry. The %s is the actual error message, the #. two %d give the current and maximum number of tries. #. Do not translate the "SETERROR" keyword. +#. TRANSLATORS: The string is appended to an error message in +#. the pinentry. The %s is the actual error message, the +#. two %d give the current and maximum number of tries. #, c-format msgid "SETERROR %s (try %d of %d)" msgstr "SETERROR %s (forsøk %d av %d)" @@ -3482,6 +3485,9 @@ msgstr "«%s» er et ugyldig fingeravtrykk\n" msgid "subkey \"%s\" not found\n" msgstr "fant ikke undernøkkel «%s»\n" +msgid "AEAD: " +msgstr "" + msgid "Digest: " msgstr "Kontrollsum: " @@ -6148,6 +6154,25 @@ msgstr "" "Syntaks: kbxutil [valg] [filer]\n" "Vis, eksporter eller importer Keybox-data\n" +#. TRANSLATORS: Put a \x1f right before a colon. This can be +#. * used by pinentry to nicely align the names and values. Keep +#. * the %s at the start and end of the string. +#, c-format +msgid "%sNumber: %s%%0AHolder: %s%s" +msgstr "%sNummer\\x1f: %s%%0AHolder\\x1f: %s%s" + +#. TRANSLATORS: This is the number of remaining attempts to +#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. +#, c-format +msgid "Remaining attempts: %d" +msgstr "GjenstÃ¥ende forsøk: %d" + +msgid "||Please enter the PIN for the key to create qualified signatures." +msgstr "||Skriv inn PIN for Ã¥ la nøkkelen lage kvalifiserte signaturer." + +msgid "||Please enter the PIN for the standard keys." +msgstr "||Skriv inn PIN-kode for standardnøkler." + #, c-format msgid "RSA modulus missing or not of size %d bits\n" msgstr "RSA-modulus mangler eller er av annen størrelse enn %d bit\n" @@ -6167,9 +6192,6 @@ msgstr "NullPIN er ikke blitt endret enda\n" msgid "|N|Please enter a new PIN for the standard keys." msgstr "|N|Skriv inn ny PIN-kode for standardnøkler." -msgid "||Please enter the PIN for the standard keys." -msgstr "||Skriv inn PIN-kode for standardnøkler." - msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys." msgstr "|NP|Skriv inn ny PIN-opplÃ¥singskode (PUK) for standardnøkler." @@ -6179,9 +6201,6 @@ msgstr "|P|Skriv inn PIN-opplÃ¥singskode (PUK) for standardnøkler." msgid "|N|Please enter a new PIN for the key to create qualified signatures." msgstr "|N|Skriv inn ny PIN for Ã¥ la nøkkelen lage kvalifiserte signaturer." -msgid "||Please enter the PIN for the key to create qualified signatures." -msgstr "||Skriv inn PIN for Ã¥ la nøkkelen lage kvalifiserte signaturer." - msgid "" "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create " "qualified signatures." @@ -6237,16 +6256,6 @@ msgid "%sNumber: %s%%0AHolder: %s%%0ACounter: %lu%s" msgstr "%sNummer\\x1f: %s%%0AHolder\\x1f: %s%%0ATeller\\x1f: %lu%s" #, c-format -msgid "%sNumber: %s%%0AHolder: %s%s" -msgstr "%sNummer\\x1f: %s%%0AHolder\\x1f: %s%s" - -#. TRANSLATORS: This is the number of remaining attempts to -#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. -#, c-format -msgid "Remaining attempts: %d" -msgstr "GjenstÃ¥ende forsøk: %d" - -#, c-format msgid "using default PIN as %s\n" msgstr "bruker forvalgt PIN som %s\n" @@ -6492,6 +6501,10 @@ msgid "certificate policy not allowed" msgstr "sertifikatregelverk tillates ikke" #, c-format +msgid "failed to get the fingerprint\n" +msgstr "klarte ikke Ã¥ hente fingeravtrykk\n" + +#, c-format msgid "looking up issuer at external location\n" msgstr "slÃ¥r opp utsteder pÃ¥ ekstern plassering\n" @@ -6500,6 +6513,10 @@ msgid "number of issuers matching: %d\n" msgstr "antall ustedere funnet: %d\n" #, c-format +msgid "can't get authorityInfoAccess: %s\n" +msgstr "klarte ikke Ã¥ hente «authorityInfoAccess»: %s\n" + +#, c-format msgid "looking up issuer from the Dirmngr cache\n" msgstr "slÃ¥r opp utsteder fra Dirmngr-hurtiglager\n" @@ -7083,10 +7100,6 @@ msgid "error reading input: %s\n" msgstr "feil under lesing av inndata: %s\n" #, c-format -msgid "failed to get the fingerprint\n" -msgstr "klarte ikke Ã¥ hente fingeravtrykk\n" - -#, c-format msgid "problem looking for existing certificate: %s\n" msgstr "klarte ikke Ã¥ søke etter sertifikat: %s\n" @@ -7176,9 +7189,10 @@ msgstr "Signatur fullført" msgid "[date not given]" msgstr "[dato ikke oppgitt]" -#, c-format -msgid " using certificate ID 0x%08lX\n" -msgstr " ved bruk av sertifikat-ID 0x%08lX\n" +#, fuzzy, c-format +#| msgid "algorithm: %s" +msgid "algorithm:" +msgstr "algoritme: %s" #, c-format msgid "" @@ -7504,14 +7518,6 @@ msgid "error getting data from cache file: %s\n" msgstr "feil under henting av data fra hurtiglager-fil: %s\n" #, c-format -msgid "unknown hash algorithm '%s'\n" -msgstr "«%s» er en ugyldig summeringsalgoritme\n" - -#, c-format -msgid "gcry_md_open for algorithm %d failed: %s\n" -msgstr "«gcry_md_open» for algoritme %d mislyktes: %s\n" - -#, c-format msgid "got an invalid S-expression from libksba\n" msgstr "fikk ugyldig S-uttrykk fra libksba\n" @@ -7520,6 +7526,14 @@ msgid "converting S-expression failed: %s\n" msgstr "konvertering av S-uttrykk mislyktes: %s\n" #, c-format +msgid "unknown hash algorithm '%s'\n" +msgstr "«%s» er en ugyldig summeringsalgoritme\n" + +#, c-format +msgid "gcry_md_open for algorithm %d failed: %s\n" +msgstr "«gcry_md_open» for algoritme %d mislyktes: %s\n" + +#, c-format msgid "creating S-expression failed: %s\n" msgstr "oppretting av S-uttrykk mislyktes: %s\n" @@ -8272,10 +8286,6 @@ msgid "failed to allocate OCSP context: %s\n" msgstr "klarte ikke Ã¥ tildele OCSP-kontekst: %s\n" #, c-format -msgid "can't get authorityInfoAccess: %s\n" -msgstr "klarte ikke Ã¥ hente «authorityInfoAccess»: %s\n" - -#, c-format msgid "no default OCSP responder defined\n" msgstr "ingen forvalgt OCSP-svartjeneste\n" @@ -8850,6 +8860,9 @@ msgstr "" "Syntaks: gpg-check-pattern [valg] mønsterfil\n" "Kontroller passordfrase oppgitt pÃ¥ standard innkanal mot valgt mønsterfil\n" +#~ msgid " using certificate ID 0x%08lX\n" +#~ msgstr " ved bruk av sertifikat-ID 0x%08lX\n" + #, fuzzy #~| msgid "option '%s' may not be used in %s mode\n" #~ msgid "" @@ -95,6 +95,9 @@ msgstr "nie pasujÄ… - proszÄ™ spróbować jeszcze raz" #. the pinentry. The %s is the actual error message, the #. two %d give the current and maximum number of tries. #. Do not translate the "SETERROR" keyword. +#. TRANSLATORS: The string is appended to an error message in +#. the pinentry. The %s is the actual error message, the +#. two %d give the current and maximum number of tries. #, c-format msgid "SETERROR %s (try %d of %d)" msgstr "SETERROR %s (próba %d z %d)" @@ -3500,6 +3503,9 @@ msgstr ",,%s'' nie jest wÅ‚aÅ›ciwym odciskiem\n" msgid "subkey \"%s\" not found\n" msgstr "podklucz ,,%s'' nie zostaÅ‚ odnaleziony\n" +msgid "AEAD: " +msgstr "" + msgid "Digest: " msgstr "Skrót: " @@ -6249,6 +6255,26 @@ msgstr "" "SkÅ‚adnia: kbxutil [opcje] [pliki]\n" "Wypisywanie, eksport, import danych Keybox\n" +#. TRANSLATORS: Put a \x1f right before a colon. This can be +#. * used by pinentry to nicely align the names and values. Keep +#. * the %s at the start and end of the string. +#, c-format +msgid "%sNumber: %s%%0AHolder: %s%s" +msgstr "%sNumer: %s%%0AWÅ‚aÅ›ciciel: %s%s" + +#. TRANSLATORS: This is the number of remaining attempts to +#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. +#, c-format +msgid "Remaining attempts: %d" +msgstr "PozostaÅ‚o prób: %d" + +msgid "||Please enter the PIN for the key to create qualified signatures." +msgstr "" +"||ProszÄ™ wprowadzić PIN PIN dla klucza do tworzenia podpisów kwalifikowanych." + +msgid "||Please enter the PIN for the standard keys." +msgstr "||ProszÄ™ wprowadzić PIN dla zwykÅ‚ych kluczy." + #, c-format msgid "RSA modulus missing or not of size %d bits\n" msgstr "reszta RSA brakujÄ…ca lub o rozmiarze innym niż %d bity\n" @@ -6268,9 +6294,6 @@ msgstr "NullPIN nie zostaÅ‚ jeszcze zmieniony\n" msgid "|N|Please enter a new PIN for the standard keys." msgstr "|N|ProszÄ™ wprowadzić nowy PIN dla zwykÅ‚ych kluczy." -msgid "||Please enter the PIN for the standard keys." -msgstr "||ProszÄ™ wprowadzić PIN dla zwykÅ‚ych kluczy." - msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys." msgstr "" "|NP|ProszÄ™ wprowadzić nowy kod oblokowujÄ…cy PIN (PUK) dla zwykÅ‚ych kluczy." @@ -6283,10 +6306,6 @@ msgstr "" "|N|ProszÄ™ wprowadzić nowy PIN dla klucza do tworzenia podpisów " "kwalifikowanych." -msgid "||Please enter the PIN for the key to create qualified signatures." -msgstr "" -"||ProszÄ™ wprowadzić PIN PIN dla klucza do tworzenia podpisów kwalifikowanych." - msgid "" "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create " "qualified signatures." @@ -6345,16 +6364,6 @@ msgid "%sNumber: %s%%0AHolder: %s%%0ACounter: %lu%s" msgstr "%sNumer: %s%%0AWÅ‚aÅ›ciciel: %s%%0ALicznik: %lu%s" #, c-format -msgid "%sNumber: %s%%0AHolder: %s%s" -msgstr "%sNumer: %s%%0AWÅ‚aÅ›ciciel: %s%s" - -#. TRANSLATORS: This is the number of remaining attempts to -#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. -#, c-format -msgid "Remaining attempts: %d" -msgstr "PozostaÅ‚o prób: %d" - -#, c-format msgid "using default PIN as %s\n" msgstr "użycie domyÅ›lnego PIN-u jako %s\n" @@ -6607,6 +6616,10 @@ msgid "certificate policy not allowed" msgstr "polityka certyfikatu niedozwolona" #, c-format +msgid "failed to get the fingerprint\n" +msgstr "nie udaÅ‚o siÄ™ pobrać odcisku\n" + +#, c-format msgid "looking up issuer at external location\n" msgstr "poszukiwanie wystawcy na zewnÄ…trz\n" @@ -6615,6 +6628,10 @@ msgid "number of issuers matching: %d\n" msgstr "liczba pasujÄ…cych wystawców: %d\n" #, c-format +msgid "can't get authorityInfoAccess: %s\n" +msgstr "nie można uzyskać authorityInfoAccess: %s\n" + +#, c-format msgid "looking up issuer from the Dirmngr cache\n" msgstr "poszukiwanie wystawcy w pamiÄ™ci podrÄ™cznej Dirmngr\n" @@ -7198,10 +7215,6 @@ msgid "error reading input: %s\n" msgstr "bÅ‚Ä…d odczytu wejÅ›cia: %s\n" #, c-format -msgid "failed to get the fingerprint\n" -msgstr "nie udaÅ‚o siÄ™ pobrać odcisku\n" - -#, c-format msgid "problem looking for existing certificate: %s\n" msgstr "problem odszukaniem istniejÄ…cego certyfikatu: %s\n" @@ -7292,9 +7305,10 @@ msgstr "Podpisano w " msgid "[date not given]" msgstr "[nie podano daty]" -#, c-format -msgid " using certificate ID 0x%08lX\n" -msgstr " przy użyciu certyfikatu o ID 0x%08lX\n" +#, fuzzy, c-format +#| msgid "algorithm: %s" +msgid "algorithm:" +msgstr "algorytm: %s" #, c-format msgid "" @@ -7628,14 +7642,6 @@ msgid "error getting data from cache file: %s\n" msgstr "bÅ‚Ä…d pobierania danych z pliku pamiÄ™ci podrÄ™cznej: %s\n" #, c-format -msgid "unknown hash algorithm '%s'\n" -msgstr "niewÅ‚aÅ›ciwy algorytm skrótu ,,%s''\n" - -#, c-format -msgid "gcry_md_open for algorithm %d failed: %s\n" -msgstr "gcry_md_open dla algorytmu %d nie powiodÅ‚o siÄ™: %s\n" - -#, c-format msgid "got an invalid S-expression from libksba\n" msgstr "odebrano bÅ‚Ä™dne S-wyrażenie z libksba\n" @@ -7644,6 +7650,14 @@ msgid "converting S-expression failed: %s\n" msgstr "konwersja S-wyrażenia nie powiodÅ‚a siÄ™: %s\n" #, c-format +msgid "unknown hash algorithm '%s'\n" +msgstr "niewÅ‚aÅ›ciwy algorytm skrótu ,,%s''\n" + +#, c-format +msgid "gcry_md_open for algorithm %d failed: %s\n" +msgstr "gcry_md_open dla algorytmu %d nie powiodÅ‚o siÄ™: %s\n" + +#, c-format msgid "creating S-expression failed: %s\n" msgstr "tworzenie S-wyrażenia nie powiodÅ‚o siÄ™: %s\n" @@ -8404,10 +8418,6 @@ msgid "failed to allocate OCSP context: %s\n" msgstr "nie udaÅ‚o siÄ™ przydzielić kontekstu OCSP: %s\n" #, c-format -msgid "can't get authorityInfoAccess: %s\n" -msgstr "nie można uzyskać authorityInfoAccess: %s\n" - -#, c-format msgid "no default OCSP responder defined\n" msgstr "nie zdefiniowano domyÅ›lnego respondera OCSP\n" @@ -8983,6 +8993,9 @@ msgstr "" "SkÅ‚adnia: gpg-check-pattern [opcje] plik-wzorców\n" "Sprawdzanie hasÅ‚a ze standardowego wejÅ›cia wzglÄ™dem pliku wzorców\n" +#~ msgid " using certificate ID 0x%08lX\n" +#~ msgstr " przy użyciu certyfikatu o ID 0x%08lX\n" + #, fuzzy #~| msgid "option '%s' may not be used in %s mode\n" #~ msgid "" @@ -96,6 +96,9 @@ msgstr "" #. the pinentry. The %s is the actual error message, the #. two %d give the current and maximum number of tries. #. Do not translate the "SETERROR" keyword. +#. TRANSLATORS: The string is appended to an error message in +#. the pinentry. The %s is the actual error message, the +#. two %d give the current and maximum number of tries. #, c-format msgid "SETERROR %s (try %d of %d)" msgstr "" @@ -3695,6 +3698,9 @@ msgstr "%s: versão de ficheiro inválida %d\n" msgid "subkey \"%s\" not found\n" msgstr "chave `%s' não encontrada: %s\n" +msgid "AEAD: " +msgstr "" + msgid "Digest: " msgstr "'Digest': " @@ -6413,6 +6419,26 @@ msgid "" "List, export, import Keybox data\n" msgstr "Uso: gpg [opções] [ficheiros] (-h para ajuda)" +#. TRANSLATORS: Put a \x1f right before a colon. This can be +#. * used by pinentry to nicely align the names and values. Keep +#. * the %s at the start and end of the string. +#, c-format +msgid "%sNumber: %s%%0AHolder: %s%s" +msgstr "" + +#. TRANSLATORS: This is the number of remaining attempts to +#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. +#, c-format +msgid "Remaining attempts: %d" +msgstr "" + +msgid "||Please enter the PIN for the key to create qualified signatures." +msgstr "" + +#, fuzzy +msgid "||Please enter the PIN for the standard keys." +msgstr "muda a frase secreta" + #, c-format msgid "RSA modulus missing or not of size %d bits\n" msgstr "" @@ -6434,10 +6460,6 @@ msgid "|N|Please enter a new PIN for the standard keys." msgstr "muda a frase secreta" #, fuzzy -msgid "||Please enter the PIN for the standard keys." -msgstr "muda a frase secreta" - -#, fuzzy msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys." msgstr "motivo da revocação: " @@ -6448,9 +6470,6 @@ msgstr "motivo da revocação: " msgid "|N|Please enter a new PIN for the key to create qualified signatures." msgstr "" -msgid "||Please enter the PIN for the key to create qualified signatures." -msgstr "" - msgid "" "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create " "qualified signatures." @@ -6506,16 +6525,6 @@ msgid "%sNumber: %s%%0AHolder: %s%%0ACounter: %lu%s" msgstr "" #, c-format -msgid "%sNumber: %s%%0AHolder: %s%s" -msgstr "" - -#. TRANSLATORS: This is the number of remaining attempts to -#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. -#, c-format -msgid "Remaining attempts: %d" -msgstr "" - -#, c-format msgid "using default PIN as %s\n" msgstr "" @@ -6771,6 +6780,10 @@ msgstr "a escrever chave privada para `%s'\n" msgid "certificate policy not allowed" msgstr "a escrever chave privada para `%s'\n" +#, fuzzy, c-format +msgid "failed to get the fingerprint\n" +msgstr "falha ao inicializar a base de dados de confiança: %s\n" + #, c-format msgid "looking up issuer at external location\n" msgstr "" @@ -6779,6 +6792,11 @@ msgstr "" msgid "number of issuers matching: %d\n" msgstr "" +#, fuzzy, c-format +#| msgid "%s: can't access: %s\n" +msgid "can't get authorityInfoAccess: %s\n" +msgstr "%s: impossÃvel aceder: %s\n" + #, c-format msgid "looking up issuer from the Dirmngr cache\n" msgstr "" @@ -7389,10 +7407,6 @@ msgstr "erro na criação da frase secreta: %s\n" msgid "error reading input: %s\n" msgstr "erro na leitura de `%s': %s\n" -#, fuzzy, c-format -msgid "failed to get the fingerprint\n" -msgstr "falha ao inicializar a base de dados de confiança: %s\n" - #, c-format msgid "problem looking for existing certificate: %s\n" msgstr "" @@ -7472,8 +7486,8 @@ msgid "[date not given]" msgstr "" #, fuzzy, c-format -msgid " using certificate ID 0x%08lX\n" -msgstr "erro na criação da frase secreta: %s\n" +msgid "algorithm:" +msgstr "armadura: %s\n" #, c-format msgid "" @@ -7802,6 +7816,14 @@ msgstr "" msgid "error getting data from cache file: %s\n" msgstr "erro na criação da frase secreta: %s\n" +#, c-format +msgid "got an invalid S-expression from libksba\n" +msgstr "" + +#, fuzzy, c-format +msgid "converting S-expression failed: %s\n" +msgstr "impossÃvel abrir %s: %s\n" + #, fuzzy, c-format #| msgid "invalid hash algorithm `%s'\n" msgid "unknown hash algorithm '%s'\n" @@ -7811,14 +7833,6 @@ msgstr "algoritmo de dispersão inválido `%s'\n" msgid "gcry_md_open for algorithm %d failed: %s\n" msgstr "" -#, c-format -msgid "got an invalid S-expression from libksba\n" -msgstr "" - -#, fuzzy, c-format -msgid "converting S-expression failed: %s\n" -msgstr "impossÃvel abrir %s: %s\n" - #, fuzzy, c-format msgid "creating S-expression failed: %s\n" msgstr "remoção do bloco de chave falhou: %s\n" @@ -8602,11 +8616,6 @@ msgstr "gerar um certificado de revogação" msgid "failed to allocate OCSP context: %s\n" msgstr "falha ao inicializar a base de dados de confiança: %s\n" -#, fuzzy, c-format -#| msgid "%s: can't access: %s\n" -msgid "can't get authorityInfoAccess: %s\n" -msgstr "%s: impossÃvel aceder: %s\n" - #, c-format msgid "no default OCSP responder defined\n" msgstr "" @@ -9202,6 +9211,10 @@ msgid "" msgstr "" #, fuzzy +#~ msgid " using certificate ID 0x%08lX\n" +#~ msgstr "erro na criação da frase secreta: %s\n" + +#, fuzzy #~| msgid "you may not use %s while in %s mode\n" #~ msgid "" #~ "keyserver option \"honor-keyserver-url\" may not be used in Tor mode\n" @@ -100,6 +100,9 @@ msgstr "" #. the pinentry. The %s is the actual error message, the #. two %d give the current and maximum number of tries. #. Do not translate the "SETERROR" keyword. +#. TRANSLATORS: The string is appended to an error message in +#. the pinentry. The %s is the actual error message, the +#. two %d give the current and maximum number of tries. #, c-format msgid "SETERROR %s (try %d of %d)" msgstr "" @@ -3736,6 +3739,9 @@ msgstr "amprentă invalidă" msgid "subkey \"%s\" not found\n" msgstr "cheia \"%s\" nu a fost găsită: %s\n" +msgid "AEAD: " +msgstr "" + msgid "Digest: " msgstr "Rezumat: " @@ -6502,6 +6508,26 @@ msgid "" "List, export, import Keybox data\n" msgstr "Folosire: gpg [opÅ£iuni] [fiÅŸiere] (-h pentru ajutor)" +#. TRANSLATORS: Put a \x1f right before a colon. This can be +#. * used by pinentry to nicely align the names and values. Keep +#. * the %s at the start and end of the string. +#, c-format +msgid "%sNumber: %s%%0AHolder: %s%s" +msgstr "" + +#. TRANSLATORS: This is the number of remaining attempts to +#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. +#, c-format +msgid "Remaining attempts: %d" +msgstr "" + +msgid "||Please enter the PIN for the key to create qualified signatures." +msgstr "" + +#, fuzzy +msgid "||Please enter the PIN for the standard keys." +msgstr "||Vă rugăm introduceÅ£i PIN%%0A[semnături făcute: %lu]" + #, c-format msgid "RSA modulus missing or not of size %d bits\n" msgstr "modulus-ul RSA lipseÅŸte sau nu are %d biÅ£i\n" @@ -6523,10 +6549,6 @@ msgid "|N|Please enter a new PIN for the standard keys." msgstr "||Vă rugăm introduceÅ£i PIN%%0A[semnături făcute: %lu]" #, fuzzy -msgid "||Please enter the PIN for the standard keys." -msgstr "||Vă rugăm introduceÅ£i PIN%%0A[semnături făcute: %lu]" - -#, fuzzy msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys." msgstr "||Vă rugăm introduceÅ£i PIN%%0A[semnături făcute: %lu]" @@ -6537,9 +6559,6 @@ msgstr "||Vă rugăm introduceÅ£i PIN%%0A[semnături făcute: %lu]" msgid "|N|Please enter a new PIN for the key to create qualified signatures." msgstr "" -msgid "||Please enter the PIN for the key to create qualified signatures." -msgstr "" - msgid "" "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create " "qualified signatures." @@ -6595,16 +6614,6 @@ msgid "%sNumber: %s%%0AHolder: %s%%0ACounter: %lu%s" msgstr "" #, c-format -msgid "%sNumber: %s%%0AHolder: %s%s" -msgstr "" - -#. TRANSLATORS: This is the number of remaining attempts to -#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. -#, c-format -msgid "Remaining attempts: %d" -msgstr "" - -#, c-format msgid "using default PIN as %s\n" msgstr "" @@ -6866,6 +6875,10 @@ msgstr "exportul cheilor secrete nu este permis\n" msgid "certificate policy not allowed" msgstr "exportul cheilor secrete nu este permis\n" +#, fuzzy, c-format +msgid "failed to get the fingerprint\n" +msgstr "am eÅŸuat să stochez amprenta: %s\n" + #, c-format msgid "looking up issuer at external location\n" msgstr "" @@ -6874,6 +6887,11 @@ msgstr "" msgid "number of issuers matching: %d\n" msgstr "" +#, fuzzy, c-format +#| msgid "%s: can't access: %s\n" +msgid "can't get authorityInfoAccess: %s\n" +msgstr "%s: nu pot accesa: %s\n" + #, c-format msgid "looking up issuer from the Dirmngr cache\n" msgstr "" @@ -7486,10 +7504,6 @@ msgstr "eroare la obÅ£inerea numărului serial: %s\n" msgid "error reading input: %s\n" msgstr "eroare la citire `%s': %s\n" -#, fuzzy, c-format -msgid "failed to get the fingerprint\n" -msgstr "am eÅŸuat să stochez amprenta: %s\n" - #, c-format msgid "problem looking for existing certificate: %s\n" msgstr "" @@ -7569,8 +7583,8 @@ msgid "[date not given]" msgstr "" #, fuzzy, c-format -msgid " using certificate ID 0x%08lX\n" -msgstr "eroare la obÅ£inerea numărului serial: %s\n" +msgid "algorithm:" +msgstr "validitate: %s" #, c-format msgid "" @@ -7904,15 +7918,6 @@ msgid "error getting data from cache file: %s\n" msgstr "eroare la obÅ£inere noului PIN: %s\n" #, fuzzy, c-format -#| msgid "invalid hash algorithm `%s'\n" -msgid "unknown hash algorithm '%s'\n" -msgstr "algoritm hash invalid `%s'\n" - -#, c-format -msgid "gcry_md_open for algorithm %d failed: %s\n" -msgstr "" - -#, fuzzy, c-format #| msgid "invalid response from agent\n" msgid "got an invalid S-expression from libksba\n" msgstr "răspuns invalid de la agent\n" @@ -7922,6 +7927,15 @@ msgid "converting S-expression failed: %s\n" msgstr "nu pot deschide fiÅŸierul: %s\n" #, fuzzy, c-format +#| msgid "invalid hash algorithm `%s'\n" +msgid "unknown hash algorithm '%s'\n" +msgstr "algoritm hash invalid `%s'\n" + +#, c-format +msgid "gcry_md_open for algorithm %d failed: %s\n" +msgstr "" + +#, fuzzy, c-format msgid "creating S-expression failed: %s\n" msgstr "citirea cheii publice a eÅŸuat: %s\n" @@ -8724,11 +8738,6 @@ msgstr "generează un certificat de revocare" msgid "failed to allocate OCSP context: %s\n" msgstr "am eÅŸuat să stochez cheia: %s\n" -#, fuzzy, c-format -#| msgid "%s: can't access: %s\n" -msgid "can't get authorityInfoAccess: %s\n" -msgstr "%s: nu pot accesa: %s\n" - #, c-format msgid "no default OCSP responder defined\n" msgstr "" @@ -9327,6 +9336,10 @@ msgid "" msgstr "" #, fuzzy +#~ msgid " using certificate ID 0x%08lX\n" +#~ msgstr "eroare la obÅ£inerea numărului serial: %s\n" + +#, fuzzy #~| msgid "you may not use %s while in %s mode\n" #~ msgid "" #~ "keyserver option \"honor-keyserver-url\" may not be used in Tor mode\n" @@ -98,6 +98,9 @@ msgstr "не подходит - попробуйте еще раз" #. the pinentry. The %s is the actual error message, the #. two %d give the current and maximum number of tries. #. Do not translate the "SETERROR" keyword. +#. TRANSLATORS: The string is appended to an error message in +#. the pinentry. The %s is the actual error message, the +#. two %d give the current and maximum number of tries. #, c-format msgid "SETERROR %s (try %d of %d)" msgstr "SETERROR %s (попытка %d из %d)" @@ -3495,6 +3498,9 @@ msgstr "\"%s\" - не правильный отпечаток\n" msgid "subkey \"%s\" not found\n" msgstr "подключ \"%s\" не найден\n" +msgid "AEAD: " +msgstr "" + msgid "Digest: " msgstr "Хеш: " @@ -6213,6 +6219,25 @@ msgstr "" "СинтакÑиÑ: kbxutil [параметры] [файлы]\n" "ПроÑмотр, ÑкÑпорт, импорт данных щита Ñ ÐºÐ»ÑŽÑ‡Ð°Ð¼Ð¸\n" +#. TRANSLATORS: Put a \x1f right before a colon. This can be +#. * used by pinentry to nicely align the names and values. Keep +#. * the %s at the start and end of the string. +#, c-format +msgid "%sNumber: %s%%0AHolder: %s%s" +msgstr "%sÐомер: %s%%0AДержатель: %s%s" + +#. TRANSLATORS: This is the number of remaining attempts to +#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. +#, c-format +msgid "Remaining attempts: %d" +msgstr "ОÑталоÑÑŒ попыток: %d" + +msgid "||Please enter the PIN for the key to create qualified signatures." +msgstr "||Введите PIN ключа Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ ÐºÐ²Ð°Ð»Ð¸Ñ„Ð¸Ñ†Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð½Ñ‹Ñ… подпиÑей." + +msgid "||Please enter the PIN for the standard keys." +msgstr "|A|Введите PIN Ð´Ð»Ñ Ñтандартных ключей." + #, c-format msgid "RSA modulus missing or not of size %d bits\n" msgstr "Модули RSA пропущены, или их размер не равен %d бит\n" @@ -6232,9 +6257,6 @@ msgstr "пуÑтой PIN до Ñих пор не изменен\n" msgid "|N|Please enter a new PIN for the standard keys." msgstr "|A|Введите новый PIN Ð´Ð»Ñ Ñтандартных ключей." -msgid "||Please enter the PIN for the standard keys." -msgstr "|A|Введите PIN Ð´Ð»Ñ Ñтандартных ключей." - msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys." msgstr "|NP|Введите новый код разблокировки PIN (PUK) Ð´Ð»Ñ Ñтандартных ключей." @@ -6244,9 +6266,6 @@ msgstr "|P|Введите код разблокировки PIN (PUK) Ð´Ð»Ñ ÑÑ msgid "|N|Please enter a new PIN for the key to create qualified signatures." msgstr "|N|Введите новый PIN ключа Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ ÐºÐ²Ð°Ð»Ð¸Ñ„Ð¸Ñ†Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð½Ñ‹Ñ… подпиÑей." -msgid "||Please enter the PIN for the key to create qualified signatures." -msgstr "||Введите PIN ключа Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ ÐºÐ²Ð°Ð»Ð¸Ñ„Ð¸Ñ†Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð½Ñ‹Ñ… подпиÑей." - msgid "" "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create " "qualified signatures." @@ -6305,16 +6324,6 @@ msgid "%sNumber: %s%%0AHolder: %s%%0ACounter: %lu%s" msgstr "%sÐомер: %s%%0AДержатель: %s%%0AСчетчик: %lu%s" #, c-format -msgid "%sNumber: %s%%0AHolder: %s%s" -msgstr "%sÐомер: %s%%0AДержатель: %s%s" - -#. TRANSLATORS: This is the number of remaining attempts to -#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. -#, c-format -msgid "Remaining attempts: %d" -msgstr "ОÑталоÑÑŒ попыток: %d" - -#, c-format msgid "using default PIN as %s\n" msgstr "оÑновной PIN применÑетÑÑ ÐºÐ°Ðº %s\n" @@ -6567,6 +6576,10 @@ msgid "certificate policy not allowed" msgstr "правила Ñертификата недопуÑтимы" #, c-format +msgid "failed to get the fingerprint\n" +msgstr "Ñбой Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð¾Ñ‚Ð¿ÐµÑ‡Ð°Ñ‚ÐºÐ°\n" + +#, c-format msgid "looking up issuer at external location\n" msgstr "внешний поиÑк издателÑ\n" @@ -6575,6 +6588,10 @@ msgid "number of issuers matching: %d\n" msgstr "чиÑло ÑоответÑтвующих издателей: %d\n" #, c-format +msgid "can't get authorityInfoAccess: %s\n" +msgstr "не могу получить authorityInfoAccess: %s\n" + +#, c-format msgid "looking up issuer from the Dirmngr cache\n" msgstr "поиÑк Ð¸Ð·Ð´Ð°Ñ‚ÐµÐ»Ñ Ð² буфере Dirmngr\n" @@ -7158,10 +7175,6 @@ msgid "error reading input: %s\n" msgstr "ошибка Ñ‡Ñ‚ÐµÐ½Ð¸Ñ Ð²Ð²Ð¾Ð´Ð°: %s\n" #, c-format -msgid "failed to get the fingerprint\n" -msgstr "Ñбой Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð¾Ñ‚Ð¿ÐµÑ‡Ð°Ñ‚ÐºÐ°\n" - -#, c-format msgid "problem looking for existing certificate: %s\n" msgstr "проблема поиÑка ÑущеÑтвующего Ñертификата: %s\n" @@ -7253,9 +7266,10 @@ msgstr "ПодпиÑÑŒ Ñделана " msgid "[date not given]" msgstr "[дата не указана]" -#, c-format -msgid " using certificate ID 0x%08lX\n" -msgstr " Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ Ñертификата Ñ Ð¸Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ‚Ð¾Ñ€Ð¾Ð¼ 0x%08lX\n" +#, fuzzy, c-format +#| msgid "algorithm: %s" +msgid "algorithm:" +msgstr "алгоритм: %s" #, c-format msgid "" @@ -7591,14 +7605,6 @@ msgid "error getting data from cache file: %s\n" msgstr "ошибка Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ… из файла буфера: %s\n" #, c-format -msgid "unknown hash algorithm '%s'\n" -msgstr "недопуÑÑ‚Ð¸Ð¼Ð°Ñ Ñ…ÐµÑˆ-Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ '%s'\n" - -#, c-format -msgid "gcry_md_open for algorithm %d failed: %s\n" -msgstr "Ñбой gcry_md_open Ð´Ð»Ñ Ð°Ð»Ð³Ð¾Ñ€Ð¸Ñ‚Ð¼Ð° %d: %s\n" - -#, c-format msgid "got an invalid S-expression from libksba\n" msgstr "из libksba получено недопуÑтимое S-выражение\n" @@ -7607,6 +7613,14 @@ msgid "converting S-expression failed: %s\n" msgstr "Ñбой Ð¿Ñ€ÐµÐ¾Ð±Ñ€Ð°Ð·Ð¾Ð²Ð°Ð½Ð¸Ñ S-выражениÑ: %s\n" #, c-format +msgid "unknown hash algorithm '%s'\n" +msgstr "недопуÑÑ‚Ð¸Ð¼Ð°Ñ Ñ…ÐµÑˆ-Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ '%s'\n" + +#, c-format +msgid "gcry_md_open for algorithm %d failed: %s\n" +msgstr "Ñбой gcry_md_open Ð´Ð»Ñ Ð°Ð»Ð³Ð¾Ñ€Ð¸Ñ‚Ð¼Ð° %d: %s\n" + +#, c-format msgid "creating S-expression failed: %s\n" msgstr "Ñбой ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ S-выражениÑ: %s\n" @@ -8382,10 +8396,6 @@ msgid "failed to allocate OCSP context: %s\n" msgstr "Ñбой при выделении памÑти под контекÑÑ‚ OCSP: %s\n" #, c-format -msgid "can't get authorityInfoAccess: %s\n" -msgstr "не могу получить authorityInfoAccess: %s\n" - -#, c-format msgid "no default OCSP responder defined\n" msgstr "не определен оÑновной ответчик OCSP\n" @@ -8962,6 +8972,9 @@ msgstr "" "СинтакÑиÑ: gpg-check-pattern [параметры] файл_образцов\n" "Проверить фразу-пароль, поÑтупающую из stdin, по файлу образцов\n" +#~ msgid " using certificate ID 0x%08lX\n" +#~ msgstr " Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ Ñертификата Ñ Ð¸Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ‚Ð¾Ñ€Ð¾Ð¼ 0x%08lX\n" + #, fuzzy #~| msgid "option '%s' may not be used in %s mode\n" #~ msgid "" @@ -96,6 +96,9 @@ msgstr "" #. the pinentry. The %s is the actual error message, the #. two %d give the current and maximum number of tries. #. Do not translate the "SETERROR" keyword. +#. TRANSLATORS: The string is appended to an error message in +#. the pinentry. The %s is the actual error message, the +#. two %d give the current and maximum number of tries. #, c-format msgid "SETERROR %s (try %d of %d)" msgstr "" @@ -3712,6 +3715,9 @@ msgstr "chyba: neplatný odtlaÄok\n" msgid "subkey \"%s\" not found\n" msgstr "kÄ¾ÃºÄ `%s' nebol nájdený: %s\n" +msgid "AEAD: " +msgstr "" + msgid "Digest: " msgstr "Digest: " @@ -6446,6 +6452,26 @@ msgid "" "List, export, import Keybox data\n" msgstr "Použitie: gpg [možnosti] [súbory] (-h pre pomoc)" +#. TRANSLATORS: Put a \x1f right before a colon. This can be +#. * used by pinentry to nicely align the names and values. Keep +#. * the %s at the start and end of the string. +#, c-format +msgid "%sNumber: %s%%0AHolder: %s%s" +msgstr "" + +#. TRANSLATORS: This is the number of remaining attempts to +#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. +#, c-format +msgid "Remaining attempts: %d" +msgstr "" + +msgid "||Please enter the PIN for the key to create qualified signatures." +msgstr "" + +#, fuzzy +msgid "||Please enter the PIN for the standard keys." +msgstr "zmeniÅ¥ heslo" + #, c-format msgid "RSA modulus missing or not of size %d bits\n" msgstr "" @@ -6467,10 +6493,6 @@ msgid "|N|Please enter a new PIN for the standard keys." msgstr "zmeniÅ¥ heslo" #, fuzzy -msgid "||Please enter the PIN for the standard keys." -msgstr "zmeniÅ¥ heslo" - -#, fuzzy msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys." msgstr "ProsÃm výberte dôvod na revokáciu:\n" @@ -6481,9 +6503,6 @@ msgstr "ProsÃm výberte dôvod na revokáciu:\n" msgid "|N|Please enter a new PIN for the key to create qualified signatures." msgstr "" -msgid "||Please enter the PIN for the key to create qualified signatures." -msgstr "" - msgid "" "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create " "qualified signatures." @@ -6539,16 +6558,6 @@ msgid "%sNumber: %s%%0AHolder: %s%%0ACounter: %lu%s" msgstr "" #, c-format -msgid "%sNumber: %s%%0AHolder: %s%s" -msgstr "" - -#. TRANSLATORS: This is the number of remaining attempts to -#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. -#, c-format -msgid "Remaining attempts: %d" -msgstr "" - -#, c-format msgid "using default PIN as %s\n" msgstr "" @@ -6804,6 +6813,10 @@ msgstr "zapisujem tajný kÄ¾ÃºÄ do `%s'\n" msgid "certificate policy not allowed" msgstr "zapisujem tajný kÄ¾ÃºÄ do `%s'\n" +#, fuzzy, c-format +msgid "failed to get the fingerprint\n" +msgstr "nemôžem inicializovaÅ¥ databázu dôvery: %s\n" + #, c-format msgid "looking up issuer at external location\n" msgstr "" @@ -6812,6 +6825,11 @@ msgstr "" msgid "number of issuers matching: %d\n" msgstr "" +#, fuzzy, c-format +#| msgid "%s: can't access: %s\n" +msgid "can't get authorityInfoAccess: %s\n" +msgstr "%s: nemôžem pristupovaÅ¥ k: %s\n" + #, c-format msgid "looking up issuer from the Dirmngr cache\n" msgstr "" @@ -7422,10 +7440,6 @@ msgstr "chyba pri vytváranà hesla: %s\n" msgid "error reading input: %s\n" msgstr "chyba pri ÄÃtanà `%s': %s\n" -#, fuzzy, c-format -msgid "failed to get the fingerprint\n" -msgstr "nemôžem inicializovaÅ¥ databázu dôvery: %s\n" - #, c-format msgid "problem looking for existing certificate: %s\n" msgstr "" @@ -7505,8 +7519,8 @@ msgid "[date not given]" msgstr "" #, fuzzy, c-format -msgid " using certificate ID 0x%08lX\n" -msgstr "chyba pri vytváranà hesla: %s\n" +msgid "algorithm:" +msgstr "ASCII kódovanie: %s\n" #, c-format msgid "" @@ -7836,15 +7850,6 @@ msgid "error getting data from cache file: %s\n" msgstr "chyba pri vytváranà hesla: %s\n" #, fuzzy, c-format -#| msgid "invalid hash algorithm `%s'\n" -msgid "unknown hash algorithm '%s'\n" -msgstr "neplatný hashovacà algoritmus `%s'\n" - -#, c-format -msgid "gcry_md_open for algorithm %d failed: %s\n" -msgstr "" - -#, fuzzy, c-format #| msgid "invalid response from agent\n" msgid "got an invalid S-expression from libksba\n" msgstr "neplatná reakcia od agenta\n" @@ -7854,6 +7859,15 @@ msgid "converting S-expression failed: %s\n" msgstr "nemožno otvoriÅ¥ súbor: %s\n" #, fuzzy, c-format +#| msgid "invalid hash algorithm `%s'\n" +msgid "unknown hash algorithm '%s'\n" +msgstr "neplatný hashovacà algoritmus `%s'\n" + +#, c-format +msgid "gcry_md_open for algorithm %d failed: %s\n" +msgstr "" + +#, fuzzy, c-format msgid "creating S-expression failed: %s\n" msgstr "zmazanie bloku kľúÄa sa nepodarilo: %s\n" @@ -8635,11 +8649,6 @@ msgstr "vytvoriÅ¥ revokaÄný certifikát" msgid "failed to allocate OCSP context: %s\n" msgstr "nemôžem inicializovaÅ¥ databázu dôvery: %s\n" -#, fuzzy, c-format -#| msgid "%s: can't access: %s\n" -msgid "can't get authorityInfoAccess: %s\n" -msgstr "%s: nemôžem pristupovaÅ¥ k: %s\n" - #, c-format msgid "no default OCSP responder defined\n" msgstr "" @@ -9234,6 +9243,10 @@ msgid "" msgstr "" #, fuzzy +#~ msgid " using certificate ID 0x%08lX\n" +#~ msgstr "chyba pri vytváranà hesla: %s\n" + +#, fuzzy #~| msgid "you may not use %s while in %s mode\n" #~ msgid "" #~ "keyserver option \"honor-keyserver-url\" may not be used in Tor mode\n" @@ -125,6 +125,9 @@ msgstr "stämmer inte överens - försök igen" #. the pinentry. The %s is the actual error message, the #. two %d give the current and maximum number of tries. #. Do not translate the "SETERROR" keyword. +#. TRANSLATORS: The string is appended to an error message in +#. the pinentry. The %s is the actual error message, the +#. two %d give the current and maximum number of tries. #, c-format msgid "SETERROR %s (try %d of %d)" msgstr "SETERROR %s (försök %d av %d)" @@ -3833,6 +3836,9 @@ msgstr "ogiltigt fingeravtryck" msgid "subkey \"%s\" not found\n" msgstr "nyckeln \"%s\" hittades inte: %s\n" +msgid "AEAD: " +msgstr "" + msgid "Digest: " msgstr "Sammandrag: " @@ -6678,6 +6684,25 @@ msgstr "" "Syntax: kbxutil [flaggor] [filer]\n" "lista, exportera, importera nyckelskÃ¥psdata\n" +#. TRANSLATORS: Put a \x1f right before a colon. This can be +#. * used by pinentry to nicely align the names and values. Keep +#. * the %s at the start and end of the string. +#, c-format +msgid "%sNumber: %s%%0AHolder: %s%s" +msgstr "" + +#. TRANSLATORS: This is the number of remaining attempts to +#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. +#, c-format +msgid "Remaining attempts: %d" +msgstr "" + +msgid "||Please enter the PIN for the key to create qualified signatures." +msgstr "||Ange PIN-koden för nyckeln att skapa kvalificerade signaturer med." + +msgid "||Please enter the PIN for the standard keys." +msgstr "||Ange PIN-koden för standardnycklarna." + #, c-format msgid "RSA modulus missing or not of size %d bits\n" msgstr "RSA modulus saknas eller är inte %d bitar stor\n" @@ -6697,9 +6722,6 @@ msgstr "NullPIN har ännu inte ändrats\n" msgid "|N|Please enter a new PIN for the standard keys." msgstr "|N|Ange en ny PIN-kod för standardnycklarna." -msgid "||Please enter the PIN for the standard keys." -msgstr "||Ange PIN-koden för standardnycklarna." - msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys." msgstr "|NP|Ange en ny upplÃ¥sningskod (PUK-kod) för standardnycklarna." @@ -6710,9 +6732,6 @@ msgid "|N|Please enter a new PIN for the key to create qualified signatures." msgstr "" "|N|Ange en ny PIN-kod för nyckeln att skapa kvalificerade signaturer med." -msgid "||Please enter the PIN for the key to create qualified signatures." -msgstr "||Ange PIN-koden för nyckeln att skapa kvalificerade signaturer med." - msgid "" "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create " "qualified signatures." @@ -6772,16 +6791,6 @@ msgid "%sNumber: %s%%0AHolder: %s%%0ACounter: %lu%s" msgstr "" #, c-format -msgid "%sNumber: %s%%0AHolder: %s%s" -msgstr "" - -#. TRANSLATORS: This is the number of remaining attempts to -#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. -#, c-format -msgid "Remaining attempts: %d" -msgstr "" - -#, c-format msgid "using default PIN as %s\n" msgstr "använder standard-PIN som %s\n" @@ -7054,6 +7063,10 @@ msgid "certificate policy not allowed" msgstr "certifikatpolicy tillÃ¥ts inte" #, c-format +msgid "failed to get the fingerprint\n" +msgstr "misslyckades med att fÃ¥ fingeravtrycket\n" + +#, c-format msgid "looking up issuer at external location\n" msgstr "slÃ¥r upp utfärdare pÃ¥ extern plats\n" @@ -7061,6 +7074,11 @@ msgstr "slÃ¥r upp utfärdare pÃ¥ extern plats\n" msgid "number of issuers matching: %d\n" msgstr "antal utfärdare som matchar: %d\n" +#, fuzzy, c-format +#| msgid "can't access `%s': %s\n" +msgid "can't get authorityInfoAccess: %s\n" +msgstr "kan inte komma Ã¥t \"%s\": %s\n" + #, c-format msgid "looking up issuer from the Dirmngr cache\n" msgstr "slÃ¥r upp utfärdare frÃ¥n Dirmngr-cachen\n" @@ -7687,10 +7705,6 @@ msgid "error reading input: %s\n" msgstr "fel vid läsning av indata: %s\n" #, c-format -msgid "failed to get the fingerprint\n" -msgstr "misslyckades med att fÃ¥ fingeravtrycket\n" - -#, c-format msgid "problem looking for existing certificate: %s\n" msgstr "problem vid sökandet efter befintligt certifikat: %s\n" @@ -7783,9 +7797,10 @@ msgstr "Signatur gjord " msgid "[date not given]" msgstr "[datum inte angivet]" -#, c-format -msgid " using certificate ID 0x%08lX\n" -msgstr " använder certifikat-id 0x%08lX\n" +#, fuzzy, c-format +#| msgid "algorithm: %s" +msgid "algorithm:" +msgstr "algoritm: %s" #, c-format msgid "" @@ -8157,15 +8172,6 @@ msgstr "" msgid "error getting data from cache file: %s\n" msgstr "fel vid hämtning av lagrade flaggor: %s\n" -#, fuzzy, c-format -#| msgid "invalid hash algorithm `%s'\n" -msgid "unknown hash algorithm '%s'\n" -msgstr "ogiltig kontrollsummealgoritm \"%s\"\n" - -#, c-format -msgid "gcry_md_open for algorithm %d failed: %s\n" -msgstr "" - #, c-format msgid "got an invalid S-expression from libksba\n" msgstr "" @@ -8176,6 +8182,15 @@ msgid "converting S-expression failed: %s\n" msgstr "iconv_open misslyckades: %s\n" #, fuzzy, c-format +#| msgid "invalid hash algorithm `%s'\n" +msgid "unknown hash algorithm '%s'\n" +msgstr "ogiltig kontrollsummealgoritm \"%s\"\n" + +#, c-format +msgid "gcry_md_open for algorithm %d failed: %s\n" +msgstr "" + +#, fuzzy, c-format #| msgid "receiving line failed: %s\n" msgid "creating S-expression failed: %s\n" msgstr "mottagande rad misslyckades: %s\n" @@ -9058,11 +9073,6 @@ msgstr "fel vid lagring av certifikat\n" msgid "failed to allocate OCSP context: %s\n" msgstr "misslyckades med att allokera keyDB-hanterare\n" -#, fuzzy, c-format -#| msgid "can't access `%s': %s\n" -msgid "can't get authorityInfoAccess: %s\n" -msgstr "kan inte komma Ã¥t \"%s\": %s\n" - #, c-format msgid "no default OCSP responder defined\n" msgstr "" @@ -9704,6 +9714,9 @@ msgstr "" "Syntax: gpg-check-pattern [flaggor] mönsterfil\n" "Kontrollera en lösenfras angiven pÃ¥ standard in mot mönsterfilen\n" +#~ msgid " using certificate ID 0x%08lX\n" +#~ msgstr " använder certifikat-id 0x%08lX\n" + #, fuzzy #~| msgid "you may not use %s while in %s mode\n" #~ msgid "" @@ -99,6 +99,9 @@ msgstr "aynı deÄŸiller - tekrar deneyin" #. the pinentry. The %s is the actual error message, the #. two %d give the current and maximum number of tries. #. Do not translate the "SETERROR" keyword. +#. TRANSLATORS: The string is appended to an error message in +#. the pinentry. The %s is the actual error message, the +#. two %d give the current and maximum number of tries. #, c-format msgid "SETERROR %s (try %d of %d)" msgstr "SETERROR %s (%d/%d dene)" @@ -3776,6 +3779,9 @@ msgstr "parmakizi geçersiz" msgid "subkey \"%s\" not found\n" msgstr "anahtar \"%s\" yok: %s\n" +msgid "AEAD: " +msgstr "" + msgid "Digest: " msgstr "Özet: " @@ -6588,6 +6594,26 @@ msgstr "" "Sözdizimi: kbxutil [seçenekler] [dosyalar]\n" "Anahtar kutusu verisini listeler, ithal ve ihraç eder\n" +#. TRANSLATORS: Put a \x1f right before a colon. This can be +#. * used by pinentry to nicely align the names and values. Keep +#. * the %s at the start and end of the string. +#, c-format +msgid "%sNumber: %s%%0AHolder: %s%s" +msgstr "" + +#. TRANSLATORS: This is the number of remaining attempts to +#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. +#, c-format +msgid "Remaining attempts: %d" +msgstr "" + +msgid "||Please enter the PIN for the key to create qualified signatures." +msgstr "" + +#, fuzzy +msgid "||Please enter the PIN for the standard keys." +msgstr "|A|Lütfen Yönetici PIN'ini okuyucu tuÅŸtakımından giriniz" + #, c-format msgid "RSA modulus missing or not of size %d bits\n" msgstr "RSA modülü ya eksik ya da %d bitlik deÄŸil\n" @@ -6609,10 +6635,6 @@ msgid "|N|Please enter a new PIN for the standard keys." msgstr "||Lütfen PIN'inizi okuyucunun tuÅŸtakımından giriniz" #, fuzzy -msgid "||Please enter the PIN for the standard keys." -msgstr "|A|Lütfen Yönetici PIN'ini okuyucu tuÅŸtakımından giriniz" - -#, fuzzy msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys." msgstr "||Lütfen kart için Sıfırlama Kodunu giriniz" @@ -6623,9 +6645,6 @@ msgstr "||Lütfen kart için Sıfırlama Kodunu giriniz" msgid "|N|Please enter a new PIN for the key to create qualified signatures." msgstr "" -msgid "||Please enter the PIN for the key to create qualified signatures." -msgstr "" - msgid "" "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create " "qualified signatures." @@ -6681,16 +6700,6 @@ msgid "%sNumber: %s%%0AHolder: %s%%0ACounter: %lu%s" msgstr "" #, c-format -msgid "%sNumber: %s%%0AHolder: %s%s" -msgstr "" - -#. TRANSLATORS: This is the number of remaining attempts to -#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. -#, c-format -msgid "Remaining attempts: %d" -msgstr "" - -#, c-format msgid "using default PIN as %s\n" msgstr "%s olarak öntanımlı PIN kullanılıyor\n" @@ -6964,6 +6973,10 @@ msgid "certificate policy not allowed" msgstr "sertifika poliçesine izin verilmiyor" #, c-format +msgid "failed to get the fingerprint\n" +msgstr "parmakizinin alınması baÅŸarısız oldu\n" + +#, c-format msgid "looking up issuer at external location\n" msgstr "harici bir sertifikacı arar\n" @@ -6971,6 +6984,11 @@ msgstr "harici bir sertifikacı arar\n" msgid "number of issuers matching: %d\n" msgstr "eÅŸleÅŸen sertifikacı sayısı: %d\n" +#, fuzzy, c-format +#| msgid "can't access `%s': %s\n" +msgid "can't get authorityInfoAccess: %s\n" +msgstr "'%s' eriÅŸilemiyor: %s\n" + #, c-format msgid "looking up issuer from the Dirmngr cache\n" msgstr "Dirmngr önbelleÄŸinde sertifikacıyı arar\n" @@ -7595,10 +7613,6 @@ msgid "error reading input: %s\n" msgstr "girdi okunurken hata: %s\n" #, c-format -msgid "failed to get the fingerprint\n" -msgstr "parmakizinin alınması baÅŸarısız oldu\n" - -#, c-format msgid "problem looking for existing certificate: %s\n" msgstr "mevcut sertifika aranırken sorun çıktı: %s\n" @@ -7689,9 +7703,10 @@ msgstr "Ä°mza " msgid "[date not given]" msgstr "[belirtilmeyen tarihte]" -#, c-format -msgid " using certificate ID 0x%08lX\n" -msgstr " sertifika kimliÄŸi 0x%08lX kullanılarak yapıldı\n" +#, fuzzy, c-format +#| msgid "algorithm: %s" +msgid "algorithm:" +msgstr "algoritma: %s" #, c-format msgid "" @@ -8062,15 +8077,6 @@ msgstr "" msgid "error getting data from cache file: %s\n" msgstr "saklanmış bayraklar alınırken hata: %s\n" -#, fuzzy, c-format -#| msgid "invalid hash algorithm `%s'\n" -msgid "unknown hash algorithm '%s'\n" -msgstr "`%s' çittirim algoritması geçersiz\n" - -#, c-format -msgid "gcry_md_open for algorithm %d failed: %s\n" -msgstr "" - #, c-format msgid "got an invalid S-expression from libksba\n" msgstr "" @@ -8081,6 +8087,15 @@ msgid "converting S-expression failed: %s\n" msgstr "iconv_open baÅŸarısız: %s\n" #, fuzzy, c-format +#| msgid "invalid hash algorithm `%s'\n" +msgid "unknown hash algorithm '%s'\n" +msgstr "`%s' çittirim algoritması geçersiz\n" + +#, c-format +msgid "gcry_md_open for algorithm %d failed: %s\n" +msgstr "" + +#, fuzzy, c-format #| msgid "receiving line failed: %s\n" msgid "creating S-expression failed: %s\n" msgstr "satır alımı baÅŸarısız: %s\n" @@ -8958,11 +8973,6 @@ msgstr "sertifika saklanırken hata\n" msgid "failed to allocate OCSP context: %s\n" msgstr "anahtar veritabanı eylemcisine yer ayrılması baÅŸarısız oldu\n" -#, fuzzy, c-format -#| msgid "can't access `%s': %s\n" -msgid "can't get authorityInfoAccess: %s\n" -msgstr "'%s' eriÅŸilemiyor: %s\n" - #, c-format msgid "no default OCSP responder defined\n" msgstr "" @@ -9606,6 +9616,9 @@ msgstr "" "Standart girdiden verilen anahtar parolasını örüntü dosyasıyla " "karşılaÅŸtırır\n" +#~ msgid " using certificate ID 0x%08lX\n" +#~ msgstr " sertifika kimliÄŸi 0x%08lX kullanılarak yapıldı\n" + #, fuzzy #~| msgid "you may not use %s while in %s mode\n" #~ msgid "" @@ -98,6 +98,9 @@ msgstr "паролі не збігаютьÑÑ, повторіть Ñпробу" #. the pinentry. The %s is the actual error message, the #. two %d give the current and maximum number of tries. #. Do not translate the "SETERROR" keyword. +#. TRANSLATORS: The string is appended to an error message in +#. the pinentry. The %s is the actual error message, the +#. two %d give the current and maximum number of tries. #, c-format msgid "SETERROR %s (try %d of %d)" msgstr "SETERROR %s (Ñпроба %d з %d)" @@ -3563,6 +3566,9 @@ msgstr "«%s» не Ñ” відбитком\n" msgid "subkey \"%s\" not found\n" msgstr "ключ «%s» не знайдено\n" +msgid "AEAD: " +msgstr "" + msgid "Digest: " msgstr "Контрольна Ñума: " @@ -6333,6 +6339,27 @@ msgstr "" "СинтакÑиÑ: kbxutil [параметри] [файли]\n" "ПереглÑд, екÑпортуваннÑ, Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ… Keybox\n" +#. TRANSLATORS: Put a \x1f right before a colon. This can be +#. * used by pinentry to nicely align the names and values. Keep +#. * the %s at the start and end of the string. +#, c-format +msgid "%sNumber: %s%%0AHolder: %s%s" +msgstr "" + +#. TRANSLATORS: This is the number of remaining attempts to +#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. +#, c-format +msgid "Remaining attempts: %d" +msgstr "" + +msgid "||Please enter the PIN for the key to create qualified signatures." +msgstr "" +"||Будь лаÑка, вкажіть пінкод Ð´Ð»Ñ ÐºÐ»ÑŽÑ‡Ð°, призначеного Ð´Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ ÑкіÑних " +"підпиÑів." + +msgid "||Please enter the PIN for the standard keys." +msgstr "||Вкажіть пінкод Ð´Ð»Ñ Ñтандартних ключів." + #, c-format msgid "RSA modulus missing or not of size %d bits\n" msgstr "" @@ -6356,9 +6383,6 @@ msgstr "NullPIN ще не було змінено\n" msgid "|N|Please enter a new PIN for the standard keys." msgstr "|N|Вкажіть новий пінкод Ð´Ð»Ñ Ñтандартних ключів." -msgid "||Please enter the PIN for the standard keys." -msgstr "||Вкажіть пінкод Ð´Ð»Ñ Ñтандартних ключів." - msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys." msgstr "" "|NP|Будь лаÑка, вкажіть новий код Ñ€Ð¾Ð·Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ–Ð½ÐºÐ¾Ð´Ñƒ (PUK) Ð´Ð»Ñ " @@ -6374,11 +6398,6 @@ msgstr "" "|N|Будь лаÑка, вкажіть новий пінкод Ð´Ð»Ñ ÐºÐ»ÑŽÑ‡Ð°, призначеного Ð´Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ " "ÑкіÑних підпиÑів." -msgid "||Please enter the PIN for the key to create qualified signatures." -msgstr "" -"||Будь лаÑка, вкажіть пінкод Ð´Ð»Ñ ÐºÐ»ÑŽÑ‡Ð°, призначеного Ð´Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ ÑкіÑних " -"підпиÑів." - msgid "" "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create " "qualified signatures." @@ -6437,16 +6456,6 @@ msgid "%sNumber: %s%%0AHolder: %s%%0ACounter: %lu%s" msgstr "" #, c-format -msgid "%sNumber: %s%%0AHolder: %s%s" -msgstr "" - -#. TRANSLATORS: This is the number of remaining attempts to -#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. -#, c-format -msgid "Remaining attempts: %d" -msgstr "" - -#, c-format msgid "using default PIN as %s\n" msgstr "викориÑтовуємо типовий пінкод Ñк %s\n" @@ -6705,6 +6714,10 @@ msgid "certificate policy not allowed" msgstr "заборонено правила Ñертифікації" #, c-format +msgid "failed to get the fingerprint\n" +msgstr "не вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ відбиток\n" + +#, c-format msgid "looking up issuer at external location\n" msgstr "пошук Ð²Ð¸Ð´Ð°Ð²Ñ†Ñ Ð·Ð° зовнішньою адреÑою\n" @@ -6713,6 +6726,10 @@ msgid "number of issuers matching: %d\n" msgstr "кількіÑÑ‚ÑŒ відповідних видавців: %d\n" #, c-format +msgid "can't get authorityInfoAccess: %s\n" +msgstr "не вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ authorityInfoAccess: %s\n" + +#, c-format msgid "looking up issuer from the Dirmngr cache\n" msgstr "пошук Ð²Ð¸Ð´Ð°Ð²Ñ†Ñ Ñƒ кеші dirmngr\n" @@ -7304,10 +7321,6 @@ msgid "error reading input: %s\n" msgstr "помилка під Ñ‡Ð°Ñ Ñпроби Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ð²Ñ…Ñ–Ð´Ð½Ð¸Ñ… даних: %s\n" #, c-format -msgid "failed to get the fingerprint\n" -msgstr "не вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ відбиток\n" - -#, c-format msgid "problem looking for existing certificate: %s\n" msgstr "проблем з пошуком вже Ñтвореного Ñертифіката: %s\n" @@ -7398,9 +7411,10 @@ msgstr "ÐŸÑ–Ð´Ð¿Ð¸Ñ Ñтворено " msgid "[date not given]" msgstr "[дату не вказано]" -#, c-format -msgid " using certificate ID 0x%08lX\n" -msgstr " викориÑтовуємо ідентифікатор Ñертифіката 0x%08lX\n" +#, fuzzy, c-format +#| msgid "algorithm: %s" +msgid "algorithm:" +msgstr "алгоритм: %s" #, c-format msgid "" @@ -7731,14 +7745,6 @@ msgid "error getting data from cache file: %s\n" msgstr "помилка під Ñ‡Ð°Ñ Ñпроби Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ… з файла кешу: %s\n" #, c-format -msgid "unknown hash algorithm '%s'\n" -msgstr "невідомий алгоритм Ñ…ÐµÑˆÑƒÐ²Ð°Ð½Ð½Ñ Â«%s»\n" - -#, c-format -msgid "gcry_md_open for algorithm %d failed: %s\n" -msgstr "помилка викориÑÑ‚Ð°Ð½Ð½Ñ gcry_md_open Ð´Ð»Ñ Ð°Ð»Ð³Ð¾Ñ€Ð¸Ñ‚Ð¼Ñƒ %d: %s\n" - -#, c-format msgid "got an invalid S-expression from libksba\n" msgstr "отримано некоректний вираз S з libksba\n" @@ -7747,6 +7753,14 @@ msgid "converting S-expression failed: %s\n" msgstr "Ñпроба Ð¿ÐµÑ€ÐµÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð²Ð¸Ñ€Ð°Ð·Ñƒ S зазнала невдачі: %s\n" #, c-format +msgid "unknown hash algorithm '%s'\n" +msgstr "невідомий алгоритм Ñ…ÐµÑˆÑƒÐ²Ð°Ð½Ð½Ñ Â«%s»\n" + +#, c-format +msgid "gcry_md_open for algorithm %d failed: %s\n" +msgstr "помилка викориÑÑ‚Ð°Ð½Ð½Ñ gcry_md_open Ð´Ð»Ñ Ð°Ð»Ð³Ð¾Ñ€Ð¸Ñ‚Ð¼Ñƒ %d: %s\n" + +#, c-format msgid "creating S-expression failed: %s\n" msgstr "Ñпроба ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð²Ð¸Ñ€Ð°Ð·Ñƒ S зазнала невдачі: %s\n" @@ -8509,10 +8523,6 @@ msgid "failed to allocate OCSP context: %s\n" msgstr "не вдалоÑÑ Ñ€Ð¾Ð·Ð¼Ñ–Ñтити контекÑÑ‚ OCSP: %s\n" #, c-format -msgid "can't get authorityInfoAccess: %s\n" -msgstr "не вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ authorityInfoAccess: %s\n" - -#, c-format msgid "no default OCSP responder defined\n" msgstr "не визначено типового відповідача за OCSP\n" @@ -9091,6 +9101,9 @@ msgstr "" "СинтакÑиÑ: gpg-check-pattern [параметри] файл_шаблонів\n" "Перевірити пароль, вказаний у stdin, за допомогою файла_шаблонів\n" +#~ msgid " using certificate ID 0x%08lX\n" +#~ msgstr " викориÑтовуємо ідентифікатор Ñертифіката 0x%08lX\n" + #, fuzzy #~| msgid "you may not use %s while in %s mode\n" #~ msgid "" diff --git a/po/zh_CN.po b/po/zh_CN.po index a46ad1b..48f2ea7 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -93,6 +93,9 @@ msgstr "ä¸åŒ¹é… - 请é‡è¯•" #. the pinentry. The %s is the actual error message, the #. two %d give the current and maximum number of tries. #. Do not translate the "SETERROR" keyword. +#. TRANSLATORS: The string is appended to an error message in +#. the pinentry. The %s is the actual error message, the +#. two %d give the current and maximum number of tries. #, c-format msgid "SETERROR %s (try %d of %d)" msgstr "" @@ -3418,6 +3421,9 @@ msgstr "“%s†ä¸æ˜¯ä¸€ä¸ªæ£ç¡®çš„指纹\n" msgid "subkey \"%s\" not found\n" msgstr "å密钥 “%s†未找到\n" +msgid "AEAD: " +msgstr "AEAD: " + msgid "Digest: " msgstr "摘è¦ï¼š " @@ -5969,6 +5975,25 @@ msgstr "" "è¯æ³•ï¼škbxutil [选项] [文件]\n" "列出ã€å¯¼å‡ºæˆ–导入钥匙箱数æ®\n" +#. TRANSLATORS: Put a \x1f right before a colon. This can be +#. * used by pinentry to nicely align the names and values. Keep +#. * the %s at the start and end of the string. +#, c-format +msgid "%sNumber: %s%%0AHolder: %s%s" +msgstr "%sæ•°å—: %s%%0AæŒæœ‰è€…: %s%s" + +#. TRANSLATORS: This is the number of remaining attempts to +#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. +#, c-format +msgid "Remaining attempts: %d" +msgstr "剩余å°è¯•ï¼š%d" + +msgid "||Please enter the PIN for the key to create qualified signatures." +msgstr "||请为这个密钥输入 PIN 以创建åˆæ ¼çš„ç¾å。" + +msgid "||Please enter the PIN for the standard keys." +msgstr "||è¯·è¾“å…¥æ ‡å‡†å¯†é’¥çš„ PIN。" + #, c-format msgid "RSA modulus missing or not of size %d bits\n" msgstr "RSA 余数缺失或者ä¸æ˜¯ %d ä½é•¿\n" @@ -5988,9 +6013,6 @@ msgstr "尚未å˜æ›´ NullPIN\n" msgid "|N|Please enter a new PIN for the standard keys." msgstr "|N|è¯·ä¸ºæ ‡å‡†å¯†é’¥è¾“å…¥ä¸€ä¸ªæ–°çš„ PIN。" -msgid "||Please enter the PIN for the standard keys." -msgstr "||è¯·è¾“å…¥æ ‡å‡†å¯†é’¥çš„ PIN。" - msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys." msgstr "|NP|è¯·ä¸ºæ ‡å‡†å¯†é’¥è¾“å…¥ä¸€ä¸ªæ–°çš„ PIN 解é”ç (PUK)。" @@ -6000,9 +6022,6 @@ msgstr "|NP|è¯·è¾“å…¥æ ‡å‡†å¯†é’¥çš„ PIN 解é”ç (PUK)。" msgid "|N|Please enter a new PIN for the key to create qualified signatures." msgstr "|N|请为这个密钥输入一个新的 PIN 以创建åˆæ ¼çš„ç¾å。" -msgid "||Please enter the PIN for the key to create qualified signatures." -msgstr "||请为这个密钥输入 PIN 以创建åˆæ ¼çš„ç¾å。" - msgid "" "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create " "qualified signatures." @@ -6057,16 +6076,6 @@ msgid "%sNumber: %s%%0AHolder: %s%%0ACounter: %lu%s" msgstr "%sæ•°å—: %s%%0AæŒæœ‰è€…: %s%%0A计数: %lu%s" #, c-format -msgid "%sNumber: %s%%0AHolder: %s%s" -msgstr "%sæ•°å—: %s%%0AæŒæœ‰è€…: %s%s" - -#. TRANSLATORS: This is the number of remaining attempts to -#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. -#, c-format -msgid "Remaining attempts: %d" -msgstr "剩余å°è¯•ï¼š%d" - -#, c-format msgid "using default PIN as %s\n" msgstr "使用默认 PIN 作为 %s\n" @@ -6308,6 +6317,10 @@ msgid "certificate policy not allowed" msgstr "è¯ä¹¦ç–ç•¥ä¸è¢«å…许" #, c-format +msgid "failed to get the fingerprint\n" +msgstr "获å–指纹失败\n" + +#, c-format msgid "looking up issuer at external location\n" msgstr "在外部ä½ç½®æŸ¥æ‰¾ç¾å‘者\n" @@ -6316,6 +6329,10 @@ msgid "number of issuers matching: %d\n" msgstr "匹é…çš„ç¾å‘者数目:%d\n" #, c-format +msgid "can't get authorityInfoAccess: %s\n" +msgstr "æ— æ³•èŽ·å– authorityInfoAccess:%s\n" + +#, c-format msgid "looking up issuer from the Dirmngr cache\n" msgstr "在 Dirmngr 缓å˜ä¸æŸ¥æ‰¾ç¾å‘者\n" @@ -6892,10 +6909,6 @@ msgid "error reading input: %s\n" msgstr "读å–输入时出现错误:%s\n" #, c-format -msgid "failed to get the fingerprint\n" -msgstr "获å–指纹失败\n" - -#, c-format msgid "problem looking for existing certificate: %s\n" msgstr "查找现å˜è¯ä¹¦æ—¶å‡ºçŽ°é—®é¢˜ï¼š%s\n" @@ -6981,9 +6994,10 @@ msgstr "å·²ç¾å " msgid "[date not given]" msgstr "[日期未指定]" -#, c-format -msgid " using certificate ID 0x%08lX\n" -msgstr " æ£åœ¨ä½¿ç”¨çš„è¯ä¹¦æ ‡è¯† 0x%08lX\n" +#, fuzzy, c-format +#| msgid "algorithm: %s" +msgid "algorithm:" +msgstr "算法: %s" #, c-format msgid "" @@ -7312,14 +7326,6 @@ msgid "error getting data from cache file: %s\n" msgstr "从缓å˜æ–‡ä»¶ä¸èŽ·å–æ•°æ®æ—¶å‡ºçŽ°é”™è¯¯ï¼š%s\n" #, c-format -msgid "unknown hash algorithm '%s'\n" -msgstr "未知的散列算法‘%s’\n" - -#, c-format -msgid "gcry_md_open for algorithm %d failed: %s\n" -msgstr "算法 %d çš„ gcry_md_open 方法失败:%s\n" - -#, c-format msgid "got an invalid S-expression from libksba\n" msgstr "从 libksba èŽ·å¾—äº†æ— æ•ˆçš„ S 表达å¼\n" @@ -7328,6 +7334,14 @@ msgid "converting S-expression failed: %s\n" msgstr "è½¬æ¢ S 表达å¼æ—¶å¤±è´¥ï¼š%s\n" #, c-format +msgid "unknown hash algorithm '%s'\n" +msgstr "未知的散列算法‘%s’\n" + +#, c-format +msgid "gcry_md_open for algorithm %d failed: %s\n" +msgstr "算法 %d çš„ gcry_md_open 方法失败:%s\n" + +#, c-format msgid "creating S-expression failed: %s\n" msgstr "创建 S 表达å¼æ—¶å¤±è´¥ï¼š%s\n" @@ -8074,10 +8088,6 @@ msgid "failed to allocate OCSP context: %s\n" msgstr "åˆ†é… OCSP 上下文时失败:%s\n" #, c-format -msgid "can't get authorityInfoAccess: %s\n" -msgstr "æ— æ³•èŽ·å– authorityInfoAccess:%s\n" - -#, c-format msgid "no default OCSP responder defined\n" msgstr "未定义默认的 OCSP å“应者\n" @@ -8652,6 +8662,9 @@ msgstr "" "è¯æ³•ï¼šgpg-check-pattern [选项] patternfile\n" "按照 patternfile æ£€æŸ¥ä¸€ä¸ªç”±æ ‡å‡†è¾“å…¥ï¼ˆstdin)给定的密ç \n" +#~ msgid " using certificate ID 0x%08lX\n" +#~ msgstr " æ£åœ¨ä½¿ç”¨çš„è¯ä¹¦æ ‡è¯† 0x%08lX\n" + #, fuzzy #~| msgid "option '%s' may not be used in %s mode\n" #~ msgid "" @@ -8733,9 +8746,6 @@ msgstr "" #~ msgid " \"%s\": preference for AEAD algorithm %s\n" #~ msgstr " \"%s\":关于 AEAD 算法 %s çš„å好设置\n" -#~ msgid "AEAD: " -#~ msgstr "AEAD: " - #~ msgid "too many AEAD preferences\n" #~ msgstr "过多的 AEAD å好设置\n" diff --git a/po/zh_TW.po b/po/zh_TW.po index beb8bc1..50d7ca6 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -106,6 +106,9 @@ msgstr "å‰å¾Œä¸ä¸€è‡´ - è«‹å†è©¦ä¸€æ¬¡" #. the pinentry. The %s is the actual error message, the #. two %d give the current and maximum number of tries. #. Do not translate the "SETERROR" keyword. +#. TRANSLATORS: The string is appended to an error message in +#. the pinentry. The %s is the actual error message, the +#. two %d give the current and maximum number of tries. #, c-format msgid "SETERROR %s (try %d of %d)" msgstr "SETERROR %s (第 %d 次嘗試, 最多 %d 次)" @@ -3516,6 +3519,9 @@ msgstr "\"%s\" ä¸æ˜¯æŒ‡ç´‹\n" msgid "subkey \"%s\" not found\n" msgstr "找ä¸åˆ°é‡‘é‘° \"%s\": %s\n" +msgid "AEAD: " +msgstr "" + msgid "Digest: " msgstr "摘è¦: " @@ -6165,6 +6171,25 @@ msgstr "" "語法: kbxutil [é¸é …] [檔案]\n" "列出, 匯出, 匯入金鑰鑰匙盒資料\n" +#. TRANSLATORS: Put a \x1f right before a colon. This can be +#. * used by pinentry to nicely align the names and values. Keep +#. * the %s at the start and end of the string. +#, c-format +msgid "%sNumber: %s%%0AHolder: %s%s" +msgstr "" + +#. TRANSLATORS: This is the number of remaining attempts to +#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. +#, c-format +msgid "Remaining attempts: %d" +msgstr "" + +msgid "||Please enter the PIN for the key to create qualified signatures." +msgstr "||請輸入金鑰的個人è˜åˆ¥ç¢¼ (PIN) ä»¥å»ºç«‹å®Œå–„çš„ç°½ç« ." + +msgid "||Please enter the PIN for the standard keys." +msgstr "||請輸入標準金鑰的個人è˜åˆ¥ç¢¼ (PIN)." + #, c-format msgid "RSA modulus missing or not of size %d bits\n" msgstr "RSA 模組缺æ¼æˆ–è€…ä¸¦éž %d ä½å…ƒå¤§\n" @@ -6184,9 +6209,6 @@ msgstr "NullPIN 還沒有變更éŽ\n" msgid "|N|Please enter a new PIN for the standard keys." msgstr "|N|請輸入標準金鑰將採用的新個人è˜åˆ¥ç¢¼ (PIN)." -msgid "||Please enter the PIN for the standard keys." -msgstr "||請輸入標準金鑰的個人è˜åˆ¥ç¢¼ (PIN)." - msgid "|NP|Please enter a new PIN Unblocking Code (PUK) for the standard keys." msgstr "|NP|請輸入標準金鑰將採用的 PIN é‡è¨ç¢¼ (PUK)." @@ -6196,9 +6218,6 @@ msgstr "|P|請輸入標準金鑰的 PIN é‡è¨ç¢¼ (PUK)." msgid "|N|Please enter a new PIN for the key to create qualified signatures." msgstr "|N|請輸入金鑰的新個人è˜åˆ¥ç¢¼ (PIN) ä»¥å»ºç«‹å®Œå–„çš„ç°½ç« ." -msgid "||Please enter the PIN for the key to create qualified signatures." -msgstr "||請輸入金鑰的個人è˜åˆ¥ç¢¼ (PIN) ä»¥å»ºç«‹å®Œå–„çš„ç°½ç« ." - msgid "" "|NP|Please enter a new PIN Unblocking Code (PUK) for the key to create " "qualified signatures." @@ -6254,16 +6273,6 @@ msgid "%sNumber: %s%%0AHolder: %s%%0ACounter: %lu%s" msgstr "" #, c-format -msgid "%sNumber: %s%%0AHolder: %s%s" -msgstr "" - -#. TRANSLATORS: This is the number of remaining attempts to -#. * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. -#, c-format -msgid "Remaining attempts: %d" -msgstr "" - -#, c-format msgid "using default PIN as %s\n" msgstr "以 %s åšç‚ºé è¨ PIN\n" @@ -6510,6 +6519,10 @@ msgid "certificate policy not allowed" msgstr "未å…許憑è‰åŽŸå‰‡" #, c-format +msgid "failed to get the fingerprint\n" +msgstr "å–得指紋失敗\n" + +#, c-format msgid "looking up issuer at external location\n" msgstr "從外部ä½ç½®å°‹æ‰¾ç™¼è¡Œè€…\n" @@ -6518,6 +6531,10 @@ msgid "number of issuers matching: %d\n" msgstr "å»åˆçš„發行者數é‡: %d\n" #, c-format +msgid "can't get authorityInfoAccess: %s\n" +msgstr "無法å–å¾— authorityInfoAccess: %s\n" + +#, c-format msgid "looking up issuer from the Dirmngr cache\n" msgstr "從 Dirmngr å¿«å–尋找發行者\n" @@ -7094,10 +7111,6 @@ msgid "error reading input: %s\n" msgstr "讀å–輸入時出錯: %s\n" #, c-format -msgid "failed to get the fingerprint\n" -msgstr "å–得指紋失敗\n" - -#, c-format msgid "problem looking for existing certificate: %s\n" msgstr "查找既有憑è‰çš„å•é¡Œ: %s\n" @@ -7183,9 +7196,10 @@ msgstr "ç°½ç« å»ºç«‹æ–¼ " msgid "[date not given]" msgstr "[ 未給定日期 ]" -#, c-format -msgid " using certificate ID 0x%08lX\n" -msgstr " ä»¥æ†‘è‰ ID 0x%08lX\n" +#, fuzzy, c-format +#| msgid "algorithm: %s" +msgid "algorithm:" +msgstr "演算法: %s" #, c-format msgid "" @@ -7506,14 +7520,6 @@ msgid "error getting data from cache file: %s\n" msgstr "從快å–檔案å–得資料時出錯: %s\n" #, c-format -msgid "unknown hash algorithm '%s'\n" -msgstr "未知的雜湊演算法 '%s'\n" - -#, c-format -msgid "gcry_md_open for algorithm %d failed: %s\n" -msgstr "演算法 %d çš„ gcry_md_open 失敗: %s\n" - -#, c-format msgid "got an invalid S-expression from libksba\n" msgstr "從 libksba 得到無效的 S-表示å¼\n" @@ -7522,6 +7528,14 @@ msgid "converting S-expression failed: %s\n" msgstr "è½‰æ› S-表示å¼æ™‚失敗: %s\n" #, c-format +msgid "unknown hash algorithm '%s'\n" +msgstr "未知的雜湊演算法 '%s'\n" + +#, c-format +msgid "gcry_md_open for algorithm %d failed: %s\n" +msgstr "演算法 %d çš„ gcry_md_open 失敗: %s\n" + +#, c-format msgid "creating S-expression failed: %s\n" msgstr "建立 S-表示å¼æ™‚失敗: %s\n" @@ -8270,10 +8284,6 @@ msgid "failed to allocate OCSP context: %s\n" msgstr "é…ç½® OCSP 脈絡失敗: %s\n" #, c-format -msgid "can't get authorityInfoAccess: %s\n" -msgstr "無法å–å¾— authorityInfoAccess: %s\n" - -#, c-format msgid "no default OCSP responder defined\n" msgstr "無定義é è¨ OCSP 回應程å¼\n" @@ -8865,6 +8875,9 @@ msgstr "" "語法: gpg-check-pattern [é¸é …] 樣å¼æª”案\n" "用樣å¼æª”案來檢查由標準輸入給定的密語\n" +#~ msgid " using certificate ID 0x%08lX\n" +#~ msgstr " ä»¥æ†‘è‰ ID 0x%08lX\n" + #, fuzzy #~| msgid "you may not use %s while in %s mode\n" #~ msgid "" @@ -475,7 +475,7 @@ dump_reader_status (int slot) if (reader_table[slot].atrlen) { log_info ("slot %d: ATR=", slot); - log_printhex ("", reader_table[slot].atr, reader_table[slot].atrlen); + log_printhex (reader_table[slot].atr, reader_table[slot].atrlen, ""); } } @@ -739,7 +739,7 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen, return err; if (DBG_CARD_IO) - log_printhex (" PCSC_data:", apdu, apdulen); + log_printhex (apdu, apdulen, " PCSC_data:"); if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_T1)) send_pci.protocol = PCSC_PROTOCOL_T1; @@ -1453,7 +1453,7 @@ send_apdu_ccid (int slot, unsigned char *apdu, size_t apdulen, return err; if (DBG_CARD_IO) - log_printhex (" raw apdu:", apdu, apdulen); + log_printhex (apdu, apdulen, " raw apdu:"); maxbuflen = *buflen; if (pininfo) @@ -1723,7 +1723,7 @@ my_rapdu_send_apdu (int slot, unsigned char *apdu, size_t apdulen, *buflen = 0; if (DBG_CARD_IO) - log_printhex (" APDU_data:", apdu, apdulen); + log_printhex (apdu, apdulen, " APDU_data:"); if (apdulen < 4) { @@ -2879,7 +2879,7 @@ send_le (int slot, int class, int ins, int p0, int p1, log_debug (" response: sw=%04X datalen=%d\n", sw, (unsigned int)resultlen); if ( !retbuf && (sw == SW_SUCCESS || (sw & 0xff00) == SW_MORE_DATA)) - log_printhex (" dump: ", result, resultlen); + log_printhex (result, resultlen, " dump: "); } if (sw == SW_SUCCESS || sw == SW_EOF_REACHED) @@ -2952,7 +2952,7 @@ send_le (int slot, int class, int ins, int p0, int p1, log_debug (" more: sw=%04X datalen=%d\n", sw, (unsigned int)resultlen); if (!retbuf && (sw==SW_SUCCESS || (sw&0xff00)==SW_MORE_DATA)) - log_printhex (" dump: ", result, resultlen); + log_printhex (result, resultlen, " dump: "); } if ((sw & 0xff00) == SW_MORE_DATA @@ -2998,7 +2998,7 @@ send_le (int slot, int class, int ins, int p0, int p1, xfree (result_buffer); if (DBG_CARD_IO && retbuf && sw == SW_SUCCESS) - log_printhex (" dump: ", *retbuf, *retbuflen); + log_printhex (*retbuf, *retbuflen, " dump: "); return sw; } @@ -3164,7 +3164,7 @@ apdu_send_direct (int slot, size_t extended_length, log_debug (" response: sw=%04X datalen=%d\n", sw, (unsigned int)resultlen); if ( !retbuf && (sw == SW_SUCCESS || (sw & 0xff00) == SW_MORE_DATA)) - log_printhex (" dump: ", result, resultlen); + log_printhex (result, resultlen, " dump: "); } if (handle_more && (sw & 0xff00) == SW_MORE_DATA) @@ -3220,7 +3220,7 @@ apdu_send_direct (int slot, size_t extended_length, log_debug (" more: sw=%04X datalen=%d\n", sw, (unsigned int)resultlen); if (!retbuf && (sw==SW_SUCCESS || (sw&0xff00)==SW_MORE_DATA)) - log_printhex (" dump: ", result, resultlen); + log_printhex (result, resultlen, " dump: "); } if ((sw & 0xff00) == SW_MORE_DATA @@ -3292,7 +3292,7 @@ apdu_send_direct (int slot, size_t extended_length, *r_sw = sw; if (DBG_CARD_IO && retbuf) - log_printhex (" dump: ", *retbuf, *retbuflen); + log_printhex (*retbuf, *retbuflen, " dump: "); return 0; diff --git a/scd/app-common.h b/scd/app-common.h index 2619823..89467dc 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -119,9 +119,26 @@ struct app_ctx_s { } fnc; }; + +/* Helper to get the slot from an APP object. */ +static inline int +app_get_slot (app_t app) +{ + /* Note that this is a similar function of the one in 2.3 which we + * use to make back porting easier. */ + if (app) + return app->slot; + return -1; +} + + /*-- app-help.c --*/ unsigned int app_help_count_bits (const unsigned char *a, size_t len); -gpg_error_t app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip); +gpg_error_t app_help_get_keygrip_string_pk (const void *pk, size_t pklen, + char *hexkeygrip, + gcry_sexp_t *r_pkey); +gpg_error_t app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip, + gcry_sexp_t *r_pkey); size_t app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff); diff --git a/scd/app-dinsig.c b/scd/app-dinsig.c index bea2856..b0c47af 100644 --- a/scd/app-dinsig.c +++ b/scd/app-dinsig.c @@ -137,7 +137,7 @@ do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags) ksba_cert_release (cert); return err; } - err = app_help_get_keygrip_string (cert, hexkeygrip); + err = app_help_get_keygrip_string (cert, hexkeygrip, NULL); if (err) { log_error ("failed to calculate the keygrip for FID 0x%04X\n", fid); diff --git a/scd/app-help.c b/scd/app-help.c index 842a73d..4b8a024 100644 --- a/scd/app-help.c +++ b/scd/app-help.c @@ -52,26 +52,24 @@ app_help_count_bits (const unsigned char *a, size_t len) } -/* Return the KEYGRIP for the certificate CERT as an hex encoded - string in the user provided buffer HEXKEYGRIP which must be of at - least 41 bytes. */ +/* Return the KEYGRIP for the canonical encoded public key (PK,PKLEN) + * as an hex encoded string in the user provided buffer HEXKEYGRIP + * which must be of at least 41 bytes. If R_PKEY is not NULL and the + * function succeeded, the S-expression representing the key is + * stored there. The caller needs to call gcry_sexp_release on + * that. */ gpg_error_t -app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip) +app_help_get_keygrip_string_pk (const void *pk, size_t pklen, char *hexkeygrip, + gcry_sexp_t *r_pkey) { gpg_error_t err; gcry_sexp_t s_pkey; - ksba_sexp_t p; - size_t n; - unsigned char array[20]; + unsigned char array[KEYGRIP_LEN]; - p = ksba_cert_get_public_key (cert); - if (!p) - return gpg_error (GPG_ERR_BUG); - n = gcry_sexp_canon_len (p, 0, NULL, NULL); - if (!n) - return gpg_error (GPG_ERR_INV_SEXP); - err = gcry_sexp_sscan (&s_pkey, NULL, (char*)p, n); - xfree (p); + if (r_pkey) + *r_pkey = NULL; + + err = gcry_sexp_sscan (&s_pkey, NULL, pk, pklen); if (err) return err; /* Can't parse that S-expression. */ if (!gcry_pk_get_keygrip (s_pkey, array)) @@ -79,14 +77,45 @@ app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip) gcry_sexp_release (s_pkey); return gpg_error (GPG_ERR_GENERAL); /* Failed to calculate the keygrip.*/ } - gcry_sexp_release (s_pkey); - bin2hex (array, 20, hexkeygrip); + if (r_pkey) + *r_pkey = s_pkey; + else + gcry_sexp_release (s_pkey); + + bin2hex (array, KEYGRIP_LEN, hexkeygrip); return 0; } +/* Return the KEYGRIP for the certificate CERT as an hex encoded + * string in the user provided buffer HEXKEYGRIP which must be of at + * least 41 bytes. If R_PKEY is not NULL and the function succeeded, + * the S-expression representing the key is stored there. The caller + * needs to call gcry_sexp_release on that. */ +gpg_error_t +app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip, + gcry_sexp_t *r_pkey) +{ + gpg_error_t err; + ksba_sexp_t p; + size_t n; + + if (r_pkey) + *r_pkey = NULL; + + p = ksba_cert_get_public_key (cert); + if (!p) + return gpg_error (GPG_ERR_BUG); + n = gcry_sexp_canon_len (p, 0, NULL, NULL); + if (!n) + return gpg_error (GPG_ERR_INV_SEXP); + err = app_help_get_keygrip_string_pk ((void*)p, n, hexkeygrip, r_pkey); + ksba_free (p); + return err; +} + /* Given the SLOT and the File ID FID, return the length of the certificate contained in that file. Returns 0 if the file does not diff --git a/scd/app-nks.c b/scd/app-nks.c index 9371932..58a5349 100644 --- a/scd/app-nks.c +++ b/scd/app-nks.c @@ -248,53 +248,17 @@ keygripstr_from_pk_file (app_t app, int fid, char *r_gripstr) /* TCOS responds to a verify with empty data (i.e. without the Lc - byte) with the status of the PIN. PWID is the PIN ID, If SIGG is - true, the application is switched into SigG mode. - Returns: - -1 = Error retrieving the data, - -2 = No such PIN, - -3 = PIN blocked, - -4 = NullPIN activ, - n >= 0 = Number of verification attempts left. */ + * byte) with the status of the PIN. PWID is the PIN ID, If SIGG is + * true, the application is switched into SigG mode. Returns: + * ISO7816_VERIFY_* codes or non-negative number of verification + * attempts left. */ static int get_chv_status (app_t app, int sigg, int pwid) { - unsigned char *result = NULL; - size_t resultlen; - char command[4]; - int rc; - if (switch_application (app, sigg)) return sigg? -2 : -1; /* No such PIN / General error. */ - command[0] = 0x00; - command[1] = 0x20; - command[2] = 0x00; - command[3] = pwid; - - if (apdu_send_direct (app->slot, 0, (unsigned char *)command, - 4, 0, NULL, &result, &resultlen)) - rc = -1; /* Error. */ - else if (resultlen < 2) - rc = -1; /* Error. */ - else - { - unsigned int sw = buf16_to_uint (result+resultlen-2); - - if (sw == 0x6a88) - rc = -2; /* No such PIN. */ - else if (sw == 0x6983) - rc = -3; /* PIN is blocked. */ - else if (sw == 0x6985) - rc = -4; /* NullPIN is activ. */ - else if ((sw & 0xfff0) == 0x63C0) - rc = (sw & 0x000f); /* PIN has N tries left. */ - else - rc = -1; /* Other error. */ - } - xfree (result); - - return rc; + return iso7816_verify_status (app_get_slot (app), pwid); } diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index fe13f28..7fc903b 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -268,6 +268,47 @@ static gpg_error_t change_keyattr_from_string void *pincb_arg, const void *value, size_t valuelen); + +/* Return the OpenPGP card manufacturer name. */ +static const char * +get_manufacturer (unsigned int no) +{ + /* Note: Make sure that there is no colon or linefeed in the string. */ + switch (no) + { + case 0x0001: return "PPC Card Systems"; + case 0x0002: return "Prism"; + case 0x0003: return "OpenFortress"; + case 0x0004: return "Wewid"; + case 0x0005: return "ZeitControl"; + case 0x0006: return "Yubico"; + case 0x0007: return "OpenKMS"; + case 0x0008: return "LogoEmail"; + case 0x0009: return "Fidesmo"; + case 0x000A: return "Dangerous Things"; + case 0x000B: return "Feitian Technologies"; + + case 0x002A: return "Magrathea"; + case 0x0042: return "GnuPG e.V."; + + case 0x1337: return "Warsaw Hackerspace"; + case 0x2342: return "warpzone"; /* hackerspace Muenster. */ + case 0x4354: return "Confidential Technologies"; /* cotech.de */ + case 0x5443: return "TIF-IT e.V."; + case 0x63AF: return "Trustica"; + case 0xBA53: return "c-base e.V."; + case 0xBD0E: return "Paranoidlabs"; + case 0xF517: return "FSIJ"; + case 0xF5EC: return "F-Secure"; + + /* 0x0000 and 0xFFFF are defined as test cards per spec, + * 0xFF00 to 0xFFFE are assigned for use with randomly created + * serial numbers. */ + case 0x0000: + case 0xffff: return "test card"; + default: return (no & 0xff00) == 0xff00? "unmanaged S/N range":"unknown"; + } +} @@ -567,7 +608,7 @@ dump_all_do (int slot) if (data_objects[i].binary) { log_info ("DO '%s': ", data_objects[i].desc); - log_printhex ("", buffer, buflen); + log_printhex (buffer, buflen, ""); } else log_info ("DO '%s': '%.*s'\n", @@ -597,7 +638,7 @@ dump_all_do (int slot) if (valuelen > 200) log_info ("[%u]\n", (unsigned int)valuelen); else - log_printhex ("", value, valuelen); + log_printhex (value, valuelen, ""); } else log_info ("DO '%s': '%.*s'\n", @@ -992,6 +1033,7 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name) { "$SIGNKEYID", 0x0000, -7 }, { "$DISPSERIALNO",0x0000, -4 }, { "KDF", 0x00F9, 5 }, + { "MANUFACTURER", 0x0000, -8 }, { NULL, 0 } }; int idx, i, rc; @@ -1083,6 +1125,13 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name) send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0); return 0; } + if (table[idx].special == -8) + { + return send_status_printf + (ctrl, table[idx].name, "%u %s", + app->app_local->manufacturer, + get_manufacturer (app->app_local->manufacturer)); + } relptr = get_one_do (app, table[idx].tag, &value, &valuelen, &rc); if (relptr) @@ -1860,6 +1909,7 @@ do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags) (void)flags; do_getattr (app, ctrl, "EXTCAP"); + do_getattr (app, ctrl, "MANUFACTURER"); do_getattr (app, ctrl, "DISP-NAME"); do_getattr (app, ctrl, "DISP-LANG"); do_getattr (app, ctrl, "DISP-SEX"); @@ -4239,7 +4289,7 @@ compare_fingerprint (app_t app, int keyno, unsigned char *sha1fpr) return gpg_error (GPG_ERR_GENERAL); } fpr = find_tlv (buffer, buflen, 0x00C5, &n); - if (!fpr || n != 60) + if (!fpr || n < 60) { xfree (buffer); log_error (_("error reading fingerprint DO\n")); @@ -5156,7 +5206,7 @@ parse_algorithm_attribute (app_t app, int keyno) curve = ecc_curve (buffer + 1, oidlen); if (!curve) - log_printhex ("Curve with OID not supported: ", buffer+1, buflen-1); + log_printhex (buffer+1, buflen-1, "Curve with OID not supported: "); else { app->app_local->keyattr[keyno].key_type = KEY_TYPE_ECC; @@ -5174,7 +5224,7 @@ parse_algorithm_attribute (app_t app, int keyno) } } else if (opt.verbose) - log_printhex ("", buffer, buflen); + log_printhex (buffer, buflen, ""); xfree (relptr); } @@ -5216,7 +5266,7 @@ app_select_openpgp (app_t app) if (opt.verbose) { log_info ("AID: "); - log_printhex ("", buffer, buflen); + log_printhex (buffer, buflen, ""); } app->card_version = buffer[6] << 8; @@ -5249,7 +5299,7 @@ app_select_openpgp (app_t app) if (opt.verbose) { log_info ("Historical Bytes: "); - log_printhex ("", buffer, buflen); + log_printhex (buffer, buflen, ""); } parse_historical (app->app_local, buffer, buflen); xfree (relptr); diff --git a/scd/app-p15.c b/scd/app-p15.c index 0bb5f9e..9ad0d16 100644 --- a/scd/app-p15.c +++ b/scd/app-p15.c @@ -1,5 +1,6 @@ /* app-p15.c - The pkcs#15 card application. * Copyright (C) 2005 Free Software Foundation, Inc. + * Copyright (C) 2020 g10 Code GmbH * * This file is part of GnuPG. * @@ -15,6 +16,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, see <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-3.0-or-later */ /* Information pertaining to the BELPIC developer card samples: @@ -39,6 +41,7 @@ #include "iso7816.h" #include "app-common.h" +#include "../common/i18n.h" #include "../common/tlv.h" #include "apdu.h" /* fixme: we should move the card detection to a separate file */ @@ -49,10 +52,22 @@ typedef enum CARD_TYPE_UNKNOWN, CARD_TYPE_TCOS, CARD_TYPE_MICARDO, + CARD_TYPE_CARDOS_50, CARD_TYPE_BELPIC /* Belgian eID card specs. */ } card_type_t; +/* The OS of card as specified by card_type_t is not always + * sufficient. Thus we also distinguish the actual product build upon + * the given OS. */ +typedef enum + { + CARD_PRODUCT_UNKNOWN, + CARD_PRODUCT_DTRUST /* D-Trust GmbH (bundesdruckerei.de) */ + } +card_product_t; + + /* A list card types with ATRs noticed with these cards. */ #define X(a) ((unsigned char const *)(a)) static struct @@ -79,7 +94,8 @@ static struct { 26, X("\x3B\xFE\x94\x00\xFF\x80\xB1\xFA\x45\x1F\x03\x45\x73\x74\x45\x49" "\x44\x20\x76\x65\x72\x20\x31\x2E\x30\x43"), CARD_TYPE_MICARDO }, /* EstEID (Estonian Big Brother card) */ - + { 11, X("\x3b\xd2\x18\x00\x81\x31\xfe\x58\xc9\x01\x14"), + CARD_TYPE_CARDOS_50 }, /* CardOS 5.0 */ { 0 } }; #undef X @@ -135,7 +151,12 @@ struct cdf_object_s /* Link to next item when used in a linked list. */ struct cdf_object_s *next; - /* Length and allocated buffer with the Id of this object. */ + /* Flags to indicate whether fields are valid. */ + unsigned int have_off:1; + + /* Length and allocated buffer with the Id of this object. + * This field is used for X.509 in PKCS#11 to make it easier to + * match a private key with a certificate. */ size_t objidlen; unsigned char *objid; @@ -144,8 +165,6 @@ struct cdf_object_s size_t imagelen; unsigned char *image; - /* Set to true if a length and offset is available. */ - int have_off; /* The offset and length of the object. They are only valid if HAVE_OFF is true and set to 0 if HAVE_OFF is false. */ unsigned long off, len; @@ -169,6 +188,37 @@ struct prkdf_object_s /* Link to next item when used in a linked list. */ struct prkdf_object_s *next; + /* Flags to indicate whether fields are valid. */ + unsigned int keygrip_valid:1; + unsigned int key_reference_valid:1; + unsigned int have_off:1; + + /* Flag indicating that the corresponding PIN has already been + * verified. */ + unsigned int pin_verified:1; + + /* The key's usage flags. */ + keyusage_flags_t usageflags; + + /* The keygrip of the key. This is used as a cache. */ + char keygrip[2*KEYGRIP_LEN+1]; + + /* The Gcrypt algo identifier for the key. It is valid if the + * keygrip is also valid. */ + int keyalgo; + + /* The length of the key in bits (e.g. for RSA the length of the + * modulus). It is valid if the keygrip is also valid. */ + unsigned int keynbits; + + /* Malloced CN from the Subject-DN of the corresponding certificate + * or NULL if not known. */ + char *common_name; + + /* Malloced SerialNumber from the Subject-DN of the corresponding + * certificate or NULL if not known. */ + char *serial_number; + /* Length and allocated buffer with the Id of this object. */ size_t objidlen; unsigned char *objid; @@ -178,17 +228,11 @@ struct prkdf_object_s size_t authidlen; unsigned char *authid; - /* The key's usage flags. */ - keyusage_flags_t usageflags; - /* The keyReference and a flag telling whether it is valid. */ unsigned long key_reference; - int key_reference_valid; - /* Set to true if a length and offset is available. */ - int have_off; /* The offset and length of the object. They are only valid if - HAVE_OFF is true and set to 0 if HAVE_OFF is false. */ + * HAVE_OFF is true otherwise they are set to 0. */ unsigned long off, len; /* The length of the path as given in the PrKDF and the path itself. @@ -209,6 +253,9 @@ struct aodf_object_s /* Link to next item when used in a linked list. */ struct aodf_object_s *next; + /* Flags to indicate whether fields are valid. */ + unsigned int have_off:1; + /* Length and allocated buffer with the Id of this object. */ size_t objidlen; unsigned char *objid; @@ -218,6 +265,9 @@ struct aodf_object_s size_t authidlen; unsigned char *authid; + /* The file ID of this AODF. */ + unsigned short fid; + /* The PIN Flags. */ struct { @@ -256,9 +306,6 @@ struct aodf_object_s char pad_char; int pad_char_valid; - - /* Set to true if a length and offset is available. */ - int have_off; /* The offset and length of the object. They are only valid if HAVE_OFF is true and set to 0 if HAVE_OFF is false. */ unsigned long off, len; @@ -279,9 +326,12 @@ struct app_local_s hierarchy. Thus we assume this is directly below the MF. */ unsigned short home_df; - /* The type of the card. */ + /* The type of the card's OS. */ card_type_t card_type; + /* The vendor's product. */ + card_product_t card_product; + /* Flag indicating whether we may use direct path selection. */ int direct_path_selection; @@ -304,6 +354,9 @@ struct app_local_s unsigned char *serialno; size_t serialnolen; + /* The manufacturerID from the TokenInfo EF. Malloced. */ + char *manufacturer_id; + /* Information on all certificates. */ cdf_object_t certificate_info; /* Information on all trusted certificates. */ @@ -321,8 +374,11 @@ struct app_local_s /*** Local prototypes. ***/ +static gpg_error_t keygrip_from_prkdf (app_t app, prkdf_object_t prkdf); static gpg_error_t readcert_by_cdf (app_t app, cdf_object_t cdf, unsigned char **r_cert, size_t *r_certlen); +static char *get_dispserialno (app_t app, prkdf_object_t prkdf); +static gpg_error_t do_getattr (app_t app, ctrl_t ctrl, const char *name); @@ -347,6 +403,8 @@ release_prkdflist (prkdf_object_t a) while (a) { prkdf_object_t tmp = a->next; + xfree (a->common_name); + xfree (a->serial_number); xfree (a->objid); xfree (a->authid); xfree (a); @@ -391,6 +449,7 @@ do_deinit (app_t app) release_cdflist (app->app_local->useful_certificate_info); release_prkdflist (app->app_local->private_key_info); release_aodflist (app->app_local->auth_object_info); + xfree (app->app_local->manufacturer_id); xfree (app->app_local->serialno); xfree (app->app_local); app->app_local = NULL; @@ -412,14 +471,14 @@ select_and_read_binary (int slot, unsigned short efid, const char *efid_desc, err = iso7816_select_file (slot, efid, 0); if (err) { - log_error ("error selecting %s (0x%04X): %s\n", + log_error ("p15: error selecting %s (0x%04X): %s\n", efid_desc, efid, gpg_strerror (err)); return err; } err = iso7816_read_binary (slot, 0, 0, buffer, buflen); if (err) { - log_error ("error reading %s (0x%04X): %s\n", + log_error ("p15: error reading %s (0x%04X): %s\n", efid_desc, efid, gpg_strerror (err)); return err; } @@ -439,14 +498,14 @@ select_ef_by_path (app_t app, const unsigned short *path, size_t pathlen) return gpg_error (GPG_ERR_INV_VALUE); if (pathlen && *path != 0x3f00 ) - log_debug ("WARNING: relative path selection not yet implemented\n"); + log_error ("p15: warning: relative path selection not yet implemented\n"); if (app->app_local->direct_path_selection) { err = iso7816_select_path (app->slot, path+1, pathlen-1); if (err) { - log_error ("error selecting path "); + log_error ("p15: error selecting path "); for (j=0; j < pathlen; j++) log_printf ("%04hX", path[j]); log_printf (": %s\n", gpg_strerror (err)); @@ -464,7 +523,7 @@ select_ef_by_path (app_t app, const unsigned short *path, size_t pathlen) err = iso7816_select_file (app->slot, path[i], !(i+1 == pathlen)); if (err) { - log_error ("error selecting part %d from path ", i); + log_error ("p15: error selecting part %d from path ", i); for (j=0; j < pathlen; j++) log_printf ("%04hX", path[j]); log_printf (": %s\n", gpg_strerror (err)); @@ -492,35 +551,55 @@ parse_certid (app_t app, const char *certid, *r_objid = NULL; *r_objidlen = 0; - if (app->app_local->home_df) - snprintf (tmpbuf, sizeof tmpbuf, - "P15-%04X.", (unsigned int)(app->app_local->home_df & 0xffff)); - else - strcpy (tmpbuf, "P15."); - if (strncmp (certid, tmpbuf, strlen (tmpbuf)) ) - { - if (!strncmp (certid, "P15.", 4) - || (!strncmp (certid, "P15-", 4) - && hexdigitp (certid+4) - && hexdigitp (certid+5) - && hexdigitp (certid+6) - && hexdigitp (certid+7) - && certid[8] == '.')) + if (certid[0] != 'P' && strlen (certid) == 40) /* This is a keygrip. */ + { + prkdf_object_t prkdf; + + for (prkdf = app->app_local->private_key_info; + prkdf; prkdf = prkdf->next) + if (!keygrip_from_prkdf (app, prkdf) + && !strcmp (certid, prkdf->keygrip)) + break; + if (!prkdf || !prkdf->objidlen || !prkdf->objid) return gpg_error (GPG_ERR_NOT_FOUND); - return gpg_error (GPG_ERR_INV_ID); - } - certid += strlen (tmpbuf); - - for (s=certid, objidlen=0; hexdigitp (s); s++, objidlen++) - ; - if (*s || !objidlen || (objidlen%2)) - return gpg_error (GPG_ERR_INV_ID); - objidlen /= 2; - objid = xtrymalloc (objidlen); - if (!objid) - return gpg_error_from_syserror (); - for (s=certid, i=0; i < objidlen; i++, s+=2) - objid[i] = xtoi_2 (s); + objidlen = prkdf->objidlen; + objid = xtrymalloc (objidlen); + if (!objid) + return gpg_error_from_syserror (); + memcpy (objid, prkdf->objid, prkdf->objidlen); + } + else /* This is a usual keyref. */ + { + if (app->app_local->home_df) + snprintf (tmpbuf, sizeof tmpbuf, "P15-%04X.", + (unsigned int)(app->app_local->home_df & 0xffff)); + else + strcpy (tmpbuf, "P15."); + if (strncmp (certid, tmpbuf, strlen (tmpbuf)) ) + { + if (!strncmp (certid, "P15.", 4) + || (!strncmp (certid, "P15-", 4) + && hexdigitp (certid+4) + && hexdigitp (certid+5) + && hexdigitp (certid+6) + && hexdigitp (certid+7) + && certid[8] == '.')) + return gpg_error (GPG_ERR_NOT_FOUND); + return gpg_error (GPG_ERR_INV_ID); + } + certid += strlen (tmpbuf); + for (s=certid, objidlen=0; hexdigitp (s); s++, objidlen++) + ; + if (*s || !objidlen || (objidlen%2)) + return gpg_error (GPG_ERR_INV_ID); + objidlen /= 2; + objid = xtrymalloc (objidlen); + if (!objid) + return gpg_error_from_syserror (); + for (s=certid, i=0; i < objidlen; i++, s+=2) + objid[i] = xtoi_2 (s); + } + *r_objid = objid; *r_objidlen = objidlen; return 0; @@ -595,9 +674,9 @@ prkdf_object_from_keyidstr (app_t app, const char *keyidstr, A0 06 30 04 04 02 60 34 = Private Keys A4 06 30 04 04 02 60 35 = Certificates - A5 06 30 04 04 02 60 36 = TrustedCertificates - A7 06 30 04 04 02 60 37 = DataObjects - A8 06 30 04 04 02 60 38 = AuthObjects + A5 06 30 04 04 02 60 36 = Trusted Certificates + A7 06 30 04 04 02 60 37 = Data Objects + A8 06 30 04 04 02 60 38 = Auth Objects These are all PathOrObjects using the path CHOICE element. The paths are octet strings of length 2. Using this Path CHOICE @@ -608,9 +687,10 @@ read_ef_odf (app_t app, unsigned short odf_fid) { gpg_error_t err; unsigned char *buffer, *p; - size_t buflen; + size_t buflen, n; unsigned short value; size_t offset; + unsigned short home_df = 0; err = select_and_read_binary (app->slot, odf_fid, "ODF", &buffer, &buflen); if (err) @@ -618,10 +698,12 @@ read_ef_odf (app_t app, unsigned short odf_fid) if (buflen < 8) { - log_error ("error: ODF too short\n"); + log_error ("p15: error: ODF too short\n"); xfree (buffer); return gpg_error (GPG_ERR_INV_OBJ); } + + home_df = app->app_local->home_df; p = buffer; while (buflen && *p && *p != 0xff) { @@ -634,17 +716,35 @@ read_ef_odf (app_t app, unsigned short odf_fid) else if ( buflen >= 12 && (p[0] & 0xf0) == 0xA0 && !memcmp (p+1, "\x0a\x30\x08\x04\x06\x3F\x00", 7) - && app->app_local->home_df == ((p[8]<<8)|p[9]) ) + && (!home_df || home_df == ((p[8]<<8)|p[9])) ) { + /* If we do not know the home DF, we take it from the first + * ODF object. Here are sample values: + * a0 0a 30 08 0406 3f00 5015 4401 + * a1 0a 30 08 0406 3f00 5015 4411 + * a4 0a 30 08 0406 3f00 5015 4441 + * a5 0a 30 08 0406 3f00 5015 4451 + * a8 0a 30 08 0406 3f00 5015 4481 + * 00000000 */ + if (!home_df) + { + home_df = ((p[8]<<8)|p[9]); + app->app_local->home_df = home_df; + log_info ("p15: application directory detected as 0x%04hX\n", + home_df); + /* We assume that direct path selection is possible. */ + app->app_local->direct_path_selection = 1; + } + /* We only allow a full path if all files are at the same - level and below the home directory. The extend this we + level and below the home directory. To extend this we would need to make use of new data type capable of keeping a full path. */ offset = 10; } else { - log_error ("ODF format is not supported by us\n"); + log_printhex (p, buflen, "p15: ODF format not supported:"); xfree (buffer); return gpg_error (GPG_ERR_INV_OBJ); } @@ -663,7 +763,8 @@ read_ef_odf (app_t app, unsigned short odf_fid) } if (value) { - log_error ("duplicate object type %d in ODF ignored\n",(p[0]&0x0f)); + log_error ("p15: duplicate object type %d in ODF ignored\n", + (p[0]&0x0f)); continue; } value = ((p[offset] << 8) | p[offset+1]); @@ -679,7 +780,8 @@ read_ef_odf (app_t app, unsigned short odf_fid) case 7: app->app_local->odf.data_objects = value; break; case 8: app->app_local->odf.auth_objects = value; break; default: - log_error ("unknown object type %d in ODF ignored\n", (p[0]&0x0f)); + log_error ("p15: unknown object type %d in ODF ignored\n", + (p[0]&0x0f)); } offset += 2; @@ -690,8 +792,16 @@ read_ef_odf (app_t app, unsigned short odf_fid) } if (buflen) - log_info ("warning: %u bytes of garbage detected at end of ODF\n", - (unsigned int)buflen); + { + /* Print a warning if non-null garbage is left over. */ + for (n=0; n < buflen && !p[n]; n++) + ; + if (n < buflen) + { + log_info ("p15: warning: garbage detected at end of ODF: "); + log_printhex (p, buflen, ""); + } + } xfree (buffer); return 0; @@ -861,7 +971,8 @@ read_ef_prkdf (app_t app, unsigned short fid, prkdf_object_t *result) err = gpg_error (GPG_ERR_INV_OBJ); if (err) { - log_error ("error parsing PrKDF record: %s\n", gpg_strerror (err)); + log_error ("p15: error parsing PrKDF record: %s\n", + gpg_strerror (err)); goto leave; } pp = p; @@ -1202,38 +1313,41 @@ read_ef_prkdf (app_t app, unsigned short fid, prkdf_object_t *result) } - log_debug ("PrKDF %04hX: id=", fid); - for (i=0; i < prkdf->objidlen; i++) - log_printf ("%02X", prkdf->objid[i]); - log_printf (" path="); - for (i=0; i < prkdf->pathlen; i++) - log_printf ("%04hX", prkdf->path[i]); - if (prkdf->have_off) - log_printf ("[%lu/%lu]", prkdf->off, prkdf->len); - if (prkdf->authid) - { - log_printf (" authid="); - for (i=0; i < prkdf->authidlen; i++) - log_printf ("%02X", prkdf->authid[i]); - } - if (prkdf->key_reference_valid) - log_printf (" keyref=0x%02lX", prkdf->key_reference); - log_printf (" usage="); - s = ""; - if (prkdf->usageflags.encrypt) log_printf ("%sencrypt", s), s = ","; - if (prkdf->usageflags.decrypt) log_printf ("%sdecrypt", s), s = ","; - if (prkdf->usageflags.sign ) log_printf ("%ssign", s), s = ","; - if (prkdf->usageflags.sign_recover) - log_printf ("%ssign_recover", s), s = ","; - if (prkdf->usageflags.wrap ) log_printf ("%swrap", s), s = ","; - if (prkdf->usageflags.unwrap ) log_printf ("%sunwrap", s), s = ","; - if (prkdf->usageflags.verify ) log_printf ("%sverify", s), s = ","; - if (prkdf->usageflags.verify_recover) - log_printf ("%sverify_recover", s), s = ","; - if (prkdf->usageflags.derive ) log_printf ("%sderive", s), s = ","; - if (prkdf->usageflags.non_repudiation) - log_printf ("%snon_repudiation", s), s = ","; - log_printf ("\n"); + if (opt.verbose) + { + log_info ("p15: PrKDF %04hX: id=", fid); + for (i=0; i < prkdf->objidlen; i++) + log_printf ("%02X", prkdf->objid[i]); + log_printf (" path="); + for (i=0; i < prkdf->pathlen; i++) + log_printf ("%s%04hX", i?"/":"",prkdf->path[i]); + if (prkdf->have_off) + log_printf ("[%lu/%lu]", prkdf->off, prkdf->len); + if (prkdf->authid) + { + log_printf (" authid="); + for (i=0; i < prkdf->authidlen; i++) + log_printf ("%02X", prkdf->authid[i]); + } + if (prkdf->key_reference_valid) + log_printf (" keyref=0x%02lX", prkdf->key_reference); + log_info ("p15: usage="); + s = ""; + if (prkdf->usageflags.encrypt) log_printf ("%sencrypt", s), s = ","; + if (prkdf->usageflags.decrypt) log_printf ("%sdecrypt", s), s = ","; + if (prkdf->usageflags.sign ) log_printf ("%ssign", s), s = ","; + if (prkdf->usageflags.sign_recover) + log_printf ("%ssign_recover", s), s = ","; + if (prkdf->usageflags.wrap ) log_printf ("%swrap", s), s = ","; + if (prkdf->usageflags.unwrap ) log_printf ("%sunwrap", s), s = ","; + if (prkdf->usageflags.verify ) log_printf ("%sverify", s), s = ","; + if (prkdf->usageflags.verify_recover) + log_printf ("%sverify_recover", s), s = ","; + if (prkdf->usageflags.derive ) log_printf ("%sderive", s), s = ","; + if (prkdf->usageflags.non_repudiation) + log_printf ("%snon_repudiation", s), s = ","; + log_printf ("\n"); + } /* Put it into the list. */ prkdf->next = prkdflist; @@ -1242,7 +1356,7 @@ read_ef_prkdf (app_t app, unsigned short fid, prkdf_object_t *result) continue; /* Ready. */ parse_error: - log_error ("error parsing PrKDF record (%d): %s - skipped\n", + log_error ("p15: error parsing PrKDF record (%d): %s - skipped\n", where, errstr? errstr : gpg_strerror (err)); if (prkdf) { @@ -1309,7 +1423,7 @@ read_ef_cdf (app_t app, unsigned short fid, cdf_object_t *result) err = gpg_error (GPG_ERR_INV_OBJ); if (err) { - log_error ("error parsing CDF record: %s\n", gpg_strerror (err)); + log_error ("p15: error parsing CDF record: %s\n", gpg_strerror (err)); goto leave; } pp = p; @@ -1470,15 +1584,18 @@ read_ef_cdf (app_t app, unsigned short fid, cdf_object_t *result) cdf->len = ul; } - log_debug ("CDF %04hX: id=", fid); - for (i=0; i < cdf->objidlen; i++) - log_printf ("%02X", cdf->objid[i]); - log_printf (" path="); - for (i=0; i < cdf->pathlen; i++) - log_printf ("%04hX", cdf->path[i]); - if (cdf->have_off) - log_printf ("[%lu/%lu]", cdf->off, cdf->len); - log_printf ("\n"); + if (opt.verbose) + { + log_info ("p15: CDF %04hX: id=", fid); + for (i=0; i < cdf->objidlen; i++) + log_printf ("%02X", cdf->objid[i]); + log_printf (" path="); + for (i=0; i < cdf->pathlen; i++) + log_printf ("%s%04hX", i?"/":"", cdf->path[i]); + if (cdf->have_off) + log_printf ("[%lu/%lu]", cdf->off, cdf->len); + log_printf ("\n"); + } /* Put it into the list. */ cdf->next = cdflist; @@ -1487,7 +1604,7 @@ read_ef_cdf (app_t app, unsigned short fid, cdf_object_t *result) continue; /* Ready. */ parse_error: - log_error ("error parsing CDF record (%d): %s - skipped\n", + log_error ("p15: error parsing CDF record (%d): %s - skipped\n", where, errstr? errstr : gpg_strerror (err)); xfree (cdf); err = 0; @@ -1583,7 +1700,8 @@ read_ef_aodf (app_t app, unsigned short fid, aodf_object_t *result) err = gpg_error (GPG_ERR_INV_OBJ); if (err) { - log_error ("error parsing AODF record: %s\n", gpg_strerror (err)); + log_error ("p15: error parsing AODF record: %s\n", + gpg_strerror (err)); goto leave; } pp = p; @@ -1595,6 +1713,7 @@ read_ef_aodf (app_t app, unsigned short fid, aodf_object_t *result) aodf = xtrycalloc (1, sizeof *aodf); if (!aodf) goto no_core; + aodf->fid = fid; /* Parse the commonObjectAttributes. */ where = __LINE__; @@ -2057,73 +2176,77 @@ read_ef_aodf (app_t app, unsigned short fid, aodf_object_t *result) extensions of pkcs#15. */ ready: - log_debug ("AODF %04hX: id=", fid); - for (i=0; i < aodf->objidlen; i++) - log_printf ("%02X", aodf->objid[i]); - if (aodf->authid) - { - log_printf (" authid="); - for (i=0; i < aodf->authidlen; i++) - log_printf ("%02X", aodf->authid[i]); - } - log_printf (" flags="); - s = ""; - if (aodf->pinflags.case_sensitive) - log_printf ("%scase_sensitive", s), s = ","; - if (aodf->pinflags.local) - log_printf ("%slocal", s), s = ","; - if (aodf->pinflags.change_disabled) - log_printf ("%schange_disabled", s), s = ","; - if (aodf->pinflags.unblock_disabled) - log_printf ("%sunblock_disabled", s), s = ","; - if (aodf->pinflags.initialized) - log_printf ("%sinitialized", s), s = ","; - if (aodf->pinflags.needs_padding) - log_printf ("%sneeds_padding", s), s = ","; - if (aodf->pinflags.unblocking_pin) - log_printf ("%sunblocking_pin", s), s = ","; - if (aodf->pinflags.so_pin) - log_printf ("%sso_pin", s), s = ","; - if (aodf->pinflags.disable_allowed) - log_printf ("%sdisable_allowed", s), s = ","; - if (aodf->pinflags.integrity_protected) - log_printf ("%sintegrity_protected", s), s = ","; - if (aodf->pinflags.confidentiality_protected) - log_printf ("%sconfidentiality_protected", s), s = ","; - if (aodf->pinflags.exchange_ref_data) - log_printf ("%sexchange_ref_data", s), s = ","; - { - char numbuf[50]; - switch (aodf->pintype) + if (opt.verbose) + { + log_info ("p15: AODF %04hX: id=", fid); + for (i=0; i < aodf->objidlen; i++) + log_printf ("%02X", aodf->objid[i]); + if (aodf->authid) + { + log_printf (" authid="); + for (i=0; i < aodf->authidlen; i++) + log_printf ("%02X", aodf->authid[i]); + } + if (aodf->pin_reference_valid) + log_printf (" pinref=0x%02lX", aodf->pin_reference); + if (aodf->pathlen) + { + log_printf (" path="); + for (i=0; i < aodf->pathlen; i++) + log_printf ("%s%04hX", i?"/":"",aodf->path[i]); + if (aodf->have_off) + log_printf ("[%lu/%lu]", aodf->off, aodf->len); + } + log_printf (" min=%lu", aodf->min_length); + log_printf (" stored=%lu", aodf->stored_length); + if (aodf->max_length_valid) + log_printf (" max=%lu", aodf->max_length); + if (aodf->pad_char_valid) + log_printf (" pad=0x%02x", aodf->pad_char); + + log_info ("p15: flags="); + s = ""; + if (aodf->pinflags.case_sensitive) + log_printf ("%scase_sensitive", s), s = ","; + if (aodf->pinflags.local) + log_printf ("%slocal", s), s = ","; + if (aodf->pinflags.change_disabled) + log_printf ("%schange_disabled", s), s = ","; + if (aodf->pinflags.unblock_disabled) + log_printf ("%sunblock_disabled", s), s = ","; + if (aodf->pinflags.initialized) + log_printf ("%sinitialized", s), s = ","; + if (aodf->pinflags.needs_padding) + log_printf ("%sneeds_padding", s), s = ","; + if (aodf->pinflags.unblocking_pin) + log_printf ("%sunblocking_pin", s), s = ","; + if (aodf->pinflags.so_pin) + log_printf ("%sso_pin", s), s = ","; + if (aodf->pinflags.disable_allowed) + log_printf ("%sdisable_allowed", s), s = ","; + if (aodf->pinflags.integrity_protected) + log_printf ("%sintegrity_protected", s), s = ","; + if (aodf->pinflags.confidentiality_protected) + log_printf ("%sconfidentiality_protected", s), s = ","; + if (aodf->pinflags.exchange_ref_data) + log_printf ("%sexchange_ref_data", s), s = ","; { - case PIN_TYPE_BCD: s = "bcd"; break; - case PIN_TYPE_ASCII_NUMERIC: s = "ascii-numeric"; break; - case PIN_TYPE_UTF8: s = "utf8"; break; - case PIN_TYPE_HALF_NIBBLE_BCD: s = "half-nibble-bcd"; break; - case PIN_TYPE_ISO9564_1: s = "iso9564-1"; break; - default: - sprintf (numbuf, "%lu", (unsigned long)aodf->pintype); - s = numbuf; + char numbuf[50]; + switch (aodf->pintype) + { + case PIN_TYPE_BCD: s = "bcd"; break; + case PIN_TYPE_ASCII_NUMERIC: s = "ascii-numeric"; break; + case PIN_TYPE_UTF8: s = "utf8"; break; + case PIN_TYPE_HALF_NIBBLE_BCD: s = "half-nibble-bcd"; break; + case PIN_TYPE_ISO9564_1: s = "iso9564-1"; break; + default: + sprintf (numbuf, "%lu", (unsigned long)aodf->pintype); + s = numbuf; + } + log_printf (" type=%s", s); } - log_printf (" type=%s", s); - } - log_printf (" min=%lu", aodf->min_length); - log_printf (" stored=%lu", aodf->stored_length); - if (aodf->max_length_valid) - log_printf (" max=%lu", aodf->max_length); - if (aodf->pad_char_valid) - log_printf (" pad=0x%02x", aodf->pad_char); - if (aodf->pin_reference_valid) - log_printf (" pinref=0x%02lX", aodf->pin_reference); - if (aodf->pathlen) - { - log_printf (" path="); - for (i=0; i < aodf->pathlen; i++) - log_printf ("%04hX", aodf->path[i]); - if (aodf->have_off) - log_printf ("[%lu/%lu]", aodf->off, aodf->len); + log_printf ("\n"); } - log_printf ("\n"); /* Put it into the list. */ aodf->next = aodflist; @@ -2137,7 +2260,7 @@ read_ef_aodf (app_t app, unsigned short fid, aodf_object_t *result) goto leave; parse_error: - log_error ("error parsing AODF record (%d): %s - skipped\n", + log_error ("p15: error parsing AODF record (%d): %s - skipped\n", where, errstr? errstr : gpg_strerror (err)); err = 0; release_aodf_object (aodf); @@ -2153,6 +2276,62 @@ read_ef_aodf (app_t app, unsigned short fid, aodf_object_t *result) } +/* Print the BIT STRING with the tokenflags from the TokenInfo. */ +static void +print_tokeninfo_tokenflags (const unsigned char *der, size_t derlen) +{ + unsigned int bits, mask; + int i, unused, full; + int other = 0; + + if (!derlen) + { + log_printf (" [invalid object]"); + return; + } + + unused = *der++; derlen--; + if ((!derlen && unused) || unused/8 > derlen) + { + log_printf (" [wrong encoding]"); + return; + } + full = derlen - (unused+7)/8; + unused %= 8; + mask = 0; + for (i=1; unused; i <<= 1, unused--) + mask |= i; + + /* First octet */ + if (derlen) + { + bits = *der++; derlen--; + if (full) + full--; + else + { + bits &= ~mask; + mask = 0; + } + } + else + bits = 0; + if ((bits & 0x80)) log_printf (" readonly"); + if ((bits & 0x40)) log_printf (" loginRequired"); + if ((bits & 0x20)) log_printf (" prnGeneration"); + if ((bits & 0x10)) log_printf (" eidCompliant"); + if ((bits & 0x08)) other = 1; + if ((bits & 0x04)) other = 1; + if ((bits & 0x02)) other = 1; + if ((bits & 0x01)) other = 1; + + /* Next octet. */ + if (derlen) + other = 1; + + if (other) + log_printf (" [unknown]"); +} @@ -2216,6 +2395,10 @@ read_ef_tokeninfo (app_t app) int class, tag, constructed, ndef; unsigned long ul; + xfree (app->app_local->manufacturer_id); + app->app_local->manufacturer_id = NULL; + app->app_local->card_product = CARD_PRODUCT_UNKNOWN; + err = select_and_read_binary (app->slot, 0x5032, "TokenInfo", &buffer, &buflen); if (err) @@ -2230,7 +2413,7 @@ read_ef_tokeninfo (app_t app) err = gpg_error (GPG_ERR_INV_OBJ); if (err) { - log_error ("error parsing TokenInfo: %s\n", gpg_strerror (err)); + log_error ("p15: error parsing TokenInfo: %s\n", gpg_strerror (err)); goto leave; } @@ -2252,11 +2435,13 @@ read_ef_tokeninfo (app_t app) } if (ul) { - log_error ("invalid version %lu in TokenInfo\n", ul); + log_error ("p15: invalid version %lu in TokenInfo\n", ul); err = gpg_error (GPG_ERR_INV_OBJ); goto leave; } + if (opt.verbose) + log_info ("p15: TokenInfo:\n"); /* serialNumber. */ err = parse_ber_header (&p, &n, &class, &tag, &constructed, &ndef, &objlen, &hdrlen); @@ -2274,7 +2459,68 @@ read_ef_tokeninfo (app_t app) } memcpy (app->app_local->serialno, p, objlen); app->app_local->serialnolen = objlen; - log_printhex ("Serialnumber from EF(TokenInfo) is:", p, objlen); + if (opt.verbose) + { + /* (We use a separate log_info to avoid the "DBG:" prefix.) */ + log_info ("p15: serialNumber .: "); + log_printhex (p, objlen, ""); + } + p += objlen; + n -= objlen; + + /* Is there an optional manufacturerID? */ + err = parse_ber_header (&p, &n, &class, &tag, &constructed, + &ndef, &objlen, &hdrlen); + if (!err && (objlen > n || !objlen)) + err = gpg_error (GPG_ERR_INV_OBJ); + if (err) + goto leave; + if (class == CLASS_UNIVERSAL && tag == TAG_UTF8_STRING) + { + if (opt.verbose) + log_info ("p15: manufacturerID: %.*s\n", (int)objlen, p); + app->app_local->manufacturer_id = percent_data_escape (0, NULL, + p, objlen); + p += objlen; + n -= objlen; + /* Get next TLV. */ + err = parse_ber_header (&p, &n, &class, &tag, &constructed, + &ndef, &objlen, &hdrlen); + if (!err && (objlen > n || !objlen)) + err = gpg_error (GPG_ERR_INV_OBJ); + if (err) + goto leave; + } + if (class == CLASS_CONTEXT && tag == 0) + { + if (opt.verbose) + log_info ("p15: label ........: %.*s\n", (int)objlen, p); + if (objlen > 15 && !memcmp (p, "D-TRUST Card V3", 15) + && app->app_local->card_type == CARD_TYPE_CARDOS_50) + app->app_local->card_product = CARD_PRODUCT_DTRUST; + + p += objlen; + n -= objlen; + /* Get next TLV. */ + err = parse_ber_header (&p, &n, &class, &tag, &constructed, + &ndef, &objlen, &hdrlen); + if (!err && (objlen > n || !objlen)) + err = gpg_error (GPG_ERR_INV_OBJ); + if (err) + goto leave; + } + /* The next is the mandatory tokenflags object. */ + if (class == CLASS_UNIVERSAL && tag == TAG_BIT_STRING) + { + if (opt.verbose) + { + log_info ("p15: tokenflags ...:"); + print_tokeninfo_tokenflags (p, objlen); + log_printf ("\n"); + } + p += objlen; + n -= objlen; + } leave: xfree (buffer); @@ -2386,21 +2632,31 @@ send_certinfo (app_t app, ctrl_t ctrl, const char *certtype, /* Get the keygrip of the private key object PRKDF. On success the - keygrip gets returned in the caller provided 41 byte buffer - R_GRIPSTR. */ + * keygrip, the algo and the length are stored in the KEYGRIP, + * KEYALGO, and KEYNBITS fields of the PRKDF object. */ static gpg_error_t -keygripstr_from_prkdf (app_t app, prkdf_object_t prkdf, char *r_gripstr) +keygrip_from_prkdf (app_t app, prkdf_object_t prkdf) { gpg_error_t err; cdf_object_t cdf; unsigned char *der; size_t derlen; ksba_cert_t cert; + gcry_sexp_t s_pkey = NULL; + + /* Easy if we got a cached version. */ + if (prkdf->keygrip_valid) + return 0; + + xfree (prkdf->common_name); + prkdf->common_name = NULL; + xfree (prkdf->serial_number); + prkdf->serial_number = NULL; /* FIXME: We should check whether a public key directory file and a matching public key for PRKDF is available. This should make extraction of the key much easier. My current test card doesn't - have one, so we can only use the fallback solution bu looking for + have one, so we can only use the fallback solution by looking for a matching certificate and extract the key from there. */ /* Look for a matching certificate. A certificate matches if the Id @@ -2420,67 +2676,172 @@ keygripstr_from_prkdf (app_t app, prkdf_object_t prkdf, char *r_gripstr) && !memcmp (cdf->objid, prkdf->objid, prkdf->objidlen)) break; if (!cdf) - return gpg_error (GPG_ERR_NOT_FOUND); + { + err = gpg_error (GPG_ERR_NOT_FOUND); + goto leave; + } err = readcert_by_cdf (app, cdf, &der, &derlen); if (err) - return err; + goto leave; err = ksba_cert_new (&cert); if (!err) err = ksba_cert_init_from_mem (cert, der, derlen); xfree (der); if (!err) - err = app_help_get_keygrip_string (cert, r_gripstr); + err = app_help_get_keygrip_string (cert, prkdf->keygrip, &s_pkey); + if (!err) + { + /* Try to get the CN and the SerialNumber from the certificate; + * we use a very simple approach here which should work in many + * cases. Eventually we should add a rfc-2253 parser into + * libksba to make it easier to parse such a string. + * + * First example string: + * "CN=Otto Schily,O=Miniluv,C=DE" + * Second example string: + * "2.5.4.5=#445452323030303236333531,2.5.4.4=#4B6F6368," + * "2.5.4.42=#5765726E6572,CN=Werner Koch,OU=For testing" + * " purposes only!,O=Testorganisation,C=DE" + */ + char *dn = ksba_cert_get_subject (cert, 0); + if (dn) + { + char *p, *pend, *buf; + + p = strstr (dn, "CN="); + if (p && (p==dn || p[-1] == ',')) + { + p += 3; + if (!(pend = strchr (p, ','))) + pend = p + strlen (p); + if (pend && pend > p + && (prkdf->common_name = xtrymalloc ((pend - p) + 1))) + { + memcpy (prkdf->common_name, p, pend-p); + prkdf->common_name[pend-p] = 0; + } + } + p = strstr (dn, "2.5.4.5=#"); /* OID of the SerialNumber */ + if (p && (p==dn || p[-1] == ',')) + { + p += 9; + if (!(pend = strchr (p, ','))) + pend = p + strlen (p); + if (pend && pend > p + && (buf = xtrymalloc ((pend - p) + 1))) + { + memcpy (buf, p, pend-p); + buf[pend-p] = 0; + if (!hex2str (buf, buf, strlen (buf)+1, NULL)) + xfree (buf); /* Invalid hex encoding. */ + else + prkdf->serial_number = buf; + } + } + ksba_free (dn); + } + } + ksba_cert_release (cert); + if (err) + goto leave; + + prkdf->keyalgo = get_pk_algo_from_key (s_pkey); + if (!prkdf->keyalgo) + { + err = gpg_error (GPG_ERR_PUBKEY_ALGO); + goto leave; + } + + prkdf->keynbits = gcry_pk_get_nbits (s_pkey); + if (!prkdf->keynbits) + { + err = gpg_error (GPG_ERR_PUBKEY_ALGO); + goto leave; + } + + prkdf->keygrip_valid = 1; /* Yeah, got everything. */ + leave: + gcry_sexp_release (s_pkey); return err; } +/* Return a malloced keyref string for PRKDF. Returns NULL on + * malloc failure. */ +static char * +keyref_from_prkdf (app_t app, prkdf_object_t prkdf) +{ + char *buf, *p; + + buf = xtrymalloc (4 + 5 + prkdf->objidlen*2 + 1); + if (!buf) + return NULL; + p = stpcpy (buf, "P15"); + if (app->app_local->home_df) + { + snprintf (p, 6, "-%04X", + (unsigned int)(app->app_local->home_df & 0xffff)); + p += 5; + } + p = stpcpy (p, "."); + bin2hex (prkdf->objid, prkdf->objidlen, p); + return buf; +} /* Helper to do_learn_status: Send information about all known keypairs back. FIXME: much code duplication from send_certinfo(). */ static gpg_error_t -send_keypairinfo (app_t app, ctrl_t ctrl, prkdf_object_t keyinfo) +send_keypairinfo (app_t app, ctrl_t ctrl, prkdf_object_t prkdf) { gpg_error_t err; - for (; keyinfo; keyinfo = keyinfo->next) + for (; prkdf; prkdf = prkdf->next) { - char gripstr[40+1]; - char *buf, *p; + char *buf; int j; - buf = xtrymalloc (9 + keyinfo->objidlen*2 + 1); + buf = keyref_from_prkdf (app, prkdf); if (!buf) return gpg_error_from_syserror (); - p = stpcpy (buf, "P15"); - if (app->app_local->home_df) - { - snprintf (p, 6, "-%04X", - (unsigned int)(app->app_local->home_df & 0xffff)); - p += 5; - } - p = stpcpy (p, "."); - bin2hex (keyinfo->objid, keyinfo->objidlen, p); - err = keygripstr_from_prkdf (app, keyinfo, gripstr); + err = keygrip_from_prkdf (app, prkdf); if (err) { - log_error ("can't get keygrip from "); - for (j=0; j < keyinfo->pathlen; j++) - log_printf ("%04hX", keyinfo->path[j]); + log_error ("p15: error getting keygrip from "); + for (j=0; j < prkdf->pathlen; j++) + log_printf ("%s%04hX", j?"/":"", prkdf->path[j]); log_printf (": %s\n", gpg_strerror (err)); } else { - assert (strlen (gripstr) == 40); + char usage[5]; + size_t usagelen = 0; + + if (prkdf->usageflags.sign + || prkdf->usageflags.sign_recover + || prkdf->usageflags.non_repudiation) + usage[usagelen++] = 's'; + if (prkdf->usageflags.sign + || prkdf->usageflags.sign_recover) + usage[usagelen++] = 'c'; + if (prkdf->usageflags.decrypt + || prkdf->usageflags.unwrap) + usage[usagelen++] = 'e'; + if (prkdf->usageflags.sign + || prkdf->usageflags.sign_recover) + usage[usagelen++] = 'a'; + + log_assert (strlen (prkdf->keygrip) == 40); send_status_info (ctrl, "KEYPAIRINFO", - gripstr, 40, + prkdf->keygrip, 2*KEYGRIP_LEN, buf, strlen (buf), + usage, usagelen, NULL, (size_t)0); } xfree (buf); @@ -2500,7 +2861,10 @@ do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags) err = 0; else { - err = send_certinfo (app, ctrl, "100", app->app_local->certificate_info); + err = do_getattr (app, ctrl, "MANUFACTURER"); + if (!err) + err = send_certinfo (app, ctrl, "100", + app->app_local->certificate_info); if (!err) err = send_certinfo (app, ctrl, "101", app->app_local->trusted_certificate_info); @@ -2553,14 +2917,18 @@ readcert_by_cdf (app_t app, cdf_object_t cdf, if (err) goto leave; - err = iso7816_read_binary (app->slot, cdf->off, cdf->len, &buffer, &buflen); + err = iso7816_read_binary_ext (app_get_slot (app), 1, cdf->off, cdf->len, + &buffer, &buflen); if (!err && (!buflen || *buffer == 0xff)) err = gpg_error (GPG_ERR_NOT_FOUND); if (err) { - log_error ("error reading certificate with Id "); + log_error ("p15: error reading certificate id="); for (i=0; i < cdf->objidlen; i++) log_printf ("%02X", cdf->objid[i]); + log_printf (" at "); + for (i=0; i < cdf->pathlen; i++) + log_printf ("%s%04hX", i? "/":"", cdf->path[i]); log_printf (": %s\n", gpg_strerror (err)); goto leave; } @@ -2666,37 +3034,42 @@ static gpg_error_t do_getattr (app_t app, ctrl_t ctrl, const char *name) { gpg_error_t err; + prkdf_object_t prkdf; - if (!strcmp (name, "$AUTHKEYID")) + if (!strcmp (name, "$AUTHKEYID") + || !strcmp (name, "$ENCRKEYID") + || !strcmp (name, "$SIGNKEYID")) { - char *buf, *p; - prkdf_object_t prkdf; + char *buf; - /* We return the ID of the first private keycapable of - signing. */ + /* We return the ID of the first private key capable of the + * requested action. Note that we do not yet return + * non_repudiation keys for $SIGNKEYID because our D-Trust + * testcard uses rsaPSS, which is not supported by gpgsm and not + * covered by the VS-NfD approval. */ for (prkdf = app->app_local->private_key_info; prkdf; prkdf = prkdf->next) - if (prkdf->usageflags.sign) - break; + { + if (name[1] == 'A' && (prkdf->usageflags.sign + || prkdf->usageflags.sign_recover)) + break; + else if (name[1] == 'E' && (prkdf->usageflags.decrypt + || prkdf->usageflags.unwrap)) + break; + else if (name[1] == 'S' && (prkdf->usageflags.sign + || prkdf->usageflags.sign_recover)) + break; + } if (prkdf) { - buf = xtrymalloc (9 + prkdf->objidlen*2 + 1); + buf = keyref_from_prkdf (app, prkdf); if (!buf) return gpg_error_from_syserror (); - p = stpcpy (buf, "P15"); - if (app->app_local->home_df) - { - snprintf (p, 6, "-%04X", - (unsigned int)(app->app_local->home_df & 0xffff)); - p += 5; - } - p = stpcpy (p, "."); - bin2hex (prkdf->objid, prkdf->objidlen, p); send_status_info (ctrl, name, buf, strlen (buf), NULL, 0); xfree (buf); - return 0; } + return 0; } else if (!strcmp (name, "$DISPSERIALNO")) { @@ -2716,7 +3089,8 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name) err = iso7816_read_binary (app->slot, 0, 0, &buffer, &buflen); if (err) { - log_error ("error accessing EF(ID): %s\n", gpg_strerror (err)); + log_error ("p15: error accessing EF(ID): %s\n", + gpg_strerror (err)); return err; } @@ -2736,7 +3110,41 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name) } xfree (buffer); } - + else + { + /* We use the first private key object which has a serial + * number set. If none was found, we parse the first + * object and see whether this has then a serial number. */ + for (prkdf = app->app_local->private_key_info; prkdf; + prkdf = prkdf->next) + if (prkdf->serial_number) + break; + if (!prkdf && app->app_local->private_key_info) + { + prkdf = app->app_local->private_key_info; + keygrip_from_prkdf (app, prkdf); + if (!prkdf->serial_number) + prkdf = NULL; + } + if (prkdf) + { + char *sn = get_dispserialno (app, prkdf); + /* Unless there is a bogus S/N in the cert we should + * have a suitable one from the cert here now. */ + err = send_status_printf (ctrl, name, "%s", sn); + xfree (sn); + return err; + } + } + /* No abbreviated serial number. */ + } + else if (!strcmp (name, "MANUFACTURER")) + { + if (app->app_local->manufacturer_id) + return send_status_printf (ctrl, "MANUFACTURER", "0 %s", + app->app_local->manufacturer_id); + else + return 0; } return gpg_error (GPG_ERR_INV_NAME); } @@ -2761,7 +3169,7 @@ micardo_mse (app_t app, unsigned short fid) err = iso7816_select_file (app->slot, 0x0013, 0); if (err) { - log_error ("error reading EF_keyD: %s\n", gpg_strerror (err)); + log_error ("p15: error reading EF_keyD: %s\n", gpg_strerror (err)); return err; } @@ -2777,11 +3185,15 @@ micardo_mse (app_t app, unsigned short fid) break; /* ready */ if (err) { - log_error ("error reading EF_keyD record: %s\n", + log_error ("p15: error reading EF_keyD record: %s\n", gpg_strerror (err)); return err; } - log_printhex ("keyD record:", buffer, buflen); + if (opt.verbose) + { + log_info (buffer, buflen, "p15: keyD record: "); + log_printhex (buffer, buflen, ""); + } p = find_tlv (buffer, buflen, 0x83, &n); if (p && n == 4 && ((p[2]<<8)|p[3]) == fid) { @@ -2803,7 +3215,7 @@ micardo_mse (app_t app, unsigned short fid) } if (se_num == -1) { - log_error ("CRT for keyfile %04hX not found\n", fid); + log_error ("p15: CRT for keyfile %04hX not found\n", fid); return gpg_error (GPG_ERR_NOT_FOUND); } @@ -2814,7 +3226,7 @@ micardo_mse (app_t app, unsigned short fid) err = iso7816_manage_security_env (app->slot, 0xf3, se_num, NULL, 0); if (err) { - log_error ("restoring SE to %d failed: %s\n", + log_error ("p15: restoring SE to %d failed: %s\n", se_num, gpg_strerror (err)); return err; } @@ -2829,7 +3241,7 @@ micardo_mse (app_t app, unsigned short fid) err = iso7816_manage_security_env (app->slot, 0x41, 0xb6, msebuf, 5); if (err) { - log_error ("setting SE to reference file %04hX failed: %s\n", + log_error ("p15: setting SE to reference file %04hX failed: %s\n", refdata, gpg_strerror (err)); return err; } @@ -2838,6 +3250,372 @@ micardo_mse (app_t app, unsigned short fid) +/* Prepare the verification of the PIN for the key PRKDF by checking + * the AODF and selecting the key file. KEYREF is used for error + * messages. */ +static gpg_error_t +prepare_verify_pin (app_t app, const char *keyref, + prkdf_object_t prkdf, aodf_object_t aodf) +{ + gpg_error_t err; + int i; + + if (opt.verbose) + { + log_info ("p15: using AODF %04hX id=", aodf->fid); + for (i=0; i < aodf->objidlen; i++) + log_printf ("%02X", aodf->objid[i]); + log_printf ("\n"); + } + + if (aodf->authid && opt.verbose) + log_info ("p15: PIN is controlled by another authentication token\n"); + + if (aodf->pinflags.integrity_protected + || aodf->pinflags.confidentiality_protected) + { + log_error ("p15: " + "PIN verification requires unsupported protection method\n"); + return gpg_error (GPG_ERR_BAD_PIN_METHOD); + } + if (!aodf->stored_length && aodf->pinflags.needs_padding) + { + log_error ("p15: " + "PIN verification requires padding but no length known\n"); + return gpg_error (GPG_ERR_INV_CARD); + } + + + if (app->app_local->card_product == CARD_PRODUCT_DTRUST) + { + /* According to our protocol analysis we need to select a + * special AID here. Before that the master file needs to be + * selected. (RID A000000167 is assigned to IBM) */ + static char const dtrust_aid[] = + { 0xA0, 0x00, 0x00, 0x01, 0x67, 0x45, 0x53, 0x49, 0x47, 0x4E }; + + err = iso7816_select_mf (app_get_slot (app)); + if (!err) + err = iso7816_select_application (app_get_slot (app), + dtrust_aid, sizeof dtrust_aid, 0); + if (err) + log_error ("p15: error selecting D-TRUST's AID for key %s: %s\n", + keyref, gpg_strerror (err)); + } + else + { + /* Standard case: Select the key file. Note that this may + * change the security environment thus we need to do it before + * PIN verification. */ + err = select_ef_by_path (app, prkdf->path, prkdf->pathlen); + if (err) + log_error ("p15: error selecting file for key %s: %s\n", + keyref, gpg_strerror (err)); + } + + return err; +} + + +static int +any_control_or_space (const char *string) +{ + const unsigned char *s; + + for (s = string; *string; string++) + if (*s <= 0x20 || *s >= 0x7f) + return 1; + return 0; +} + + +/* Return a malloced serial number to be shown to the user. PRKDF is + * used to get it from a certificate; PRKDF may be NULL. */ +static char * +get_dispserialno (app_t app, prkdf_object_t prkdf) +{ + char *serial; + + /* We prefer the SerialNumber RDN from the Subject-DN but we don't + * use it if it features a percent sign (special character in pin + * prompts) or has any control character. */ + if (prkdf && prkdf->serial_number && *prkdf->serial_number + && !strchr (prkdf->serial_number, '%') + && !any_control_or_space (prkdf->serial_number)) + { + serial = xtrystrdup (prkdf->serial_number); + } + else + { + serial = app_get_serialno (app); + } + return serial; +} + + +/* Return an allocated string to be used as prompt. Returns NULL on + * malloc error. */ +static char * +make_pin_prompt (app_t app, int remaining, const char *firstline, + prkdf_object_t prkdf) +{ + char *serial, *tmpbuf, *result; + + serial = get_dispserialno (app, prkdf); + + /* TRANSLATORS: Put a \x1f right before a colon. This can be + * used by pinentry to nicely align the names and values. Keep + * the %s at the start and end of the string. */ + result = xtryasprintf (_("%s" + "Number\x1f: %s%%0A" + "Holder\x1f: %s" + "%s"), + "\x1e", + serial, + prkdf->common_name? prkdf->common_name: "", + ""); + xfree (serial); + if (!result) + return NULL; /* Out of core. */ + + /* Append a "remaining attempts" info if needed. */ + if (remaining != -1 && remaining < 3) + { + char *rembuf; + + /* TRANSLATORS: This is the number of remaining attempts to + * enter a PIN. Use %%0A (double-percent,0A) for a linefeed. */ + rembuf = xtryasprintf (_("Remaining attempts: %d"), remaining); + if (rembuf) + { + tmpbuf = strconcat (firstline, "%0A%0A", result, + "%0A%0A", rembuf, NULL); + xfree (rembuf); + } + else + tmpbuf = NULL; + xfree (result); + result = tmpbuf; + } + else + { + tmpbuf = strconcat (firstline, "%0A%0A", result, NULL); + xfree (result); + result = tmpbuf; + } + + return result; +} + + +/* Given the private key object PRKDF and its authentication object + * AODF ask for the PIN and verify that PIN. */ +static gpg_error_t +verify_pin (app_t app, + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, + prkdf_object_t prkdf, aodf_object_t aodf) +{ + gpg_error_t err; + char *pinvalue; + size_t pinvaluelen; + const char *label; + const char *errstr; + const char *s; + int remaining; + int pin_reference; + int i; + + if (!aodf) + return 0; + + pin_reference = aodf->pin_reference_valid? aodf->pin_reference : 0; + + if (app->app_local->card_type == CARD_TYPE_CARDOS_50) + { + /* We know that this card supports a verify status check. Note + * that in contrast to PIV cards ISO7816_VERIFY_NOT_NEEDED is + * not supported. */ + remaining = iso7816_verify_status (app_get_slot (app), pin_reference); + if (remaining < 0) + remaining = -1; /* We don't care about the concrete error. */ + if (remaining < 3) + { + if (remaining >= 0) + log_info ("p15: PIN has %d attempts left\n", remaining); + /* On error or if less than 3 better ask. */ + prkdf->pin_verified = 0; + } + } + else + remaining = -1; /* Unknown. */ + + /* Check whether we already verified it. */ + if (prkdf->pin_verified) + return 0; /* Already done. */ + + if (prkdf->usageflags.non_repudiation + && (app->app_local->card_type == CARD_TYPE_BELPIC + || app->app_local->card_product == CARD_PRODUCT_DTRUST)) + label = _("||Please enter the PIN for the key to create " + "qualified signatures."); + else + label = _("||Please enter the PIN for the standard keys."); + + { + char *prompt = make_pin_prompt (app, remaining, label, prkdf); + if (!prompt) + err = gpg_error_from_syserror (); + else + err = pincb (pincb_arg, prompt, &pinvalue); + xfree (prompt); + } + if (err) + { + log_info ("p15: PIN callback returned error: %s\n", gpg_strerror (err)); + return err; + } + + /* We might need to cope with UTF8 things here. Not sure how + min_length etc. are exactly defined, for now we take them as + a plain octet count. */ + if (strlen (pinvalue) < aodf->min_length) + { + log_error ("p15: PIN is too short; minimum length is %lu\n", + aodf->min_length); + err = gpg_error (GPG_ERR_BAD_PIN); + } + else if (aodf->stored_length && strlen (pinvalue) > aodf->stored_length) + { + /* This would otherwise truncate the PIN silently. */ + log_error ("p15: PIN is too large; maximum length is %lu\n", + aodf->stored_length); + err = gpg_error (GPG_ERR_BAD_PIN); + } + else if (aodf->max_length_valid && strlen (pinvalue) > aodf->max_length) + { + log_error ("p15: PIN is too large; maximum length is %lu\n", + aodf->max_length); + err = gpg_error (GPG_ERR_BAD_PIN); + } + + if (err) + { + xfree (pinvalue); + return err; + } + + errstr = NULL; + err = 0; + switch (aodf->pintype) + { + case PIN_TYPE_BCD: + case PIN_TYPE_ASCII_NUMERIC: + for (s=pinvalue; digitp (s); s++) + ; + if (*s) + { + errstr = "Non-numeric digits found in PIN"; + err = gpg_error (GPG_ERR_BAD_PIN); + } + break; + case PIN_TYPE_UTF8: + break; + case PIN_TYPE_HALF_NIBBLE_BCD: + errstr = "PIN type Half-Nibble-BCD is not supported"; + break; + case PIN_TYPE_ISO9564_1: + errstr = "PIN type ISO9564-1 is not supported"; + break; + default: + errstr = "Unknown PIN type"; + break; + } + if (errstr) + { + log_error ("p15: can't verify PIN: %s\n", errstr); + xfree (pinvalue); + return err? err : gpg_error (GPG_ERR_BAD_PIN_METHOD); + } + + + if (aodf->pintype == PIN_TYPE_BCD ) + { + char *paddedpin; + int ndigits; + + for (ndigits=0, s=pinvalue; *s; ndigits++, s++) + ; + paddedpin = xtrymalloc (aodf->stored_length+1); + if (!paddedpin) + { + err = gpg_error_from_syserror (); + xfree (pinvalue); + return err; + } + + i = 0; + paddedpin[i++] = 0x20 | (ndigits & 0x0f); + for (s=pinvalue; i < aodf->stored_length && *s && s[1]; s = s+2 ) + paddedpin[i++] = (((*s - '0') << 4) | ((s[1] - '0') & 0x0f)); + if (i < aodf->stored_length && *s) + paddedpin[i++] = (((*s - '0') << 4) + |((aodf->pad_char_valid?aodf->pad_char:0)&0x0f)); + + if (aodf->pinflags.needs_padding) + { + while (i < aodf->stored_length) + paddedpin[i++] = aodf->pad_char_valid? aodf->pad_char : 0; + } + + xfree (pinvalue); + pinvalue = paddedpin; + pinvaluelen = i; + } + else if (aodf->pinflags.needs_padding) + { + char *paddedpin; + + paddedpin = xtrymalloc (aodf->stored_length+1); + if (!paddedpin) + { + err = gpg_error_from_syserror (); + xfree (pinvalue); + return err; + } + for (i=0, s=pinvalue; i < aodf->stored_length && *s; i++, s++) + paddedpin[i] = *s; + /* Not sure what padding char to use if none has been set. + For now we use 0x00; maybe a space would be better. */ + for (; i < aodf->stored_length; i++) + paddedpin[i] = aodf->pad_char_valid? aodf->pad_char : 0; + paddedpin[i] = 0; + pinvaluelen = i; + xfree (pinvalue); + pinvalue = paddedpin; + } + else + pinvaluelen = strlen (pinvalue); + + /* log_printhex (pinvalue, pinvaluelen, */ + /* "about to verify with ref %lu pin:", pin_reference); */ + err = iso7816_verify (app_get_slot (app), pin_reference, + pinvalue, pinvaluelen); + xfree (pinvalue); + if (err) + { + log_error ("p15: PIN verification failed: %s\n", gpg_strerror (err)); + return err; + } + if (opt.verbose) + log_info ("p15: PIN verification succeeded\n"); + prkdf->pin_verified = 1; + + return 0; +} + + + + /* Handler for the PKSIGN command. Create the signature and return the allocated result in OUTDATA. @@ -2851,6 +3629,9 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, const void *indata, size_t indatalen, unsigned char **outdata, size_t *outdatalen ) { + static unsigned char sha256_prefix[19] = /* OID: 2.16.840.1.101.3.4.2.1 */ + { 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, + 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 }; static unsigned char sha1_prefix[15] = /* Object ID is 1.3.14.3.2.26 */ { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 }; @@ -2859,18 +3640,24 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, 0x02, 0x01, 0x05, 0x00, 0x04, 0x14 }; gpg_error_t err; - int i; - unsigned char data[36]; /* Must be large enough for a SHA-1 digest - + the largest OID prefix above and also - fit the 36 bytes of md5sha1. */ + unsigned char data[32+19]; /* Must be large enough for a SHA-256 digest + * + the largest OID prefix above and also + * fit the 36 bytes of md5sha1. */ prkdf_object_t prkdf; /* The private key object. */ aodf_object_t aodf; /* The associated authentication object. */ int no_data_padding = 0; /* True if the card want the data without padding.*/ int mse_done = 0; /* Set to true if the MSE has been done. */ + unsigned int hashlen; /* Length of the hash. */ + unsigned int datalen; /* Length of the data to sign (prefix+hash). */ + unsigned char *dataptr; + int exmode, le_value; + if (!keyidstr || !*keyidstr) return gpg_error (GPG_ERR_INV_VALUE); - if (indatalen != 20 && indatalen != 16 && indatalen != 35 && indatalen != 36) + if (indatalen != 20 && indatalen != 16 + && indatalen != 35 && indatalen != 36 + && indatalen != (32+19)) return gpg_error (GPG_ERR_INV_VALUE); err = prkdf_object_from_keyidstr (app, keyidstr, &prkdf); @@ -2879,13 +3666,13 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, if (!(prkdf->usageflags.sign || prkdf->usageflags.sign_recover ||prkdf->usageflags.non_repudiation)) { - log_error ("key %s may not be used for signing\n", keyidstr); + log_error ("p15: key %s may not be used for signing\n", keyidstr); return gpg_error (GPG_ERR_WRONG_KEY_USAGE); } if (!prkdf->authid) { - log_error ("no authentication object defined for %s\n", keyidstr); + log_error ("p15: no authentication object defined for %s\n", keyidstr); /* fixme: we might want to go ahead and do without PIN verification. */ return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); @@ -2898,37 +3685,25 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, break; if (!aodf) { - log_error ("authentication object for %s missing\n", keyidstr); - return gpg_error (GPG_ERR_INV_CARD); - } - if (aodf->authid) - { - log_error ("PIN verification is protected by an " - "additional authentication token\n"); - return gpg_error (GPG_ERR_BAD_PIN_METHOD); - } - if (aodf->pinflags.integrity_protected - || aodf->pinflags.confidentiality_protected) - { - log_error ("PIN verification requires unsupported protection method\n"); - return gpg_error (GPG_ERR_BAD_PIN_METHOD); - } - if (!aodf->stored_length && aodf->pinflags.needs_padding) - { - log_error ("PIN verification requires padding but no length known\n"); + log_error ("p15: authentication object for %s missing\n", keyidstr); return gpg_error (GPG_ERR_INV_CARD); } - /* Select the key file. Note that this may change the security - environment thus we do it before PIN verification. */ - err = select_ef_by_path (app, prkdf->path, prkdf->pathlen); + /* We need some more info about the key - get the keygrip to + * populate these fields. */ + err = keygrip_from_prkdf (app, prkdf); if (err) { - log_error ("error selecting file for key %s: %s\n", - keyidstr, gpg_strerror (errno)); + log_error ("p15: keygrip_from_prkdf failed: %s\n", gpg_strerror (err)); return err; } + /* Prepare PIN verification. This is split so that we can do + * MSE operation for some task after having selected the key file but + * before sending the verify APDU. */ + err = prepare_verify_pin (app, keyidstr, prkdf, aodf); + if (err) + return err; /* Due to the fact that the non-repudiation signature on a BELPIC card requires a verify immediately before the DSO we set the @@ -2956,162 +3731,16 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, } if (err) { - log_error ("MSE failed: %s\n", gpg_strerror (err)); + log_error ("p15: MSE failed: %s\n", gpg_strerror (err)); return err; } + /* Now that we have all the information available run the actual PIN + * verification.*/ + err = verify_pin (app, pincb, pincb_arg, prkdf, aodf); + if (err) + return err; - /* Now that we have all the information available, prepare and run - the PIN verification.*/ - if (1) - { - char *pinvalue; - size_t pinvaluelen; - const char *errstr; - const char *s; - - if (prkdf->usageflags.non_repudiation - && app->app_local->card_type == CARD_TYPE_BELPIC) - err = pincb (pincb_arg, "PIN (qualified signature!)", &pinvalue); - else - err = pincb (pincb_arg, "PIN", &pinvalue); - if (err) - { - log_info ("PIN callback returned error: %s\n", gpg_strerror (err)); - return err; - } - - /* We might need to cope with UTF8 things here. Not sure how - min_length etc. are exactly defined, for now we take them as - a plain octet count. */ - - if (strlen (pinvalue) < aodf->min_length) - { - log_error ("PIN is too short; minimum length is %lu\n", - aodf->min_length); - err = gpg_error (GPG_ERR_BAD_PIN); - } - else if (aodf->stored_length && strlen (pinvalue) > aodf->stored_length) - { - /* This would otherwise truncate the PIN silently. */ - log_error ("PIN is too large; maximum length is %lu\n", - aodf->stored_length); - err = gpg_error (GPG_ERR_BAD_PIN); - } - else if (aodf->max_length_valid && strlen (pinvalue) > aodf->max_length) - { - log_error ("PIN is too large; maximum length is %lu\n", - aodf->max_length); - err = gpg_error (GPG_ERR_BAD_PIN); - } - - if (err) - { - xfree (pinvalue); - return err; - } - - errstr = NULL; - err = 0; - switch (aodf->pintype) - { - case PIN_TYPE_BCD: - case PIN_TYPE_ASCII_NUMERIC: - for (s=pinvalue; digitp (s); s++) - ; - if (*s) - { - errstr = "Non-numeric digits found in PIN"; - err = gpg_error (GPG_ERR_BAD_PIN); - } - break; - case PIN_TYPE_UTF8: - break; - case PIN_TYPE_HALF_NIBBLE_BCD: - errstr = "PIN type Half-Nibble-BCD is not supported"; - break; - case PIN_TYPE_ISO9564_1: - errstr = "PIN type ISO9564-1 is not supported"; - break; - default: - errstr = "Unknown PIN type"; - break; - } - if (errstr) - { - log_error ("can't verify PIN: %s\n", errstr); - xfree (pinvalue); - return err? err : gpg_error (GPG_ERR_BAD_PIN_METHOD); - } - - - if (aodf->pintype == PIN_TYPE_BCD ) - { - char *paddedpin; - int ndigits; - - for (ndigits=0, s=pinvalue; *s; ndigits++, s++) - ; - paddedpin = xtrymalloc (aodf->stored_length+1); - if (!paddedpin) - { - err = gpg_error_from_syserror (); - xfree (pinvalue); - return err; - } - - i = 0; - paddedpin[i++] = 0x20 | (ndigits & 0x0f); - for (s=pinvalue; i < aodf->stored_length && *s && s[1]; s = s+2 ) - paddedpin[i++] = (((*s - '0') << 4) | ((s[1] - '0') & 0x0f)); - if (i < aodf->stored_length && *s) - paddedpin[i++] = (((*s - '0') << 4) - |((aodf->pad_char_valid?aodf->pad_char:0)&0x0f)); - - if (aodf->pinflags.needs_padding) - while (i < aodf->stored_length) - paddedpin[i++] = aodf->pad_char_valid? aodf->pad_char : 0; - - xfree (pinvalue); - pinvalue = paddedpin; - pinvaluelen = i; - } - else if (aodf->pinflags.needs_padding) - { - char *paddedpin; - - paddedpin = xtrymalloc (aodf->stored_length+1); - if (!paddedpin) - { - err = gpg_error_from_syserror (); - xfree (pinvalue); - return err; - } - for (i=0, s=pinvalue; i < aodf->stored_length && *s; i++, s++) - paddedpin[i] = *s; - /* Not sure what padding char to use if none has been set. - For now we use 0x00; maybe a space would be better. */ - for (; i < aodf->stored_length; i++) - paddedpin[i] = aodf->pad_char_valid? aodf->pad_char : 0; - paddedpin[i] = 0; - pinvaluelen = i; - xfree (pinvalue); - pinvalue = paddedpin; - } - else - pinvaluelen = strlen (pinvalue); - - err = iso7816_verify (app->slot, - aodf->pin_reference_valid? aodf->pin_reference : 0, - pinvalue, pinvaluelen); - xfree (pinvalue); - if (err) - { - log_error ("PIN verification failed: %s\n", gpg_strerror (err)); - return err; - } - log_debug ("PIN verification succeeded\n"); - } /* Prepare the DER object from INDATA. */ if (indatalen == 36) @@ -3120,6 +3749,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, if (hashalgo != MD_USER_TLS_MD5SHA1) return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); memcpy (data, indata, indatalen); + datalen = hashlen = 36; } else if (indatalen == 35) { @@ -3134,20 +3764,50 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, else return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); memcpy (data, indata, indatalen); + datalen = 35; + hashlen = 20; + } + else if (indatalen == 32 + 19) + { + /* Seems to be a prepared SHA256 DER object. */ + if (hashalgo == GCRY_MD_SHA256 && !memcmp (indata, sha256_prefix, 19)) + ; + else + return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); + memcpy (data, indata, indatalen); + datalen = 51; + hashlen = 32; } else { /* Need to prepend the prefix. */ - if (hashalgo == GCRY_MD_SHA1) - memcpy (data, sha1_prefix, 15); + if (hashalgo == GCRY_MD_SHA256) + { + memcpy (data, sha256_prefix, 19); + memcpy (data+19, indata, indatalen); + datalen = 51; + hashlen = 32; + } + else if (hashalgo == GCRY_MD_SHA1) + { + memcpy (data, sha1_prefix, 15); + memcpy (data+15, indata, indatalen); + datalen = 35; + hashlen = 20; + } else if (hashalgo == GCRY_MD_RMD160) - memcpy (data, rmd160_prefix, 15); + { + memcpy (data, rmd160_prefix, 15); + memcpy (data+15, indata, indatalen); + datalen = 35; + hashlen = 20; + } else return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); - memcpy (data+15, indata, indatalen); } - /* Manage security environment needs to be weaked for certain cards. */ + + /* Manage security environment needs to be tweaked for certain cards. */ if (mse_done) err = 0; else if (app->app_local->card_type == CARD_TYPE_TCOS) @@ -3176,16 +3836,32 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, } if (err) { - log_error ("MSE failed: %s\n", gpg_strerror (err)); + log_error ("p15: MSE failed: %s\n", gpg_strerror (err)); return err; } - if (hashalgo == MD_USER_TLS_MD5SHA1) - err = iso7816_compute_ds (app->slot, 0, data, 36, 0, outdata, outdatalen); - else if (no_data_padding) - err = iso7816_compute_ds (app->slot, 0, data+15, 20, 0,outdata,outdatalen); + dataptr = data; + if (no_data_padding) + { + dataptr += datalen - hashlen; + datalen = hashlen; + } + + if (prkdf->keyalgo == GCRY_PK_RSA && prkdf->keynbits > 2048) + { + exmode = 1; + le_value = prkdf->keynbits / 8; + } else - err = iso7816_compute_ds (app->slot, 0, data, 35, 0, outdata, outdatalen); + { + exmode = 0; + le_value = 0; + } + + err = iso7816_compute_ds (app_get_slot (app), + exmode, dataptr, datalen, + le_value, outdata, outdatalen); + return err; } @@ -3215,7 +3891,7 @@ do_auth (app_t app, const char *keyidstr, return err; if (!prkdf->usageflags.sign) { - log_error ("key %s may not be used for authentication\n", keyidstr); + log_error ("p15: key %s may not be used for authentication\n", keyidstr); return gpg_error (GPG_ERR_WRONG_KEY_USAGE); } @@ -3225,6 +3901,134 @@ do_auth (app_t app, const char *keyidstr, } +/* Handler for the PKDECRYPT command. Decrypt the data in INDATA and + * return the allocated result in OUTDATA. If a PIN is required the + * PINCB will be used to ask for the PIN; it should return the PIN in + * an allocated buffer and put it into PIN. */ +static gpg_error_t +do_decipher (app_t app, const char *keyidstr, + gpg_error_t (*pincb)(void*, const char *, char **), + void *pincb_arg, + const void *indata, size_t indatalen, + unsigned char **outdata, size_t *outdatalen, + unsigned int *r_info) +{ + gpg_error_t err; + prkdf_object_t prkdf; /* The private key object. */ + aodf_object_t aodf; /* The associated authentication object. */ + int exmode, le_value, padind; + + (void)r_info; + + if (!keyidstr || !*keyidstr) + return gpg_error (GPG_ERR_INV_VALUE); + if (!indatalen || !indata || !outdatalen || !outdata) + return gpg_error (GPG_ERR_INV_ARG); + + err = prkdf_object_from_keyidstr (app, keyidstr, &prkdf); + if (err) + return err; + if (!(prkdf->usageflags.decrypt || prkdf->usageflags.unwrap)) + { + log_error ("p15: key %s may not be used for decruption\n", keyidstr); + return gpg_error (GPG_ERR_WRONG_KEY_USAGE); + } + + /* Find the authentication object to this private key object. */ + if (!prkdf->authid) + { + log_error ("p15: no authentication object defined for %s\n", keyidstr); + /* fixme: we might want to go ahead and do without PIN + verification. */ + return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); + } + for (aodf = app->app_local->auth_object_info; aodf; aodf = aodf->next) + if (aodf->objidlen == prkdf->authidlen + && !memcmp (aodf->objid, prkdf->authid, prkdf->authidlen)) + break; + if (!aodf) + { + log_error ("p15: authentication object for %s missing\n", keyidstr); + return gpg_error (GPG_ERR_INV_CARD); + } + + /* We need some more info about the key - get the keygrip to + * populate these fields. */ + err = keygrip_from_prkdf (app, prkdf); + if (err) + { + log_error ("p15: keygrip_from_prkdf failed: %s\n", gpg_strerror (err)); + return err; + } + + /* Verify the PIN. */ + err = prepare_verify_pin (app, keyidstr, prkdf, aodf); + if (!err) + err = verify_pin (app, pincb, pincb_arg, prkdf, aodf); + if (err) + return err; + + + /* The next is guess work for CardOS. */ + if (app->app_local->card_product == CARD_PRODUCT_DTRUST) + { + /* From analyzing an USB trace of a Windows signing application + * we see that the SE is simply reset to 0x14. It seems to be + * sufficient to do this for decryption; signing still works + * with the standard code despite that our trace showed that + * there the SE is restored to 0x09. Note that the special + * D-Trust AID is in any case select by prepare_verify_pin. + * + * Hey, D-Trust please hand over the specs so that you can + * actually sell your cards and we can properly implement it; + * other vendors understand this and do not demand ridiculous + * paper work or complicated procedures to get samples. */ + err = iso7816_manage_security_env (app_get_slot (app), + 0xF3, 0x14, NULL, 0); + + } + else if (prkdf->key_reference_valid) + { + unsigned char mse[6]; + + /* Note: This works with CardOS but the D-Trust card has the + * problem that the next created signature would be broken. */ + + mse[0] = 0x80; /* Algorithm reference. */ + mse[1] = 1; + mse[2] = 0x0a; /* RSA, no padding. */ + mse[3] = 0x84; + mse[4] = 1; + mse[5] = prkdf->key_reference; + err = iso7816_manage_security_env (app_get_slot (app), 0x41, 0xB8, + mse, sizeof mse); + } + /* Check for MSE error. */ + if (err) + { + log_error ("p15: MSE failed: %s\n", gpg_strerror (err)); + return err; + } + + exmode = le_value = 0; + padind = 0; + if (prkdf->keyalgo == GCRY_PK_RSA && prkdf->keynbits > 2048) + { + exmode = 1; /* Extended length w/o a limit. */ + le_value = prkdf->keynbits / 8; + } + + if (app->app_local->card_product == CARD_PRODUCT_DTRUST) + padind = 0x81; + + err = iso7816_decipher (app_get_slot (app), exmode, + indata, indatalen, + le_value, padind, + outdata, outdatalen); + return err; +} + + /* Assume that EF(DIR) has been selected. Read its content and figure out the home EF of pkcs#15. Return that home DF or 0 if not found @@ -3244,7 +4048,7 @@ read_home_df (int slot, int *r_belpic) err = iso7816_read_binary (slot, 0, 0, &buffer, &buflen); if (err) { - log_error ("error reading EF{DIR}: %s\n", gpg_strerror (err)); + log_error ("p15: error reading EF(DIR): %s\n", gpg_strerror (err)); return 0; } @@ -3258,14 +4062,15 @@ read_home_df (int slot, int *r_belpic) && !memcmp (pp, pkcs15be_aid, nn))))) { pp = find_tlv (p, n, 0x50, &nn); - if (pp) /* fixme: Filter log value? */ - log_info ("pkcs#15 application label from EF(DIR) is '%.*s'\n", + if (pp && opt.verbose) + log_info ("p15: application label from EF(DIR) is '%.*s'\n", (int)nn, pp); pp = find_tlv (p, n, 0x51, &nn); if (pp && nn == 4 && *pp == 0x3f && !pp[1]) { result = ((pp[2] << 8) | pp[3]); - log_info ("pkcs#15 application directory is 0x%04hX\n", result); + if (opt.verbose) + log_info ("p15: application directory is 0x%04hX\n", result); } } } @@ -3294,11 +4099,11 @@ app_select_p15 (app_t app) does only allow for that. Many other cards supports this selection method too. Note, that we don't use select_application above for the Belgian card - the call - works but it seems that it did not switch to the correct DF. + works but it seems that it does not switch to the correct DF. Using the 2f02 just works. */ unsigned short path[1] = { 0x2f00 }; - rc = iso7816_select_path (app->slot, path, 1); + rc = iso7816_select_path (slot, path, 1); if (!rc) { direct = 1; @@ -3306,7 +4111,7 @@ app_select_p15 (app_t app) if (def_home_df) { path[0] = def_home_df; - rc = iso7816_select_path (app->slot, path, 1); + rc = iso7816_select_path (slot, path, 1); } } } @@ -3368,6 +4173,8 @@ app_select_p15 (app_t app) the common APP structure. */ app->app_local->card_type = card_type; + app->app_local->card_product = CARD_PRODUCT_UNKNOWN; + /* Store whether we may and should use direct path selection. */ app->app_local->direct_path_selection = direct; @@ -3411,7 +4218,7 @@ app_select_p15 (app_t app) app->fnc.genkey = NULL; app->fnc.sign = do_sign; app->fnc.auth = do_auth; - app->fnc.decipher = NULL; + app->fnc.decipher = do_decipher; app->fnc.change_pin = NULL; app->fnc.check_pin = NULL; diff --git a/scd/app-sc-hsm.c b/scd/app-sc-hsm.c index 8094b24..352b16c 100644 --- a/scd/app-sc-hsm.c +++ b/scd/app-sc-hsm.c @@ -1354,7 +1354,7 @@ keygripstr_from_prkdf (app_t app, prkdf_object_t prkdf, char *r_gripstr) err = ksba_cert_init_from_mem (cert, der, derlen); xfree (der); if (!err) - err = app_help_get_keygrip_string (cert, r_gripstr); + err = app_help_get_keygrip_string (cert, r_gripstr, NULL); ksba_cert_release (cert); return err; diff --git a/scd/iso7816.c b/scd/iso7816.c index 627481f..092a119 100644 --- a/scd/iso7816.c +++ b/scd/iso7816.c @@ -103,6 +103,8 @@ map_sw (int sw) ec = GPG_ERR_GENERAL; /* Should not happen. */ else if ((sw & 0xff00) == SW_MORE_DATA) ec = 0; /* This should actually never been seen here. */ + else if ((sw & 0xfff0) == 0x63C0) + ec = GPG_ERR_BAD_PIN; else ec = GPG_ERR_CARD; } @@ -139,6 +141,32 @@ iso7816_select_application (int slot, const char *aid, size_t aidlen, } +/* This is the same as iso7816_select_application but may return data + * at RESULT,RESULTLEN). */ +gpg_error_t +iso7816_select_application_ext (int slot, const char *aid, size_t aidlen, + unsigned int flags, + unsigned char **result, size_t *resultlen) +{ + int sw; + sw = apdu_send (slot, 0, 0x00, CMD_SELECT_FILE, 4, + (flags&1)? 0:0x0c, aidlen, aid, + result, resultlen); + return map_sw (sw); +} + + +/* Simple MF selection as supported by some cards. */ +gpg_error_t +iso7816_select_mf (int slot) +{ + int sw; + + sw = apdu_send_simple (slot, 0, 0x00, CMD_SELECT_FILE, 0x000, 0x0c, -1, NULL); + return map_sw (sw); +} + + gpg_error_t iso7816_select_file (int slot, int tag, int is_dir) { @@ -289,6 +317,39 @@ iso7816_verify (int slot, int chvno, const char *chv, size_t chvlen) return map_sw (sw); } + +/* Some cards support a VERIFY command variant to check the status of + * the the CHV without a need to try a CHV. In contrast to the other + * functions this function returns the special codes ISO7816_VERIFY_* + * or a non-negative number with the left attempts. */ +int +iso7816_verify_status (int slot, int chvno) +{ + unsigned char apdu[4]; + unsigned int sw; + int result; + + apdu[0] = 0x00; + apdu[1] = ISO7816_VERIFY; + apdu[2] = 0x00; + apdu[3] = chvno; + if (!iso7816_apdu_direct (slot, apdu, 4, 0, &sw, NULL, NULL)) + result = ISO7816_VERIFY_NOT_NEEDED; /* Not returned by all cards. */ + else if (sw == 0x6a88 || sw == 0x6a80) + result = ISO7816_VERIFY_NO_PIN; + else if (sw == 0x6983) + result = ISO7816_VERIFY_BLOCKED; + else if (sw == 0x6985) + result = ISO7816_VERIFY_NULLPIN; /* TCOS card */ + else if ((sw & 0xfff0) == 0x63C0) + result = (sw & 0x000f); + else + result = ISO7816_VERIFY_ERROR; + + return result; +} + + /* Perform a CHANGE_REFERENCE_DATA command on SLOT for the card holder verification vector CHVNO. With PININFO non-NULL the pinpad of the reader will be used. If IS_EXCHANGE is 0, a "change reference @@ -722,8 +783,9 @@ iso7816_get_challenge (int slot, int length, unsigned char *buffer) stored in a newly allocated buffer at the address passed by RESULT. Returns the length of this data at the address of RESULTLEN. */ gpg_error_t -iso7816_read_binary (int slot, size_t offset, size_t nmax, - unsigned char **result, size_t *resultlen) +iso7816_read_binary_ext (int slot, int extended_mode, + size_t offset, size_t nmax, + unsigned char **result, size_t *resultlen) { int sw; unsigned char *buffer; @@ -746,13 +808,13 @@ iso7816_read_binary (int slot, size_t offset, size_t nmax, buffer = NULL; bufferlen = 0; n = read_all? 0 : nmax; - sw = apdu_send_le (slot, 0, 0x00, CMD_READ_BINARY, + sw = apdu_send_le (slot, extended_mode, 0x00, CMD_READ_BINARY, ((offset>>8) & 0xff), (offset & 0xff) , -1, NULL, n, &buffer, &bufferlen); if ( SW_EXACT_LENGTH_P(sw) ) { n = (sw & 0x00ff); - sw = apdu_send_le (slot, 0, 0x00, CMD_READ_BINARY, + sw = apdu_send_le (slot, extended_mode, 0x00, CMD_READ_BINARY, ((offset>>8) & 0xff), (offset & 0xff) , -1, NULL, n, &buffer, &bufferlen); } @@ -811,6 +873,15 @@ iso7816_read_binary (int slot, size_t offset, size_t nmax, return 0; } + +gpg_error_t +iso7816_read_binary (int slot, size_t offset, size_t nmax, + unsigned char **result, size_t *resultlen) +{ + return iso7816_read_binary_ext (slot, 0, offset, nmax, result, resultlen); +} + + /* Perform a READ RECORD command. RECNO gives the record number to read with 0 indicating the current record. RECCOUNT must be 1 (not all cards support reading of more than one record). SHORT_EF diff --git a/scd/iso7816.h b/scd/iso7816.h index 8da5a94..bad558d 100644 --- a/scd/iso7816.h +++ b/scd/iso7816.h @@ -29,6 +29,15 @@ #define ISO7816_CHANGE_REFERENCE_DATA 0x24 #define ISO7816_RESET_RETRY_COUNTER 0x2C +/* Error codes returned by iso7816_verify_status. A non-negative + * number gives the number of left tries. + * NB: The values are also used by the CHV-STATUS lines and thus are + * part of the public interface. Do not change them. */ +#define ISO7816_VERIFY_ERROR (-1) +#define ISO7816_VERIFY_NO_PIN (-2) +#define ISO7816_VERIFY_BLOCKED (-3) +#define ISO7816_VERIFY_NULLPIN (-4) +#define ISO7816_VERIFY_NOT_NEEDED (-5) /* Information to be passed to pinpad equipped readers. See ccid-driver.c for details. */ @@ -51,6 +60,12 @@ gpg_error_t iso7816_map_sw (int sw); gpg_error_t iso7816_select_application (int slot, const char *aid, size_t aidlen, unsigned int flags); +gpg_error_t iso7816_select_application_ext (int slot, + const char *aid, size_t aidlen, + unsigned int flags, + unsigned char **result, + size_t *resultlen); +gpg_error_t iso7816_select_mf (int slot); gpg_error_t iso7816_select_file (int slot, int tag, int is_dir); gpg_error_t iso7816_select_path (int slot, const unsigned short *path, size_t pathlen); @@ -65,6 +80,7 @@ gpg_error_t iso7816_check_pinpad (int slot, int command, gpg_error_t iso7816_verify (int slot, int chvno, const char *chv, size_t chvlen); gpg_error_t iso7816_verify_kp (int slot, int chvno, pininfo_t *pininfo); +int iso7816_verify_status (int slot, int chvno); gpg_error_t iso7816_change_reference_data (int slot, int chvno, const char *oldchv, size_t oldchvlen, const char *newchv, size_t newchvlen); @@ -117,6 +133,9 @@ gpg_error_t iso7816_read_public_key (int slot, int extended_mode, gpg_error_t iso7816_get_challenge (int slot, int length, unsigned char *buffer); +gpg_error_t iso7816_read_binary_ext (int slot, int extended_mode, + size_t offset, size_t nmax, + unsigned char **result, size_t *resultlen); gpg_error_t iso7816_read_binary (int slot, size_t offset, size_t nmax, unsigned char **result, size_t *resultlen); gpg_error_t iso7816_read_record (int slot, int recno, int reccount, diff --git a/sm/call-agent.c b/sm/call-agent.c index 281e479..d9c419e 100644 --- a/sm/call-agent.c +++ b/sm/call-agent.c @@ -1248,7 +1248,7 @@ gpgsm_agent_ask_passphrase (ctrl_t ctrl, const char *desc_msg, int repeat, return gpg_error_from_syserror (); snprintf (line, DIM(line), "GET_PASSPHRASE --data%s -- X X X %s", - repeat? " --repeat=1 --check --qualitybar":"", + repeat? " --repeat=1 --check":"", arg4); xfree (arg4); diff --git a/sm/call-dirmngr.c b/sm/call-dirmngr.c index fb05413..36afd22 100644 --- a/sm/call-dirmngr.c +++ b/sm/call-dirmngr.c @@ -756,20 +756,24 @@ lookup_status_cb (void *opaque, const char *line) /* Run the Directory Manager's lookup command using the pattern - compiled from the strings given in NAMES. The caller must provide - the callback CB which will be passed cert by cert. Note that CTRL - is optional. With CACHE_ONLY the dirmngr will search only its own - key cache. */ + compiled from the strings given in NAMES or from URI. The caller + must provide the callback CB which will be passed cert by cert. + Note that CTRL is optional. With CACHE_ONLY the dirmngr will + search only its own key cache. */ int -gpgsm_dirmngr_lookup (ctrl_t ctrl, strlist_t names, int cache_only, +gpgsm_dirmngr_lookup (ctrl_t ctrl, strlist_t names, const char *uri, + int cache_only, void (*cb)(void*, ksba_cert_t), void *cb_value) { int rc; - char *pattern; char line[ASSUAN_LINELENGTH]; struct lookup_parm_s parm; size_t len; assuan_context_t ctx; + const char *s; + + if ((names && uri) || (!names && !uri)) + return gpg_error (GPG_ERR_INV_ARG); /* The lookup function can be invoked from the callback of a lookup function, for example to walk the chain. */ @@ -792,19 +796,35 @@ gpgsm_dirmngr_lookup (ctrl_t ctrl, strlist_t names, int cache_only, log_fatal ("both dirmngr contexts are in use\n"); } - pattern = pattern_from_strlist (names); - if (!pattern) + if (names) { - if (ctx == dirmngr_ctx) - release_dirmngr (ctrl); - else - release_dirmngr2 (ctrl); + char *pattern = pattern_from_strlist (names); + if (!pattern) + { + if (ctx == dirmngr_ctx) + release_dirmngr (ctrl); + else + release_dirmngr2 (ctrl); - return out_of_core (); + return out_of_core (); + } + snprintf (line, DIM(line), "LOOKUP%s %s", + cache_only? " --cache-only":"", pattern); + xfree (pattern); + } + else + { + for (s=uri; *s; s++) + if (*s <= ' ') + { + if (ctx == dirmngr_ctx) + release_dirmngr (ctrl); + else + release_dirmngr2 (ctrl); + return gpg_error (GPG_ERR_INV_URI); + } + snprintf (line, DIM(line), "LOOKUP --url %s", uri); } - snprintf (line, DIM(line), "LOOKUP%s %s", - cache_only? " --cache-only":"", pattern); - xfree (pattern); parm.ctrl = ctrl; parm.ctx = ctx; diff --git a/sm/certchain.c b/sm/certchain.c index f59dc75..5f83202 100644 --- a/sm/certchain.c +++ b/sm/certchain.c @@ -38,6 +38,10 @@ #include "../common/tlv.h" +/* The OID for the authorityInfoAccess's caIssuers. */ +static const char oidstr_caIssuers[] = "1.3.6.1.5.5.7.48.2"; + + /* Object to keep track of certain root certificates. */ struct marktrusted_info_s { @@ -573,6 +577,9 @@ struct find_up_store_certs_s { ctrl_t ctrl; int count; + unsigned int want_fpr:1; + unsigned int got_fpr:1; + unsigned char fpr[20]; }; static void @@ -582,6 +589,13 @@ find_up_store_certs_cb (void *cb_value, ksba_cert_t cert) if (keydb_store_cert (parm->ctrl, cert, 1, NULL)) log_error ("error storing issuer certificate as ephemeral\n"); + else if (parm->want_fpr && !parm->got_fpr) + { + if (!gpgsm_get_fingerprint (cert, 0, parm->fpr, NULL)) + log_error (_("failed to get the fingerprint\n")); + else + parm->got_fpr = 1; + } parm->count++; } @@ -602,6 +616,8 @@ find_up_external (ctrl_t ctrl, KEYDB_HANDLE kh, const char *s; find_up_store_certs_parm.ctrl = ctrl; + find_up_store_certs_parm.want_fpr = 0; + find_up_store_certs_parm.got_fpr = 0; find_up_store_certs_parm.count = 0; if (opt.verbose) @@ -620,7 +636,7 @@ find_up_external (ctrl_t ctrl, KEYDB_HANDLE kh, add_to_strlist (&names, pattern); xfree (pattern); - rc = gpgsm_dirmngr_lookup (ctrl, names, 0, find_up_store_certs_cb, + rc = gpgsm_dirmngr_lookup (ctrl, names, NULL, 0, find_up_store_certs_cb, &find_up_store_certs_parm); free_strlist (names); @@ -653,6 +669,105 @@ find_up_external (ctrl_t ctrl, KEYDB_HANDLE kh, } +/* Helper for find_up(). Locate the certificate for CERT using the + * caIssuer from the authorityInfoAccess. KH is the keydb context we + * are currently using. On success 0 is returned and the certificate + * may be retrieved from the keydb using keydb_get_cert(). If no + * suitable authorityInfoAccess is encoded in the certificate + * GPG_ERR_NOT_FOUND is returned. */ +static gpg_error_t +find_up_via_auth_info_access (ctrl_t ctrl, KEYDB_HANDLE kh, ksba_cert_t cert) +{ + gpg_error_t err; + struct find_up_store_certs_s find_up_store_certs_parm; + char *url, *ldapurl; + int idx, i; + char *oid; + ksba_name_t name; + + find_up_store_certs_parm.ctrl = ctrl; + find_up_store_certs_parm.want_fpr = 1; + find_up_store_certs_parm.got_fpr = 0; + find_up_store_certs_parm.count = 0; + + /* Find suitable URLs; if there is a http scheme we prefer that. */ + url = ldapurl = NULL; + for (idx=0; + !url && !(err = ksba_cert_get_authority_info_access (cert, idx, + &oid, &name)); + idx++) + { + if (!strcmp (oid, oidstr_caIssuers)) + { + for (i=0; !url && ksba_name_enum (name, i); i++) + { + char *p = ksba_name_get_uri (name, i); + if (p) + { + if (!strncmp (p, "http:", 5) || !strncmp (p, "https:", 6)) + url = p; + else if (ldapurl) + xfree (p); /* We already got one. */ + else if (!strncmp (p, "ldap:",5) || !strncmp (p, "ldaps:",6)) + ldapurl = p; + } + else + xfree (p); + } + } + ksba_name_release (name); + ksba_free (oid); + } + if (err && gpg_err_code (err) != GPG_ERR_EOF) + { + log_error (_("can't get authorityInfoAccess: %s\n"), gpg_strerror (err)); + return err; + } + if (!url && ldapurl) + { + /* No HTTP scheme; fallback to LDAP if available. */ + url = ldapurl; + ldapurl = NULL; + } + xfree (ldapurl); + if (!url) + return gpg_error (GPG_ERR_NOT_FOUND); + + if (opt.verbose) + log_info ("looking up issuer via authorityInfoAccess.caIssuers\n"); + + err = gpgsm_dirmngr_lookup (ctrl, NULL, url, 0, find_up_store_certs_cb, + &find_up_store_certs_parm); + + /* Although we might receive several certificates we use only the + * first one. Or more exacty the first one for which we retrieved + * the fingerprint. */ + if (opt.verbose) + log_info ("number of caIssuers found: %d\n", + find_up_store_certs_parm.count); + if (err) + { + log_error ("external URL lookup failed: %s\n", gpg_strerror (err)); + err = gpg_error (GPG_ERR_NOT_FOUND); + } + else if (!find_up_store_certs_parm.got_fpr) + err = gpg_error (GPG_ERR_NOT_FOUND); + else + { + int old; + /* The retrieved certificates are currently stored in the + * ephemeral key DB, so we temporary switch to ephemeral + * mode. */ + old = keydb_set_ephemeral (kh, 1); + keydb_search_reset (kh); + err = keydb_search_fpr (ctrl, kh, find_up_store_certs_parm.fpr); + keydb_set_ephemeral (kh, old); + } + + return err; +} + + /* Helper for find_up(). Ask the dirmngr for the certificate for ISSUER with optional SERIALNO. KH is the keydb context we are currently using. With SUBJECT_MODE set, ISSUER is searched as the @@ -693,7 +808,7 @@ find_up_dirmngr (ctrl_t ctrl, KEYDB_HANDLE kh, add_to_strlist (&names, pattern); xfree (pattern); - rc = gpgsm_dirmngr_lookup (ctrl, names, 1, find_up_store_certs_cb, + rc = gpgsm_dirmngr_lookup (ctrl, names, NULL, 1, find_up_store_certs_cb, &find_up_store_certs_parm); free_strlist (names); @@ -813,11 +928,24 @@ find_up (ctrl_t ctrl, KEYDB_HANDLE kh, } /* If we still didn't found it, try an external lookup. */ - if (rc == -1 && opt.auto_issuer_key_retrieve && !find_next) + if (rc == -1 && !find_next && !ctrl->offline) { - rc = find_up_external (ctrl, kh, issuer, keyid); - if (!rc && DBG_X509) - log_debug (" found via authid and external lookup\n"); + /* We allow AIA also if CRLs are enabled; both can be used + * as a web bug so it does not make sense to not use AIA if + * CRL checks are enabled. */ + if ((opt.auto_issuer_key_retrieve || !opt.no_crl_check) + && !find_up_via_auth_info_access (ctrl, kh, cert)) + { + if (DBG_X509) + log_debug (" found via authorityInfoAccess.caIssuers\n"); + rc = 0; + } + else if (opt.auto_issuer_key_retrieve) + { + rc = find_up_external (ctrl, kh, issuer, keyid); + if (!rc && DBG_X509) + log_debug (" found via authid and external lookup\n"); + } } @@ -876,11 +1004,21 @@ find_up (ctrl_t ctrl, KEYDB_HANDLE kh, } /* Still not found. If enabled, try an external lookup. */ - if (rc == -1 && opt.auto_issuer_key_retrieve && !find_next) + if (rc == -1 && !find_next && !ctrl->offline) { - rc = find_up_external (ctrl, kh, issuer, NULL); - if (!rc && DBG_X509) - log_debug (" found via issuer and external lookup\n"); + if ((opt.auto_issuer_key_retrieve || !opt.no_crl_check) + && !find_up_via_auth_info_access (ctrl, kh, cert)) + { + if (DBG_X509) + log_debug (" found via authorityInfoAccess.caIssuers\n"); + rc = 0; + } + else if (opt.auto_issuer_key_retrieve) + { + rc = find_up_external (ctrl, kh, issuer, NULL); + if (!rc && DBG_X509) + log_debug (" found via issuer and external lookup\n"); + } } return rc; @@ -1054,6 +1192,24 @@ is_cert_still_valid (ctrl_t ctrl, int force_ocsp, int lm, estream_t fp, return 0; } + + if (!(force_ocsp || ctrl->use_ocsp) + && !opt.enable_issuer_based_crl_check) + { + err = ksba_cert_get_crl_dist_point (subject_cert, 0, NULL, NULL, NULL); + if (gpg_err_code (err) == GPG_ERR_EOF) + { + /* No DP specified in the certificate. Thus the CA does not + * consider a CRL useful and the user of the certificate + * also does not consider this to be a critical thing. In + * this case we can conclude that the certificate shall not + * be revocable. Note that we reach this point here only if + * no OCSP responder shall be used. */ + audit_log_ok (ctrl->audit, AUDIT_CRL_CHECK, gpg_error (GPG_ERR_TRUE)); + return 0; + } + } + err = gpgsm_dirmngr_isvalid (ctrl, subject_cert, issuer_cert, force_ocsp? 2 : !!ctrl->use_ocsp); diff --git a/sm/certcheck.c b/sm/certcheck.c index 1102bcc..12b3ec9 100644 --- a/sm/certcheck.c +++ b/sm/certcheck.c @@ -1,5 +1,7 @@ /* certcheck.c - check one certificate - * Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc. + * Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc. + * Copyright (C) 2001-2019 Werner Koch + * Copyright (C) 2015-2020 g10 Code GmbH * * This file is part of GnuPG. * @@ -15,6 +17,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, see <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-3.0-or-later */ #include <config.h> @@ -220,6 +223,126 @@ pk_algo_from_sexp (gcry_sexp_t pkey) } +/* Return the hash algorithm's algo id from its name given in the + * non-null termnated string in (buffer,buflen). Returns 0 on failure + * or if the algo is not known. */ +static int +hash_algo_from_buffer (const void *buffer, size_t buflen) +{ + char *string; + int algo; + + string = xtrymalloc (buflen + 1); + if (!string) + { + log_error (_("out of core\n")); + return 0; + } + memcpy (string, buffer, buflen); + string[buflen] = 0; + algo = gcry_md_map_name (string); + if (!algo) + log_error ("unknown digest algorithm '%s' used in certificate\n", string); + xfree (string); + return algo; +} + + +/* Return an unsigned integer from the non-null termnated string + * (buffer,buflen). Returns 0 on failure. */ +static unsigned int +uint_from_buffer (const void *buffer, size_t buflen) +{ + char *string; + unsigned int val; + + string = xtrymalloc (buflen + 1); + if (!string) + { + log_error (_("out of core\n")); + return 0; + } + memcpy (string, buffer, buflen); + string[buflen] = 0; + val = strtoul (string, NULL, 10); + xfree (string); + return val; +} + + +/* Extract the hash algorithm and the salt length from the sigval. */ +static gpg_error_t +extract_pss_params (gcry_sexp_t s_sig, int *r_algo, unsigned int *r_saltlen) +{ + gpg_error_t err; + gcry_buffer_t ioarray[2] = { {0}, {0} }; + + err = gcry_sexp_extract_param (s_sig, "sig-val", + "&'hash-algo''salt-length'", + ioarray+0, ioarray+1, NULL); + if (err) + { + log_error ("extracting params from PSS failed: %s\n", gpg_strerror (err)); + return err; + } + + *r_algo = hash_algo_from_buffer (ioarray[0].data, ioarray[0].len); + *r_saltlen = uint_from_buffer (ioarray[1].data, ioarray[1].len); + xfree (ioarray[0].data); + xfree (ioarray[1].data); + if (*r_saltlen < 20) + { + log_error ("length of PSS salt too short\n"); + gcry_sexp_release (s_sig); + return gpg_error (GPG_ERR_DIGEST_ALGO); + } + if (!*r_algo) + { + return gpg_error (GPG_ERR_DIGEST_ALGO); + } + + /* PSS has no hash function firewall like PKCS#1 and thus offers + * a path for hash algorithm replacement. To avoid this it makes + * sense to restrict the allowed hash algorithms and also allow only + * matching salt lengths. According to Peter Gutmann: + * "Beware of bugs in the above signature scheme; + * I have only proved it secure, not implemented it" + * - Apologies to Donald Knuth. + * https://www.metzdowd.com/pipermail/cryptography/2019-November/035449.html + * + * Given the set of supported algorithms currently available in + * Libgcrypt and the extra hash checks we have in some compliance + * modes, it would be hard to trick gpgsm to verify a forged + * signature. However, if eventually someone adds the xor256 hash + * algorithm (1.3.6.1.4.1.3029.3.2) to Libgcrypt we would be doomed. + */ + switch (*r_algo) + { + case GCRY_MD_SHA1: + case GCRY_MD_SHA256: + case GCRY_MD_SHA384: + case GCRY_MD_SHA512: + case GCRY_MD_SHA3_256: + case GCRY_MD_SHA3_384: + case GCRY_MD_SHA3_512: + break; + default: + log_error ("PSS hash algorithm '%s' rejected\n", + gcry_md_algo_name (*r_algo)); + return gpg_error (GPG_ERR_DIGEST_ALGO); + } + + if (gcry_md_get_algo_dlen (*r_algo) != *r_saltlen) + { + log_error ("PSS hash algorithm '%s' rejected due to salt length %u\n", + gcry_md_algo_name (*r_algo), *r_saltlen); + return gpg_error (GPG_ERR_DIGEST_ALGO); + } + + return 0; +} + + /* Check the signature on CERT using the ISSUER-CERT. This function does only test the cryptographic signature and nothing else. It is assumed that the ISSUER_CERT is valid. */ @@ -229,66 +352,76 @@ gpgsm_check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert) const char *algoid; gcry_md_hd_t md; int rc, algo; - gcry_mpi_t frame; ksba_sexp_t p; size_t n; - gcry_sexp_t s_sig, s_hash, s_pkey; + gcry_sexp_t s_sig, s_data, s_pkey; + int use_pss = 0; + unsigned int saltlen; algo = gcry_md_map_name ( (algoid=ksba_cert_get_digest_algo (cert))); - if (!algo) + if (!algo && algoid && !strcmp (algoid, "1.2.840.113549.1.1.10")) + use_pss = 1; + else if (!algo) { - log_error ("unknown hash algorithm '%s'\n", algoid? algoid:"?"); + log_error ("unknown digest algorithm '%s' used certificate\n", + algoid? algoid:"?"); if (algoid && ( !strcmp (algoid, "1.2.840.113549.1.1.2") ||!strcmp (algoid, "1.2.840.113549.2.2"))) log_info (_("(this is the MD2 algorithm)\n")); return gpg_error (GPG_ERR_GENERAL); } - rc = gcry_md_open (&md, algo, 0); - if (rc) - { - log_error ("md_open failed: %s\n", gpg_strerror (rc)); - return rc; - } - if (DBG_HASHING) - gcry_md_debug (md, "hash.cert"); - - rc = ksba_cert_hash (cert, 1, HASH_FNC, md); - if (rc) - { - log_error ("ksba_cert_hash failed: %s\n", gpg_strerror (rc)); - gcry_md_close (md); - return rc; - } - gcry_md_final (md); + /* The the signature from the certificate. */ p = ksba_cert_get_sig_val (cert); n = gcry_sexp_canon_len (p, 0, NULL, NULL); if (!n) { log_error ("libksba did not return a proper S-Exp\n"); - gcry_md_close (md); ksba_free (p); return gpg_error (GPG_ERR_BUG); } + rc = gcry_sexp_sscan ( &s_sig, NULL, (char*)p, n); + ksba_free (p); + if (rc) + { + log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc)); + return rc; + } if (DBG_CRYPTO) + gcry_log_debugsxp ("sigval", s_sig); + + if (use_pss) { - int j; - log_debug ("signature value:"); - for (j=0; j < n; j++) - log_printf (" %02X", p[j]); - log_printf ("\n"); + rc = extract_pss_params (s_sig, &algo, &saltlen); + if (rc) + { + gcry_sexp_release (s_sig); + return rc; + } } - rc = gcry_sexp_sscan ( &s_sig, NULL, (char*)p, n); - ksba_free (p); + + /* Hash the to-be-signed parts of the certificate. */ + rc = gcry_md_open (&md, algo, 0); if (rc) { - log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc)); + log_error ("md_open failed: %s\n", gpg_strerror (rc)); + return rc; + } + if (DBG_HASHING) + gcry_md_debug (md, "hash.cert"); + + rc = ksba_cert_hash (cert, 1, HASH_FNC, md); + if (rc) + { + log_error ("ksba_cert_hash failed: %s\n", gpg_strerror (rc)); gcry_md_close (md); return rc; } + gcry_md_final (md); + /* Get the public key from the certificate. */ p = ksba_cert_get_public_key (issuer_cert); n = gcry_sexp_canon_len (p, 0, NULL, NULL); if (!n) @@ -308,29 +441,50 @@ gpgsm_check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert) gcry_sexp_release (s_sig); return rc; } + if (DBG_CRYPTO) + gcry_log_debugsxp ("pubkey:", s_pkey); - rc = do_encode_md (md, algo, pk_algo_from_sexp (s_pkey), - gcry_pk_get_nbits (s_pkey), s_pkey, &frame); - if (rc) + if (use_pss) { - gcry_md_close (md); - gcry_sexp_release (s_sig); - gcry_sexp_release (s_pkey); - return rc; + rc = gcry_sexp_build (&s_data, NULL, + "(data (flags pss)" + "(hash %s %b)" + "(salt-length %u))", + hash_algo_to_string (algo), + (int)gcry_md_get_algo_dlen (algo), + gcry_md_read (md, algo), + saltlen); + if (rc) + BUG (); } + else + { + /* RSA or DSA: Prepare the hash for verification. */ + gcry_mpi_t frame; - /* put hash into the S-Exp s_hash */ - if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) ) - BUG (); - gcry_mpi_release (frame); - + rc = do_encode_md (md, algo, pk_algo_from_sexp (s_pkey), + gcry_pk_get_nbits (s_pkey), s_pkey, &frame); + if (rc) + { + gcry_md_close (md); + gcry_sexp_release (s_sig); + gcry_sexp_release (s_pkey); + return rc; + } + if ( gcry_sexp_build (&s_data, NULL, "%m", frame) ) + BUG (); + gcry_mpi_release (frame); + } + if (DBG_CRYPTO) + gcry_log_debugsxp ("data:", s_data); - rc = gcry_pk_verify (s_sig, s_hash, s_pkey); + /* Verify. */ + rc = gcry_pk_verify (s_sig, s_data, s_pkey); if (DBG_X509) log_debug ("gcry_pk_verify: %s\n", gpg_strerror (rc)); gcry_md_close (md); gcry_sexp_release (s_sig); - gcry_sexp_release (s_hash); + gcry_sexp_release (s_data); gcry_sexp_release (s_pkey); return rc; } @@ -338,30 +492,41 @@ gpgsm_check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert) int -gpgsm_check_cms_signature (ksba_cert_t cert, ksba_const_sexp_t sigval, - gcry_md_hd_t md, int mdalgo, int *r_pkalgo) +gpgsm_check_cms_signature (ksba_cert_t cert, gcry_sexp_t s_sig, + gcry_md_hd_t md, int mdalgo, + unsigned int pkalgoflags, int *r_pkalgo) { int rc; ksba_sexp_t p; - gcry_mpi_t frame; - gcry_sexp_t s_sig, s_hash, s_pkey; + gcry_sexp_t s_hash, s_pkey; size_t n; int pkalgo; + int use_pss; + unsigned int saltlen = 0; if (r_pkalgo) *r_pkalgo = 0; - n = gcry_sexp_canon_len (sigval, 0, NULL, NULL); - if (!n) - { - log_error ("libksba did not return a proper S-Exp\n"); - return gpg_error (GPG_ERR_BUG); - } - rc = gcry_sexp_sscan (&s_sig, NULL, (char*)sigval, n); - if (rc) + /* Check whether rsaPSS is needed. This information is indicated in + * the SIG-VAL and already provided to us by the caller so that we + * do not need to parse this out. */ + use_pss = !!(pkalgoflags & PK_ALGO_FLAG_RSAPSS); + if (use_pss) { - log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc)); - return rc; + int algo; + + rc = extract_pss_params (s_sig, &algo, &saltlen); + if (rc) + { + gcry_sexp_release (s_sig); + return rc; + } + if (algo != mdalgo) + { + log_error ("PSS hash algo mismatch (%d/%d)\n", mdalgo, algo); + gcry_sexp_release (s_sig); + return gpg_error (GPG_ERR_DIGEST_ALGO); + } } p = ksba_cert_get_public_key (cert); @@ -370,41 +535,57 @@ gpgsm_check_cms_signature (ksba_cert_t cert, ksba_const_sexp_t sigval, { log_error ("libksba did not return a proper S-Exp\n"); ksba_free (p); - gcry_sexp_release (s_sig); return gpg_error (GPG_ERR_BUG); } if (DBG_CRYPTO) - log_printhex ("public key: ", p, n); + log_printhex (p, n, "public key: "); rc = gcry_sexp_sscan ( &s_pkey, NULL, (char*)p, n); ksba_free (p); if (rc) { log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc)); - gcry_sexp_release (s_sig); return rc; } pkalgo = pk_algo_from_sexp (s_pkey); if (r_pkalgo) *r_pkalgo = pkalgo; - rc = do_encode_md (md, mdalgo, pkalgo, - gcry_pk_get_nbits (s_pkey), s_pkey, &frame); - if (rc) + + if (use_pss) { - gcry_sexp_release (s_sig); - gcry_sexp_release (s_pkey); - return rc; + rc = gcry_sexp_build (&s_hash, NULL, + "(data (flags pss)" + "(hash %s %b)" + "(salt-length %u))", + hash_algo_to_string (mdalgo), + (int)gcry_md_get_algo_dlen (mdalgo), + gcry_md_read (md, mdalgo), + saltlen); + if (rc) + BUG (); + } + else + { + /* RSA or DSA: Prepare the hash for verification. */ + gcry_mpi_t frame; + + rc = do_encode_md (md, mdalgo, pkalgo, + gcry_pk_get_nbits (s_pkey), s_pkey, &frame); + if (rc) + { + gcry_sexp_release (s_pkey); + return rc; + } + /* put hash into the S-Exp s_hash */ + if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) ) + BUG (); + gcry_mpi_release (frame); } - /* put hash into the S-Exp s_hash */ - if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) ) - BUG (); - gcry_mpi_release (frame); rc = gcry_pk_verify (s_sig, s_hash, s_pkey); if (DBG_X509) - log_debug ("gcry_pk_verify: %s\n", gpg_strerror (rc)); - gcry_sexp_release (s_sig); + log_debug ("gcry_pk_verify: %s\n", gpg_strerror (rc)); gcry_sexp_release (s_hash); gcry_sexp_release (s_pkey); return rc; diff --git a/sm/certdump.c b/sm/certdump.c index ede1210..c177cab 100644 --- a/sm/certdump.c +++ b/sm/certdump.c @@ -38,7 +38,7 @@ #include "keydb.h" #include "../common/i18n.h" - +#include "../common/membuf.h" struct dn_array_s { char *key; @@ -73,6 +73,85 @@ gpgsm_print_serial (estream_t fp, ksba_const_sexp_t sn) } +/* Print the first element of an S-Expression in decimal notation + * assuming it is a non-negative integer. */ +void +gpgsm_print_serial_decimal (estream_t fp, ksba_const_sexp_t sn) +{ + const char *p = (const char *)sn; + unsigned long n, i; + char *endp; + gcry_mpi_t a, r, ten; +#if GCRYPT_VERSION_NUMBER >= 0x010900 /* >= 1.9.0 */ + unsigned int dd; +#else + unsigned char numbuf[10]; +#endif + + if (!p) + es_fputs (_("none"), fp); + else if (*p != '(') + es_fputs ("[Internal error - not an S-expression]", fp); + else + { + p++; + n = strtoul (p, &endp, 10); + p = endp; + if (*p++ != ':') + es_fputs ("[Internal Error - invalid S-expression]", fp); + else if (gcry_mpi_scan (&a, GCRYMPI_FMT_USG, p, n, NULL)) + es_fputs ("[Internal Error - can't convert to decimal]", fp); + else + { + membuf_t mb = MEMBUF_ZERO; + char *buf; + int c; + + ten = gcry_mpi_set_ui (NULL, 10); + r = gcry_mpi_new (0); + + do + { + gcry_mpi_div (a, r, a, ten, 0); +#if GCRYPT_VERSION_NUMBER >= 0x010900 /* >= 1.9.0 */ + gcry_mpi_get_ui (&dd, r); + put_membuf_printf (&mb, "%u", dd); +#else + *numbuf = 0; /* Need to clear because USB format prints + * an empty string for a value of 0. */ + gcry_mpi_print (GCRYMPI_FMT_USG, numbuf, 10, NULL, r); + put_membuf_printf (&mb, "%u", (unsigned int)*numbuf); +#endif + } + while (gcry_mpi_cmp_ui (a, 0)); + + /* Make sure we have at least an empty string, get it, + * reverse it, and print it. */ + put_membuf (&mb, "", 1); + buf = get_membuf (&mb, NULL); + if (!buf) + es_fputs ("[Internal Error - out of core]", fp); + else + { + n = strlen (buf); + for (i=0; i < n/2; i++) + { + c = buf[i]; + buf[i] = buf[n-1-i]; + buf[n-1-i] = c; + } + es_fputs (buf, fp); + xfree (buf); + } + + gcry_mpi_release (r); + gcry_mpi_release (ten); + gcry_mpi_release (a); + } + } +} + + /* Dump the serial number or any other simple S-expression. */ void gpgsm_dump_serial (ksba_const_sexp_t sn) @@ -167,7 +246,7 @@ gpgsm_dump_string (const char *string) else { log_printf ( "[ "); - log_printhex (NULL, string, strlen (string)); + log_printhex (string, strlen (string), NULL); log_printf ( " ]"); } } diff --git a/sm/certreqgen.c b/sm/certreqgen.c index 3dec4fa..92d6ffe 100644 --- a/sm/certreqgen.c +++ b/sm/certreqgen.c @@ -198,7 +198,7 @@ parse_parameter_usage (struct para_data_s *para, enum para_name key) use |= GCRY_PK_USAGE_CERT; else { - log_error ("line %d: invalid usage list\n", r->lnr); + log_error ("line %d: invalid usage list\n", r?r->lnr:0); return -1; /* error */ } } @@ -461,7 +461,10 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para, if ( (i < 1 || i != GCRY_PK_RSA) && !cardkeyid ) { r = get_parameter (para, pKEYTYPE, 0); - log_error (_("line %d: invalid algorithm\n"), r->lnr); + if (r) + log_error (_("line %d: invalid algorithm\n"), r?r->lnr:0); + else + log_error ("No Key-Type specified\n"); return gpg_error (GPG_ERR_INV_PARAMETER); } @@ -476,7 +479,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para, /* The BSI specs dated 2002-11-25 don't allow lengths below 1024. */ r = get_parameter (para, pKEYLENGTH, 0); log_error (_("line %d: invalid key length %u (valid are %d to %d)\n"), - r->lnr, nbits, 1024, 4096); + r?r->lnr:0, nbits, 1024, 4096); xfree (cardkeyid); return gpg_error (GPG_ERR_INV_PARAMETER); } @@ -493,7 +496,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para, if (!(s=get_parameter_value (para, pNAMEDN, 0))) { r = get_parameter (para, pNAMEDN, 0); - log_error (_("line %d: no subject name given\n"), r->lnr); + log_error (_("line %d: no subject name given\n"), r?r->lnr:0); xfree (cardkeyid); return gpg_error (GPG_ERR_INV_PARAMETER); } @@ -503,10 +506,10 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para, r = get_parameter (para, pNAMEDN, 0); if (gpg_err_code (err) == GPG_ERR_UNKNOWN_NAME) log_error (_("line %d: invalid subject name label '%.*s'\n"), - r->lnr, (int)errlen, s+erroff); + r?r->lnr:0, (int)errlen, s+erroff); else log_error (_("line %d: invalid subject name '%s' at pos %d\n"), - r->lnr, s, (int)erroff); + r?r->lnr:0, s, (int)erroff); xfree (cardkeyid); return gpg_error (GPG_ERR_INV_PARAMETER); @@ -522,7 +525,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para, || strstr(s, "..")) { r = get_parameter (para, pNAMEEMAIL, seq); - log_error (_("line %d: not a valid email address\n"), r->lnr); + log_error (_("line %d: not a valid email address\n"), r?r->lnr:0); xfree (cardkeyid); return gpg_error (GPG_ERR_INV_PARAMETER); } @@ -541,7 +544,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para, if (*s) { r = get_parameter (para, pSERIAL, 0); - log_error (_("line %d: invalid serial number\n"), r->lnr); + log_error (_("line %d: invalid serial number\n"), r?r->lnr:0); xfree (cardkeyid); return gpg_error (GPG_ERR_INV_PARAMETER); } @@ -558,10 +561,10 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para, r = get_parameter (para, pISSUERDN, 0); if (gpg_err_code (err) == GPG_ERR_UNKNOWN_NAME) log_error (_("line %d: invalid issuer name label '%.*s'\n"), - r->lnr, (int)errlen, string+erroff); + r?r->lnr:0, (int)errlen, string+erroff); else log_error (_("line %d: invalid issuer name '%s' at pos %d\n"), - r->lnr, string, (int)erroff); + r?r->lnr:0, string, (int)erroff); xfree (cardkeyid); return gpg_error (GPG_ERR_INV_PARAMETER); } @@ -572,7 +575,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para, if (string && !string2isotime (NULL, string)) { r = get_parameter (para, pNOTBEFORE, 0); - log_error (_("line %d: invalid date given\n"), r->lnr); + log_error (_("line %d: invalid date given\n"), r?r->lnr:0); xfree (cardkeyid); return gpg_error (GPG_ERR_INV_PARAMETER); } @@ -583,7 +586,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para, if (string && !string2isotime (NULL, string)) { r = get_parameter (para, pNOTAFTER, 0); - log_error (_("line %d: invalid date given\n"), r->lnr); + log_error (_("line %d: invalid date given\n"), r?r->lnr:0); xfree (cardkeyid); return gpg_error (GPG_ERR_INV_PARAMETER); } @@ -597,7 +600,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para, { r = get_parameter (para, pKEYTYPE, 0); log_error (_("line %d: error getting signing key by keygrip '%s'" - ": %s\n"), r->lnr, s, gpg_strerror (rc)); + ": %s\n"), r?r->lnr:0, s, gpg_strerror (rc)); xfree (cardkeyid); return rc; } @@ -615,7 +618,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para, || mdalgo == GCRY_MD_SHA512))) { r = get_parameter (para, pHASHALGO, 0); - log_error (_("line %d: invalid hash algorithm given\n"), r->lnr); + log_error (_("line %d: invalid hash algorithm given\n"), r?r->lnr:0); xfree (cardkeyid); return gpg_error (GPG_ERR_INV_PARAMETER); } @@ -630,7 +633,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para, if (*s || (i&1)) { r = get_parameter (para, pAUTHKEYID, 0); - log_error (_("line %d: invalid authority-key-id\n"), r->lnr); + log_error (_("line %d: invalid authority-key-id\n"), r?r->lnr:0); xfree (cardkeyid); return gpg_error (GPG_ERR_INV_PARAMETER); } @@ -645,7 +648,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para, if (*s || (i&1)) { r = get_parameter (para, pSUBJKEYID, 0); - log_error (_("line %d: invalid subject-key-id\n"), r->lnr); + log_error (_("line %d: invalid subject-key-id\n"), r?r->lnr:0); xfree (cardkeyid); return gpg_error (GPG_ERR_INV_PARAMETER); } @@ -683,7 +686,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para, if (!okay) { r = get_parameter (para, pEXTENSION, seq); - log_error (_("line %d: invalid extension syntax\n"), r->lnr); + log_error (_("line %d: invalid extension syntax\n"), r? r->lnr:0); xfree (cardkeyid); return gpg_error (GPG_ERR_INV_PARAMETER); } @@ -697,7 +700,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para, { r = get_parameter (para, pKEYTYPE, 0); log_error (_("line %d: error reading key '%s' from card: %s\n"), - r->lnr, cardkeyid, gpg_strerror (rc)); + r?r->lnr:0, cardkeyid, gpg_strerror (rc)); xfree (sigkey); xfree (cardkeyid); return rc; @@ -727,7 +730,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para, { r = get_parameter (para, pKEYTYPE, 0); log_error (_("line %d: key generation failed: %s <%s>\n"), - r->lnr, gpg_strerror (rc), gpg_strsource (rc)); + r?r->lnr:0, gpg_strerror (rc), gpg_strsource (rc)); xfree (sigkey); xfree (cardkeyid); return rc; diff --git a/sm/decrypt.c b/sm/decrypt.c index db0768e..90eba88 100644 --- a/sm/decrypt.c +++ b/sm/decrypt.c @@ -72,7 +72,7 @@ prepare_decryption (ctrl_t ctrl, const char *hexkeygrip, const char *desc, } if (DBG_CRYPTO) - log_printhex ("pkcs1 encoded session key:", seskey, seskeylen); + log_printhex (seskey, seskeylen, "pkcs1 encoded session key:"); n=0; if (seskeylen == 32 || seskeylen == 24 || seskeylen == 16) @@ -115,7 +115,7 @@ prepare_decryption (ctrl_t ctrl, const char *hexkeygrip, const char *desc, } if (DBG_CRYPTO) - log_printhex ("session key:", seskey+n, seskeylen-n); + log_printhex (seskey+n, seskeylen-n, "session key:"); rc = gcry_cipher_open (&parm->hd, parm->algo, parm->mode, 0); if (rc) @@ -483,7 +483,7 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp) /* Check compliance. */ if (!gnupg_pk_is_allowed (opt.compliance, PK_USE_DECRYPTION, - pk_algo, NULL, nbits, NULL)) + pk_algo, 0, NULL, nbits, NULL)) { char kidstr[10+1]; @@ -501,7 +501,7 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp) /* Check that all certs are compliant with CO_DE_VS. */ is_de_vs = (is_de_vs - && gnupg_pk_is_compliant (CO_DE_VS, pk_algo, NULL, + && gnupg_pk_is_compliant (CO_DE_VS, pk_algo, 0, NULL, nbits, NULL)); } diff --git a/sm/encrypt.c b/sm/encrypt.c index 6213a66..f03097c 100644 --- a/sm/encrypt.c +++ b/sm/encrypt.c @@ -480,7 +480,8 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, estream_t out_fp) /* Check compliance. */ pk_algo = gpgsm_get_key_algo_info (cl->cert, &nbits); - if (!gnupg_pk_is_compliant (opt.compliance, pk_algo, NULL, nbits, NULL)) + if (!gnupg_pk_is_compliant (opt.compliance, pk_algo, 0, + NULL, nbits, NULL)) { char kidstr[10+1]; @@ -495,7 +496,7 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, estream_t out_fp) /* Fixme: When adding ECC we need to provide the curvename and * the key to gnupg_pk_is_compliant. */ if (compliant - && !gnupg_pk_is_compliant (CO_DE_VS, pk_algo, NULL, nbits, NULL)) + && !gnupg_pk_is_compliant (CO_DE_VS, pk_algo, 0, NULL, nbits, NULL)) compliant = 0; rc = encrypt_dek (dek, cl->cert, &encval); diff --git a/sm/fingerprint.c b/sm/fingerprint.c index fbcec58..2e01cf1 100644 --- a/sm/fingerprint.c +++ b/sm/fingerprint.c @@ -196,7 +196,7 @@ gpgsm_get_keygrip (ksba_cert_t cert, unsigned char *array) return NULL; } if (DBG_X509) - log_printhex ("keygrip=", array, 20); + log_printhex (array, 20, "keygrip="); return array; } @@ -277,6 +277,41 @@ gpgsm_get_key_algo_info (ksba_cert_t cert, unsigned int *nbits) } +/* This is a wrapper around pubkey_algo_string which takes a KSBA + * certificate instead of a Gcrypt public key. Note that this + * function may return NULL on error. */ +char * +gpgsm_pubkey_algo_string (ksba_cert_t cert, int *r_algoid) +{ + gpg_error_t err; + gcry_sexp_t s_pkey; + ksba_sexp_t p; + size_t n; + enum gcry_pk_algos algoid; + char *algostr; + + p = ksba_cert_get_public_key (cert); + if (!p) + return NULL; + n = gcry_sexp_canon_len (p, 0, NULL, NULL); + if (!n) + { + xfree (p); + return NULL; + } + err = gcry_sexp_sscan (&s_pkey, NULL, (char *)p, n); + xfree (p); + if (err) + return NULL; + + algostr = pubkey_algo_string (s_pkey, r_algoid? &algoid : NULL); + if (algostr && r_algoid) + *r_algoid = algoid; + + gcry_sexp_release (s_pkey); + return algostr; +} + /* For certain purposes we need a certificate id which has an upper @@ -144,6 +144,7 @@ enum cmd_and_opt_values { oDisableTrustedCertCRLCheck, oEnableTrustedCertCRLCheck, oForceCRLRefresh, + oEnableIssuerBasedCRLCheck, oDisableOCSP, oEnableOCSP, @@ -402,6 +403,8 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_n (oNoCommonCertsImport, "no-common-certs-import", "@"), ARGPARSE_s_s (oIgnoreCertExtension, "ignore-cert-extension", "@"), ARGPARSE_s_n (oNoAutostart, "no-autostart", "@"), + ARGPARSE_s_n (oEnableIssuerBasedCRLCheck, "enable-issuer-based-crl-check", + "@"), /* Command aliases. */ ARGPARSE_c (aListKeys, "list-key", "@"), @@ -1202,6 +1205,9 @@ main ( int argc, char **argv) case oForceCRLRefresh: opt.force_crl_refresh = 1; break; + case oEnableIssuerBasedCRLCheck: + opt.enable_issuer_based_crl_check = 1; + break; case oDisableOCSP: ctrl.use_ocsp = opt.enable_ocsp = 0; @@ -124,6 +124,7 @@ struct int no_crl_check; /* Don't do a CRL check */ int no_trusted_cert_crl_check; /* Don't run a CRL check for trusted certs. */ int force_crl_refresh; /* Force refreshing the CRL. */ + int enable_issuer_based_crl_check; /* Backward compatibility hack. */ int enable_ocsp; /* Default to use OCSP checks. */ char *policy_file; /* full pathname of policy file */ @@ -263,11 +264,13 @@ unsigned long gpgsm_get_short_fingerprint (ksba_cert_t cert, unsigned char *gpgsm_get_keygrip (ksba_cert_t cert, unsigned char *array); char *gpgsm_get_keygrip_hexstring (ksba_cert_t cert); int gpgsm_get_key_algo_info (ksba_cert_t cert, unsigned int *nbits); +char *gpgsm_pubkey_algo_string (ksba_cert_t cert, int *r_algoid); char *gpgsm_get_certid (ksba_cert_t cert); /*-- certdump.c --*/ void gpgsm_print_serial (estream_t fp, ksba_const_sexp_t p); +void gpgsm_print_serial_decimal (estream_t fp, ksba_const_sexp_t sn); void gpgsm_print_time (estream_t fp, ksba_isotime_t t); void gpgsm_print_name2 (FILE *fp, const char *string, int translate); void gpgsm_print_name (FILE *fp, const char *string); @@ -293,8 +296,10 @@ char *gpgsm_format_keydesc (ksba_cert_t cert); /*-- certcheck.c --*/ int gpgsm_check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert); -int gpgsm_check_cms_signature (ksba_cert_t cert, ksba_const_sexp_t sigval, - gcry_md_hd_t md, int hash_algo, int *r_pkalgo); +int gpgsm_check_cms_signature (ksba_cert_t cert, gcry_sexp_t sigval, + gcry_md_hd_t md, + int hash_algo, unsigned int pkalgoflags, + int *r_pkalgo); /* fixme: move create functions to another file */ int gpgsm_create_cms_signature (ctrl_t ctrl, ksba_cert_t cert, gcry_md_hd_t md, int mdalgo, @@ -423,7 +428,8 @@ gpg_error_t gpgsm_agent_export_key (ctrl_t ctrl, const char *keygrip, int gpgsm_dirmngr_isvalid (ctrl_t ctrl, ksba_cert_t cert, ksba_cert_t issuer_cert, int use_ocsp); -int gpgsm_dirmngr_lookup (ctrl_t ctrl, strlist_t names, int cache_only, +int gpgsm_dirmngr_lookup (ctrl_t ctrl, strlist_t names, const char *uri, + int cache_only, void (*cb)(void*, ksba_cert_t), void *cb_value); int gpgsm_dirmngr_run_command (ctrl_t ctrl, const char *command, int argc, char **argv); @@ -435,6 +441,9 @@ gpg_error_t transform_sigval (const unsigned char *sigval, size_t sigvallen, int mdalgo, unsigned char **r_newsigval, size_t *r_newsigvallen); +gcry_sexp_t gpgsm_ksba_cms_get_sig_val (ksba_cms_t cms, int idx); +int gpgsm_get_hash_algo_from_sigval (gcry_sexp_t sigval, + unsigned int *r_pkalgo_flags); diff --git a/sm/import.c b/sm/import.c index 8796cd2..ca69382 100644 --- a/sm/import.c +++ b/sm/import.c @@ -836,7 +836,7 @@ parse_p12 (ctrl_t ctrl, ksba_reader_t reader, struct stats_s *stats) log_error ("can't calculate keygrip\n"); goto leave; } - log_printhex ("keygrip=", grip, 20); + log_printhex (grip, 20, "keygrip="); /* Convert to canonical encoding using a function which pads it to a multiple of 64 bits. We need this padding for AESWRAP. */ diff --git a/sm/keylist.c b/sm/keylist.c index 6efc6bd..8c7fafc 100644 --- a/sm/keylist.c +++ b/sm/keylist.c @@ -361,7 +361,10 @@ print_compliance_flags (ksba_cert_t cert, int algo, unsigned int nbits, { int hashalgo; - if (gnupg_pk_is_compliant (CO_DE_VS, algo, NULL, nbits, NULL)) + /* Note that we do not need to test for PK_ALGO_FLAG_RSAPSS because + * that is not a property of the key but one of the created + * signature. */ + if (gnupg_pk_is_compliant (CO_DE_VS, algo, 0, NULL, nbits, NULL)) { hashalgo = gcry_md_map_name (ksba_cert_get_digest_algo (cert)); if (gnupg_digest_is_compliant (CO_DE_VS, hashalgo)) @@ -738,8 +741,11 @@ list_cert_raw (ctrl_t ctrl, KEYDB_HANDLE hd, sexp = ksba_cert_get_serial (cert); es_fputs (" S/N: ", fp); gpgsm_print_serial (fp, sexp); - ksba_free (sexp); es_putc ('\n', fp); + es_fputs (" (dec): ", fp); + gpgsm_print_serial_decimal (fp, sexp); + es_putc ('\n', fp); + ksba_free (sexp); dn = ksba_cert_get_issuer (cert, 0); es_fputs (" Issuer: ", fp); @@ -1118,8 +1124,11 @@ list_cert_std (ctrl_t ctrl, ksba_cert_t cert, estream_t fp, int have_secret, sexp = ksba_cert_get_serial (cert); es_fputs (" S/N: ", fp); gpgsm_print_serial (fp, sexp); - ksba_free (sexp); es_putc ('\n', fp); + es_fputs (" (dec): ", fp); + gpgsm_print_serial_decimal (fp, sexp); + es_putc ('\n', fp); + ksba_free (sexp); dn = ksba_cert_get_issuer (cert, 0); es_fputs (" Issuer: ", fp); @@ -1607,7 +1616,7 @@ list_external_keys (ctrl_t ctrl, strlist_t names, estream_t fp, int raw_mode) parm.with_chain = ctrl->with_chain; parm.raw_mode = raw_mode; - rc = gpgsm_dirmngr_lookup (ctrl, names, 0, list_external_cb, &parm); + rc = gpgsm_dirmngr_lookup (ctrl, names, NULL, 0, list_external_cb, &parm); if (gpg_err_code (rc) == GPG_ERR_EOF || rc == -1 || gpg_err_code (rc) == GPG_ERR_NOT_FOUND) rc = 0; /* "Not found" is not an error here. */ @@ -216,3 +216,93 @@ transform_sigval (const unsigned char *sigval, size_t sigvallen, int mdalgo, return err; } + + +/* Wrapper around ksba_cms_get_sig_val to return a gcrypt object + * instaed of ksba's canonical s-expression. On errror NULL is return + * and in some cases an error message is printed. */ +gcry_sexp_t +gpgsm_ksba_cms_get_sig_val (ksba_cms_t cms, int idx) +{ + gpg_error_t err; + ksba_sexp_t sigval; + gcry_sexp_t s_sigval; + size_t n; + + sigval = ksba_cms_get_sig_val (cms, idx); + if (!sigval) + return NULL; + n = gcry_sexp_canon_len (sigval, 0, NULL, NULL); + if (!n) + { + log_error ("%s: libksba did not return a proper S-Exp\n", __func__); + ksba_free (sigval); + return NULL; + } + err = gcry_sexp_sscan (&s_sigval, NULL, (char*)sigval, n); + ksba_free (sigval); + if (err) + { + log_error ("%s: gcry_sexp_scan failed: %s\n", + __func__, gpg_strerror (err)); + s_sigval = NULL; + } + + return s_sigval; +} + + +/* Return the hash algorithm from the S-expression SIGVAL. Returns 0 + * if the hash algorithm is not encoded in SIGVAL or it is not + * supported by libgcrypt. It further stores flag values for the + * public key algorithm at R_PKALGO_FLAGS; the only flag we currently + * support is PK_ALGO_FLAG_RSAPSS. */ +int +gpgsm_get_hash_algo_from_sigval (gcry_sexp_t sigval_arg, + unsigned int *r_pkalgo_flags) +{ + gcry_sexp_t sigval, l1; + size_t n; + const char *s; + char *string; + int hashalgo; + int i; + + *r_pkalgo_flags = 0; + + sigval = gcry_sexp_find_token (sigval_arg, "sig-val", 0); + if (!sigval) + return 0; /* Not a sig-val. */ + + /* First check whether this is a rsaPSS signature and return that as + * additional info. */ + l1 = gcry_sexp_find_token (sigval, "flags", 0); + if (l1) + { + /* Note that the flag parser assumes that the list of flags + * contains only strings and in particular not a sub-list. This + * is always the case for the current libksba. */ + for (i=1; (s = gcry_sexp_nth_data (l1, i, &n)); i++) + if (n == 3 && !memcmp (s, "pss", 3)) + { + *r_pkalgo_flags |= PK_ALGO_FLAG_RSAPSS; + break; + } + gcry_sexp_release (l1); + } + + l1 = gcry_sexp_find_token (sigval, "hash", 0); + if (!l1) + { + gcry_sexp_release (sigval); + return 0; /* hash algorithm not given in sigval. */ + } + string = gcry_sexp_nth_string (l1, 1); + gcry_sexp_release (sigval); + if (!string) + return 0; /* hash algorithm has no value. */ + hashalgo = gcry_md_map_name (string); + gcry_free (string); + + return hashalgo; +} @@ -486,7 +486,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, unsigned int nbits; int pk_algo = gpgsm_get_key_algo_info (cl->cert, &nbits); - if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_SIGNING, pk_algo, + if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_SIGNING, pk_algo, 0, NULL, nbits, NULL)) { char kidstr[10+1]; diff --git a/sm/verify.c b/sm/verify.c index 10b3f43..0fa365f 100644 --- a/sm/verify.c +++ b/sm/verify.c @@ -1,6 +1,8 @@ /* verify.c - Verify a messages signature * Copyright (C) 2001, 2002, 2003, 2007, * 2010 Free Software Foundation, Inc. + * Copyright (C) 2001-2019 Werner Koch + * Copyright (C) 2015-2020 g10 Code GmbH * * This file is part of GnuPG. * @@ -16,6 +18,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, see <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-3.0-or-later */ #include <config.h> @@ -286,7 +289,7 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp) for (signer=0; ; signer++) { char *issuer = NULL; - ksba_sexp_t sigval = NULL; + gcry_sexp_t sigval = NULL; ksba_isotime_t sigtime, keyexptime; ksba_sexp_t serial; char *msgdigest = NULL; @@ -294,7 +297,11 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp) char *ctattr; int sigval_hash_algo; int info_pkalgo; - unsigned int verifyflags; + unsigned int nbits; + int pkalgo; + char *pkalgostr = NULL; + char *pkfpr = NULL; + unsigned int pkalgoflags, verifyflags; rc = ksba_cms_get_issuer_serial (cms, signer, &issuer, &serial); if (!signer && gpg_err_code (rc) == GPG_ERR_NO_DATA @@ -400,20 +407,19 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp) rc = 0; - sigval = ksba_cms_get_sig_val (cms, signer); + sigval = gpgsm_ksba_cms_get_sig_val (cms, signer); if (!sigval) { log_error ("no signature value available\n"); audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "bad"); goto next_signer; } - sigval_hash_algo = hash_algo_from_sigval (sigval); + + sigval_hash_algo = gpgsm_get_hash_algo_from_sigval (sigval, &pkalgoflags); if (DBG_X509) { - log_debug ("signer %d - signature available (sigval hash=%d)", - signer, sigval_hash_algo); -/* log_printhex ("sigval ", sigval, */ -/* gcry_sexp_canon_len (sigval, 0, NULL, NULL)); */ + log_debug ("signer %d - signature available (sigval hash=%d pkaf=%u)", + signer, sigval_hash_algo, pkalgoflags); } if (!sigval_hash_algo) sigval_hash_algo = algo; /* Fallback used e.g. with old libksba. */ @@ -450,49 +456,68 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp) goto next_signer; } - /* Check compliance. */ - { - unsigned int nbits; - int pk_algo = gpgsm_get_key_algo_info (cert, &nbits); - - if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_VERIFICATION, - pk_algo, NULL, nbits, NULL)) - { - char kidstr[10+1]; - - snprintf (kidstr, sizeof kidstr, "0x%08lX", - gpgsm_get_short_fingerprint (cert, NULL)); - log_error (_("key %s may not be used for signing in %s mode\n"), - kidstr, - gnupg_compliance_option_string (opt.compliance)); - goto next_signer; - } - - if (! gnupg_digest_is_allowed (opt.compliance, 0, sigval_hash_algo)) - { - log_error (_("digest algorithm '%s' may not be used in %s mode\n"), - gcry_md_algo_name (sigval_hash_algo), - gnupg_compliance_option_string (opt.compliance)); - goto next_signer; - } - - /* Check compliance with CO_DE_VS. */ - if (gnupg_pk_is_compliant (CO_DE_VS, pk_algo, NULL, nbits, NULL) - && gnupg_digest_is_compliant (CO_DE_VS, sigval_hash_algo)) - gpgsm_status (ctrl, STATUS_VERIFICATION_COMPLIANCE_MODE, - gnupg_status_compliance_flag (CO_DE_VS)); - } + pkfpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1); + pkalgostr = gpgsm_pubkey_algo_string (cert, NULL); + pkalgo = gpgsm_get_key_algo_info (cert, &nbits); log_info (_("Signature made ")); if (*sigtime) - dump_isotime (sigtime); + { + /* We take the freedom as noted in RFC3339 to use a space + * instead of the "T" delimiter between date and time. We + * also append a separate UTC instead of a "Z" or "+00:00" + * suffix because that makes it clear to everyone what kind + * of time this is. */ + dump_isotime (sigtime); + log_printf (" UTC"); + } else log_printf (_("[date not given]")); - log_printf (_(" using certificate ID 0x%08lX\n"), - gpgsm_get_short_fingerprint (cert, NULL)); + log_info (_(" using %s key %s\n"), pkalgostr, pkfpr); + if (opt.verbose) + { + log_info (_("algorithm:")); + log_printf (" %s + %s", + pubkey_algo_to_string (pkalgo), + gcry_md_algo_name (sigval_hash_algo)); + if (algo != sigval_hash_algo) + log_printf (" (%s)", gcry_md_algo_name (algo)); + log_printf ("\n"); + } audit_log_i (ctrl->audit, AUDIT_DATA_HASH_ALGO, algo); + /* Check compliance. */ + if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_VERIFICATION, + pkalgo, pkalgoflags, NULL, nbits, NULL)) + { + char kidstr[10+1]; + + snprintf (kidstr, sizeof kidstr, "0x%08lX", + gpgsm_get_short_fingerprint (cert, NULL)); + log_error (_("key %s may not be used for signing in %s mode\n"), + kidstr, + gnupg_compliance_option_string (opt.compliance)); + goto next_signer; + } + + if (!gnupg_digest_is_allowed (opt.compliance, 0, sigval_hash_algo)) + { + log_error (_("digest algorithm '%s' may not be used in %s mode\n"), + gcry_md_algo_name (sigval_hash_algo), + gnupg_compliance_option_string (opt.compliance)); + goto next_signer; + } + + /* Check compliance with CO_DE_VS. */ + if (gnupg_pk_is_compliant (CO_DE_VS, pkalgo, pkalgoflags, + NULL, nbits, NULL) + && gnupg_digest_is_compliant (CO_DE_VS, sigval_hash_algo)) + gpgsm_status (ctrl, STATUS_VERIFICATION_COMPLIANCE_MODE, + gnupg_status_compliance_flag (CO_DE_VS)); + + + /* Now we can check the signature. */ if (msgdigest) { /* Signed attributes are available. */ gcry_md_hd_t md; @@ -512,10 +537,10 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp) if (DBG_X509) { if (msgdigest) - log_printhex ("message: ", msgdigest, msgdigestlen); + log_printhex (msgdigest, msgdigestlen, "message: "); if (s) - log_printhex ("computed: ", - s, gcry_md_get_algo_dlen (algo)); + log_printhex (s, gcry_md_get_algo_dlen (algo), + "computed: "); } fpr = gpgsm_fpr_and_name_for_status (cert); gpgsm_status (ctrl, STATUS_BADSIG, fpr); @@ -545,14 +570,14 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp) audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "error"); goto next_signer; } - rc = gpgsm_check_cms_signature (cert, sigval, md, - sigval_hash_algo, &info_pkalgo); + rc = gpgsm_check_cms_signature (cert, sigval, md, sigval_hash_algo, + pkalgoflags, &info_pkalgo); gcry_md_close (md); } else { rc = gpgsm_check_cms_signature (cert, sigval, data_md, - algo, &info_pkalgo); + algo, pkalgoflags, &info_pkalgo); } if (rc) @@ -669,8 +694,10 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp) rc = 0; xfree (issuer); xfree (serial); - xfree (sigval); + gcry_sexp_release (sigval); xfree (msgdigest); + xfree (pkalgostr); + xfree (pkfpr); ksba_cert_release (cert); cert = NULL; } diff --git a/tools/send-mail.c b/tools/send-mail.c index 9f07c7a..6492c43 100644 --- a/tools/send-mail.c +++ b/tools/send-mail.c @@ -33,7 +33,7 @@ static gpg_error_t run_sendmail (estream_t data) { gpg_error_t err; - const char pgmname[] = "/usr/lib/sendmail"; + const char pgmname[] = NAME_OF_SENDMAIL; const char *argv[3]; argv[0] = "-oi"; |