Merge branch 'master' into switch-to-gpgk

This commit is contained in:
Werner Koch 2019-07-12 13:57:00 +02:00
commit a5118b19c1
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
142 changed files with 7869 additions and 3007 deletions

183
NEWS
View File

@ -1,6 +1,184 @@
Noteworthy changes in version 2.3.0 (unreleased)
------------------------------------------------
Changes also found in 2.2.16:
* gpg,gpgsm: Fix deadlock on Windows due to a keybox sharing
violation. [#4505]
* gpg: Allow deletion of subkeys with --delete-key. This finally
makes the bang-suffix work as expected for that command. [#4457]
* gpg: Replace SHA-1 by SHA-256 in self-signatures when updating
them with --quick-set-expire or --quick-set-primary-uid. [#4508]
* gpg: Improve the photo image viewer selection. [#4334]
* gpg: Fix decryption with --use-embedded-filename. [#4500]
* gpg: Remove hints on using the --keyserver option. [#4512]
* gpg: Fix export of certain secret keys with comments. [#4490]
* gpg: Reject too long user-ids in --quick-gen-key. [#4532]
* gpg: Fix a double free in the best key selection code. [#4462]
* gpg: Fix the key generation dialog for switching back from EdDSA
to ECDSA.
* gpg: Use AES-192 with SHA-384 to comply with RFC-6637.
* gpg: Use only the addrspec from the Signer's UID subpacket to
mitigate a problem with another implementation.
* gpg: Skip invalid packets during a keyring listing and sync
diagnostics with the output.
* gpgsm: Avoid confusing diagnostic when signing with the default
key. [#4535]
* agent: Do not delete any secret key in --dry-run mode.
* agent: Fix failures on 64 bit big-endian boxes related to URIs in
a keyfile. [#4501]
* agent: Stop scdaemon after a reload with disable-scdaemon newly
configured. [#4326]
* dirmngr: Improve caching algorithm for WKD domains.
* dirmngr: Support other hash algorithms than SHA-1 for OCSP. [#3966]
* gpgconf: Make --homedir work for --launch. [#4496]
* gpgconf: Before --launch check for a valid config file. [#4497]
* wkd: Do not import more than 5 keys from one WKD address.
* wkd: Accept keys which are stored in armored format in the
directory.
* The installer for Windows now comes with signed binaries.
Release-info: https://dev.gnupg.org/T4509
See-also: gnupg-announce/2019q2/000438.html
Changes also found in 2.2.15:
* sm: Fix --logger-fd and --status-fd on Windows for non-standard
file descriptors.
* sm: Allow decryption even if expired keys are configured. [#4431]
* agent: Change command KEYINFO to print ssh fingerprints with other
hash algos.
* dirmngr: Fix build problems on Solaris due to the use of reserved
symbol names. [#4420]
* wkd: New commands --print-wkd-hash and --print-wkd-url for
gpg-wks-client.
Release-info: https://dev.gnupg.org/T4434
See-also: gnupg-announce/2019q1/000436.html
Changes also found in 2.2.14:
* gpg: Allow import of PGP desktop exported secret keys. Also avoid
importing secret keys if the secret keyblock is not valid. [#4392]
* gpg: Make invalid primary key algo obvious in key listings.
* sm: Do not mark a certificate in a key listing as de-vs compliant
if its use for a signature will not be possible.
* sm: Fix certificate creation with key on card.
* sm: Create rsa3072 bit certificates by default.
* sm: Print Yubikey attestation extensions with --dump-cert.
* agent: Fix cancellation handling for scdaemon.
* agent: Support --mode=ssh option for CLEAR_PASSPHRASE. [#4340]
* scd: Fix flushing of the CA-FPR DOs in app-openpgp.
* scd: Avoid a conflict error with the "undefined" app.
* dirmngr: Add CSRF protection exception for protonmail.
* dirmngr: Fix build problems with gcc 9 in libdns.
* gpgconf: New option --show-socket for use with --launch.
* gpgtar: Make option -C work for archive creation.
Release-info: https://dev.gnupg.org/T4412
See-also: gnupg-announce/2019q1/000435.html
Changes also found in 2.2.13:
* gpg: Implement key lookup via keygrip (using the & prefix).
* gpg: Allow generating Ed25519 key from existing key.
* gpg: Emit an ERROR status line if no key was found with -k.
* gpg: Stop early when trying to create a primary Elgamal key. [#4329]
* gpgsm: Print the card's key algorithms along with their keygrips
in interactive key generation.
* agent: Clear bogus pinentry cache in the error case. [#4348]
* scd: Support "acknowledge button" feature.
* scd: Fix for USB INTERRUPT transfer. [#4308]
* wks: Do no use compression for the the encrypted challenge and
response.
Release-info: https://dev.gnupg.org/T4290
See-also: gnupg-announce/2019q1/000434.html
Changes also found in 2.2.12:
* tools: New commands --install-key and --remove-key for
gpg-wks-client. This allows to prepare a Web Key Directory on a
local file system for later upload to a web server.
* gpg: New --list-option "show-only-fpr-mbox". This makes the use
of the new gpg-wks-client --install-key command easier on Windows.
* gpg: Improve processing speed when --skip-verify is used.
* gpg: Fix a bug where a LF was accidentally written to the console.
* gpg: --card-status now shows whether a card has the new KDF
feature enabled.
* agent: New runtime option --s2k-calibration=MSEC. New configure
option --with-agent-s2k-calibration=MSEC. [#3399]
* dirmngr: Try another keyserver from the pool on receiving a 502,
503, or 504 error. [#4175]
* dirmngr: Avoid possible CSRF attacks via http redirects. A HTTP
query will not anymore follow a 3xx redirect unless the Location
header gives the same host. If the host is different only the
host and port is taken from the Location header and the original
path and query parts are kept.
* dirmngr: New command FLUSHCRL to flush all CRLS from disk and
memory. [#3967]
* New simplified Chinese translation (zh_CN).
Release-info: https://dev.gnupg.org/T4289
See-also: gnupg-announce/2018q4/000433.html
Changes also found in 2.2.11:
* gpgsm: Fix CRL loading when intermediate certicates are not yet
@ -388,6 +566,11 @@ Noteworthy changes in version 2.3.0 (unreleased)
Version 2.2.9 (2018-07-12)
Version 2.2.10 (2018-08-30)
Version 2.2.11 (2018-11-06)
Version 2.2.12 (2018-12-14)
Version 2.2.13 (2019-02-12)
Version 2.2.14 (2019-03-19)
Version 2.2.15 (2019-03-26)
Version 2.2.16 (2019-05-28)
Noteworthy changes in version 2.2.0 (2017-08-28)

View File

@ -361,6 +361,15 @@ typedef int (*lookup_ttl_t)(const char *hexgrip);
#endif
/* Information from scdaemon for card keys. */
struct card_key_info_s
{
struct card_key_info_s *next;
char keygrip[40];
char *serialno;
char *idstr;
};
/*-- gpg-agent.c --*/
void agent_exit (int rc)
GPGRT_ATTR_NORETURN; /* Also implemented in other tools */
@ -389,8 +398,11 @@ void bump_key_eventcounter (void);
void bump_card_eventcounter (void);
void start_command_handler (ctrl_t, gnupg_fd_t, gnupg_fd_t);
gpg_error_t pinentry_loopback (ctrl_t, const char *keyword,
unsigned char **buffer, size_t *size,
size_t max_length);
unsigned char **buffer, size_t *size,
size_t max_length);
gpg_error_t pinentry_loopback_confirm (ctrl_t ctrl, const char *desc,
int ask_confirmation,
const char *ok, const char *notok);
#ifdef HAVE_W32_SYSTEM
int serve_mmapped_ssh_request (ctrl_t ctrl,
@ -414,7 +426,8 @@ void start_command_handler_ssh (ctrl_t, gnupg_fd_t);
gpg_error_t agent_modify_description (const char *in, const char *comment,
const gcry_sexp_t key, char **result);
int agent_write_private_key (const unsigned char *grip,
const void *buffer, size_t length, int force);
const void *buffer, size_t length, int force,
const char *serialno, const char *keyref);
gpg_error_t agent_key_from_file (ctrl_t ctrl,
const char *cache_nonce,
const char *desc_text,
@ -543,10 +556,12 @@ void agent_reload_trustlist (void);
/*-- divert-scd.c --*/
int divert_pksign (ctrl_t ctrl, const char *desc_text,
const unsigned char *grip,
const unsigned char *digest, size_t digestlen, int algo,
const unsigned char *shadow_info, unsigned char **r_sig,
size_t *r_siglen);
int divert_pkdecrypt (ctrl_t ctrl, const char *desc_text,
const unsigned char *grip,
const unsigned char *cipher,
const unsigned char *shadow_info,
char **r_buf, size_t *r_len, int *r_padding);
@ -603,6 +618,10 @@ int agent_card_scd (ctrl_t ctrl, const char *cmdline,
int (*getpin_cb)(void *, const char *,
const char *, char*, size_t),
void *getpin_cb_arg, void *assuan_context);
void agent_card_free_keyinfo (struct card_key_info_s *l);
gpg_error_t agent_card_keyinfo (ctrl_t ctrl, const char *keygrip,
struct card_key_info_s **result);
void agent_card_killscd (void);
/*-- learncard.c --*/

View File

@ -23,7 +23,6 @@
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <assert.h>
#include <npth.h>
#include "agent.h"

View File

@ -24,7 +24,6 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <unistd.h>
#include <sys/stat.h>
#ifndef HAVE_W32_SYSTEM
@ -424,7 +423,17 @@ start_pinentry (ctrl_t ctrl)
opt.no_grab? "OPTION no-grab":"OPTION grab",
NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return unlock_pinentry (ctrl, rc);
{
if (gpg_err_code (rc) == GPG_ERR_NOT_SUPPORTED
|| gpg_err_code (rc) == GPG_ERR_UNKNOWN_OPTION)
{
if (opt.verbose)
log_info ("Option no-grab/grab is ignored by pinentry.\n");
/* Keep going even if the feature is not supported. */
}
else
return unlock_pinentry (ctrl, rc);
}
value = session_env_getenv (ctrl->session_env, "GPG_TTY");
if (value)
@ -439,7 +448,7 @@ start_pinentry (ctrl_t ctrl)
return unlock_pinentry (ctrl, rc);
}
value = session_env_getenv (ctrl->session_env, "TERM");
if (value)
if (value && *value)
{
char *optstr;
if (asprintf (&optstr, "OPTION ttytype=%s", value) < 0 )
@ -949,15 +958,14 @@ build_cmd_setdesc (char *line, size_t linelen, const char *desc)
static void *
watch_sock (void *arg)
{
gnupg_fd_t *p = (gnupg_fd_t *)arg;
pid_t pid = assuan_get_pid (entry_ctx);
while (1)
{
int err;
gnupg_fd_t sock = *p;
fd_set fdset;
struct timeval timeout = { 0, 500000 };
gnupg_fd_t sock = *(gnupg_fd_t *)arg;
if (sock == GNUPG_INVALID_FD)
return NULL;
@ -995,18 +1003,11 @@ watch_sock (void *arg)
}
/* 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)
watch_sock_start (gnupg_fd_t *sock_p, npth_t *thread_p)
{
npth_attr_t tattr;
gpg_error_t rc;
int err;
npth_t thread;
int saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL);
gnupg_fd_t sock_watched = ctrl->thread_startup.fd;
err = npth_attr_init (&tattr);
if (err)
@ -1016,7 +1017,7 @@ do_getpin (ctrl_t ctrl, struct entry_parm_s *parm)
}
npth_attr_setdetachstate (&tattr, NPTH_CREATE_JOINABLE);
err = npth_create (&thread, &tattr, watch_sock, (void *)&sock_watched);
err = npth_create (thread_p, &tattr, watch_sock, sock_p);
npth_attr_destroy (&tattr);
if (err)
{
@ -1024,6 +1025,36 @@ do_getpin (ctrl_t ctrl, struct entry_parm_s *parm)
return gpg_error_from_errno (err);
}
return 0;
}
static void
watch_sock_end (gnupg_fd_t *sock_p, npth_t *thread_p)
{
int err;
*sock_p = GNUPG_INVALID_FD;
err = npth_join (*thread_p, NULL);
if (err)
log_error ("watch_sock_end: error joining thread: %s\n", strerror (err));
}
/* 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);
gnupg_fd_t sock_watched = ctrl->thread_startup.fd;
npth_t thread;
rc = watch_sock_start (&sock_watched, &thread);
if (rc)
return rc;
assuan_begin_confidential (entry_ctx);
rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, parm,
inq_quality, entry_ctx,
@ -1040,10 +1071,7 @@ do_getpin (ctrl_t ctrl, struct entry_parm_s *parm)
&& gpg_err_code (rc) == GPG_ERR_CANCELED)
rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED);
sock_watched = GNUPG_INVALID_FD;
err = npth_join (thread, NULL);
if (err)
log_error ("do_getpin: error joining thread: %s\n", strerror (err));
watch_sock_end (&sock_watched, &thread);
return rc;
}
@ -1392,6 +1420,9 @@ agent_get_confirmation (ctrl_t ctrl,
if (ctrl->pinentry_mode == PINENTRY_MODE_CANCEL)
return gpg_error (GPG_ERR_CANCELED);
if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK)
return pinentry_loopback_confirm (ctrl, desc, 1, ok, notok);
return gpg_error (GPG_ERR_NO_PIN_ENTRY);
}
@ -1445,70 +1476,38 @@ agent_get_confirmation (ctrl_t ctrl,
return unlock_pinentry (ctrl, rc);
}
rc = assuan_transact (entry_ctx, "CONFIRM",
NULL, NULL, NULL, NULL, NULL, NULL);
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);
{
gnupg_fd_t sock_watched = ctrl->thread_startup.fd;
npth_t thread;
return unlock_pinentry (ctrl, rc);
rc = watch_sock_start (&sock_watched, &thread);
if (rc)
return rc;
rc = assuan_transact (entry_ctx, "CONFIRM",
NULL, NULL, NULL, NULL, NULL, NULL);
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);
watch_sock_end (&sock_watched, &thread);
return unlock_pinentry (ctrl, rc);
}
}
/* Pop up the PINentry, display the text DESC and a button with the
text OK_BTN (which may be NULL to use the default of "OK") and wait
for the user to hit this button. The return value is not
relevant. */
int
agent_show_message (ctrl_t ctrl, const char *desc, const char *ok_btn)
{
int rc;
char line[ASSUAN_LINELENGTH];
if (ctrl->pinentry_mode != PINENTRY_MODE_ASK)
return gpg_error (GPG_ERR_CANCELED);
rc = start_pinentry (ctrl);
if (rc)
return rc;
if (desc)
build_cmd_setdesc (line, DIM(line), desc);
else
snprintf (line, DIM(line), "RESET");
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
/* 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);
if (rc)
return unlock_pinentry (ctrl, rc);
if (ok_btn)
{
snprintf (line, DIM(line), "SETOK %s", ok_btn);
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL,
NULL, NULL, NULL);
if (rc)
return unlock_pinentry (ctrl, rc);
}
rc = assuan_transact (entry_ctx, "CONFIRM --one-button", NULL, NULL, NULL,
NULL, NULL, NULL);
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);
return unlock_pinentry (ctrl, rc);
}
/* The thread running the popup message. */
static void *
popup_message_thread (void *arg)
{
(void)arg;
gpg_error_t rc;
gnupg_fd_t sock_watched = *(gnupg_fd_t *)arg;
npth_t thread;
rc = watch_sock_start (&sock_watched, &thread);
if (rc)
return NULL;
/* We use the --one-button hack instead of the MESSAGE command to
allow the use of old Pinentries. Those old Pinentries will then
@ -1516,6 +1515,7 @@ popup_message_thread (void *arg)
annoyance. */
assuan_transact (entry_ctx, "CONFIRM --one-button",
NULL, NULL, NULL, NULL, NULL, NULL);
watch_sock_end (&sock_watched, &thread);
popup_finished = 1;
return NULL;
}
@ -1536,7 +1536,15 @@ agent_popup_message_start (ctrl_t ctrl, const char *desc, const char *ok_btn)
int err;
if (ctrl->pinentry_mode != PINENTRY_MODE_ASK)
return gpg_error (GPG_ERR_CANCELED);
{
if (ctrl->pinentry_mode == PINENTRY_MODE_CANCEL)
return gpg_error (GPG_ERR_CANCELED);
if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK)
return pinentry_loopback_confirm (ctrl, desc, 0, ok_btn, NULL);
return gpg_error (GPG_ERR_NO_PIN_ENTRY);
}
rc = start_pinentry (ctrl);
if (rc)
@ -1564,7 +1572,8 @@ agent_popup_message_start (ctrl_t ctrl, const char *desc, const char *ok_btn)
npth_attr_setdetachstate (&tattr, NPTH_CREATE_JOINABLE);
popup_finished = 0;
err = npth_create (&popup_tid, &tattr, popup_message_thread, NULL);
err = npth_create (&popup_tid, &tattr, popup_message_thread,
&ctrl->thread_startup.fd);
npth_attr_destroy (&tattr);
if (err)
{
@ -1587,6 +1596,9 @@ agent_popup_message_stop (ctrl_t ctrl)
(void)ctrl;
if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK)
return;
if (!popup_tid || !entry_ctx)
{
log_debug ("agent_popup_message_stop called with no active popup\n");

View File

@ -25,7 +25,6 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <unistd.h>
#ifdef HAVE_SIGNAL_H
# include <signal.h>
@ -330,13 +329,13 @@ start_scd (ctrl_t ctrl)
{
ctrl->scd_local = xtrycalloc (1, sizeof *ctrl->scd_local);
if (!ctrl->scd_local)
{
err = gpg_error_from_syserror ();
rc = npth_mutex_unlock (&start_scd_lock);
if (rc)
log_error ("failed to release the start_scd lock: %s\n", strerror (rc));
return err;
}
{
err = gpg_error_from_syserror ();
rc = npth_mutex_unlock (&start_scd_lock);
if (rc)
log_error ("failed to release the start_scd lock: %s\n", strerror (rc));
return err;
}
ctrl->scd_local->next_local = scd_local_list;
scd_local_list = ctrl->scd_local;
}
@ -1282,6 +1281,156 @@ agent_card_cardlist (ctrl_t ctrl, strlist_t *result)
}
struct card_keyinfo_parm_s {
int error;
struct card_key_info_s *list;
};
/* Callback function for agent_card_keylist. */
static gpg_error_t
card_keyinfo_cb (void *opaque, const char *line)
{
struct card_keyinfo_parm_s *parm = opaque;
const char *keyword = line;
int keywordlen;
for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
;
while (spacep (line))
line++;
if (keywordlen == 7 && !memcmp (keyword, "KEYINFO", keywordlen))
{
const char *s;
int n;
struct card_key_info_s *keyinfo;
struct card_key_info_s **l_p = &parm->list;
while ((*l_p))
l_p = &(*l_p)->next;
keyinfo = xtrycalloc (1, sizeof *keyinfo);
if (!keyinfo)
{
alloc_error:
if (!parm->error)
parm->error = gpg_error_from_syserror ();
return 0;
}
for (n=0,s=line; hexdigitp (s); s++, n++)
;
if (n != 40)
{
parm_error:
if (!parm->error)
parm->error = gpg_error (GPG_ERR_ASS_PARAMETER);
return 0;
}
memcpy (keyinfo->keygrip, line, 40);
line = s;
if (!*line)
goto parm_error;
while (spacep (line))
line++;
if (*line++ != 'T')
goto parm_error;
if (!*line)
goto parm_error;
while (spacep (line))
line++;
for (n=0,s=line; hexdigitp (s); s++, n++)
;
if (!n)
goto parm_error;
keyinfo->serialno = xtrymalloc (n+1);
if (!keyinfo->serialno)
goto alloc_error;
memcpy (keyinfo->serialno, line, n);
keyinfo->serialno[n] = 0;
line = s;
if (!*line)
goto parm_error;
while (spacep (line))
line++;
if (!*line)
goto parm_error;
keyinfo->idstr = xtrystrdup (line);
if (!keyinfo->idstr)
goto alloc_error;
*l_p = keyinfo;
}
return 0;
}
void
agent_card_free_keyinfo (struct card_key_info_s *l)
{
struct card_key_info_s *l_next;
for (; l; l = l_next)
{
l_next = l->next;
free (l->serialno);
free (l->idstr);
free (l);
}
}
/* Call the scdaemon to check if a key of KEYGRIP is available, or
retrieve list of available keys on cards. On success the allocated
structure is stored at RESULT. On error an error code is returned
and NULL is stored at RESULT. */
gpg_error_t
agent_card_keyinfo (ctrl_t ctrl, const char *keygrip,
struct card_key_info_s **result)
{
int err;
struct card_keyinfo_parm_s parm;
char line[ASSUAN_LINELENGTH];
*result = NULL;
memset (&parm, 0, sizeof parm);
snprintf (line, sizeof line, "KEYINFO %s", keygrip ? keygrip : "--list");
err = start_scd (ctrl);
if (err)
return err;
err = assuan_transact (ctrl->scd_local->ctx, line,
NULL, NULL, NULL, NULL,
card_keyinfo_cb, &parm);
if (!err && parm.error)
err = parm.error;
if (!err)
*result = parm.list;
else
agent_card_free_keyinfo (parm.list);
return unlock_scd (ctrl, err);
}
static gpg_error_t
pass_status_thru (void *opaque, const char *line)
@ -1366,3 +1515,12 @@ agent_card_scd (ctrl_t ctrl, const char *cmdline,
return unlock_scd (ctrl, 0);
}
void
agent_card_killscd (void)
{
if (primary_scd_ctx == NULL)
return;
assuan_transact (primary_scd_ctx, "KILLSCD",
NULL, NULL, NULL, NULL, NULL, NULL);
}

View File

@ -41,7 +41,6 @@
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <assert.h>
#ifndef HAVE_W32_SYSTEM
#include <sys/socket.h>
#include <sys/un.h>
@ -1030,7 +1029,7 @@ search_control_file (ssh_control_file_t cf, const char *hexgrip,
{
gpg_error_t err;
assert (strlen (hexgrip) == 40 );
log_assert (strlen (hexgrip) == 40 );
if (r_disabled)
*r_disabled = 0;
@ -2646,7 +2645,7 @@ ssh_handler_request_identities (ctrl_t ctrl,
continue; /* Should not happen. */
if (cf->item.disabled)
continue;
assert (strlen (cf->item.hexgrip) == 40);
log_assert (strlen (cf->item.hexgrip) == 40);
hex2bin (cf->item.hexgrip, grip, sizeof (grip));
err = agent_public_key_from_file (ctrl, grip, &key_public);
@ -3008,8 +3007,8 @@ ssh_key_to_protected_buffer (gcry_sexp_t key, const char *passphrase,
goto out;
}
gcry_sexp_sprint (key, GCRYSEXP_FMT_CANON, buffer_new, buffer_new_n);
/* FIXME: guarantee? */
buffer_new_n = gcry_sexp_sprint (key, GCRYSEXP_FMT_CANON,
buffer_new, buffer_new_n);
if (*passphrase)
err = agent_protect (buffer_new, passphrase, buffer, buffer_n, 0, -1);
@ -3142,7 +3141,7 @@ ssh_identity_register (ctrl_t ctrl, ssh_key_type_spec_t *spec,
goto out;
/* Store this key to our key storage. */
err = agent_write_private_key (key_grip_raw, buffer, buffer_n, 0);
err = agent_write_private_key (key_grip_raw, buffer, buffer_n, 0, NULL, NULL);
if (err)
goto out;

View File

@ -30,7 +30,6 @@
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
@ -1075,7 +1074,7 @@ cmd_readkey (assuan_context_t ctx, char *line)
static const char hlp_keyinfo[] =
"KEYINFO [--[ssh-]list] [--data] [--ssh-fpr] [--with-ssh] <keygrip>\n"
"KEYINFO [--[ssh-]list] [--data] [--ssh-fpr[=algo]] [--with-ssh] <keygrip>\n"
"\n"
"Return information about the key specified by the KEYGRIP. If the\n"
"key is not available GPG_ERR_NOT_FOUND is returned. If the option\n"
@ -1111,7 +1110,9 @@ static const char hlp_keyinfo[] =
" '-' - Unknown protection.\n"
"\n"
"FPR returns the formatted ssh-style fingerprint of the key. It is only\n"
" printed if the option --ssh-fpr has been used. It defaults to '-'.\n"
" printed if the option --ssh-fpr has been used. If ALGO is not given\n"
" to that option the default ssh fingerprint algo is used. Without the\n"
" option a '-' is printed.\n"
"\n"
"TTL is the TTL in seconds for that key or '-' if n/a.\n"
"\n"
@ -1119,13 +1120,14 @@ static const char hlp_keyinfo[] =
" 'D' - The key has been disabled,\n"
" 'S' - The key is listed in sshcontrol (requires --with-ssh),\n"
" 'c' - Use of the key needs to be confirmed,\n"
" 'A' - The key is available on card,\n"
" '-' - No flags given.\n"
"\n"
"More information may be added in the future.";
static gpg_error_t
do_one_keyinfo (ctrl_t ctrl, const unsigned char *grip, assuan_context_t ctx,
int data, int with_ssh_fpr, int in_ssh,
int ttl, int disabled, int confirm)
int ttl, int disabled, int confirm, int on_card)
{
gpg_error_t err;
char hexgrip[40+1];
@ -1166,6 +1168,8 @@ do_one_keyinfo (ctrl_t ctrl, const unsigned char *grip, assuan_context_t ctx,
strcat (flagsbuf, "S");
if (confirm)
strcat (flagsbuf, "c");
if (on_card)
strcat (flagsbuf, "A");
if (!*flagsbuf)
strcpy (flagsbuf, "-");
@ -1198,7 +1202,7 @@ do_one_keyinfo (ctrl_t ctrl, const unsigned char *grip, assuan_context_t ctx,
if (!agent_raw_key_from_file (ctrl, grip, &key))
{
ssh_get_fingerprint_string (key, GCRY_MD_MD5, &fpr);
ssh_get_fingerprint_string (key, with_ssh_fpr, &fpr);
gcry_sexp_release (key);
}
}
@ -1256,8 +1260,8 @@ do_one_keyinfo (ctrl_t ctrl, const unsigned char *grip, assuan_context_t ctx,
}
/* Entry int for the command KEYINFO. This function handles the
command option processing. For details see hlp_keyinfo above. */
/* Entry into the command KEYINFO. This function handles the
* command option processing. For details see hlp_keyinfo above. */
static gpg_error_t
cmd_keyinfo (assuan_context_t ctx, char *line)
{
@ -1270,6 +1274,9 @@ cmd_keyinfo (assuan_context_t ctx, char *line)
ssh_control_file_t cf = NULL;
char hexgrip[41];
int disabled, ttl, confirm, is_ssh;
struct card_key_info_s *keyinfo_on_cards;
struct card_key_info_s *l;
int on_card;
if (ctrl->restricted)
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
@ -1279,13 +1286,29 @@ cmd_keyinfo (assuan_context_t ctx, char *line)
else
list_mode = has_option (line, "--list");
opt_data = has_option (line, "--data");
opt_ssh_fpr = has_option (line, "--ssh-fpr");
if (has_option_name (line, "--ssh-fpr"))
{
if (has_option (line, "--ssh-fpr=md5"))
opt_ssh_fpr = GCRY_MD_MD5;
else if (has_option (line, "--ssh-fpr=sha1"))
opt_ssh_fpr = GCRY_MD_SHA1;
else if (has_option (line, "--ssh-fpr=sha256"))
opt_ssh_fpr = GCRY_MD_SHA256;
else
opt_ssh_fpr = opt.ssh_fingerprint_digest;
}
else
opt_ssh_fpr = 0;
opt_with_ssh = has_option (line, "--with-ssh");
line = skip_options (line);
if (opt_with_ssh || list_mode == 2)
cf = ssh_open_control_file ();
agent_card_keyinfo (ctrl, NULL, &keyinfo_on_cards);
if (list_mode == 2)
{
if (cf)
@ -1295,8 +1318,14 @@ cmd_keyinfo (assuan_context_t ctx, char *line)
{
if (hex2bin (hexgrip, grip, 20) < 0 )
continue; /* Bad hex string. */
on_card = 0;
for (l = keyinfo_on_cards; l; l = l->next)
if (!memcmp (l->keygrip, hexgrip, 40))
on_card = 1;
err = do_one_keyinfo (ctrl, grip, ctx, opt_data, opt_ssh_fpr, 1,
ttl, disabled, confirm);
ttl, disabled, confirm, on_card);
if (err)
goto leave;
}
@ -1346,8 +1375,13 @@ cmd_keyinfo (assuan_context_t ctx, char *line)
goto leave;
}
on_card = 0;
for (l = keyinfo_on_cards; l; l = l->next)
if (!memcmp (l->keygrip, hexgrip, 40))
on_card = 1;
err = do_one_keyinfo (ctrl, grip, ctx, opt_data, opt_ssh_fpr, is_ssh,
ttl, disabled, confirm);
ttl, disabled, confirm, on_card);
if (err)
goto leave;
}
@ -1369,11 +1403,17 @@ cmd_keyinfo (assuan_context_t ctx, char *line)
goto leave;
}
on_card = 0;
for (l = keyinfo_on_cards; l; l = l->next)
if (!memcmp (l->keygrip, line, 40))
on_card = 1;
err = do_one_keyinfo (ctrl, grip, ctx, opt_data, opt_ssh_fpr, is_ssh,
ttl, disabled, confirm);
ttl, disabled, confirm, on_card);
}
leave:
agent_card_free_keyinfo (keyinfo_on_cards);
ssh_close_control_file (cf);
if (dir)
closedir (dir);
@ -2196,7 +2236,7 @@ cmd_import_key (assuan_context_t ctx, char *line)
goto leave; /* Invalid canonical encoded S-expression. */
if (passphrase)
{
assert (!opt_unattended);
log_assert (!opt_unattended);
if (!cache_nonce)
{
char buf[12];
@ -2239,10 +2279,11 @@ cmd_import_key (assuan_context_t ctx, char *line)
err = agent_protect (key, passphrase, &finalkey, &finalkeylen,
ctrl->s2k_count, -1);
if (!err)
err = agent_write_private_key (grip, finalkey, finalkeylen, force);
err = agent_write_private_key (grip, finalkey, finalkeylen, force,
NULL, NULL);
}
else
err = agent_write_private_key (grip, key, realkeylen, force);
err = agent_write_private_key (grip, key, realkeylen, force, NULL, NULL);
leave:
gcry_sexp_release (openpgp_sexp);
@ -3069,7 +3110,7 @@ cmd_getinfo (assuan_context_t ctx, char *line)
{
cmdopt = line;
if (!command_has_option (cmd, cmdopt))
rc = gpg_error (GPG_ERR_GENERAL);
rc = gpg_error (GPG_ERR_FALSE);
}
}
}
@ -3083,7 +3124,7 @@ cmd_getinfo (assuan_context_t ctx, char *line)
}
else if (!strcmp (line, "restricted"))
{
rc = ctrl->restricted? 0 : gpg_error (GPG_ERR_GENERAL);
rc = ctrl->restricted? 0 : gpg_error (GPG_ERR_FALSE);
}
else if (ctrl->restricted)
{
@ -3117,7 +3158,7 @@ cmd_getinfo (assuan_context_t ctx, char *line)
}
else if (!strcmp (line, "scd_running"))
{
rc = agent_scd_check_running ()? 0 : gpg_error (GPG_ERR_GENERAL);
rc = agent_scd_check_running ()? 0 : gpg_error (GPG_ERR_FALSE);
}
else if (!strcmp (line, "std_env_names"))
{
@ -3639,3 +3680,26 @@ pinentry_loopback(ctrl_t ctrl, const char *keyword,
assuan_end_confidential (ctx);
return rc;
}
/* Helper for the pinentry loopback mode to ask confirmation
or just to show message. */
gpg_error_t
pinentry_loopback_confirm (ctrl_t ctrl, const char *desc,
int ask_confirmation,
const char *ok, const char *notok)
{
gpg_error_t err = 0;
assuan_context_t ctx = ctrl->server_local->assuan_ctx;
if (desc)
err = print_assuan_status (ctx, "SETDESC", "%s", desc);
if (!err && ok)
err = print_assuan_status (ctx, "SETOK", "%s", ok);
if (!err && notok)
err = print_assuan_status (ctx, "SETNOTOK", "%s", notok);
if (!err)
err = assuan_inquire (ctx, ask_confirmation ? "CONFIRM 1" : "CONFIRM 0",
NULL, NULL, 0);
return err;
}

View File

@ -22,7 +22,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "agent.h"
#include "../common/i18n.h"
@ -571,7 +570,7 @@ do_unprotect (const char *passphrase,
}
skey[i] = NULL;
skeylen = i;
assert (skeylen <= skeysize);
log_assert (skeylen <= skeysize);
/* Note: at this point NDATA should be 2 for a simple
checksum or 20 for the sha1 digest. */
@ -1067,7 +1066,8 @@ convert_from_openpgp_native (ctrl_t ctrl,
if (!agent_protect (*r_key, passphrase,
&protectedkey, &protectedkeylen,
ctrl->s2k_count, -1))
agent_write_private_key (grip, protectedkey, protectedkeylen, 1);
agent_write_private_key (grip, protectedkey, protectedkeylen, 1,
NULL, NULL);
xfree (protectedkey);
}
else
@ -1076,7 +1076,7 @@ convert_from_openpgp_native (ctrl_t ctrl,
agent_write_private_key (grip,
*r_key,
gcry_sexp_canon_len (*r_key, 0, NULL,NULL),
1);
1, NULL, NULL);
}
}
@ -1104,8 +1104,8 @@ apply_protection (gcry_mpi_t *array, int npkey, int nskey,
int ndata;
unsigned char *p, *data;
assert (npkey < nskey);
assert (nskey < DIM (bufarr));
log_assert (npkey < nskey);
log_assert (nskey < DIM (bufarr));
/* Collect only the secret key parameters into BUFARR et al and
compute the required size of the data buffer. */
@ -1142,7 +1142,7 @@ apply_protection (gcry_mpi_t *array, int npkey, int nskey,
xfree (bufarr[i]);
bufarr[i] = NULL;
}
assert (p == data + ndata - 20);
log_assert (p == data + ndata - 20);
/* Append a hash of the secret key parameters. */
gcry_md_hash_buffer (GCRY_MD_SHA1, p, data, ndata - 20);

View File

@ -32,28 +32,50 @@
#include "../common/sexp-parse.h"
static int
ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info, char **r_kid)
static gpg_error_t
ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info,
const unsigned char *grip, char **r_kid)
{
int rc, i;
int i;
char *serialno;
int no_card = 0;
char *desc;
char *want_sn, *want_kid, *want_sn_disp;
int len;
struct card_key_info_s *keyinfo;
gpg_error_t err;
char hexgrip[41];
*r_kid = NULL;
rc = parse_shadow_info (shadow_info, &want_sn, &want_kid, NULL);
if (rc)
return rc;
/* Scan device(s), and check if key for GRIP is available. */
err = agent_card_serialno (ctrl, &serialno, NULL);
if (!err)
{
xfree (serialno);
bin2hex (grip, 20, hexgrip);
err = agent_card_keyinfo (ctrl, hexgrip, &keyinfo);
if (!err)
{
/* Key for GRIP found, use it directly. */
agent_card_free_keyinfo (keyinfo);
if ((*r_kid = xtrystrdup (hexgrip)))
return 0;
else
return gpg_error_from_syserror ();
}
}
err = parse_shadow_info (shadow_info, &want_sn, &want_kid, NULL);
if (err)
return err;
want_sn_disp = xtrystrdup (want_sn);
if (!want_sn_disp)
{
rc = gpg_error_from_syserror ();
err = gpg_error_from_syserror ();
xfree (want_sn);
xfree (want_kid);
return rc;
return err;
}
len = strlen (want_sn_disp);
@ -76,8 +98,8 @@ ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info, char **r_kid)
for (;;)
{
rc = agent_card_serialno (ctrl, &serialno, want_sn);
if (!rc)
err = agent_card_serialno (ctrl, &serialno, want_sn);
if (!err)
{
log_debug ("detected card with S/N %s\n", serialno);
i = strcmp (serialno, want_sn);
@ -91,24 +113,24 @@ ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info, char **r_kid)
return 0; /* yes, we have the correct card */
}
}
else if (gpg_err_code (rc) == GPG_ERR_ENODEV)
else if (gpg_err_code (err) == GPG_ERR_ENODEV)
{
log_debug ("no device present\n");
rc = 0;
err = 0;
no_card = 1;
}
else if (gpg_err_code (rc) == GPG_ERR_CARD_NOT_PRESENT)
else if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT)
{
log_debug ("no card present\n");
rc = 0;
err = 0;
no_card = 2;
}
else
{
log_error ("error accessing card: %s\n", gpg_strerror (rc));
log_error ("error accessing card: %s\n", gpg_strerror (err));
}
if (!rc)
if (!err)
{
if (asprintf (&desc,
"%s:%%0A%%0A"
@ -119,24 +141,24 @@ ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info, char **r_kid)
"insert the one with serial number"),
want_sn_disp) < 0)
{
rc = out_of_core ();
err = out_of_core ();
}
else
{
rc = agent_get_confirmation (ctrl, desc, NULL, NULL, 0);
err = agent_get_confirmation (ctrl, desc, NULL, NULL, 0);
if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK &&
gpg_err_code (rc) == GPG_ERR_NO_PIN_ENTRY)
rc = gpg_error (GPG_ERR_CARD_NOT_PRESENT);
gpg_err_code (err) == GPG_ERR_NO_PIN_ENTRY)
err = gpg_error (GPG_ERR_CARD_NOT_PRESENT);
xfree (desc);
}
}
if (rc)
if (err)
{
xfree (want_sn_disp);
xfree (want_sn);
xfree (want_kid);
return rc;
return err;
}
}
}
@ -434,7 +456,7 @@ getpin_cb (void *opaque, const char *desc_text, const char *info,
*
* FIXME: Explain the other args. */
int
divert_pksign (ctrl_t ctrl, const char *desc_text,
divert_pksign (ctrl_t ctrl, const char *desc_text, const unsigned char *grip,
const unsigned char *digest, size_t digestlen, int algo,
const unsigned char *shadow_info, unsigned char **r_sig,
size_t *r_siglen)
@ -446,7 +468,7 @@ divert_pksign (ctrl_t ctrl, const char *desc_text,
(void)desc_text;
rc = ask_for_card (ctrl, shadow_info, &kid);
rc = ask_for_card (ctrl, shadow_info, grip, &kid);
if (rc)
return rc;
@ -490,6 +512,7 @@ divert_pksign (ctrl_t ctrl, const char *desc_text,
R_PADDING with -1 for not known. */
int
divert_pkdecrypt (ctrl_t ctrl, const char *desc_text,
const unsigned char *grip,
const unsigned char *cipher,
const unsigned char *shadow_info,
char **r_buf, size_t *r_len, int *r_padding)
@ -581,7 +604,7 @@ divert_pkdecrypt (ctrl_t ctrl, const char *desc_text,
ciphertext = s;
ciphertextlen = n;
rc = ask_for_card (ctrl, shadow_info, &kid);
rc = ask_for_card (ctrl, shadow_info, grip, &kid);
if (rc)
return rc;

View File

@ -1,7 +1,7 @@
/* findkey.c - Locate the secret key
* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007,
* 2010, 2011 Free Software Foundation, Inc.
* Copyright (C) 2014 Werner Koch
* Copyright (C) 2014, 2019 Werner Koch
*
* This file is part of GnuPG.
*
@ -26,10 +26,8 @@
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <assert.h>
#include <unistd.h>
#include <sys/stat.h>
#include <assert.h>
#include <npth.h> /* (we use pth_sleep) */
#include "agent.h"
@ -52,15 +50,47 @@ struct try_unprotect_arg_s
};
/* Repalce all linefeeds in STRING by "%0A" and return a new malloced
* string. May return NULL on memory error. */
static char *
linefeed_to_percent0A (const char *string)
{
const char *s;
size_t n;
char *buf, *p;
for (n=0, s=string; *s; s++)
if (*s == '\n')
n += 3;
else
n++;
p = buf = xtrymalloc (n+1);
if (!buf)
return NULL;
for (s=string; *s; s++)
if (*s == '\n')
{
memcpy (p, "%0A", 3);
p += 3;
}
else
*p++ = *s;
*p = 0;
return buf;
}
/* Note: Ownership of FNAME and FP are moved to this function. */
static gpg_error_t
write_extended_private_key (char *fname, estream_t fp, int update,
const void *buf, size_t len)
const void *buf, size_t len,
const char *serialno, const char *keyref)
{
gpg_error_t err;
nvc_t pk = NULL;
gcry_sexp_t key = NULL;
int remove = 0;
char *token = NULL;
if (update)
{
@ -93,6 +123,37 @@ write_extended_private_key (char *fname, estream_t fp, int update,
if (err)
goto leave;
/* If requested write a Token line. */
if (serialno && keyref)
{
nve_t item;
const char *s;
token = strconcat (serialno, " ", keyref, NULL);
if (!token)
{
err = gpg_error_from_syserror ();
goto leave;
}
/* fixme: the strcmp should compare only the first two strings. */
for (item = nvc_lookup (pk, "Token:");
item;
item = nve_next_value (item, "Token:"))
if ((s = nve_value (item)) && !strcmp (s, token))
break;
if (!item)
{
/* No token or no token with that value exists. Add a new
* one so that keys which have been stored on several cards
* are well supported. */
err = nvc_add (pk, "Token:", token);
if (err)
goto leave;
}
}
err = es_fseek (fp, 0, SEEK_SET);
if (err)
goto leave;
@ -132,15 +193,18 @@ write_extended_private_key (char *fname, estream_t fp, int update,
xfree (fname);
gcry_sexp_release (key);
nvc_release (pk);
xfree (token);
return err;
}
/* Write an S-expression formatted key to our key storage. With FORCE
passed as true an existing key with the given GRIP will get
overwritten. */
* passed as true an existing key with the given GRIP will get
* overwritten. If SERIALNO and KEYREF are give an a Token line is added to
* th key if the extended format ist used. */
int
agent_write_private_key (const unsigned char *grip,
const void *buffer, size_t length, int force)
const void *buffer, size_t length, int force,
const char *serialno, const char *keyref)
{
char *fname;
estream_t fp;
@ -208,17 +272,20 @@ agent_write_private_key (const unsigned char *grip,
if (first != '(')
{
/* Key is already in the extended format. */
return write_extended_private_key (fname, fp, 1, buffer, length);
return write_extended_private_key (fname, fp, 1, buffer, length,
serialno, keyref);
}
if (first == '(' && opt.enable_extended_key_format)
{
/* Key is in the old format - but we want the extended format. */
return write_extended_private_key (fname, fp, 0, buffer, length);
return write_extended_private_key (fname, fp, 0, buffer, length,
serialno, keyref);
}
}
if (opt.enable_extended_key_format)
return write_extended_private_key (fname, fp, 0, buffer, length);
return write_extended_private_key (fname, fp, 0, buffer, length,
serialno, keyref);
if (es_fwrite (buffer, length, 1, fp) != 1)
{
@ -267,7 +334,7 @@ try_unprotect_cb (struct pin_entry_info_s *pi)
gnupg_isotime_t now, protected_at, tmptime;
char *desc = NULL;
assert (!arg->unprotected_key);
log_assert (!arg->unprotected_key);
arg->change_required = 0;
err = agent_unprotect (ctrl, arg->protected_key, pi->pin, protected_at,
@ -332,6 +399,33 @@ try_unprotect_cb (struct pin_entry_info_s *pi)
}
/* Return true if the STRING has an %C or %c expando. */
static int
has_comment_expando (const char *string)
{
const char *s;
int percent = 0;
if (!string)
return 0;
for (s = string; *s; s++)
{
if (percent)
{
if (*s == 'c' || *s == 'C')
return 1;
percent = 0;
}
else if (*s == '%')
percent = 1;
}
return 0;
}
/* Modify a Key description, replacing certain special format
characters. List of currently supported replacements:
@ -644,7 +738,7 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text,
}
else
{
assert (arg.unprotected_key);
log_assert (arg.unprotected_key);
if (arg.change_required)
{
/* The callback told as that the user should change their
@ -652,7 +746,7 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text,
size_t canlen, erroff;
gcry_sexp_t s_skey;
assert (arg.unprotected_key);
log_assert (arg.unprotected_key);
canlen = gcry_sexp_canon_len (arg.unprotected_key, 0, NULL, NULL);
rc = gcry_sexp_sscan (&s_skey, &erroff,
(char*)arg.unprotected_key, canlen);
@ -695,10 +789,13 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text,
/* Read the key identified by GRIP from the private key directory and
return it as an gcrypt S-expression object in RESULT. On failure
returns an error code and stores NULL at RESULT. */
* return it as an gcrypt S-expression object in RESULT. If R_KEYMETA
* is not NULl and the extended key format is used, the meta data
* items are stored there. However the "Key:" item is removed from
* it. On failure returns an error code and stores NULL at RESULT and
* R_KEYMETA. */
static gpg_error_t
read_key_file (const unsigned char *grip, gcry_sexp_t *result)
read_key_file (const unsigned char *grip, gcry_sexp_t *result, nvc_t *r_keymeta)
{
gpg_error_t err;
char *fname;
@ -711,6 +808,8 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result)
char first;
*result = NULL;
if (r_keymeta)
*r_keymeta = NULL;
bin2hex (grip, 20, hexgrip);
strcpy (hexgrip+40, ".key");
@ -749,7 +848,7 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result)
if (first != '(')
{
/* Key is in extended format. */
nvc_t pk;
nvc_t pk = NULL;
int line;
err = nvc_parse_private_key (&pk, &line, fp);
@ -761,12 +860,17 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result)
else
{
err = nvc_get_private_key (pk, result);
nvc_release (pk);
if (err)
log_error ("error getting private key from '%s': %s\n",
fname, gpg_strerror (err));
else
nvc_delete_named (pk, "Key:");
}
if (!err && r_keymeta)
*r_keymeta = pk;
else
nvc_release (pk);
xfree (fname);
return err;
}
@ -866,6 +970,8 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce,
unsigned char *buf;
size_t len, buflen, erroff;
gcry_sexp_t s_skey;
nvc_t keymeta = NULL;
char *desc_text_buffer = NULL; /* Used in case we extend DESC_TEXT. */
*result = NULL;
if (shadow_info)
@ -873,7 +979,7 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce,
if (r_passphrase)
*r_passphrase = NULL;
err = read_key_file (grip, &s_skey);
err = read_key_file (grip, &s_skey, &keymeta);
if (err)
{
if (gpg_err_code (err) == GPG_ERR_ENOENT)
@ -886,7 +992,11 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce,
now. */
err = make_canon_sexp (s_skey, &buf, &len);
if (err)
return err;
{
nvc_release (keymeta);
xfree (desc_text_buffer);
return err;
}
switch (agent_private_key_type (buf))
{
@ -911,25 +1021,43 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce,
case PRIVATE_KEY_PROTECTED:
{
char *desc_text_final;
char *comment = NULL;
char *comment_buffer = NULL;
const char *comment = NULL;
/* Note, that we will take the comment as a C string for
display purposes; i.e. all stuff beyond a Nul character is
ignored. */
{
gcry_sexp_t comment_sexp;
* display purposes; i.e. all stuff beyond a Nul character is
* ignored. If a "Label" entry is available in the meta data
* this is used instead of the s-ecpression comment. */
if (keymeta && (comment = nvc_get_string (keymeta, "Label:")))
{
if (strchr (comment, '\n')
&& (comment_buffer = linefeed_to_percent0A (comment)))
comment = comment_buffer;
/* In case DESC_TEXT has no escape pattern for a comment
* we append one. */
if (desc_text && !has_comment_expando (desc_text))
{
desc_text_buffer = strconcat (desc_text, "%0A%C", NULL);
if (desc_text_buffer)
desc_text = desc_text_buffer;
}
}
else
{
gcry_sexp_t comment_sexp;
comment_sexp = gcry_sexp_find_token (s_skey, "comment", 0);
if (comment_sexp)
comment = gcry_sexp_nth_string (comment_sexp, 1);
gcry_sexp_release (comment_sexp);
}
comment_sexp = gcry_sexp_find_token (s_skey, "comment", 0);
if (comment_sexp)
comment_buffer = gcry_sexp_nth_string (comment_sexp, 1);
gcry_sexp_release (comment_sexp);
comment = comment_buffer;
}
desc_text_final = NULL;
if (desc_text)
err = agent_modify_description (desc_text, comment, s_skey,
&desc_text_final);
gcry_free (comment);
gcry_free (comment_buffer);
if (!err)
{
@ -984,6 +1112,8 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce,
xfree (*r_passphrase);
*r_passphrase = NULL;
}
nvc_release (keymeta);
xfree (desc_text_buffer);
return err;
}
@ -1000,10 +1130,14 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce,
xfree (*r_passphrase);
*r_passphrase = NULL;
}
nvc_release (keymeta);
xfree (desc_text_buffer);
return err;
}
*result = s_skey;
nvc_release (keymeta);
xfree (desc_text_buffer);
return 0;
}
@ -1203,7 +1337,7 @@ agent_raw_key_from_file (ctrl_t ctrl, const unsigned char *grip,
*result = NULL;
err = read_key_file (grip, &s_skey);
err = read_key_file (grip, &s_skey, NULL);
if (!err)
*result = s_skey;
return err;
@ -1230,6 +1364,7 @@ agent_public_key_from_file (ctrl_t ctrl,
gcry_sexp_t uri_sexp, comment_sexp;
const char *uri, *comment;
size_t uri_length, comment_length;
int uri_intlen, comment_intlen;
char *format, *p;
void *args[2+7+2+2+1]; /* Size is 2 + max. # of elements + 2 for uri + 2
for comment + end-of-list. */
@ -1241,7 +1376,7 @@ agent_public_key_from_file (ctrl_t ctrl,
*result = NULL;
err = read_key_file (grip, &s_skey);
err = read_key_file (grip, &s_skey, NULL);
if (err)
return err;
@ -1278,7 +1413,7 @@ agent_public_key_from_file (ctrl_t ctrl,
such a task. After all that is what we do in protect.c. Need
to find common patterns and write a straightformward API to use
them. */
assert (sizeof (size_t) <= sizeof (void*));
log_assert (sizeof (size_t) <= sizeof (void*));
format = xtrymalloc (15+4+7*npkey+10+15+1+1);
if (!format)
@ -1303,27 +1438,29 @@ agent_public_key_from_file (ctrl_t ctrl,
*p++ = '(';
*p++ = *s++;
p = stpcpy (p, " %m)");
assert (argidx < DIM (args));
log_assert (argidx < DIM (args));
args[argidx++] = &array[idx];
}
*p++ = ')';
if (uri)
{
p = stpcpy (p, "(uri %b)");
assert (argidx+1 < DIM (args));
args[argidx++] = (void *)&uri_length;
log_assert (argidx+1 < DIM (args));
uri_intlen = (int)uri_length;
args[argidx++] = (void *)&uri_intlen;
args[argidx++] = (void *)&uri;
}
if (comment)
{
p = stpcpy (p, "(comment %b)");
assert (argidx+1 < DIM (args));
args[argidx++] = (void *)&comment_length;
log_assert (argidx+1 < DIM (args));
comment_intlen = (int)comment_length;
args[argidx++] = (void *)&comment_intlen;
args[argidx++] = (void*)&comment;
}
*p++ = ')';
*p = 0;
assert (argidx < DIM (args));
log_assert (argidx < DIM (args));
args[argidx] = NULL;
err = gcry_sexp_build_array (&list, NULL, format, args);
@ -1386,7 +1523,7 @@ agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
{
gcry_sexp_t sexp;
err = read_key_file (grip, &sexp);
err = read_key_file (grip, &sexp, NULL);
if (err)
{
if (gpg_err_code (err) == GPG_ERR_ENOENT)
@ -1420,7 +1557,7 @@ agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
if (!err)
{
n = gcry_sexp_canon_len (s, 0, NULL, NULL);
assert (n);
log_assert (n);
*r_shadow_info = xtrymalloc (n);
if (!*r_shadow_info)
err = gpg_error_from_syserror ();
@ -1470,7 +1607,7 @@ agent_delete_key (ctrl_t ctrl, const char *desc_text,
char *default_desc = NULL;
int key_type;
err = read_key_file (grip, &s_skey);
err = read_key_file (grip, &s_skey, NULL);
if (gpg_err_code (err) == GPG_ERR_ENOENT)
err = gpg_error (GPG_ERR_NO_SECKEY);
if (err)
@ -1580,6 +1717,13 @@ agent_write_shadow_key (const unsigned char *grip,
unsigned char *shdkey;
size_t len;
/* Just in case some caller did not parse the stuff correctly, skip
* leading spaces. */
while (spacep (serialno))
serialno++;
while (spacep (keyid))
keyid++;
shadow_info = make_shadow_info (serialno, keyid);
if (!shadow_info)
return gpg_error_from_syserror ();
@ -1593,7 +1737,7 @@ agent_write_shadow_key (const unsigned char *grip,
}
len = gcry_sexp_canon_len (shdkey, 0, NULL, NULL);
err = agent_write_private_key (grip, shdkey, len, force);
err = agent_write_private_key (grip, shdkey, len, force, serialno, keyid);
xfree (shdkey);
if (err)
log_error ("error writing key: %s\n", gpg_strerror (err));

View File

@ -24,7 +24,6 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include "agent.h"
#include "../common/i18n.h"
@ -47,12 +46,12 @@ store_key (gcry_sexp_t private, const char *passphrase, int force,
}
len = gcry_sexp_sprint (private, GCRYSEXP_FMT_CANON, NULL, 0);
assert (len);
log_assert (len);
buf = gcry_malloc_secure (len);
if (!buf)
return out_of_core ();
len = gcry_sexp_sprint (private, GCRYSEXP_FMT_CANON, buf, len);
assert (len);
log_assert (len);
if (passphrase)
{
@ -68,7 +67,7 @@ store_key (gcry_sexp_t private, const char *passphrase, int force,
buf = p;
}
rc = agent_write_private_key (grip, buf, len, force);
rc = agent_write_private_key (grip, buf, len, force, NULL, NULL);
xfree (buf);
return rc;
}
@ -127,7 +126,7 @@ check_passphrase_pattern (ctrl_t ctrl, const char *pw)
argv[i++] = "--",
argv[i++] = opt.check_passphrase_pattern,
argv[i] = NULL;
assert (i < sizeof argv);
log_assert (i < sizeof argv);
if (gnupg_spawn_process_fd (pgmname, argv, fileno (infp), -1, -1, &pid))
result = 1; /* Execute error - assume password should no be used. */
@ -149,27 +148,10 @@ check_passphrase_pattern (ctrl_t ctrl, const char *pw)
static int
take_this_one_anyway2 (ctrl_t ctrl, const char *desc, const char *anyway_btn)
take_this_one_anyway (ctrl_t ctrl, const char *desc, const char *anyway_btn)
{
gpg_error_t err;
if (opt.enforce_passphrase_constraints)
{
err = agent_show_message (ctrl, desc, L_("Enter new passphrase"));
if (!err)
err = gpg_error (GPG_ERR_CANCELED);
}
else
err = agent_get_confirmation (ctrl, desc,
anyway_btn, L_("Enter new passphrase"), 0);
return err;
}
static int
take_this_one_anyway (ctrl_t ctrl, const char *desc)
{
return take_this_one_anyway2 (ctrl, desc, L_("Take this one anyway"));
return agent_get_confirmation (ctrl, desc,
anyway_btn, L_("Enter new passphrase"), 0);
}
@ -212,8 +194,8 @@ check_passphrase_constraints (ctrl_t ctrl, const char *pw,
if (opt.enforce_passphrase_constraints)
*failed_constraint = xstrdup (desc);
else
err = take_this_one_anyway2 (ctrl, desc,
L_("Yes, protection is not needed"));
err = take_this_one_anyway (ctrl, desc,
L_("Yes, protection is not needed"));
}
goto leave;
@ -311,7 +293,7 @@ check_passphrase_constraints (ctrl_t ctrl, const char *pw,
*failed_constraint = msg;
else
{
err = take_this_one_anyway (ctrl, msg);
err = take_this_one_anyway (ctrl, msg, L_("Take this one anyway"));
xfree (msg);
}
}
@ -557,7 +539,7 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce,
if (DBG_CRYPTO)
log_debug ("returning public key\n");
len = gcry_sexp_sprint (s_public, GCRYSEXP_FMT_CANON, NULL, 0);
assert (len);
log_assert (len);
buf = xtrymalloc (len);
if (!buf)
{
@ -567,7 +549,7 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce,
return tmperr;
}
len = gcry_sexp_sprint (s_public, GCRYSEXP_FMT_CANON, buf, len);
assert (len);
log_assert (len);
put_membuf (outbuf, buf, len);
gcry_sexp_release (s_public);
xfree (buf);

View File

@ -26,7 +26,6 @@
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <time.h>
#include <fcntl.h>
#include <sys/stat.h>
@ -1952,7 +1951,7 @@ agent_set_progress_cb (void (*cb)(ctrl_t ctrl, const char *what,
static void
agent_init_default_ctrl (ctrl_t ctrl)
{
assert (ctrl->session_env);
log_assert (ctrl->session_env);
/* Note we ignore malloc errors because we can't do much about it
and the request will fail anyway shortly after this
@ -2442,6 +2441,9 @@ agent_sighup_action (void)
"pinentry" binary that one can be used in case the
"pinentry-basic" fallback was in use. */
gnupg_module_name_flush_some ();
if (opt.disable_scdaemon)
agent_card_killscd ();
}

View File

@ -18,7 +18,8 @@ hexadecimal representation of the keygrip[2] and suffixed with ".key".
* Extended Private Key Format
GnuPG 2.3+ will use a new format to store private keys that is both
** Overview
GnuPG 2.3+ uses a new format to store private keys that is both
more flexible and easier to read and edit by human beings. The new
format stores name,value-pairs using the common mail and http header
convention. Example (here indented with two spaces):
@ -28,6 +29,8 @@ convention. Example (here indented with two spaces):
Use-for-ssh: yes
OpenSSH-cert: long base64 encoded string wrapped so that this
key file can be easily edited with a standard editor.
Token: D2760001240102000005000011730000 OPENPGP.1
Token: FF020001008A77C1 PIV.9C
Key: (shadowed-private-key
(rsa
(n #00AA1AD2A55FD8C8FDE9E1941772D9CC903FA43B268CB1B5A1BAFDC900
@ -52,33 +55,66 @@ Keys in the extended format can be recognized by looking at the first
byte of the file. If it starts with a '(' it is a naked S-expression,
otherwise it is a key in extended format.
** Names
*** Names
A name must start with a letter and end with a colon. Valid
characters are all ASCII letters, numbers and the hyphen. Comparison
of names is done case insensitively. Names may be used several times
to represent an array of values.
The name "Key:" is special in that it may occur only once and the
associated value holds the actual S-expression with the cryptographic
key. The S-expression is formatted using the 'Advanced Format'
(GCRYSEXP_FMT_ADVANCED) that avoids non-printable characters so that
the file can be easily inspected and edited. See section 'Private Key
Format' below for details.
** Values
to represent an array of values. Note that the name "Key" is special
in that it is madandory must occur only once.
*** Values
Values are UTF-8 encoded strings. Values can be wrapped at any point,
and continued in the next line indicated by leading whitespace. A
continuation line with one leading space does not introduce a blank so
that the lines can be effectively concatenated. A blank line as part
of a continuation line encodes a newline.
** Comments
*** Comments
Lines containing only whitespace, and lines starting with whitespace
followed by '#' are considered to be comments and are ignored.
** Well defined names
*** Description
This is a human readable string describing the key.
*** Key
The name "Key" is special in that it is mandatory and must occur only
once. The associated value holds the actual S-expression with the
cryptographic key. The S-expression is formatted using the 'Advanced
Format' (GCRYSEXP_FMT_ADVANCED) that avoids non-printable characters
so that the file can be easily inspected and edited. See section
'Private Key Format' below for details.
*** Label
This is a short human readable description for the key which can be
used by the software to describe the key in a user interface. For
example as part of the description in a prompt for a PIN or
passphrase. It is often used instead of a comment element as present
in the S-expression of the "Key" item.
*** OpenSSH-cert
This takes a base64 encoded string wrapped so that this
key file can be easily edited with a standard editor. Several of such
items can be used.
*** Token
If such an item exists it overrides the info given by the "shadow"
parameter in the S-expression. Using this item makes it possible to
describe a key which is stored on several tokens and also makes it
easy to update this info using a standard editor. The syntax is the
same as with the "shadow" parameter:
- Serialnumber of the token
- Key reference from the token in full format (e.g. "OpenPGP.2")
- An optional fixed length of the PIN.
*** Use-for-ssh
If given and the value is "yes" or "1" the key is allowed for use by
gpg-agent's ssh-agent implementation. This is thus the same as
putting the keygrip into the 'sshcontrol' file. Only one such item
should exist.
* Private Key Format
** Unprotected Private Key Format

View File

@ -23,7 +23,6 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <unistd.h>
#include <sys/stat.h>

View File

@ -23,7 +23,6 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <unistd.h>
#include <sys/stat.h>
@ -86,8 +85,8 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
goto leave;
}
rc = divert_pkdecrypt (ctrl, desc_text, ciphertext, shadow_info,
&buf, &len, r_padding);
rc = divert_pkdecrypt (ctrl, desc_text, ctrl->keygrip, ciphertext,
shadow_info, &buf, &len, r_padding);
if (rc)
{
log_error ("smartcard decryption failed: %s\n", gpg_strerror (rc));
@ -119,10 +118,10 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
gcry_sexp_dump (s_plain);
}
len = gcry_sexp_sprint (s_plain, GCRYSEXP_FMT_CANON, NULL, 0);
assert (len);
log_assert (len);
buf = xmalloc (len);
len = gcry_sexp_sprint (s_plain, GCRYSEXP_FMT_CANON, buf, len);
assert (len);
log_assert (len);
if (*buf == '(')
put_membuf (outbuf, buf, len);
else

View File

@ -24,8 +24,6 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <unistd.h>
#include <sys/stat.h>
#include "agent.h"
@ -46,16 +44,21 @@ do_encode_md (const byte * md, size_t mdlen, int algo, gcry_sexp_t * r_hash,
int i;
s = gcry_md_algo_name (algo);
if (s && strlen (s) < 16)
if (!s || strlen (s) >= 16)
{
hash = NULL;
rc = gpg_error (GPG_ERR_DIGEST_ALGO);
}
else
{
for (i=0; i < strlen (s); i++)
tmp[i] = tolower (s[i]);
for (i=0; s[i]; i++)
tmp[i] = ascii_tolower (s[i]);
tmp[i] = '\0';
}
rc = gcry_sexp_build (&hash, NULL,
"(data (flags pkcs1) (hash %s %b))",
tmp, (int)mdlen, md);
rc = gcry_sexp_build (&hash, NULL,
"(data (flags pkcs1) (hash %s %b))",
tmp, (int)mdlen, md);
}
}
else
{
@ -250,13 +253,13 @@ do_encode_raw_pkcs1 (const byte *md, size_t mdlen, unsigned int nbits,
frame[n++] = 0;
frame[n++] = 1; /* Block type. */
i = nframe - mdlen - 3 ;
assert (i >= 8); /* At least 8 bytes of padding. */
log_assert (i >= 8); /* At least 8 bytes of padding. */
memset (frame+n, 0xff, i );
n += i;
frame[n++] = 0;
memcpy (frame+n, md, mdlen );
n += mdlen;
assert (n == nframe);
log_assert (n == nframe);
/* Create the S-expression. */
rc = gcry_sexp_build (&hash, NULL,
@ -354,6 +357,7 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
agent_modify_description (desc_text, NULL, s_skey, &desc2);
err = divert_pksign (ctrl, desc2? desc2 : desc_text,
ctrl->keygrip,
data, datalen,
ctrl->digest.algo,
shadow_info, &buf, &len);

View File

@ -25,7 +25,6 @@
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <sys/stat.h>
#include <unistd.h>
#ifdef HAVE_LOCALE_H

View File

@ -25,7 +25,6 @@
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <sys/stat.h>
#include <unistd.h>
#ifdef HAVE_LOCALE_H
@ -198,10 +197,10 @@ make_canonical (const char *fname, const char *buf, size_t buflen)
return NULL;
}
len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, NULL, 0);
assert (len);
log_assert (len);
result = xmalloc (len);
len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, result, len);
assert (len);
log_assert (len);
gcry_sexp_release (sexp);
return result;
}
@ -222,10 +221,10 @@ make_advanced (const unsigned char *buf, size_t buflen)
return NULL;
}
len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0);
assert (len);
log_assert (len);
result = xmalloc (len);
len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, result, len);
assert (len);
log_assert (len);
gcry_sexp_release (sexp);
return result;
}
@ -433,7 +432,7 @@ read_and_shadow (const char *fname)
return;
}
resultlen = gcry_sexp_canon_len (result, 0, NULL,NULL);
assert (resultlen);
log_assert (resultlen);
if (opt_armor)
{
@ -469,7 +468,7 @@ show_shadow_info (const char *fname)
return;
}
infolen = gcry_sexp_canon_len (info, 0, NULL,NULL);
assert (infolen);
log_assert (infolen);
if (opt_armor)
{
@ -496,7 +495,7 @@ show_file (const char *fname)
return;
keylen = gcry_sexp_canon_len (key, 0, NULL,NULL);
assert (keylen);
log_assert (keylen);
if (opt_canonical)
{
@ -723,7 +722,7 @@ get_passphrase (int promptno)
gpg_strerror (err));
agent_exit (0);
}
assert (pw);
log_assert (pw);
return pw;
}
@ -799,12 +798,15 @@ agent_askpin (ctrl_t ctrl,
* to stdout. */
int
agent_write_private_key (const unsigned char *grip,
const void *buffer, size_t length, int force)
const void *buffer, size_t length, int force,
const char *serialno, const char *keyref)
{
char hexgrip[40+4+1];
char *p;
(void)force;
(void)serialno;
(void)keyref;
bin2hex (grip, 20, hexgrip);
strcpy (hexgrip+40, ".key");

View File

@ -528,7 +528,7 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
memcpy (p, iv+blklen, blklen); /* Add padding. */
p += blklen;
}
assert ( p - outbuf == outlen);
log_assert ( p - outbuf == outlen);
if (use_ocb)
{
gcry_cipher_final (hd);
@ -718,11 +718,11 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
hash_end = s;
s++;
/* Skip to the end of the S-expression. */
assert (depth == 1);
log_assert (depth == 1);
rc = sskip (&s, &depth);
if (rc)
return rc;
assert (!depth);
log_assert (!depth);
real_end = s-1;
rc = do_encryption (hash_begin, hash_end - hash_begin + 1,
@ -760,7 +760,7 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
memcpy (p, prot_end+1, real_end - prot_end);
p += real_end - prot_end;
assert ( p - *result == *resultlen);
log_assert ( p - *result == *resultlen);
xfree (protected);
return 0;
@ -999,7 +999,7 @@ merge_lists (const unsigned char *protectedkey,
/* Skip over the protected list element in the original list. */
s = protectedkey + replacepos;
assert (*s == '(');
log_assert (*s == '(');
s++;
i = 1;
rc = sskip (&s, &i);
@ -1026,7 +1026,7 @@ merge_lists (const unsigned char *protectedkey,
rc = sskip (&s, &i);
if (rc)
goto failure;
assert (s[-1] == ')');
log_assert (s[-1] == ')');
endpos = s; /* one behind the end of the list */
/* Append the rest. */
@ -1571,7 +1571,7 @@ agent_shadow_key (const unsigned char *pubkey,
point = s; /* insert right before the point */
depth--;
s++;
assert (depth == 1);
log_assert (depth == 1);
/* Calculate required length by taking in account: the "shadowed-"
prefix, the "shadowed", "t1-v1" as well as some parenthesis */
@ -1667,7 +1667,8 @@ agent_get_shadow_info (const unsigned char *shadowkey,
R_HEXSN and the Id string as a malloced string at R_IDSTR. On
error an error code is returned and NULL is stored at the result
parameters addresses. If the serial number or the ID string is not
required, NULL may be passed for them. */
required, NULL may be passed for them. Note that R_PINLEN is
currently not used by any caller. */
gpg_error_t
parse_shadow_info (const unsigned char *shadow_info,
char **r_hexsn, char **r_idstr, int *r_pinlen)

View File

@ -28,7 +28,6 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <unistd.h>
#include <sys/stat.h>

View File

@ -24,7 +24,6 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <unistd.h>
#include <sys/stat.h>
#include <npth.h>
@ -550,7 +549,7 @@ insert_colons (const char *string)
}
}
*p = 0;
assert (strlen (buffer) <= nnew);
log_assert (strlen (buffer) <= nnew);
return buffer;
}

View File

@ -624,6 +624,7 @@ Section "GnuPG" SEC_gnupg
File "bin/gpgsm.exe"
File "bin/gpgconf.exe"
File "bin/gpg-connect-agent.exe"
File "bin/gpg-card.exe"
File "bin/gpgtar.exe"
File "libexec/dirmngr_ldap.exe"
File "libexec/gpg-preset-passphrase.exe"
@ -1313,6 +1314,7 @@ Section "-un.gnupg"
Delete "$INSTDIR\bin\gpgconf.exe"
Delete "$INSTDIR\bin\gpg-connect-agent.exe"
Delete "$INSTDIR\bin\gpgtar.exe"
Delete "$INSTDIR\bin\gpg-card.exe"
Delete "$INSTDIR\bin\dirmngr_ldap.exe"
Delete "$INSTDIR\bin\gpg-preset-passphrase.exe"
Delete "$INSTDIR\bin\gpg-wks-client.exe"

View File

@ -149,13 +149,13 @@ if MAINTAINER_MODE
audit-events.h: Makefile.am mkstrtable.awk exaudit.awk audit.h
$(AWK) -f $(srcdir)/exaudit.awk $(srcdir)/audit.h \
| $(AWK) -f $(srcdir)/mkstrtable.awk -v textidx=3 -v nogettext=1 \
-v namespace=eventstr_ > $(srcdir)/audit-events.h
-v pkg_namespace=eventstr_ > $(srcdir)/audit-events.h
# Create the status-codes.h include file from status.h
status-codes.h: Makefile.am mkstrtable.awk exstatus.awk status.h
$(AWK) -f $(srcdir)/exstatus.awk $(srcdir)/status.h \
| $(AWK) -f $(srcdir)/mkstrtable.awk -v textidx=3 -v nogettext=1 \
-v namespace=statusstr_ > $(srcdir)/status-codes.h
-v pkg_namespace=statusstr_ > $(srcdir)/status-codes.h
endif
#

View File

@ -856,6 +856,7 @@ gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
STARTUPINFO si;
int cr_flags;
char *cmdline;
BOOL in_job = FALSE;
/* We don't use ENVP. */
@ -884,6 +885,50 @@ gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
| GetPriorityClass (GetCurrentProcess ())
| CREATE_NEW_PROCESS_GROUP
| DETACHED_PROCESS);
/* Check if we were spawned as part of a Job.
* In a job we need to add CREATE_BREAKAWAY_FROM_JOB
* to the cr_flags, otherwise our child processes
* are killed when we terminate. */
if (!IsProcessInJob (GetCurrentProcess(), NULL, &in_job))
{
log_error ("IsProcessInJob() failed: %s\n", w32_strerror (-1));
in_job = FALSE;
}
if (in_job)
{
/* Only try to break away from job if it is allowed, otherwise
* CreateProcess() would fail with an "Access is denied" error. */
JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
if (!QueryInformationJobObject (NULL, JobObjectExtendedLimitInformation,
&info, sizeof info, NULL))
{
log_error ("QueryInformationJobObject() failed: %s\n",
w32_strerror (-1));
}
else if ((info.BasicLimitInformation.LimitFlags &
JOB_OBJECT_LIMIT_BREAKAWAY_OK))
{
log_debug ("Using CREATE_BREAKAWAY_FROM_JOB flag\n");
cr_flags |= CREATE_BREAKAWAY_FROM_JOB;
}
else if ((info.BasicLimitInformation.LimitFlags &
JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK))
{
/* The child process should automatically detach from the job. */
log_debug ("Not using CREATE_BREAKAWAY_FROM_JOB flag; "
"JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK is set\n");
}
else
{
/* It seems that the child process must remain in the job.
* This is not necessarily an error, although it can cause premature
* termination of the child process when the job is closed. */
log_debug ("Not using CREATE_BREAKAWAY_FROM_JOB flag\n");
}
}
/* log_debug ("CreateProcess(detached), path='%s' cmdline='%s'\n", */
/* pgmname, cmdline); */
if (!CreateProcess (pgmname, /* Program to start. */

View File

@ -76,7 +76,7 @@
#
# The variable prefix can be used to prepend a string to each message.
#
# The variable namespace can be used to prepend a string to each
# The variable pkg_namespace can be used to prepend a string to each
# variable and macro name.
BEGIN {
@ -101,7 +101,7 @@ header {
print "/* The purpose of this complex string table is to produce";
print " optimal code with a minimum of relocations. */";
print "";
print "static const char " namespace "msgstr[] = ";
print "static const char " pkg_namespace "msgstr[] = ";
header = 0;
}
else
@ -109,7 +109,7 @@ header {
}
!header {
sub (/\#.+/, "");
sub (/#.+/, "");
sub (/[ ]+$/, ""); # Strip trailing space and tab characters.
if (/^$/)
@ -149,14 +149,14 @@ END {
else
print " gettext_noop (\"" prefix last_msgstr "\");";
print "";
print "static const int " namespace "msgidx[] =";
print "static const int " pkg_namespace "msgidx[] =";
print " {";
for (i = 0; i < coded_msgs; i++)
print " " pos[i] ",";
print " " pos[coded_msgs];
print " };";
print "";
print "#define " namespace "msgidxof(code) (0 ? -1 \\";
print "#define " pkg_namespace "msgidxof(code) (0 ? -1 \\";
# Gather the ranges.
skip = code[0];

View File

@ -514,6 +514,21 @@ nvc_delete (nvc_t pk, nve_t entry)
nve_release (entry, pk->private_key_mode);
}
/* Delete the entries with NAME from PK. */
void
nvc_delete_named (nvc_t pk, const char *name)
{
nve_t e;
if (!valid_name (name))
return;
while ((e = nvc_lookup (pk, name)))
nvc_delete (pk, e);
}
/* Lookup and iteration. */
@ -563,6 +578,25 @@ nve_next_value (nve_t entry, const char *name)
return NULL;
}
/* Return the string for the first entry in NVC with NAME. If an
* entry with NAME is missing in NVC or its value is the empty string
* NULL is returned. Note that the The returned string is a pointer
* into NVC. */
const char *
nvc_get_string (nvc_t nvc, const char *name)
{
nve_t item;
if (!nvc)
return NULL;
item = nvc_lookup (nvc, name);
if (!item)
return NULL;
return nve_value (item);
}
/* Private key handling. */
@ -778,29 +812,56 @@ nvc_parse_private_key (nvc_t *result, int *errlinep, estream_t stream)
}
/* Helper fpr nvc_write. */
static gpg_error_t
write_one_entry (nve_t entry, estream_t stream)
{
gpg_error_t err;
strlist_t sl;
if (entry->name)
es_fputs (entry->name, stream);
err = assert_raw_value (entry);
if (err)
return err;
for (sl = entry->raw_value; sl; sl = sl->next)
es_fputs (sl->d, stream);
if (es_ferror (stream))
return my_error_from_syserror ();
return 0;
}
/* Write a representation of PK to STREAM. */
gpg_error_t
nvc_write (nvc_t pk, estream_t stream)
{
gpg_error_t err;
gpg_error_t err = 0;
nve_t entry;
strlist_t s;
nve_t keyentry = NULL;
for (entry = pk->first; entry; entry = entry->next)
{
if (entry->name)
es_fputs (entry->name, stream);
if (pk->private_key_mode
&& entry->name && !ascii_strcasecmp (entry->name, "Key:"))
{
if (!keyentry)
keyentry = entry;
continue;
}
err = assert_raw_value (entry);
err = write_one_entry (entry, stream);
if (err)
return err;
for (s = entry->raw_value; s; s = s->next)
es_fputs (s->d, stream);
if (es_ferror (stream))
return my_error_from_syserror ();
}
return 0;
/* In private key mode we write the Key always last. */
if (keyentry)
err = write_one_entry (keyentry, stream);
return err;
}

View File

@ -72,6 +72,9 @@ nve_t nve_next (nve_t entry);
/* Get the next entry with the given name. */
nve_t nve_next_value (nve_t entry, const char *name);
/* Return the string for the first entry in NVC with NAME or NULL. */
const char *nvc_get_string (nvc_t nvc, const char *name);
/* Adding and modifying values. */
@ -88,6 +91,9 @@ gpg_error_t nvc_set (nvc_t pk, const char *name, const char *value);
/* Delete the given entry from PK. */
void nvc_delete (nvc_t pk, nve_t pke);
/* Delete the entries with NAME from PK. */
void nvc_delete_named (nvc_t pk, const char *name);
/* Private key handling. */

View File

@ -39,7 +39,7 @@
#include "openpgpdefs.h"
/* Pack an s2k iteration count into the form specified in RFC-48800.
/* Pack an s2k iteration count into the form specified in RFC-4880.
* If we're in between valid values, round up. */
unsigned char
encode_s2k_iterations (int iterations)

View File

@ -581,9 +581,9 @@ get_pk_algo_from_canon_sexp (const unsigned char *keydata, size_t keydatalen)
/* Given the public key S_PKEY, return a new buffer with a descriptive
* string for its algorithm. This function may return NULL on memory
* error. */
* error. If R_ALGOID is not NULL the gcrypt algo id is stored there. */
char *
pubkey_algo_string (gcry_sexp_t s_pkey)
pubkey_algo_string (gcry_sexp_t s_pkey, enum gcry_pk_algos *r_algoid)
{
const char *prefix;
gcry_sexp_t l1;
@ -591,6 +591,9 @@ pubkey_algo_string (gcry_sexp_t s_pkey)
int algo;
char *result;
if (r_algoid)
*r_algoid = 0;
l1 = gcry_sexp_find_token (s_pkey, "public-key", 0);
if (!l1)
return xtrystrdup ("E_no_key");
@ -632,6 +635,8 @@ pubkey_algo_string (gcry_sexp_t s_pkey)
else
result = xtryasprintf ("X_algo_%d", algo);
if (r_algoid)
*r_algoid = algo;
xfree (algoname);
return result;
}

View File

@ -292,6 +292,7 @@ run_modification_tests (void)
{
gpg_error_t err;
nvc_t pk;
nve_t e;
gcry_sexp_t key;
char *buf;
@ -344,6 +345,30 @@ run_modification_tests (void)
assert (strcmp (buf, "") == 0);
xfree (buf);
/* Test whether we can delete an entry by name. */
err = nvc_add (pk, "Key:", "(3:foo)");
assert (!err);
e = nvc_lookup (pk, "Key:");
assert (e);
nvc_delete_named (pk, "Kez:"); /* Delete an inexistant name. */
e = nvc_lookup (pk, "Key:");
assert (e);
nvc_delete_named (pk, "Key:");
e = nvc_lookup (pk, "Key:");
assert (!e);
/* Ditto but now whether it deletes all entries with that name. We
* don't use "Key" because that name is special in private key mode. */
err = nvc_add (pk, "AKey:", "A-value");
assert (!err);
err = nvc_add (pk, "AKey:", "B-value");
assert (!err);
e = nvc_lookup (pk, "AKey:");
assert (e);
nvc_delete_named (pk, "AKey:");
e = nvc_lookup (pk, "AKey:");
assert (!e);
nvc_set (pk, "Foo:", "A really long value spanning across multiple lines"
" that has to be wrapped at a convenient space.");
buf = nvc_to_string (pk);

View File

@ -380,8 +380,10 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack)
}
else if (!hexprefix)
{
/* The fingerprint in an X.509 listing is often delimited by
colons, so we try to single this case out. */
/* The fingerprint of an X.509 listing is often delimited by
* colons, so we try to single this case out. Note that the
* OpenPGP bang suffix is not supported here. */
desc->exact = 0;
mode = 0;
hexlength = strspn (s, ":0123456789abcdefABCDEF");
if (hexlength == 59 && (!s[hexlength] || spacep (s+hexlength)))
@ -454,7 +456,6 @@ classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack)
}
if (!mode) /* Default to substring search. */
{
desc->exact = 0;
desc->u.name = s;
mode = KEYDB_SEARCH_MODE_SUBSTR;
}

View File

@ -192,7 +192,7 @@ gpg_error_t get_rsa_pk_from_canon_sexp (const unsigned char *keydata,
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);
char *pubkey_algo_string (gcry_sexp_t s_pkey, enum gcry_pk_algos *r_algoid);
/*-- convert.c --*/
int hex2bin (const char *string, void *buffer, size_t length);

View File

@ -1471,6 +1471,9 @@ find_cert_bysubject (ctrl_t ctrl, const char *subject_dn, ksba_sexp_t keyid)
{
ksba_cert_ref (ci->cert);
release_cache_lock ();
if (DBG_LOOKUP)
log_debug ("%s: certificate found in the cache"
" via ocsp_certs\n", __func__);
return ci->cert; /* We use this certificate. */
}
release_cache_lock ();
@ -1478,7 +1481,7 @@ find_cert_bysubject (ctrl_t ctrl, const char *subject_dn, ksba_sexp_t keyid)
log_debug ("find_cert_bysubject: certificate not in ocsp_certs\n");
}
/* No check whether the certificate is cached. */
/* Now check whether the certificate is cached. */
for (seq=0; (cert = get_cert_bysubject (subject_dn, seq)); seq++)
{
if (!keyid)
@ -1487,6 +1490,9 @@ find_cert_bysubject (ctrl_t ctrl, const char *subject_dn, ksba_sexp_t keyid)
&& !cmp_simple_canon_sexp (keyid, subj))
{
xfree (subj);
if (DBG_LOOKUP)
log_debug ("%s: certificate found in the cache"
" via subject DN\n", __func__);
break; /* Found matching cert. */
}
xfree (subj);
@ -1495,6 +1501,34 @@ find_cert_bysubject (ctrl_t ctrl, const char *subject_dn, ksba_sexp_t keyid)
if (cert)
return cert; /* Done. */
/* If we do not have a subject DN but have a keyid, try to locate it
* by keyid. */
if (!subject_dn && keyid)
{
int i;
cert_item_t ci;
ksba_sexp_t ski;
acquire_cache_read_lock ();
for (i=0; i < 256; i++)
for (ci=cert_cache[i]; ci; ci = ci->next)
if (ci->cert && !ksba_cert_get_subj_key_id (ci->cert, NULL, &ski))
{
if (!cmp_simple_canon_sexp (keyid, ski))
{
ksba_free (ski);
ksba_cert_ref (ci->cert);
release_cache_lock ();
if (DBG_LOOKUP)
log_debug ("%s: certificate found in the cache"
" via ski\n", __func__);
return ci->cert;
}
ksba_free (ski);
}
release_cache_lock ();
}
if (DBG_LOOKUP)
log_debug ("find_cert_bysubject: certificate not in cache\n");

View File

@ -2217,8 +2217,8 @@ static void dns_p_dump3(struct dns_packet *P, struct dns_rr_i *I, FILE *fp) {
void dns_p_dump(struct dns_packet *P, FILE *fp) {
struct dns_rr_i _I = { 0 };
dns_p_dump3(P, &_I, fp);
struct dns_rr_i I_instance = { 0 };
dns_p_dump3(P, &I_instance, fp);
} /* dns_p_dump() */
@ -5275,8 +5275,8 @@ error:
struct dns_packet *dns_hosts_query(struct dns_hosts *hosts, struct dns_packet *Q, int *error_) {
union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _P = { 0 };
struct dns_packet *P = dns_p_init(&_P.p, 512);
union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } P_instance = { 0 };
struct dns_packet *P = dns_p_init(&P_instance.p, 512);
struct dns_packet *A = 0;
struct dns_rr rr;
struct dns_hosts_entry *ent;
@ -6837,7 +6837,7 @@ unsigned dns_hints_grep(struct sockaddr **sa, socklen_t *sa_len, unsigned lim, s
struct dns_packet *dns_hints_query(struct dns_hints *hints, struct dns_packet *Q, int *error_) {
union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _P = { 0 };
union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } P_instance = { 0 };
struct dns_packet *A, *P;
struct dns_rr rr;
char zone[DNS_D_MAXNAME + 1];
@ -6846,11 +6846,11 @@ struct dns_packet *dns_hints_query(struct dns_hints *hints, struct dns_packet *Q
struct sockaddr *sa;
socklen_t slen;
int error;
struct dns_rr_i _I = { 0 };
struct dns_rr_i I_instance = { 0 };
_I.section = DNS_S_QUESTION;
I_instance.section = DNS_S_QUESTION;
if (!dns_rr_grep(&rr, 1, &_I, Q, &error))
if (!dns_rr_grep(&rr, 1, &I_instance, Q, &error))
goto error;
if (!(zlen = dns_d_expand(zone, sizeof zone, rr.dn.p, Q, &error)))
@ -6858,7 +6858,7 @@ struct dns_packet *dns_hints_query(struct dns_hints *hints, struct dns_packet *Q
else if (zlen >= sizeof zone)
goto toolong;
P = dns_p_init(&_P.p, 512);
P = dns_p_init(&P_instance.p, 512);
dns_header(P)->qr = 1;
if ((error = dns_rr_copy(P, &rr, Q)))
@ -8463,8 +8463,8 @@ error:
static struct dns_packet *dns_res_glue(struct dns_resolver *R, struct dns_packet *Q) {
union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _P = { 0 };
struct dns_packet *P = dns_p_init(&_P.p, 512);
union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } P_instance = { 0 };
struct dns_packet *P = dns_p_init(&P_instance.p, 512);
char qname[DNS_D_MAXNAME + 1];
size_t qlen;
enum dns_type qtype;
@ -8537,20 +8537,20 @@ static int dns_res_nameserv_cmp(struct dns_rr *a, struct dns_rr *b, struct dns_r
int cmp, error;
if (!(error = dns_ns_parse(&ns, a, P))) {
struct dns_rr_i _I = { 0 };
struct dns_rr_i I_instance = { 0 };
_I.section = (DNS_S_ALL & ~DNS_S_QD);
_I.name = ns.host;
_I.type = DNS_T_A;
glued[0] = !!dns_rr_grep(&x, 1, &_I, P, &error);
I_instance.section = (DNS_S_ALL & ~DNS_S_QD);
I_instance.name = ns.host;
I_instance.type = DNS_T_A;
glued[0] = !!dns_rr_grep(&x, 1, &I_instance, P, &error);
}
if (!(error = dns_ns_parse(&ns, b, P))) {
struct dns_rr_i _I = { 0 };
struct dns_rr_i I_instance = { 0 };
_I.section = (DNS_S_ALL & ~DNS_S_QD);
_I.name = ns.host;
_I.type = DNS_T_A;
glued[1] = !!dns_rr_grep(&y, 1, &_I, P, &error);
I_instance.section = (DNS_S_ALL & ~DNS_S_QD);
I_instance.name = ns.host;
I_instance.type = DNS_T_A;
glued[1] = !!dns_rr_grep(&y, 1, &I_instance, P, &error);
}
if ((cmp = glued[1] - glued[0])) {
return cmp;
@ -9916,13 +9916,13 @@ exec:
return dns_ai_setent(ent, &any, rr.type, ai);
case DNS_AI_S_SUBMIT_G:
{
struct dns_rr_i _I = { 0 };
struct dns_rr_i I_instance = { 0 };
_I.section = DNS_S_QD;
_I.name = ai->g.name;
_I.type = ai->g.type;
I_instance.section = DNS_S_QD;
I_instance.name = ai->g.name;
I_instance.type = ai->g.type;
/* skip if already queried */
if (dns_rr_grep(&rr, 1, &_I, ai->glue, &error))
if (dns_rr_grep(&rr, 1, &I_instance, ai->glue, &error))
dns_ai_goto(DNS_AI_S_FOREACH_I);
/* skip if we recursed (CNAME chains should have been handled in the resolver) */
if (++ai->g_depth > 1)
@ -10598,7 +10598,7 @@ static struct dns_trace *trace(const char *mode) {
static void print_packet(struct dns_packet *P, FILE *fp) {
struct dns_rr_i _I = { 0 };
struct dns_rr_i I_instance = { 0 };
I.sort = MAIN.sort;
dns_p_dump3(P, &I, fp);
@ -10608,10 +10608,10 @@ static void print_packet(struct dns_packet *P, FILE *fp) {
static int parse_packet(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _P = { 0 };
union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _Q = { 0 };
struct dns_packet *P = dns_p_init(&_P.p, 512);
struct dns_packet *Q = dns_p_init(&_Q.p, 512);
union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } P_instance = { 0 };
union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } Q_instance = { 0 };
struct dns_packet *P = dns_p_init(&P_instance.p, 512);
struct dns_packet *Q = dns_p_init(&Q_instance.p, 512);
enum dns_section section;
struct dns_rr rr;
int error;
@ -10655,7 +10655,7 @@ static int parse_packet(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
const char *dn = "ns8.yahoo.com";
char *_name = dns_d_init(_p, sizeof _p, dn, strlen (dn), DNS_D_ANCHOR);
struct dns_rr rrset[32];
struct dns_rr_i _I = { 0 };
struct dns_rr_i I_instance = { 0 };
struct dns_rr_i *rri = &I;
unsigned rrcount = dns_rr_grep(rrset, lengthof(rrset), rri, Q, &error);
@ -10818,8 +10818,8 @@ static int show_hosts(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
static int query_hosts(int argc, char *argv[]) {
union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _Q = { 0 };
struct dns_packet *Q = dns_p_init(&_Q.p, 512);
union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } Q_instance = { 0 };
struct dns_packet *Q = dns_p_init(&Q_instance.p, 512);
struct dns_packet *A;
char qname[DNS_D_MAXNAME + 1];
size_t qlen;
@ -10937,8 +10937,8 @@ static int dump_random(int argc, char *argv[]) {
static int send_query(int argc, char *argv[]) {
union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _Q = { 0 };
struct dns_packet *A, *Q = dns_p_init(&_Q.p, 512);
union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } Q_instance = { 0 };
struct dns_packet *A, *Q = dns_p_init(&Q_instance.p, 512);
char host[INET6_ADDRSTRLEN + 1];
struct sockaddr_storage ss;
struct dns_socket *so;
@ -11033,10 +11033,10 @@ static int show_hints(int argc, char *argv[]) {
if (0 == strcmp(how, "plain")) {
dns_hints_dump(hints, stdout);
} else {
union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _P = { 0 };
union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } P_instance = { 0 };
struct dns_packet *query, *answer;
query = dns_p_init(&_P.p, 512);
query = dns_p_init(&P_instance.p, 512);
if ((error = dns_p_push(query, DNS_S_QUESTION, who, strlen(who), DNS_T_A, DNS_C_IN, 0, 0)))
panic("%s: %s", who, dns_strerror(error));
@ -11199,8 +11199,8 @@ static int echo_port(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) {
panic("127.0.0.1:5353: %s", dns_strerror(errno));
for (;;) {
union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } _P = { 0 };
struct dns_packet *pkt = dns_p_init(&_P.p, 512);
union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } P_instance = { 0 };
struct dns_packet *pkt = dns_p_init(&P_instance.p, 512);
struct sockaddr_storage ss;
socklen_t slen = sizeof ss;
ssize_t count;

View File

@ -47,6 +47,7 @@ struct domaininfo_s
unsigned int wkd_not_found:1; /* A WKD query failed. */
unsigned int wkd_supported:1; /* One WKD entry was found. */
unsigned int wkd_not_supported:1; /* Definitely does not support WKD. */
unsigned int keepmark:1; /* Private to insert_or_update(). */
char name[1];
};
typedef struct domaininfo_s *domaininfo_t;
@ -143,7 +144,10 @@ insert_or_update (const char *domain,
{
domaininfo_t di;
domaininfo_t di_new;
domaininfo_t di_cut;
domaininfo_t drop = NULL;
domaininfo_t drop_extra = NULL;
int nkept = 0;
int ndropped = 0;
u32 hash;
int count;
@ -162,7 +166,6 @@ insert_or_update (const char *domain,
/* Need to do another lookup because the malloc is a system call and
* thus the hash array may have been changed by another thread. */
di_cut = NULL;
for (count=0, di = domainbuckets[hash]; di; di = di->next, count++)
if (!strcmp (di->name, domain))
{
@ -172,16 +175,89 @@ insert_or_update (const char *domain,
}
/* Before we insert we need to check whether the chain gets too long. */
di_cut = NULL;
if (count >= MAX_DOMAINBUCKET_LEN)
{
for (count=0, di = domainbuckets[hash]; di; di = di->next, count++)
if (count >= MAX_DOMAINBUCKET_LEN/2)
{
di_cut = di->next;
di->next = NULL;
break;
}
domaininfo_t bucket;
domaininfo_t *array;
int narray, idx;
domaininfo_t keep = NULL;
/* Unlink from the global list before doing a syscall. */
bucket = domainbuckets[hash];
domainbuckets[hash] = NULL;
array = xtrycalloc (count, sizeof *array);
if (!array)
{
/* That's bad; give up the entire bucket. */
log_error ("domaininfo: error allocating helper array: %s\n",
gpg_strerror (gpg_err_code_from_syserror ()));
drop_extra = bucket;
goto leave;
}
narray = 0;
/* Move all items into an array for easier processing. */
for (di = bucket; di; di = di->next)
array[narray++] = di;
log_assert (narray == count);
/* Mark all item in the array which are flagged to support wkd
* but not more than half of the maximum. This way we will at
* the end drop half of the items. */
count = 0;
for (idx=0; idx < narray; idx++)
{
di = array[idx];
di->keepmark = 0; /* Clear flag here on the first pass. */
if (di->wkd_supported && count < MAX_DOMAINBUCKET_LEN/2)
{
di->keepmark = 1;
count++;
}
}
/* Now mark those which are marked as not found. */
/* FIXME: we should use an LRU algorithm here. */
for (idx=0; idx < narray; idx++)
{
di = array[idx];
if (!di->keepmark
&& di->wkd_not_supported && count < MAX_DOMAINBUCKET_LEN/2)
{
di->keepmark = 1;
count++;
}
}
/* Build a bucket list and a second list for later freeing the
* items (we can't do it directly because a free is a system
* call and we want to avoid locks in this module. Note that
* the kept items will be reversed order which does not matter. */
for (idx=0; idx < narray; idx++)
{
di = array[idx];
if (di->keepmark)
{
di->next = keep;
keep = di;
nkept++;
}
else
{
di->next = drop;
drop = di;
ndropped++;
}
}
/* In case another thread added new stuff to the domain list we
* simply drop them instead all. It would also be possible to
* append them to our list but then we can't guarantee that a
* bucket list is almost all of the time limited to
* MAX_DOMAINBUCKET_LEN. Not sure whether this is really a
* sensible strategy. */
drop_extra = domainbuckets[hash];
domainbuckets[hash] = keep;
}
/* Insert */
@ -190,17 +266,28 @@ insert_or_update (const char *domain,
di->next = domainbuckets[hash];
domainbuckets[hash] = di;
/* Remove the rest of the cutted chain. */
while (di_cut)
if (opt.verbose && (nkept || ndropped))
log_info ("domaininfo: bucket=%lu kept=%d purged=%d\n",
(unsigned long)hash, nkept, ndropped);
leave:
/* Remove the dropped items. */
while (drop)
{
di = di_cut->next;
xfree (di_cut);
di_cut = di;
di = drop->next;
xfree (drop);
drop = di;
}
while (drop_extra)
{
di = drop_extra->next;
xfree (drop_extra);
drop_extra = di;
}
}
/* Helper for domaininfo_set_no_name. */
/* Helper for domaininfo_set_no_name. May not do any syscalls. */
static void
set_no_name_cb (domaininfo_t di, int insert_mode)
{
@ -224,7 +311,7 @@ domaininfo_set_no_name (const char *domain)
}
/* Helper for domaininfo_set_wkd_supported. */
/* Helper for domaininfo_set_wkd_supported. May not do any syscalls. */
static void
set_wkd_supported_cb (domaininfo_t di, int insert_mode)
{
@ -245,7 +332,7 @@ domaininfo_set_wkd_supported (const char *domain)
}
/* Helper for domaininfo_set_wkd_not_supported. */
/* Helper for domaininfo_set_wkd_not_supported. May not do any syscalls. */
static void
set_wkd_not_supported_cb (domaininfo_t di, int insert_mode)
{
@ -265,7 +352,7 @@ domaininfo_set_wkd_not_supported (const char *domain)
/* Helper for domaininfo_set_wkd_not_found. */
/* Helper for domaininfo_set_wkd_not_found. May not do any syscalls. */
static void
set_wkd_not_found_cb (domaininfo_t di, int insert_mode)
{

View File

@ -3536,8 +3536,13 @@ same_host_p (parsed_uri_t a, parsed_uri_t b)
{ "protonmail.com", "api.protonmail.com" },
{ NULL, "api.protonmail.ch" },
{ "protonmail.ch", "api.protonmail.com" },
{ NULL, "api.protonmail.ch" }
{ NULL, "api.protonmail.ch" },
{ "pm.me", "api.protonmail.ch" }
};
static const char *subdomains[] =
{
"openpgpkey."
};
int i;
const char *from;
@ -3559,6 +3564,22 @@ same_host_p (parsed_uri_t a, parsed_uri_t b)
return 1;
}
/* Also consider hosts the same if they differ only in a subdomain;
* in both direction. This allows to have redirection between the
* WKD advanced and direct lookup methods. */
for (i=0; i < DIM (subdomains); i++)
{
const char *subdom = subdomains[i];
size_t subdomlen = strlen (subdom);
if (!ascii_strncasecmp (a->host, subdom, subdomlen)
&& !ascii_strcasecmp (a->host + subdomlen, b->host))
return 1;
if (!ascii_strncasecmp (b->host, subdom, subdomlen)
&& !ascii_strcasecmp (b->host + subdomlen, a->host))
return 1;
}
return 0;
}

View File

@ -68,6 +68,10 @@
/* Number of retries done for a dead host etc. */
#define SEND_REQUEST_RETRIES 3
/* Number of retries done in case of transient errors. */
#define SEND_REQUEST_EXTRA_RETRIES 5
enum ks_protocol { KS_PROTOCOL_HKP, KS_PROTOCOL_HKPS, KS_PROTOCOL_MAX };
/* Objects used to maintain information about hosts. */
@ -1217,6 +1221,7 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
/* FIXME: I am not sure whey we allow a downgrade for hkp requests.
* Needs at least an explanation here.. */
once_more:
err = http_session_new (&session, httphost,
((ctrl->http_no_crl? HTTP_FLAG_NO_CRL : 0)
| HTTP_FLAG_TRUST_DEF),
@ -1226,7 +1231,6 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
http_session_set_log_cb (session, cert_log_cb);
http_session_set_timeout (session, ctrl->timeout);
once_more:
err = http_open (ctrl, &http,
post_cb? HTTP_REQ_POST : HTTP_REQ_GET,
request,
@ -1306,6 +1310,8 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
request = request_buffer;
http_close (http, 0);
http = NULL;
http_session_release (session);
session = NULL;
}
goto once_more;
@ -1313,6 +1319,10 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
goto leave;
case 413: /* Payload too large */
err = gpg_error (GPG_ERR_TOO_LARGE);
goto leave;
default:
log_error (_("error accessing '%s': http status %u\n"),
request, http_get_status_code (http));
@ -1349,10 +1359,12 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
with REQUEST. The function returns true if the caller shall try
again. TRIES_LEFT points to a variable to track the number of
retries; this function decrements it and won't return true if it is
down to zero. */
down to zero. EXTRA_TRIES_LEFT does the same but only for
transient http status codes. */
static int
handle_send_request_error (ctrl_t ctrl, gpg_error_t err, const char *request,
unsigned int http_status, unsigned int *tries_left)
unsigned int http_status, unsigned int *tries_left,
unsigned int *extra_tries_left)
{
int retry = 0;
@ -1408,9 +1420,12 @@ handle_send_request_error (ctrl_t ctrl, gpg_error_t err, const char *request,
case 503: /* Service Unavailable */
case 504: /* Gateway Timeout */
log_info ("selecting a different host due to a %u (%s)",
http_status, http_status2string (http_status));
retry = 1;
if (*extra_tries_left)
{
log_info ("selecting a different host due to a %u (%s)",
http_status, http_status2string (http_status));
retry = 2;
}
break;
}
}
@ -1420,8 +1435,16 @@ handle_send_request_error (ctrl_t ctrl, gpg_error_t err, const char *request,
break;
}
if (*tries_left)
--*tries_left;
if (retry == 2)
{
if (*extra_tries_left)
--*extra_tries_left;
}
else
{
if (*tries_left)
--*tries_left;
}
return retry;
}
@ -1446,6 +1469,7 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
char *httphost = NULL;
unsigned int http_status;
unsigned int tries = SEND_REQUEST_RETRIES;
unsigned int extra_tries = SEND_REQUEST_EXTRA_RETRIES;
*r_fp = NULL;
@ -1521,7 +1545,8 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
/* Send the request. */
err = send_request (ctrl, request, hostport, httphost, httpflags,
NULL, NULL, &fp, &http_status);
if (handle_send_request_error (ctrl, err, request, http_status, &tries))
if (handle_send_request_error (ctrl, err, request, http_status,
&tries, &extra_tries))
{
reselect = 1;
goto again;
@ -1591,6 +1616,7 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
unsigned int httpflags;
unsigned int http_status;
unsigned int tries = SEND_REQUEST_RETRIES;
unsigned int extra_tries = SEND_REQUEST_EXTRA_RETRIES;
*r_fp = NULL;
@ -1664,7 +1690,8 @@ ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
/* Send the request. */
err = send_request (ctrl, request, hostport, httphost, httpflags,
NULL, NULL, &fp, &http_status);
if (handle_send_request_error (ctrl, err, request, http_status, &tries))
if (handle_send_request_error (ctrl, err, request, http_status,
&tries, &extra_tries))
{
reselect = 1;
goto again;
@ -1740,6 +1767,7 @@ ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen)
unsigned int httpflags;
unsigned int http_status;
unsigned int tries = SEND_REQUEST_RETRIES;
unsigned int extra_tries = SEND_REQUEST_EXTRA_RETRIES;
parm.datastring = NULL;
@ -1778,7 +1806,8 @@ ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen)
/* Send the request. */
err = send_request (ctrl, request, hostport, httphost, 0,
put_post_cb, &parm, &fp, &http_status);
if (handle_send_request_error (ctrl, err, request, http_status, &tries))
if (handle_send_request_error (ctrl, err, request, http_status,
&tries, &extra_tries))
{
reselect = 1;
goto again;

View File

@ -174,6 +174,10 @@ ks_http_fetch (ctrl_t ctrl, const char *url, unsigned int flags,
}
goto once_more;
case 413: /* Payload too large */
err = gpg_error (GPG_ERR_TOO_LARGE);
goto leave;
default:
log_error (_("error accessing '%s': http status %u\n"),
url, http_get_status_code (http));

View File

@ -116,10 +116,15 @@ read_response (estream_t fp, unsigned char **r_buffer, size_t *r_buflen)
/* Construct an OCSP request, send it to the configured OCSP responder
and parse the response. On success the OCSP context may be used to
further process the response. */
further process the response. The signature value and the
production date are returned at R_SIGVAL and R_PRODUCED_AT; they
may be NULL or an empty string if not available. A new hash
context is returned at R_MD. */
static gpg_error_t
do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md,
const char *url, ksba_cert_t cert, ksba_cert_t issuer_cert)
do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp,
const char *url, ksba_cert_t cert, ksba_cert_t issuer_cert,
ksba_sexp_t *r_sigval, ksba_isotime_t r_produced_at,
gcry_md_hd_t *r_md)
{
gpg_error_t err;
unsigned char *request, *response;
@ -132,6 +137,10 @@ do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md,
(void)ctrl;
*r_sigval = NULL;
*r_produced_at = 0;
*r_md = NULL;
if (dirmngr_use_tor ())
{
/* For now we do not allow OCSP via Tor due to possible privacy
@ -238,6 +247,10 @@ do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md,
}
break;
case 413: /* Payload too large */
err = gpg_error (GPG_ERR_TOO_LARGE);
break;
default:
log_error (_("error accessing '%s': http status %u\n"),
url, http_get_status_code (http));
@ -259,6 +272,7 @@ do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md,
xfree (free_this);
return err;
}
/* log_printhex (response, responselen, "ocsp response"); */
err = ksba_ocsp_parse_response (ocsp, response, responselen,
&response_status);
@ -286,11 +300,34 @@ do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md,
}
if (response_status == KSBA_OCSP_RSPSTATUS_SUCCESS)
{
int hash_algo;
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
* only once. */
*r_sigval = ksba_ocsp_get_sig_val (ocsp, r_produced_at);
hash_algo = hash_algo_from_sigval (*r_sigval);
if (!hash_algo)
{
if (opt.verbose)
log_info ("ocsp: using SHA-256 as fallback hash algo.\n");
hash_algo = GCRY_MD_SHA256;
}
err = gcry_md_open (r_md, hash_algo, 0);
if (err)
{
log_error (_("failed to establish a hashing context for OCSP: %s\n"),
gpg_strerror (err));
goto leave;
}
if (DBG_HASHING)
gcry_md_debug (*r_md, "ocsp");
err = ksba_ocsp_hash_response (ocsp, response, responselen,
HASH_FNC, md);
HASH_FNC, *r_md);
if (err)
log_error (_("hashing the OCSP response for '%s' failed: %s\n"),
url, gpg_strerror (err));
@ -301,8 +338,17 @@ do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md,
err = gpg_error (GPG_ERR_GENERAL);
}
leave:
xfree (response);
xfree (free_this);
if (err)
{
xfree (*r_sigval);
*r_sigval = NULL;
*r_produced_at = 0;
gcry_md_close (*r_md);
*r_md = NULL;
}
return err;
}
@ -387,7 +433,7 @@ check_signature_core (ctrl_t ctrl, ksba_cert_t cert, gcry_sexp_t s_sig,
/* We simply ignore all errors. */
gcry_sexp_release (s_pkey);
return -1;
return err;
}
@ -406,18 +452,27 @@ check_signature (ctrl_t ctrl,
int algo, cert_idx;
gcry_sexp_t s_hash;
ksba_cert_t cert;
const char *s;
/* Create a suitable S-expression with the hash value of our response. */
gcry_md_final (md);
algo = gcry_md_get_algo (md);
if (algo != GCRY_MD_SHA1 )
s = gcry_md_algo_name (algo);
if (algo && s && strlen (s) < 16)
{
log_error (_("only SHA-1 is supported for OCSP responses\n"));
return gpg_error (GPG_ERR_DIGEST_ALGO);
char hashalgostr[16+1];
int i;
for (i=0; s[i]; i++)
hashalgostr[i] = ascii_tolower (s[i]);
hashalgostr[i] = 0;
err = gcry_sexp_build (&s_hash, NULL, "(data(flags pkcs1)(hash %s %b))",
hashalgostr,
(int)gcry_md_get_algo_dlen (algo),
gcry_md_read (md, algo));
}
err = gcry_sexp_build (&s_hash, NULL, "(data(flags pkcs1)(hash sha1 %b))",
gcry_md_get_algo_dlen (algo),
gcry_md_read (md, algo));
else
err = gpg_error (GPG_ERR_DIGEST_ALGO);
if (err)
{
log_error (_("creating S-expression failed: %s\n"), gcry_strerror (err));
@ -461,6 +516,7 @@ check_signature (ctrl_t ctrl,
{
cert_ref_t cref;
/* dump_cert ("from ocsp response", cert); */
cref = xtrymalloc (sizeof *cref);
if (!cref)
log_error (_("allocating list item failed: %s\n"),
@ -496,8 +552,6 @@ check_signature (ctrl_t ctrl,
}
log_printf ("not found\n");
}
ksba_free (name);
ksba_free (keyid);
if (cert)
{
@ -506,10 +560,24 @@ check_signature (ctrl_t ctrl,
ksba_cert_release (cert);
if (!err)
{
ksba_free (name);
ksba_free (keyid);
gcry_sexp_release (s_hash);
return 0; /* Successfully verified the signature. */
}
log_error ("responder certificate ");
if (name)
log_printf ("'/%s' ", name);
if (keyid)
{
log_printf ("{");
dump_serial (keyid);
log_printf ("} ");
}
log_printf ("did not verify: %s\n", gpg_strerror (err));
}
ksba_free (name);
ksba_free (keyid);
}
gcry_sexp_release (s_hash);
@ -584,8 +652,6 @@ ocsp_isvalid (ctrl_t ctrl, ksba_cert_t cert, const char *cert_fpr,
goto leave;
}
/* Figure out the OCSP responder to use.
1. Try to get the reponder from the certificate.
We do only take http and https style URIs into account.
@ -642,14 +708,8 @@ ocsp_isvalid (ctrl_t ctrl, ksba_cert_t cert, const char *cert_fpr,
}
/* Ask the OCSP responder. */
err = gcry_md_open (&md, GCRY_MD_SHA1, 0);
if (err)
{
log_error (_("failed to establish a hashing context for OCSP: %s\n"),
gpg_strerror (err));
goto leave;
}
err = do_ocsp_request (ctrl, ocsp, md, url, cert, issuer_cert);
err = do_ocsp_request (ctrl, ocsp, url, cert, issuer_cert,
&sigval, produced_at, &md);
if (err)
goto leave;
@ -681,8 +741,7 @@ ocsp_isvalid (ctrl_t ctrl, ksba_cert_t cert, const char *cert_fpr,
}
/* We got a useful answer, check that the answer has a valid signature. */
sigval = ksba_ocsp_get_sig_val (ocsp, produced_at);
if (!sigval || !*produced_at)
if (!sigval || !*produced_at || !md)
{
err = gpg_error (GPG_ERR_INV_OBJ);
goto leave;

View File

@ -1572,6 +1572,7 @@ Description of some debug flags:
| ecc/* | 11 | ECC (set your own capabilities) |
| ecc/e | 12 | ECC (encrypt only) |
| keygrip | 13 | Existing key |
| cardkey | 14 | Existing key from card |
If one of the "foo/*" names are used a "keygen.flags" prompt needs
to be answered as well. Instead of toggling the predefined flags,

View File

@ -95,7 +95,7 @@ myman_pages = gpgsm.1 gpg-agent.1 dirmngr.8 scdaemon.1 \
watchgnupg.1 gpgconf.1 addgnupghome.8 gpg-preset-passphrase.1 \
gpg-connect-agent.1 gpgparsemail.1 symcryptrun.1 gpgtar.1 \
applygnupgdefaults.8 gpg-wks-client.1 gpg-wks-server.1 \
dirmngr-client.1 gpg-card.1
dirmngr-client.1 gpg-card.1 gpg-check-pattern.1
if USE_GPG2_HACK
myman_pages += gpg2.1 gpgv2.1
else
@ -121,6 +121,7 @@ mkdefsinc: mkdefsinc.c Makefile ../config.h
$(CC_FOR_BUILD) -I. -I.. -I$(srcdir) $(AM_CPPFLAGS) \
-o $@ $(srcdir)/mkdefsinc.c
if MAINTAINER_MODE
.svg.eps:
convert `test -f '$<' || echo '$(srcdir)/'`$< $@
@ -141,6 +142,7 @@ mkdefsinc: mkdefsinc.c Makefile ../config.h
.fig.pdf:
fig2dev -L pdf `test -f '$<' || echo '$(srcdir)/'`$< $@
endif
yat2m-stamp: $(myman_sources) defs.inc

View File

@ -251,7 +251,7 @@ The option @option{--use-tor} switches Dirmngr and thus GnuPG into
``Tor mode'' to route all network access via Tor (an anonymity
network). Certain other features are disabled in this mode. The
effect of @option{--use-tor} cannot be overridden by any other command
or even be reloading gpg-agent. The use of @option{--no-use-tor}
or even by reloading dirmngr. The use of @option{--no-use-tor}
disables the use of Tor. The default is to use Tor if it is available
on startup or after reloading dirmngr.
@ -1178,5 +1178,3 @@ as a binary blob.
@c used for this. The first one starts a search and the second one is
@c used to retrieve certificate after certificate.
@c

View File

@ -8,9 +8,9 @@
@node Smart Card Tool
@chapter Smart Card Tool
GnuPG comes with tool to administrate smart cards and USB tokens. This
tool is an extension of the @option{--edit-key} command available with
@command{gpg}.
GnuPG comes with a tool to administrate smart cards and USB tokens.
This tool is an enhanced version of the @option{--edit-key} command
available with @command{gpg}.
@menu
* gpg-card:: Administrate smart cards.
@ -135,7 +135,7 @@ featuring the PIV application (requires Yubikey-5). We assume that
the credentials have not yet been changed and thus are:
@table @asis
@item Authentication key
This is a 24 byte key described by the hex string
This is a 24 byte key described by the hex string @*
@code{010203040506070801020304050607080102030405060708}.
@item PIV Application PIN
This is the string @code{123456}.
@ -164,11 +164,13 @@ Version ..........: 2.1
[...]
@end example
It can be seen by the ``Application type'' line that GnuPG selected the
OpenPGP application of the Yubikey. This is because GnuPG assigns the
highest priority to the OpenPGP application. To use the PIV
application of the Yubikey, the OpenPGP application needs to be
disabled:
It can be seen by the ``Application type'' line that GnuPG selected
the OpenPGP application of the Yubikey. This is because GnuPG assigns
the highest priority to the OpenPGP application. To use the PIV
application of the Yubikey several methods can be used:
With a Yubikey 5 or later the OpenPGP application on the Yubikey can
be disabled:
@example
gpg/card> yubikey disable all opgp
@ -186,8 +188,32 @@ gpg/card> reset
The @code{reset} is required so that the GnuPG system rereads the
card. Note that disabled applications keep all their data and can at
any time be re-enabled (see @emph{help yubikey}). Now a @emph{list}
command shows this:
any time be re-enabled (use @kbd{help yubikey}).
Another option, which works for all Yubikey versions, is to disable
the support for OpenPGP cards in scdaemon. This is done by adding the
line
@smallexample
disable-application openpgp
@end smallexample
to @file{~/.gnupg/scdaemon.conf} and by restarting scdaemon, either by
killing the process or by using @kbd{gpgconf --kill scdaemon}. Finally
the default order in which card applications are tried by scdaemon can
be changed. For example to prefer PIV over OpenPGP it is sufficient
to add
@smallexample
application-priority piv
@end smallexample
to @file{~/.gnupg/scdaemon.conf} and to restart @command{scdaemon}.
This has an effect only on tokens which support both, PIV and OpenPGP,
but does not hamper the use of OpenPGP only tokens.
With one of these methods employed the @code{list} command of
@command{gpg-card} shows this:
@example
gpg/card> list
@ -210,7 +236,12 @@ Key management ...: [none]
keyref .....: PIV.9D
@end example
Note that the ``Displayed s/sn'' is printed on the token and also
In case several tokens are plugged into the computer, gpg-card will
show only one. To show another token the number of the token (0, 1,
2, ...) can be given as an argument to the @code{list} command. The
command @kbd{list --cards} prints a list of all inserted tokens.
Note that the ``Displayed s/n'' is printed on the token and also
shown in Pinentry prompts asking for the PIN. The four standard key
slots are always shown, if other key slots are initialized they are
shown as well. The @emph{PIV authentication} key (internal reference
@ -231,11 +262,11 @@ which needs to be provided only once so that decryption operations can
then be done until the card is reset or removed from the reader or USB
port.
We now generate tree of the four keys. Note that GnuPG does currently
not use the the @emph{Card authentication} key but because it is
mandatory by the specs we create it anyway. Key generation requires
that we authenticate to the card. This can be done either on the
command line (which would reveal the key):
We now generate three of the four keys. Note that GnuPG does
currently not use the the @emph{Card authentication} key; however,
that key is mandatory by the PIV standard and thus we create it too.
Key generation requires that we authenticate to the card. This can be
done either on the command line (which would reveal the key):
@example
gpg/card> auth 010203040506070801020304050607080102030405060708
@ -360,7 +391,7 @@ gpgsm: total number processed: 1
gpgsm: imported: 1
@end example
Note the last steps which imported the created certificate. If you
Note the last step which imported the created certificate. If you
you instead created a certificate signing request (CSR) instead of a
self-signed certificate and sent this off to a CA you would do the
same import step with the certificate received from the CA. Take note
@ -507,7 +538,111 @@ As usual use ssh-add with the uppercase @samp{-L} to list the public
ssh key. To use the certificates with Thunderbird or Mozilla, please
consult the Scute manual for details.
If you want to use the same PIV keys also for OpenPGP (for example on
a Yubikey to avoid switching between OpenPGP and PIV), this is also
possible:
@example
$ gpgsm --learn
$ gpg --full-gen-key
Please select what kind of key you want:
(1) RSA and RSA (default)
(2) DSA and Elgamal
(3) DSA (sign only)
(4) RSA (sign only)
(14) Existing key from card
Your selection? 14
Serial number of the card: FF020001008A77C1
Available keys:
(1) 213D1825FDE0F8240CB4E4229F01AF90AC658C2E PIV.9A nistp384 (auth)
(2) 7A53E6CFFE7220A0E646B4632EE29E5A7104499C PIV.9E nistp256 (auth)
(3) 32A6C6FAFCB8421878608AAB452D5470DD3223ED PIV.9C rsa2048 (cert,sign)
(4) 34798AAFE0A7565088101CC4AE31C5C8C74461CB PIV.9D rsa2048 (encr)
Your selection? 3
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0)
Key does not expire at all
Is this correct? (y/N) y
GnuPG needs to construct a user ID to identify your key.
Real name:
Email address: otto@@example.net
Comment:
You selected this USER-ID:
"otto@@example.net"
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o
gpg: key C3AFA9ED971BB365 marked as ultimately trusted
gpg: revocation certificate stored as '[...]D971BB365.rev'
public and secret key created and signed.
Note that this key cannot be used for encryption. You may want to use
the command "--edit-key" to generate a subkey for this purpose.
pub rsa2048 2019-04-04 [SC]
7F899AE2FB73159DD68A1B20C3AFA9ED971BB365
uid otto@@example.net
@end example
Note that you will be asked two times to enter the PIN of your PIV
card. If you run @command{gpg} in @option{--expert} mode you will
also ge given the option to change the usage flags of the key. The next
typescript shows how to add the encryption subkey:
@example
$ gpg --edit-key 7F899AE2FB73159DD68A1B20C3AFA9ED971BB365
Secret key is available.
sec rsa2048/C3AFA9ED971BB365
created: 2019-04-04 expires: never usage: SC
card-no: FF020001008A77C1
trust: ultimate validity: ultimate
[ultimate] (1). otto@@example.net
gpg> addkey
Secret parts of primary key are stored on-card.
Please select what kind of key you want:
(3) DSA (sign only)
(4) RSA (sign only)
(5) Elgamal (encrypt only)
(6) RSA (encrypt only)
(14) Existing key from card
Your selection? 14
Serial number of the card: FF020001008A77C1
Available keys:
(1) 213D1825FDE0F8240CB4E4229F01AF90AC658C2E PIV.9A nistp384 (auth)
(2) 7A53E6CFFE7220A0E646B4632EE29E5A7104499C PIV.9E nistp256 (auth)
(3) 32A6C6FAFCB8421878608AAB452D5470DD3223ED PIV.9C rsa2048 (cert,sign)
(4) 34798AAFE0A7565088101CC4AE31C5C8C74461CB PIV.9D rsa2048 (encr)
Your selection? 4
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0)
Key does not expire at all
Is this correct? (y/N) y
Really create? (y/N) y
sec rsa2048/C3AFA9ED971BB365
created: 2019-04-04 expires: never usage: SC
card-no: FF020001008A77C1
trust: ultimate validity: ultimate
ssb rsa2048/7067860A98FCE6E1
created: 2019-04-04 expires: never usage: E
card-no: FF020001008A77C1
[ultimate] (1). otto@@example.net
gpg> save
@end example
Now you can use your PIV card also with @command{gpg}.
@c @mansect examples

View File

@ -346,12 +346,17 @@ numbers 1-9 or "T" for 10 and above to indicate trust signature levels
@item --locate-keys
@itemx --locate-external-keys
@opindex locate-keys
@opindex locate-external-keys
Locate the keys given as arguments. This command basically uses the
same algorithm as used when locating keys for encryption or signing and
may thus be used to see what keys @command{@gpgname} might use. In
particular external methods as defined by @option{--auto-key-locate} may
be used to locate a key. Only public keys are listed.
same algorithm as used when locating keys for encryption or signing
and may thus be used to see what keys @command{@gpgname} might use.
In particular external methods as defined by
@option{--auto-key-locate} may be used to locate a key. Only public
keys are listed. The variant @option{--locate-external-keys} does not
consider a locally existing key and can thus be used to force the
refresh of a key via the defined external methods.
@item --show-keys
@opindex show-keys
@ -404,7 +409,10 @@ functionality is also available as the subcommand "passwd" with the
@opindex delete-keys
Remove key from the public keyring. In batch mode either @option{--yes} is
required or the key must be specified by fingerprint. This is a
safeguard against accidental deletion of multiple keys.
safeguard against accidental deletion of multiple keys. If the
exclamation mark syntax is used with the fingerprint of a subkey only
that subkey is deleted; if the exclamation mark is used with the
fingerprint of the primary key the entire public key is deleted.
@item --delete-secret-keys @var{name}
@opindex delete-secret-keys
@ -413,7 +421,10 @@ specified by fingerprint. The option @option{--yes} can be used to
advice gpg-agent not to request a confirmation. This extra
pre-caution is done because @command{@gpgname} can't be sure that the
secret key (as controlled by gpg-agent) is only used for the given
OpenPGP public key.
OpenPGP public key. If the exclamation mark syntax is used with the
fingerprint of a subkey only the secret part of that subkey is
deleted; if the exclamation mark is used with the fingerprint of the
primary key only the secret part of the primary key is deleted.
@item --delete-secret-and-public-key @var{name}
@ -434,9 +445,8 @@ file given with option @option{--output}. Use together with
@item --send-keys @var{keyIDs}
@opindex send-keys
Similar to @option{--export} but sends the keys to a keyserver.
Fingerprints may be used instead of key IDs. Option
@option{--keyserver} must be used to give the name of this
keyserver. Don't send your complete keyring to a keyserver --- select
Fingerprints may be used instead of key IDs.
Don't send your complete keyring to a keyserver --- select
only those keys which are new or changed by you. If no @var{keyIDs}
are given, @command{@gpgname} does nothing.
@ -491,27 +501,25 @@ signatures, user-IDs and subkeys.
@opindex receive-keys
@itemx --recv-keys @var{keyIDs}
@opindex recv-keys
Import the keys with the given @var{keyIDs} from a keyserver. Option
@option{--keyserver} must be used to give the name of this keyserver.
Import the keys with the given @var{keyIDs} from a keyserver.
@item --refresh-keys
@opindex refresh-keys
Request updates from a keyserver for keys that already exist on the
local keyring. This is useful for updating a key with the latest
signatures, user IDs, etc. Calling this with no arguments will refresh
the entire keyring. Option @option{--keyserver} must be used to give the
name of the keyserver for all keys that do not have preferred keyservers
set (see @option{--keyserver-options honor-keyserver-url}).
the entire keyring.
@item --search-keys @var{names}
@opindex search-keys
Search the keyserver for the given @var{names}. Multiple names given here will
be joined together to create the search string for the keyserver.
Option @option{--keyserver} must be used to give the name of this
keyserver. Keyservers that support different search methods allow using
the syntax specified in "How to specify a user ID" below. Note that
different keyserver types support different search methods. Currently
only LDAP supports them all.
Search the keyserver for the given @var{names}. Multiple names given
here will be joined together to create the search string for the
keyserver. Note that keyservers search for @var{names} in a different
and simpler way than gpg does. The best choice is to use a mail
address. Due to data privacy reasons keyservers may even not even
allow searching by user id or mail address and thus may only return
results when being used with the @option{--recv-key} command to
search by key fingerprint or keyid.
@item --fetch-keys @var{URIs}
@opindex fetch-keys
@ -1330,8 +1338,8 @@ give the opposite meaning. The options are:
@item show-only-fpr-mbox
@opindex list-options:show-only-fpr-mbox
For each valid user-id which also has a valid mail address print
only the fingerprint and the mail address.
For each user-id which has a valid mail address print
only the fingerprint followed by the mail address.
@end table
@item --verify-options @var{parameters}
@ -1429,19 +1437,24 @@ viewed (e.g. "f"), "%V" for the calculated validity as a string (e.g.
and "%%" for an actual percent sign. If neither %i or %I are present,
then the photo will be supplied to the viewer on standard input.
The default viewer is "xloadimage -fork -quiet -title 'KeyID 0x%k'
STDIN". Note that if your image viewer program is not secure, then
executing it from GnuPG does not make it secure.
On Unix the default viewer is
@code{xloadimage -fork -quiet -title 'KeyID 0x%k' STDIN}
with a fallback to
@code{display -title 'KeyID 0x%k' %i}
and finally to
@code{xdg-open %i}.
On Windows
@code{!ShellExecute 400 %i} is used; here the command is a meta
command to use that API call followed by a wait time in milliseconds
which is used to give the viewer time to read the temporary image file
before gpg deletes it again. Note that if your image viewer program
is not secure, then executing it from gpg does not make it secure.
@item --exec-path @var{string}
@opindex exec-path
@efindex PATH
Sets a list of directories to search for photo viewers and keyserver
helpers. If not provided, keyserver helpers use the compiled-in
default directory, and photo viewers use the @code{PATH} environment
variable.
Note, that on W32 system this value is ignored when searching for
keyserver helpers.
Sets a list of directories to search for photo viewers If not provided
photo viewers use the @code{PATH} environment variable.
@item --keyring @var{file}
@opindex keyring
@ -1766,12 +1779,11 @@ list. The default is "local,wkd".
PGP Universal method of checking @samp{ldap://keys.(thedomain)}.
@item keyserver
Locate a key using whatever keyserver is defined using the
@option{--keyserver} option.
Locate a key using a keyserver.
@item keyserver-URL
In addition, a keyserver URL as used in the @option{--keyserver} option
may be used here to query that particular keyserver.
In addition, a keyserver URL as used in the @command{dirmngr}
configuration may be used here to query that particular keyserver.
@item local
Locate the key using the local keyrings. This mechanism allows the user to
@ -1802,10 +1814,26 @@ These options enable or disable the automatic retrieving of keys from
a keyserver when verifying signatures made by keys that are not on the
local keyring. The default is @option{--no-auto-key-retrieve}.
If the method "wkd" is included in the list of methods given to
@option{auto-key-locate}, the signer's user ID is part of the
signature, and the option @option{--disable-signer-uid} is not used,
the "wkd" method may also be used to retrieve a key.
The order of methods tried to lookup the key is:
1. If a preferred keyserver is specified in the signature and the
option @option{honor-keyserver-url} is active (which is not the
default), that keyserver is tried. Note that the creator of the
signature uses the option @option{--sig-keyserver-url} to specify the
preferred keyserver for data signatures.
2. If the signature has the Signer's UID set (e.g. using
@option{--sender} while creating the signature) a Web Key Directory
(WKD) lookup is done. This is the default configuration but can be
disabled by removing WKD from the auto-key-locate list or by using the
option @option{--disable-signer-uid}.
3. If the option @option{honor-pka-record} is active, the legacy PKA
method is used.
4. If any keyserver is configured and the Issuer Fingerprint is part
of the signature (since GnuPG 2.1.16), the configured keyservers are
tried.
Note that this option makes a "web bug" like behavior possible.
Keyserver or Web Key Directory operators can see which keys you
@ -1905,6 +1933,11 @@ are available for all keyserver types, some common options are:
@end table
The default list of options is: "self-sigs-only, import-clean,
repair-keys, repair-pks-subkey-bug, export-attributes,
honor-pka-record".
@item --completes-needed @var{n}
@opindex compliant-needed
Number of completely trusted users to introduce a new
@ -2334,7 +2367,16 @@ opposite meaning. The options are:
can be used to update only the subkeys or other non-user id related
information.
@item repair-keys. After import, fix various problems with the
@item self-sigs-only
Accept only self-signatures while importing a key. All other
key-signatures are skipped at an early import stage. This option
can be used with @code{keyserver-options} to mitigate attempts to
flood a key with bogus signatures from a keyserver. The drawback is
that all other valid key-signatures, as required by the Web of Trust
are also not imported.
@item repair-keys
After import, fix various problems with the
keys. For example, this reorders signatures, and strips duplicate
signatures. Defaults to yes.
@ -2628,11 +2670,11 @@ legacy non-MDC message is exceptionally required, the option
@item --disable-signer-uid
@opindex disable-signer-uid
By default the user ID of the signing key is embedded in the data
signature. As of now this is only done if the signing key has been
specified with @option{local-user} using a mail address. This
information can be helpful for verifier to locate the key; see
option @option{--auto-key-retrieve}.
By default the user ID of the signing key is embedded in the data signature.
As of now this is only done if the signing key has been specified with
@option{local-user} using a mail address, or with @option{sender}. This
information can be helpful for verifier to locate the key; see option
@option{--auto-key-retrieve}.
@item --personal-cipher-preferences @var{string}
@opindex personal-cipher-preferences
@ -3021,7 +3063,8 @@ to display the message. This option overrides @option{--set-filename}.
@itemx --no-use-embedded-filename
@opindex use-embedded-filename
Try to create a file with a name as embedded in the data. This can be
a dangerous option as it enables overwriting files. Defaults to no.
a dangerous option as it enables overwriting files. Defaults to no.
Note that the option @option{--output} overrides this option.
@item --cipher-algo @var{name}
@opindex cipher-algo
@ -3080,10 +3123,14 @@ the same thing.
@opindex cert-digest-algo
Use @var{name} as the message digest algorithm used when signing a
key. Running the program with the command @option{--version} yields a
list of supported algorithms. Be aware that if you choose an algorithm
that GnuPG supports but other OpenPGP implementations do not, then some
users will not be able to use the key signatures you make, or quite
possibly your entire key.
list of supported algorithms. Be aware that if you choose an
algorithm that GnuPG supports but other OpenPGP implementations do
not, then some users will not be able to use the key signatures you
make, or quite possibly your entire key. Note also that a public key
algorithm must be compatible with the specified digest algorithm; thus
selecting an arbitrary digest algorithm may result in error messages
from lower crypto layers or lead to security flaws.
@item --disable-cipher-algo @var{name}
@opindex disable-cipher-algo
@ -3288,7 +3335,8 @@ secret keyrings.
@item --no-keyring
@opindex no-keyring
Do not add use any keyrings even if specified as options.
Do not use any keyring at all. This overrides the default and all
options which specify keyrings.
@item --skip-verify
@opindex skip-verify

View File

@ -349,7 +349,8 @@ verbose commands to @command{gpgsm}, such as @samp{-vv}.
@item --policy-file @var{filename}
@opindex policy-file
Change the default name of the policy file to @var{filename}.
Change the default name of the policy file to @var{filename}. The
default name is @file{policies.txt}.
@item --agent-program @var{file}
@opindex agent-program

View File

@ -288,17 +288,9 @@ To get a list of available CCID readers you may use this command:
@item --card-timeout @var{n}
@opindex card-timeout
If @var{n} is not 0 and no client is actively using the card, the card
will be powered down after @var{n} seconds. Powering down the card
avoids a potential risk of damaging a card when used with certain
cheap readers. This also allows applications that are not aware of
Scdaemon to access the card. The disadvantage of using a card timeout
is that accessing the card takes longer and that the user needs to
enter the PIN again after the next power up.
Note that with the current version of Scdaemon the card is powered
down immediately at the next timer tick for any value of @var{n} other
than 0.
This option is deprecated. In GnuPG 2.0, it used to be used for
DISCONNECT command to control timing issue. Since DISCONNECT command
works synchronously, it has no effect.
@item --enable-pinpad-varlen
@opindex enable-pinpad-varlen
@ -332,6 +324,21 @@ This option disables the use of the card application named
@var{name}. This is mainly useful for debugging or if a application
with lower priority should be used by default.
@item --application-priority @var{namelist}
@opindex application-priority
This option allows to change the order in which applications of a card
a tried if no specific application was requested. @var{namelist} is a
space or comma delimited list of application names. Unknown names are
simply skipped. Applications not mentioned in the list are put in the
former order at the end of the new priority list.
To get the list of current active applications, use
@cartouche
@smallexample
gpg-connect-agent 'scd getinfo app_list' /bye
@end smallexample
@end cartouche
@end table
All the long options may also be given in the configuration file after
@ -767,4 +774,3 @@ length up to N bytes. If N is not given a default value is used
@command{gpg2}(1)
@end ifset
@include see-also-note.texi

View File

@ -21,6 +21,7 @@ GnuPG comes with a couple of smaller tools:
* gpgparsemail:: Parse a mail message into an annotated format
* symcryptrun:: Call a simple symmetric encryption tool.
* gpgtar:: Encrypt or sign files into an archive.
* gpg-check-pattern:: Check a passphrase on stdin against the patternfile.
@end menu
@c
@ -352,11 +353,12 @@ may use this command to ensure that they are started. Using "all" for
@item --kill [@var{component}]
@opindex kill
Kill the given component. Components which support killing are
@command{gpg-agent} and @command{scdaemon}. Components which don't
support reloading are ignored. Using "all" for @var{component} kills
all components running as daemons. Note that as of now reload and
kill have the same effect for @command{scdaemon}.
Kill the given component that runs as a daemon, including
@command{gpg-agent}, @command{dirmngr}, and @command{scdaemon}. A
@command{component} which does not run as a daemon will be ignored.
Using "all" for @var{component} kills all components running as
daemons. Note that as of now reload and kill have the same effect for
@command{scdaemon}.
@item --create-socketdir
@opindex create-socketdir
@ -392,6 +394,8 @@ extends numerical field values by human-readable descriptions.
@opindex quiet
Try to be as quiet as possible.
@include opt-homedir.texi
@item -n
@itemx --dry-run
Do not actually change anything. This is currently only implemented
@ -2107,3 +2111,50 @@ gpgtar --list-archive test1
@command{tar}(1),
@end ifset
@include see-also-note.texi
@c
@c GPG-CHECK-PATTERN
@c
@manpage gpg-check-pattern.1
@node gpg-check-pattern
@section Check a passphrase on stdin against the patternfile
@ifset manverb
.B gpg-check-pattern
\- Check a passphrase on stdin against the patternfile
@end ifset
@mansect synopsis
@ifset manverb
.B gpg\-check\-pattern
.RI [ options ]
.I patternfile
@end ifset
@mansect description
@command{gpg-check-pattern} checks a passphrase given on stdin against
a specified pattern file.
@mansect options
@noindent
@table @gnupgtabopt
@item --verbose
@opindex verbose
Enable extra informational output.
@item --check
@opindex check
Run only a syntax check on the patternfile.
@item --null
@opindex null
Input is expected to be null delimited.
@end table
@mansect see also
@ifset isman
@command{gpg}(1),
@end ifset
@include see-also-note.texi

View File

@ -101,6 +101,14 @@ fingerprint and the mailbox separated by a space. The command
@option{--remove-key} removes a key from that directory, its only
argument is a user-id.
The command @option{--print-wkd-hash} prints the WKD user-id identifiers
and the corresponding mailboxes from the user-ids given on the command
line or via stdin (one user-id per line).
The command @option{--print-wkd-url} prints the URLs used to fetch the
key for the given user-ids from WKD. The meanwhile preferred format
with sub-domains is used here.
@command{gpg-wks-client} is not commonly invoked directly and thus it
is not installed in the bin directory. Here is an example how it can
be invoked manually to check for a Web Key Directory entry for

View File

@ -724,7 +724,8 @@ proc_texi_cmd (FILE *fp, const char *command, const char *rest, size_t len,
{ "url", 0, "\\fB", "\\fR" },
{ "sc", 0, "\\fB", "\\fR" },
{ "var", 0, "\\fI", "\\fR" },
{ "samp", 0, "\\(aq", "\\(aq" },
{ "samp", 0, "\\(oq", "\\(cq" },
{ "kbd", 0, "\\(oq", "\\(cq" },
{ "file", 0, "\\(oq\\fI","\\fR\\(cq" },
{ "env", 0, "\\(oq\\fI","\\fR\\(cq" },
{ "acronym", 0 },

View File

@ -121,6 +121,7 @@ common_source = \
sig-check.c \
keylist.c \
pkglue.c pkglue.h \
objcache.c objcache.h \
ecdh.c
gpg_sources = server.c \

View File

@ -1394,10 +1394,10 @@ armor_filter( void *opaque, int control,
}
/* write the comment strings */
for(s=comment->d;comment;comment=comment->next,s=comment->d)
for(;comment;comment=comment->next)
{
iobuf_writestr(a, "Comment: " );
for( ; *s; s++ )
for( s=comment->d; *s; s++ )
{
if( *s == '\n' )
iobuf_writestr(a, "\\n" );

View File

@ -447,15 +447,21 @@ do_user_id( IOBUF out, int ctb, PKT_user_id *uid )
* Without forcing HDRLEN to 2 in this case an indeterminate length
* packet would be written which is not allowed. Note that we are
* always called with a CTB indicating an old packet header format,
* so that forcing a 2 octet header works. */
* so that forcing a 2 octet header works. We also check for the
* maximum allowed packet size by the parser using an arbitrary
* extra 10 bytes for header data. */
if (uid->attrib_data)
{
if (uid->attrib_len > MAX_ATTR_PACKET_LENGTH - 10)
return gpg_error (GPG_ERR_TOO_LARGE);
hdrlen = uid->attrib_len? 0 : 2;
write_header2 (out, ctb, uid->attrib_len, hdrlen);
rc = iobuf_write( out, uid->attrib_data, uid->attrib_len );
}
else
{
if (uid->len > MAX_UID_PACKET_LENGTH - 10)
return gpg_error (GPG_ERR_TOO_LARGE);
hdrlen = uid->len? 0 : 2;
write_header2 (out, ctb, uid->len, hdrlen);
rc = iobuf_write( out, uid->name, uid->len );

View File

@ -41,6 +41,7 @@
#include "../common/status.h"
#include "../common/shareddefs.h"
#include "../common/host2net.h"
#include "../common/ttyio.h"
#define CONTROL_D ('D' - 'A' + 1)
@ -48,6 +49,13 @@
static assuan_context_t agent_ctx = NULL;
static int did_early_card_test;
struct confirm_parm_s
{
char *desc;
char *ok;
char *notok;
};
struct default_inq_parm_s
{
ctrl_t ctrl;
@ -57,6 +65,7 @@ struct default_inq_parm_s
u32 *mainkeyid;
int pubkey_algo;
} keyinfo;
struct confirm_parm_s *confirm;
};
struct cipher_parm_s
@ -136,6 +145,7 @@ default_inq_cb (void *opaque, const char *line)
{
gpg_error_t err = 0;
struct default_inq_parm_s *parm = opaque;
const char *s;
if (has_leading_keyword (line, "PINENTRY_LAUNCHED"))
{
@ -151,7 +161,7 @@ default_inq_cb (void *opaque, const char *line)
{
if (have_static_passphrase ())
{
const char *s = get_static_passphrase ();
s = get_static_passphrase ();
err = assuan_send_data (parm->ctx, s, strlen (s));
}
else
@ -176,6 +186,27 @@ default_inq_cb (void *opaque, const char *line)
xfree (pw);
}
}
else if ((s = has_leading_keyword (line, "CONFIRM"))
&& opt.pinentry_mode == PINENTRY_MODE_LOOPBACK
&& parm->confirm)
{
int ask = atoi (s);
int yes;
if (ask)
{
yes = cpr_get_answer_is_yes (NULL, parm->confirm->desc);
if (yes)
err = assuan_send_data (parm->ctx, NULL, 0);
else
err = gpg_error (GPG_ERR_NOT_CONFIRMED);
}
else
{
tty_printf ("%s", parm->confirm->desc);
err = assuan_send_data (parm->ctx, NULL, 0);
}
}
else
log_debug ("ignoring gpg-agent inquiry '%s'\n", line);
@ -336,7 +367,7 @@ start_agent (ctrl_t ctrl, int flag_for_card)
if (!(flag_for_card & FLAG_FOR_CARD_SUPPRESS_ERRORS))
rc = warn_version_mismatch (agent_ctx, SCDAEMON_NAME, 2);
if (!rc)
rc = assuan_transact (agent_ctx, "SCD SERIALNO openpgp",
rc = assuan_transact (agent_ctx, "SCD SERIALNO",
NULL, NULL, NULL, NULL,
learn_status_cb, &info);
if (rc && !(flag_for_card & FLAG_FOR_CARD_SUPPRESS_ERRORS))
@ -352,7 +383,7 @@ start_agent (ctrl_t ctrl, int flag_for_card)
break;
default:
write_status_text (STATUS_CARDCTRL, "4");
log_info ("selecting openpgp failed: %s\n", gpg_strerror (rc));
log_info ("selecting card failed: %s\n", gpg_strerror (rc));
break;
}
}
@ -726,7 +757,15 @@ learn_status_cb (void *opaque, const char *line)
return 0;
}
/* Call the scdaemon to learn about a smartcard */
/* Call the scdaemon to learn about a smartcard. Note that in
* contradiction to the function's name, gpg-agent's LEARN command is
* used and not the low-level "SCD LEARN".
* Used by:
* card-util.c
* keyedit_menu
* card_store_key_with_backup (Woth force to remove secret key data)
*/
int
agent_scd_learn (struct agent_card_info_s *info, int force)
{
@ -759,10 +798,109 @@ agent_scd_learn (struct agent_card_info_s *info, int force)
}
/* Callback for the agent_scd_keypairinfo function. */
static gpg_error_t
scd_keypairinfo_status_cb (void *opaque, const char *line)
{
strlist_t *listaddr = opaque;
const char *keyword = line;
int keywordlen;
strlist_t sl;
char *p;
for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
;
while (spacep (line))
line++;
if (keywordlen == 11 && !memcmp (keyword, "KEYPAIRINFO", keywordlen))
{
sl = append_to_strlist (listaddr, line);
p = sl->d;
/* Make sure that we only have two tokens so that future
* extensions of the format won't change the format expected by
* the caller. */
while (*p && !spacep (p))
p++;
if (*p)
{
while (spacep (p))
p++;
while (*p && !spacep (p))
p++;
if (*p)
{
*p++ = 0;
while (spacep (p))
p++;
while (*p && !spacep (p))
{
switch (*p++)
{
case 'c': sl->flags |= GCRY_PK_USAGE_CERT; break;
case 's': sl->flags |= GCRY_PK_USAGE_SIGN; break;
case 'e': sl->flags |= GCRY_PK_USAGE_ENCR; break;
case 'a': sl->flags |= GCRY_PK_USAGE_AUTH; break;
}
}
}
}
}
return 0;
}
/* Read the keypairinfo lines of the current card directly from
* scdaemon. The list is returned as a string made up of the keygrip,
* a space and the keyref. The flags of the string carry the usage
* bits. If KEYREF is not NULL, only a single string is returned
* which matches the given keyref. */
gpg_error_t
agent_scd_keypairinfo (ctrl_t ctrl, const char *keyref, strlist_t *r_list)
{
gpg_error_t err;
strlist_t list = NULL;
struct default_inq_parm_s inq_parm;
char line[ASSUAN_LINELENGTH];
*r_list = NULL;
err= start_agent (ctrl, 1);
if (err)
return err;
memset (&inq_parm, 0, sizeof inq_parm);
inq_parm.ctx = agent_ctx;
if (keyref)
snprintf (line, DIM(line), "SCD READKEY --info-only %s", keyref);
else
snprintf (line, DIM(line), "SCD LEARN --keypairinfo");
err = assuan_transact (agent_ctx, line,
NULL, NULL,
default_inq_cb, &inq_parm,
scd_keypairinfo_status_cb, &list);
if (!err && !list)
err = gpg_error (GPG_ERR_NO_DATA);
if (err)
{
free_strlist (list);
return err;
}
*r_list = list;
return 0;
}
/* Send an APDU to the current card. On success the status word is
stored at R_SW. With HEXAPDU being NULL only a RESET command is
send to scd. With HEXAPDU being the string "undefined" the command
"SERIALNO undefined" is send to scd. */
* stored at R_SW. With HEXAPDU being NULL only a RESET command is
* send to scd. With HEXAPDU being the string "undefined" the command
* "SERIALNO undefined" is send to scd.
* Used by:
* card-util.c
*/
gpg_error_t
agent_scd_apdu (const char *hexapdu, unsigned int *r_sw)
{
@ -816,6 +954,10 @@ agent_scd_apdu (const char *hexapdu, unsigned int *r_sw)
}
/* Used by:
* card_store_subkey
* card_store_key_with_backup
*/
int
agent_keytocard (const char *hexgrip, int keyno, int force,
const char *serialno, const char *timestamp)
@ -843,10 +985,100 @@ agent_keytocard (const char *hexgrip, int keyno, int force,
}
/* Object used with the agent_scd_getattr_one. */
struct getattr_one_parm_s {
const char *keyword; /* Keyword to look for. */
char *data; /* Malloced and unescaped data. */
gpg_error_t err; /* Error code or 0 on success. */
};
/* Callback for agent_scd_getattr_one. */
static gpg_error_t
getattr_one_status_cb (void *opaque, const char *line)
{
struct getattr_one_parm_s *parm = opaque;
const char *s;
if (parm->data)
return 0; /* We want only the first occurrence. */
if ((s=has_leading_keyword (line, parm->keyword)))
{
parm->data = percent_plus_unescape (s, 0xff);
if (!parm->data)
parm->err = gpg_error_from_syserror ();
}
return 0;
}
/* Simplified version of agent_scd_getattr. This function returns
* only the first occurance of the attribute NAME and stores it at
* R_VALUE. A nul in the result is silennly replaced by 0xff. On
* error NULL is stored at R_VALUE. */
gpg_error_t
agent_scd_getattr_one (const char *name, char **r_value)
{
gpg_error_t err;
char line[ASSUAN_LINELENGTH];
struct default_inq_parm_s inqparm;
struct getattr_one_parm_s parm;
*r_value = NULL;
if (!*name)
return gpg_error (GPG_ERR_INV_VALUE);
memset (&inqparm, 0, sizeof inqparm);
inqparm.ctx = agent_ctx;
memset (&parm, 0, sizeof parm);
parm.keyword = name;
/* We assume that NAME does not need escaping. */
if (12 + strlen (name) > DIM(line)-1)
return gpg_error (GPG_ERR_TOO_LARGE);
stpcpy (stpcpy (line, "SCD GETATTR "), name);
err = start_agent (NULL, 1);
if (err)
return err;
err = assuan_transact (agent_ctx, line,
NULL, NULL,
default_inq_cb, &inqparm,
getattr_one_status_cb, &parm);
if (!err && parm.err)
err = parm.err;
else if (!err && !parm.data)
err = gpg_error (GPG_ERR_NO_DATA);
if (!err)
*r_value = parm.data;
else
xfree (parm.data);
return err;
}
/* Call the agent to retrieve a data object. This function returns
the data in the same structure as used by the learn command. It is
allowed to update such a structure using this command. */
* the data in the same structure as used by the learn command. It is
* allowed to update such a structure using this command.
*
* Used by:
* build_sk_list
* enum_secret_keys
* get_signature_count
* card-util.c
* generate_keypair (KEY-ATTR)
* card_store_key_with_backup (SERIALNO)
* generate_card_subkeypair (KEY-ATTR)
*/
int
agent_scd_getattr (const char *name, struct agent_card_info_s *info)
{
@ -875,24 +1107,23 @@ agent_scd_getattr (const char *name, struct agent_card_info_s *info)
return rc;
}
/* Send an setattr command to the SCdaemon. SERIALNO is not actually
used here but required by gpg 1.4's implementation of this code in
cardglue.c. */
int
agent_scd_setattr (const char *name,
const unsigned char *value, size_t valuelen,
const char *serialno)
/* Send an setattr command to the SCdaemon.
* Used by:
* card-util.c
*/
gpg_error_t
agent_scd_setattr (const char *name, const void *value_arg, size_t valuelen)
{
int rc;
gpg_error_t err;
const unsigned char *value = value_arg;
char line[ASSUAN_LINELENGTH];
char *p;
struct default_inq_parm_s parm;
memset (&parm, 0, sizeof parm);
(void)serialno;
if (!*name || !valuelen)
return gpg_error (GPG_ERR_INV_VALUE);
@ -918,16 +1149,16 @@ agent_scd_setattr (const char *name,
}
*p = 0;
rc = start_agent (NULL, 1);
if (!rc)
err = start_agent (NULL, 1);
if (!err)
{
parm.ctx = agent_ctx;
rc = assuan_transact (agent_ctx, line, NULL, NULL,
err = assuan_transact (agent_ctx, line, NULL, NULL,
default_inq_cb, &parm, NULL, NULL);
}
status_sc_op_failure (rc);
return rc;
status_sc_op_failure (err);
return err;
}
@ -953,7 +1184,10 @@ inq_writecert_parms (void *opaque, const char *line)
}
/* Send a WRITECERT command to the SCdaemon. */
/* Send a WRITECERT command to the SCdaemon.
* Used by:
* card-util.c
*/
int
agent_scd_writecert (const char *certidstr,
const unsigned char *certdata, size_t certdatalen)
@ -984,60 +1218,6 @@ agent_scd_writecert (const char *certidstr,
}
/* Handle a KEYDATA inquiry. Note, we only send the data,
assuan_transact takes care of flushing and writing the end */
static gpg_error_t
inq_writekey_parms (void *opaque, const char *line)
{
int rc;
struct writekey_parm_s *parm = opaque;
if (has_leading_keyword (line, "KEYDATA"))
{
rc = assuan_send_data (parm->dflt->ctx, parm->keydata, parm->keydatalen);
}
else
rc = default_inq_cb (parm->dflt, line);
return rc;
}
/* Send a WRITEKEY command to the SCdaemon. */
int
agent_scd_writekey (int keyno, const char *serialno,
const unsigned char *keydata, size_t keydatalen)
{
int rc;
char line[ASSUAN_LINELENGTH];
struct writekey_parm_s parms;
struct default_inq_parm_s dfltparm;
memset (&dfltparm, 0, sizeof dfltparm);
(void)serialno;
rc = start_agent (NULL, 1);
if (rc)
return rc;
memset (&parms, 0, sizeof parms);
snprintf (line, DIM(line), "SCD WRITEKEY --force OPENPGP.%d", keyno);
dfltparm.ctx = agent_ctx;
parms.dflt = &dfltparm;
parms.keydata = keydata;
parms.keydatalen = keydatalen;
rc = assuan_transact (agent_ctx, line, NULL, NULL,
inq_writekey_parms, &parms, NULL, NULL);
status_sc_op_failure (rc);
return rc;
}
/* Status callback for the SCD GENKEY command. */
static gpg_error_t
@ -1065,10 +1245,13 @@ scd_genkey_cb (void *opaque, const char *line)
}
/* Send a GENKEY command to the SCdaemon. If *CREATETIME is not 0,
the value will be passed to SCDAEMON with --timestamp option so that
the key is created with this. Otherwise, timestamp was generated by
SCDEAMON. On success, creation time is stored back to
CREATETIME. */
* the value will be passed to SCDAEMON with --timestamp option so that
* the key is created with this. Otherwise, timestamp was generated by
* SCDEAMON. On success, creation time is stored back to
* CREATETIME.
* Used by:
* gen_card_key
*/
int
agent_scd_genkey (int keyno, int force, u32 *createtime)
{
@ -1101,9 +1284,17 @@ agent_scd_genkey (int keyno, int force, u32 *createtime)
status_sc_op_failure (rc);
return rc;
}
/* Return the serial number of the card or an appropriate error. The
serial number is returned as a hexstring. */
* serial number is returned as a hexstring. With DEMAND the active
* card is switched to the card with that serialno.
* Used by:
* card-util.c
* build_sk_list
* enum_secret_keys
*/
int
agent_scd_serialno (char **r_serialno, const char *demand)
{
@ -1111,7 +1302,7 @@ agent_scd_serialno (char **r_serialno, const char *demand)
char *serialno = NULL;
char line[ASSUAN_LINELENGTH];
err = start_agent (NULL, 1 | FLAG_FOR_CARD_SUPPRESS_ERRORS);
err = start_agent (NULL, (1 | FLAG_FOR_CARD_SUPPRESS_ERRORS));
if (err)
return err;
@ -1132,8 +1323,13 @@ agent_scd_serialno (char **r_serialno, const char *demand)
*r_serialno = serialno;
return 0;
}
/* Send a READCERT command to the SCdaemon. */
/* Send a READCERT command to the SCdaemon.
* Used by:
* card-util.c
*/
int
agent_scd_readcert (const char *certidstr,
void **r_buf, size_t *r_buflen)
@ -1171,6 +1367,51 @@ agent_scd_readcert (const char *certidstr,
return 0;
}
/* This is a variant of agent_readkey which sends a READKEY command
* directly Scdaemon. On success a new s-expression is stored at
* R_RESULT. */
gpg_error_t
agent_scd_readkey (const char *keyrefstr, gcry_sexp_t *r_result)
{
gpg_error_t err;
char line[ASSUAN_LINELENGTH];
membuf_t data;
unsigned char *buf;
size_t len, buflen;
struct default_inq_parm_s dfltparm;
memset (&dfltparm, 0, sizeof dfltparm);
dfltparm.ctx = agent_ctx;
*r_result = NULL;
err = start_agent (NULL, 1);
if (err)
return err;
init_membuf (&data, 1024);
snprintf (line, DIM(line), "SCD READKEY %s", keyrefstr);
err = assuan_transact (agent_ctx, line,
put_membuf_cb, &data,
default_inq_cb, &dfltparm,
NULL, NULL);
if (err)
{
xfree (get_membuf (&data, &len));
return err;
}
buf = get_membuf (&data, &buflen);
if (!buf)
return gpg_error_from_syserror ();
err = gcry_sexp_new (r_result, buf, buflen, 0);
xfree (buf);
return err;
}
struct card_cardlist_parm_s {
int error;
@ -1208,7 +1449,12 @@ card_cardlist_cb (void *opaque, const char *line)
return 0;
}
/* Return cardlist. */
/* Return a list of currently available cards.
* Used by:
* card-util.c
* skclist.c
*/
int
agent_scd_cardlist (strlist_t *result)
{
@ -1237,16 +1483,20 @@ agent_scd_cardlist (strlist_t *result)
return 0;
}
/* Change the PIN of an OpenPGP card or reset the retry counter.
CHVNO 1: Change the PIN
2: For v1 cards: Same as 1.
For v2 cards: Reset the PIN using the Reset Code.
3: Change the admin PIN
101: Set a new PIN and reset the retry counter
102: For v1 cars: Same as 101.
For v2 cards: Set a new Reset Code.
SERIALNO is not used.
* CHVNO 1: Change the PIN
* 2: For v1 cards: Same as 1.
* For v2 cards: Reset the PIN using the Reset Code.
* 3: Change the admin PIN
* 101: Set a new PIN and reset the retry counter
* 102: For v1 cars: Same as 101.
* For v2 cards: Set a new Reset Code.
* SERIALNO is not used.
* Used by:
* card-util.c
*/
int
agent_scd_change_pin (int chvno, const char *serialno)
@ -1280,8 +1530,11 @@ agent_scd_change_pin (int chvno, const char *serialno)
/* Perform a CHECKPIN operation. SERIALNO should be the serial
number of the card - optionally followed by the fingerprint;
however the fingerprint is ignored here. */
* number of the card - optionally followed by the fingerprint;
* however the fingerprint is ignored here.
* Used by:
* card-util.c
*/
int
agent_scd_checkpin (const char *serialno)
{
@ -1306,15 +1559,6 @@ agent_scd_checkpin (const char *serialno)
}
/* Dummy function, only used by the gpg 1.4 implementation. */
void
agent_clear_pin_cache (const char *sn)
{
(void)sn;
}
/* 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
@ -2299,6 +2543,31 @@ agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
}
/* Status callback for handling confirmation. */
static gpg_error_t
confirm_status_cb (void *opaque, const char *line)
{
struct confirm_parm_s *parm = opaque;
const char *s;
if ((s = has_leading_keyword (line, "SETDESC")))
{
xfree (parm->desc);
parm->desc = unescape_status_string (s);
}
else if ((s = has_leading_keyword (line, "SETOK")))
{
xfree (parm->ok);
parm->ok = unescape_status_string (s);
}
else if ((s = has_leading_keyword (line, "SETNOTOK")))
{
xfree (parm->notok);
parm->notok = unescape_status_string (s);
}
return 0;
}
/* Ask the agent to delete the key identified by HEXKEYGRIP. If DESC
is not NULL, display DESC instead of the default description
@ -2311,9 +2580,12 @@ agent_delete_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
gpg_error_t err;
char line[ASSUAN_LINELENGTH];
struct default_inq_parm_s dfltparm;
struct confirm_parm_s confirm_parm;
memset (&confirm_parm, 0, sizeof confirm_parm);
memset (&dfltparm, 0, sizeof dfltparm);
dfltparm.ctrl = ctrl;
dfltparm.confirm = &confirm_parm;
err = start_agent (ctrl, 0);
if (err)
@ -2335,7 +2607,10 @@ agent_delete_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
force? " --force":"", hexkeygrip);
err = assuan_transact (agent_ctx, line, NULL, NULL,
default_inq_cb, &dfltparm,
NULL, NULL);
confirm_status_cb, &confirm_parm);
xfree (confirm_parm.desc);
xfree (confirm_parm.ok);
xfree (confirm_parm.notok);
return err;
}

View File

@ -84,6 +84,10 @@ void agent_release_card_info (struct agent_card_info_s *info);
/* Return card info. */
int agent_scd_learn (struct agent_card_info_s *info, int force);
/* Get the keypariinfo directly from scdaemon. */
gpg_error_t agent_scd_keypairinfo (ctrl_t ctrl, const char *keyref,
strlist_t *r_list);
/* Return list of cards. */
int agent_scd_cardlist (strlist_t *result);
@ -93,6 +97,9 @@ int agent_scd_serialno (char **r_serialno, const char *demand);
/* Send an APDU to the card. */
gpg_error_t agent_scd_apdu (const char *hexapdu, unsigned int *r_sw);
/* Get attribute NAME from the card and store at R_VALUE. */
gpg_error_t agent_scd_getattr_one (const char *name, char **r_value);
/* Update INFO with the attribute NAME. */
int agent_scd_getattr (const char *name, struct agent_card_info_s *info);
@ -101,35 +108,29 @@ int agent_keytocard (const char *hexgrip, int keyno, int force,
const char *serialno, const char *timestamp);
/* Send a SETATTR command to the SCdaemon. */
int agent_scd_setattr (const char *name,
const unsigned char *value, size_t valuelen,
const char *serialno);
gpg_error_t agent_scd_setattr (const char *name,
const void *value, size_t valuelen);
/* Send a WRITECERT command to the SCdaemon. */
int agent_scd_writecert (const char *certidstr,
const unsigned char *certdata, size_t certdatalen);
/* Send a WRITEKEY command to the SCdaemon. */
int agent_scd_writekey (int keyno, const char *serialno,
const unsigned char *keydata, size_t keydatalen);
/* Send a GENKEY command to the SCdaemon. */
int agent_scd_genkey (int keyno, int force, u32 *createtime);
/* Send a READKEY command to the SCdaemon. */
/* Send a READCERT command to the SCdaemon. */
int agent_scd_readcert (const char *certidstr,
void **r_buf, size_t *r_buflen);
/* Send a READKEY command to the SCdaemon. */
gpg_error_t agent_scd_readkey (const char *keyrefstr, gcry_sexp_t *r_result);
/* Change the PIN of an OpenPGP card or reset the retry counter. */
int agent_scd_change_pin (int chvno, const char *serialno);
/* Send the CHECKPIN command to the SCdaemon. */
int agent_scd_checkpin (const char *serialno);
/* Dummy function, only implemented by gpg 1.4. */
void agent_clear_pin_cache (const char *sn);
/* Send the GET_PASSPHRASE command to the agent. */
gpg_error_t agent_get_passphrase (const char *cache_id,
const char *err_msg,

View File

@ -91,8 +91,6 @@ change_pin (int unblock_v2, int allow_admin)
log_info (_("OpenPGP card no. %s detected\n"),
info.serialno? info.serialno : "[none]");
agent_clear_pin_cache (info.serialno);
if (opt.batch)
{
agent_release_card_info (&info);
@ -421,36 +419,43 @@ current_card_status (ctrl_t ctrl, estream_t fp,
if (!info.serialno || strncmp (info.serialno, "D27600012401", 12)
|| strlen (info.serialno) != 32 )
{
const char *name1, *name2;
if (info.apptype && !strcmp (info.apptype, "NKS"))
{
if (opt.with_colons)
es_fputs ("netkey-card:\n", fp);
log_info ("this is a NetKey card\n");
name1 = "netkey";
name2 = "NetKey";
}
else if (info.apptype && !strcmp (info.apptype, "DINSIG"))
{
if (opt.with_colons)
es_fputs ("dinsig-card:\n", fp);
log_info ("this is a DINSIG compliant card\n");
name1 = "dinsig";
name2 = "DINSIG";
}
else if (info.apptype && !strcmp (info.apptype, "P15"))
{
if (opt.with_colons)
es_fputs ("pkcs15-card:\n", fp);
log_info ("this is a PKCS#15 compliant card\n");
name1 = "pkcs15";
name2 = "PKCS#15";
}
else if (info.apptype && !strcmp (info.apptype, "GELDKARTE"))
{
if (opt.with_colons)
es_fputs ("geldkarte-card:\n", fp);
log_info ("this is a Geldkarte compliant card\n");
name1 = "geldkarte";
name2 = "Geldkarte";
}
else if (info.apptype && !strcmp (info.apptype, "PIV"))
{
name1 = "piv";
name2 = "PIV";
}
else
{
if (opt.with_colons)
es_fputs ("unknown:\n", fp);
name1 = "unknown";
name2 = "Unknown";
}
log_info ("not an OpenPGP card\n");
if (opt.with_colons)
es_fprintf (fp, "%s-card:\n", name1);
else
tty_fprintf (fp, "Application type .: %s\n", name2);
agent_release_card_info (&info);
xfree (pk);
return;
@ -465,6 +470,8 @@ current_card_status (ctrl_t ctrl, estream_t fp,
if (opt.with_colons)
es_fputs ("openpgp-card:\n", fp);
else
tty_fprintf (fp, "Application type .: %s\n", "OpenPGP");
if (opt.with_colons)
@ -673,9 +680,8 @@ current_card_status (ctrl_t ctrl, estream_t fp,
if ( thefpr && !fpr_is_ff (thefpr, thefprlen)
&& !get_pubkey_byfprint (ctrl, pk, &keyblock, thefpr, thefprlen))
{
print_pubkey_info (ctrl, fp, pk);
if (keyblock)
print_card_key_info (fp, keyblock);
print_key_info (ctrl, fp, 0, pk, 0);
print_card_key_info (fp, keyblock);
}
else
tty_fprintf (fp, "[none]\n");
@ -697,6 +703,7 @@ card_status (ctrl_t ctrl, estream_t fp, const char *serialno)
strlist_t card_list, sl;
char *serialno0, *serialno1;
int all_cards = 0;
int any_card = 0;
if (serialno == NULL)
{
@ -724,6 +731,10 @@ card_status (ctrl_t ctrl, estream_t fp, const char *serialno)
if (!all_cards && strcmp (serialno, sl->d))
continue;
if (any_card && !opt.with_colons)
tty_fprintf (fp, "\n");
any_card = 1;
err = agent_scd_serialno (&serialno1, sl->d);
if (err)
{
@ -816,7 +827,7 @@ change_name (void)
return -1;
}
rc = agent_scd_setattr ("DISP-NAME", isoname, strlen (isoname), NULL );
rc = agent_scd_setattr ("DISP-NAME", isoname, strlen (isoname));
if (rc)
log_error ("error setting Name: %s\n", gpg_strerror (rc));
@ -837,7 +848,7 @@ change_url (void)
trim_spaces (url);
cpr_kill_prompt ();
rc = agent_scd_setattr ("PUBKEY-URL", url, strlen (url), NULL );
rc = agent_scd_setattr ("PUBKEY-URL", url, strlen (url));
if (rc)
log_error ("error setting URL: %s\n", gpg_strerror (rc));
xfree (url);
@ -995,7 +1006,7 @@ change_login (const char *args)
n = strlen (data);
}
rc = agent_scd_setattr ("LOGIN-DATA", data, n, NULL );
rc = agent_scd_setattr ("LOGIN-DATA", data, n);
if (rc)
log_error ("error setting login data: %s\n", gpg_strerror (rc));
xfree (data);
@ -1033,7 +1044,7 @@ change_private_do (const char *args, int nr)
n = strlen (data);
}
rc = agent_scd_setattr (do_name, data, n, NULL );
rc = agent_scd_setattr (do_name, data, n);
if (rc)
log_error ("error setting private DO: %s\n", gpg_strerror (rc));
xfree (data);
@ -1132,7 +1143,7 @@ change_lang (void)
return -1;
}
rc = agent_scd_setattr ("DISP-LANG", data, strlen (data), NULL );
rc = agent_scd_setattr ("DISP-LANG", data, strlen (data));
if (rc)
log_error ("error setting lang: %s\n", gpg_strerror (rc));
xfree (data);
@ -1168,7 +1179,7 @@ change_sex (void)
return -1;
}
rc = agent_scd_setattr ("DISP-SEX", str, 1, NULL );
rc = agent_scd_setattr ("DISP-SEX", str, 1);
if (rc)
log_error ("error setting salutation: %s\n", gpg_strerror (rc));
xfree (data);
@ -1216,7 +1227,7 @@ change_cafpr (int fprno)
rc = agent_scd_setattr (fprno==1?"CA-FPR-1":
fprno==2?"CA-FPR-2":
fprno==3?"CA-FPR-3":"x", fpr, fprlen, NULL );
fprno==3?"CA-FPR-3":"x", fpr, fprlen);
if (rc)
log_error ("error setting cafpr: %s\n", gpg_strerror (rc));
write_sc_op_status (rc);
@ -1242,7 +1253,7 @@ toggle_forcesig (void)
newstate = !info.chv1_cached;
agent_release_card_info (&info);
rc = agent_scd_setattr ("CHV-STATUS-1", newstate? "\x01":"", 1, NULL);
rc = agent_scd_setattr ("CHV-STATUS-1", newstate? "\x01":"", 1);
if (rc)
log_error ("error toggling signature PIN flag: %s\n", gpg_strerror (rc));
write_sc_op_status (rc);
@ -1285,14 +1296,12 @@ check_pin_for_key_operation (struct agent_card_info_s *info, int *forced_chv1)
{
int rc = 0;
agent_clear_pin_cache (info->serialno);
*forced_chv1 = !info->chv1_cached;
if (*forced_chv1)
{ /* Switch off the forced mode so that during key generation we
don't get bothered with PIN queries for each
self-signature. */
rc = agent_scd_setattr ("CHV-STATUS-1", "\x01", 1, info->serialno);
rc = agent_scd_setattr ("CHV-STATUS-1", "\x01", 1);
if (rc)
{
log_error ("error clearing forced signature PIN flag: %s\n",
@ -1323,7 +1332,7 @@ restore_forced_chv1 (int *forced_chv1)
if (*forced_chv1)
{ /* Switch back to forced state. */
rc = agent_scd_setattr ("CHV-STATUS-1", "", 1, NULL);
rc = agent_scd_setattr ("CHV-STATUS-1", "", 1);
if (rc)
{
log_error ("error setting forced signature PIN flag: %s\n",
@ -1570,7 +1579,7 @@ do_change_keyattr (int keyno, const struct key_attr *key_attr)
return gpg_error (GPG_ERR_PUBKEY_ALGO);
}
err = agent_scd_setattr ("KEY-ATTR", args, strlen (args), NULL);
err = agent_scd_setattr ("KEY-ATTR", args, strlen (args));
if (err)
log_error (_("error changing key attribute for key %d: %s\n"),
keyno+1, gpg_strerror (err));
@ -2116,8 +2125,7 @@ kdf_setup (const char *args)
goto leave_error;
err = agent_scd_setattr ("KDF", kdf_data,
single ? KDF_DATA_LENGTH_MIN : KDF_DATA_LENGTH_MAX,
NULL);
single ? KDF_DATA_LENGTH_MIN : KDF_DATA_LENGTH_MAX);
if (err)
goto leave_error;
@ -2169,7 +2177,7 @@ uif (int arg_number, const char *arg_rest)
data[1] = 0x20;
err = agent_scd_setattr (name, data, 2, NULL);
err = agent_scd_setattr (name, data, 2);
if (err)
log_error (_("error for setup UIF: %s\n"), gpg_strerror (err));
}

View File

@ -62,7 +62,7 @@ progress_cb (void *ctx, const char *what, int printchar,
/* Return true if the status message NO may currently be issued. We
need this to avoid syncronisation problem while auto retrieving a
need this to avoid synchronization problem while auto retrieving a
key. There it may happen that a status NODATA is issued for a non
available key and the user may falsely interpret this has a missing
signature. */

View File

@ -471,6 +471,7 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek)
{
char *filename = NULL;
estream_t fp;
rc = get_output_file ("", 0, ed->buf, &filename, &fp);
if (! rc)
{
@ -492,8 +493,7 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek)
filename, gpg_strerror (rc));
iobuf_close (output);
if (afx)
release_armor_context (afx);
release_armor_context (afx);
}
xfree (filename);
}

View File

@ -48,7 +48,6 @@ decrypt_message (ctrl_t ctrl, const char *filename)
armor_filter_context_t *afx = NULL;
progress_filter_context_t *pfx;
int rc;
int no_out = 0;
pfx = new_progress_context ();
@ -82,11 +81,13 @@ decrypt_message (ctrl_t ctrl, const char *filename)
if (!opt.outfile)
{
no_out = 1;
opt.outfile = "-";
opt.flags.dummy_outfile = 1;
}
else
opt.flags.dummy_outfile = 0;
rc = proc_encryption_packets (ctrl, NULL, fp );
if (no_out)
if (opt.flags.dummy_outfile)
opt.outfile = NULL;
iobuf_close (fp);

View File

@ -1,7 +1,7 @@
/* delkey.c - delete keys
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004,
* 2005, 2006 Free Software Foundation, Inc.
* Copyright (C) 2014 Werner Koch
* Copyright (C) 2014, 2019 Werner Koch
*
* This file is part of GnuPG.
*
@ -53,13 +53,15 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force,
gpg_error_t err;
kbnode_t keyblock = NULL;
kbnode_t node, kbctx;
kbnode_t targetnode;
KEYDB_HANDLE hd;
PKT_public_key *pk = NULL;
u32 keyid[2];
int okay=0;
int yes;
KEYDB_SEARCH_DESC desc;
int exactmatch;
int exactmatch; /* True if key was found by fingerprint. */
int thiskeyonly; /* 0 = false, 1 = is primary key, 2 = is a subkey. */
*r_sec_avail = 0;
@ -70,6 +72,7 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force,
/* Search the userid. */
err = classify_user_id (username, &desc, 1);
exactmatch = (desc.mode == KEYDB_SEARCH_MODE_FPR);
thiskeyonly = desc.exact;
if (!err)
err = keydb_search (hd, &desc, 1, NULL);
if (err)
@ -95,7 +98,35 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force,
err = gpg_error (GPG_ERR_GENERAL);
goto leave;
}
pk = node->pkt->pkt.public_key;
/* If an operation only on a subkey is requested, find that subkey
* now. */
if (thiskeyonly)
{
kbnode_t tmpnode;
for (kbctx=NULL; (tmpnode = walk_kbnode (keyblock, &kbctx, 0)); )
{
if (!(tmpnode->pkt->pkttype == PKT_PUBLIC_KEY
|| tmpnode->pkt->pkttype == PKT_PUBLIC_SUBKEY))
continue;
if (exact_subkey_match_p (&desc, tmpnode))
break;
}
if (!tmpnode)
{
log_error ("Oops; requested subkey not found anymore!\n");
err = gpg_error (GPG_ERR_GENERAL);
goto leave;
}
/* Set NODE to this specific subkey or primary key. */
thiskeyonly = node == tmpnode? 1 : 2;
targetnode = tmpnode;
}
else
targetnode = node;
pk = targetnode->pkt->pkt.public_key;
keyid_from_pk (pk, keyid);
if (!secret && !force)
@ -135,11 +166,33 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force,
}
else
{
if (secret)
print_seckey_info (ctrl, pk);
else
print_pubkey_info (ctrl, NULL, pk );
tty_printf( "\n" );
print_key_info (ctrl, NULL, 0, pk, secret);
tty_printf ("\n");
if (thiskeyonly == 1 && !secret)
{
/* We need to delete the entire public key despite the use
* of the thiskeyonly request. */
tty_printf (_("Note: The public primary key and all its subkeys"
" will be deleted.\n"));
}
else if (thiskeyonly == 2 && !secret)
{
tty_printf (_("Note: Only the shown public subkey"
" will be deleted.\n"));
}
if (thiskeyonly == 1 && secret)
{
tty_printf (_("Note: Only the secret part of the shown primary"
" key will be deleted.\n"));
}
else if (thiskeyonly == 2 && secret)
{
tty_printf (_("Note: Only the secret part of the shown subkey"
" will be deleted.\n"));
}
if (thiskeyonly)
tty_printf ("\n");
yes = cpr_get_answer_is_yes
(secret? "delete_key.secret.okay": "delete_key.okay",
@ -176,6 +229,9 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force,
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY))
continue;
if (thiskeyonly && targetnode != node)
continue;
if (agent_probe_secret_key (NULL, node->pkt->pkt.public_key))
continue; /* No secret key for that public (sub)key. */
@ -188,7 +244,7 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force,
* pre-caution is that since 2.1 the secret key may also
* be used for other protocols and thus deleting it from
* the gpg would also delete the key for other tools. */
if (!err)
if (!err && !opt.dry_run)
err = agent_delete_key (NULL, hexgrip, prompt,
opt.answer_yes);
xfree (prompt);
@ -217,6 +273,35 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force,
if (firsterr)
goto leave;
}
else if (thiskeyonly == 2)
{
int selected = 0;
/* Delete the specified public subkey. */
for (kbctx=NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); )
{
if (thiskeyonly && targetnode != node)
continue;
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
{
selected = targetnode == node;
if (selected)
delete_kbnode (node);
}
else if (selected && node->pkt->pkttype == PKT_SIGNATURE)
delete_kbnode (node);
else
selected = 0;
}
commit_kbnode (&keyblock);
err = keydb_update_keyblock (ctrl, hd, keyblock);
if (err)
{
log_error (_("update failed: %s\n"), gpg_strerror (err));
goto leave;
}
}
else
{
err = keydb_delete_keyblock (hd);
@ -232,7 +317,8 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force,
revalidation_mark(). This makes sense - only deleting keys
that have ownertrust set should trigger this. */
if (!secret && pk && clear_ownertrusts (ctrl, pk))
if (!secret && pk && !opt.dry_run && thiskeyonly != 2
&& clear_ownertrusts (ctrl, pk))
{
if (opt.verbose)
log_info (_("ownertrust information cleared\n"));
@ -245,7 +331,8 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force,
return err;
}
/****************
/*
* Delete a public or secret key from a keyring.
*/
gpg_error_t

View File

@ -77,37 +77,99 @@ set_exec_path(const char *path) { return GPG_ERR_GENERAL; }
static int
w32_system(const char *command)
{
#ifdef HAVE_W32CE_SYSTEM
#warning Change this code to use common/exechelp.c
#else
PROCESS_INFORMATION pi;
STARTUPINFO si;
char *string;
if (!strncmp (command, "!ShellExecute ", 14))
{
SHELLEXECUTEINFOW see;
wchar_t *wname;
int waitms;
/* We must use a copy of the command as CreateProcess modifies this
argument. */
string=xstrdup(command);
command = command + 14;
while (spacep (command))
command++;
waitms = atoi (command);
if (waitms < 0)
waitms = 0;
else if (waitms > 60*1000)
waitms = 60000;
while (*command && !spacep (command))
command++;
while (spacep (command))
command++;
memset(&pi,0,sizeof(pi));
memset(&si,0,sizeof(si));
si.cb=sizeof(si);
wname = utf8_to_wchar (command);
if (!wname)
return -1;
if(!CreateProcess(NULL,string,NULL,NULL,FALSE,
DETACHED_PROCESS,
NULL,NULL,&si,&pi))
return -1;
memset (&see, 0, sizeof see);
see.cbSize = sizeof see;
see.fMask = (SEE_MASK_NOCLOSEPROCESS
| SEE_MASK_NOASYNC
| SEE_MASK_FLAG_NO_UI
| SEE_MASK_NO_CONSOLE);
see.lpVerb = L"open";
see.lpFile = (LPCWSTR)wname;
see.nShow = SW_SHOW;
/* Wait for the child to exit */
WaitForSingleObject(pi.hProcess,INFINITE);
if (DBG_EXTPROG)
log_debug ("running ShellExecuteEx(open,'%s')\n", command);
if (!ShellExecuteExW (&see))
{
if (DBG_EXTPROG)
log_debug ("ShellExecuteEx failed: rc=%d\n", (int)GetLastError ());
xfree (wname);
return -1;
}
if (DBG_EXTPROG)
log_debug ("ShellExecuteEx succeeded (hProcess=%p,hInstApp=%d)\n",
see.hProcess, (int)see.hInstApp);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
xfree(string);
if (!see.hProcess)
{
gnupg_usleep (waitms*1000);
if (DBG_EXTPROG)
log_debug ("ShellExecuteEx ready (wait=%dms)\n", waitms);
}
else
{
WaitForSingleObject (see.hProcess, INFINITE);
if (DBG_EXTPROG)
log_debug ("ShellExecuteEx ready\n");
}
CloseHandle (see.hProcess);
xfree (wname);
}
else
{
char *string;
PROCESS_INFORMATION pi;
STARTUPINFO si;
/* We must use a copy of the command as CreateProcess modifies
* this argument. */
string = xstrdup (command);
memset (&pi, 0, sizeof(pi));
memset (&si, 0, sizeof(si));
si.cb = sizeof (si);
if (!CreateProcess (NULL, string, NULL, NULL, FALSE,
DETACHED_PROCESS,
NULL, NULL, &si, &pi))
return -1;
/* Wait for the child to exit */
WaitForSingleObject (pi.hProcess, INFINITE);
CloseHandle (pi.hProcess);
CloseHandle (pi.hThread);
xfree (string);
}
return 0;
#endif
}
#endif
#endif /*_W32*/
/* Replaces current $PATH */
int
@ -508,7 +570,7 @@ exec_read(struct exec_info *info)
if(info->flags.use_temp_files)
{
if(DBG_EXTPROG)
log_debug("system() command is %s\n",info->command);
log_debug ("running command: %s\n",info->command);
#if defined (_WIN32)
info->progreturn=w32_system(info->command);

View File

@ -436,8 +436,8 @@ new_subkey_list_item (KBNODE node)
(keyID or fingerprint) and does match the one at NODE. It is
assumed that the packet at NODE is either a public or secret
subkey. */
static int
exact_subkey_match_p (KEYDB_SEARCH_DESC *desc, KBNODE node)
int
exact_subkey_match_p (KEYDB_SEARCH_DESC *desc, kbnode_t node)
{
u32 kid[2];
byte fpr[MAX_FINGERPRINT_LEN];
@ -596,7 +596,10 @@ cleartext_secret_key_to_openpgp (gcry_sexp_t s_key, PKT_public_key *pk)
top_list = gcry_sexp_find_token (s_key, "private-key", 0);
if (!top_list)
goto bad_seckey;
if (gcry_sexp_length(top_list) != 2)
/* ignore all S-expression after the first sublist -- we assume that
they are comments or otherwise irrelevant to OpenPGP */
if (gcry_sexp_length(top_list) < 2)
goto bad_seckey;
key = gcry_sexp_nth (top_list, 1);
if (!key)
@ -2171,10 +2174,10 @@ export_ssh_key (ctrl_t ctrl, const char *userid)
{
getkey_ctx_t getkeyctx;
err = get_pubkey_byname (ctrl, &getkeyctx, NULL, userid, &keyblock,
err = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL,
&getkeyctx, NULL, userid, &keyblock,
NULL,
0 /* Only usable keys or given exact. */,
1 /* No AKL lookup. */);
0 /* Only usable keys or given exact. */);
if (!err)
{
err = getkey_next (ctrl, getkeyctx, NULL, NULL);

View File

@ -36,6 +36,7 @@
#include "../common/i18n.h"
#include "keyserver-internal.h"
#include "call-agent.h"
#include "objcache.h"
#include "../common/host2net.h"
#include "../common/mbox-util.h"
#include "../common/status.h"
@ -112,6 +113,7 @@ static struct
typedef struct keyid_list
{
struct keyid_list *next;
byte fprlen;
char fpr[MAX_FINGERPRINT_LEN];
u32 keyid[2];
} *keyid_list_t;
@ -132,15 +134,6 @@ static int pk_cache_disabled;
#if MAX_UID_CACHE_ENTRIES < 5
#error we really need the userid cache
#endif
typedef struct user_id_db
{
struct user_id_db *next;
keyid_list_t keyids;
int len;
char name[1];
} *user_id_db_t;
static user_id_db_t user_id_db;
static int uid_cache_entries; /* Number of entries in uid cache. */
static void merge_selfsigs (ctrl_t ctrl, kbnode_t keyblock);
static int lookup (ctrl_t ctrl, getkey_ctx_t ctx, int want_secret,
@ -262,112 +255,6 @@ user_id_not_found_utf8 (void)
/* Return the user ID from the given keyblock.
* We use the primary uid flag which has been set by the merge_selfsigs
* function. The returned value is only valid as long as the given
* keyblock is not changed. */
static const char *
get_primary_uid (KBNODE keyblock, size_t * uidlen)
{
KBNODE k;
const char *s;
for (k = keyblock; k; k = k->next)
{
if (k->pkt->pkttype == PKT_USER_ID
&& !k->pkt->pkt.user_id->attrib_data
&& k->pkt->pkt.user_id->flags.primary)
{
*uidlen = k->pkt->pkt.user_id->len;
return k->pkt->pkt.user_id->name;
}
}
s = user_id_not_found_utf8 ();
*uidlen = strlen (s);
return s;
}
static void
release_keyid_list (keyid_list_t k)
{
while (k)
{
keyid_list_t k2 = k->next;
xfree (k);
k = k2;
}
}
/****************
* Store the association of keyid and userid
* Feed only public keys to this function.
*/
static void
cache_user_id (KBNODE keyblock)
{
user_id_db_t r;
const char *uid;
size_t uidlen;
keyid_list_t keyids = NULL;
KBNODE k;
for (k = keyblock; k; k = k->next)
{
if (k->pkt->pkttype == PKT_PUBLIC_KEY
|| k->pkt->pkttype == PKT_PUBLIC_SUBKEY)
{
keyid_list_t a = xmalloc_clear (sizeof *a);
/* Hmmm: For a long list of keyids it might be an advantage
* to append the keys. */
fingerprint_from_pk (k->pkt->pkt.public_key, a->fpr, NULL);
keyid_from_pk (k->pkt->pkt.public_key, a->keyid);
/* First check for duplicates. */
for (r = user_id_db; r; r = r->next)
{
keyid_list_t b;
for (b = r->keyids; b; b = b->next)
{
if (!memcmp (b->fpr, a->fpr, MAX_FINGERPRINT_LEN))
{
if (DBG_CACHE)
log_debug ("cache_user_id: already in cache\n");
release_keyid_list (keyids);
xfree (a);
return;
}
}
}
/* Now put it into the cache. */
a->next = keyids;
keyids = a;
}
}
if (!keyids)
BUG (); /* No key no fun. */
uid = get_primary_uid (keyblock, &uidlen);
if (uid_cache_entries >= MAX_UID_CACHE_ENTRIES)
{
/* fixme: use another algorithm to free some cache slots */
r = user_id_db;
user_id_db = r->next;
release_keyid_list (r->keyids);
xfree (r);
uid_cache_entries--;
}
r = xmalloc (sizeof *r + uidlen - 1);
r->keyids = keyids;
r->len = uidlen;
memcpy (r->name, uid, r->len);
r->next = user_id_db;
user_id_db = r;
uid_cache_entries++;
}
/* Disable and drop the public key cache (which is filled by
cache_public_key and get_pubkey). Note: there is currently no way
@ -948,11 +835,21 @@ key_byname (ctrl_t ctrl, GETKEY_CTX *retctx, strlist_t namelist,
/* Find a public key identified by NAME.
*
* If name appears to be a valid RFC822 mailbox (i.e., email
* address) and auto key lookup is enabled (no_akl == 0), then the
* specified auto key lookup methods (--auto-key-lookup) are used to
* import the key into the local keyring. Otherwise, just the local
* keyring is consulted.
* If name appears to be a valid RFC822 mailbox (i.e., email address)
* and auto key lookup is enabled (mode != GET_PUBKEY_NO_AKL), then
* the specified auto key lookup methods (--auto-key-lookup) are used
* to import the key into the local keyring. Otherwise, just the
* local keyring is consulted.
*
* MODE can be one of:
* GET_PUBKEY_NORMAL - The standard mode
* GET_PUBKEY_NO_AKL - The auto key locate functionality is
* disabled and only the local key ring is
* considered. Note: the local key ring is
* consulted even if local is not in the
* auto-key-locate option list!
* GET_PUBKEY_NO_LOCAL - Only the auto key locate functionaly is
* used and no local search is done.
*
* If RETCTX is not NULL, then the constructed context is returned in
* *RETCTX so that getpubkey_next can be used to get subsequent
@ -988,18 +885,14 @@ key_byname (ctrl_t ctrl, GETKEY_CTX *retctx, strlist_t namelist,
* documentation for skip_unusable for an exact definition) are
* skipped unless they are looked up by key id or by fingerprint.
*
* If NO_AKL is set, then the auto key locate functionality is
* disabled and only the local key ring is considered. Note: the
* local key ring is consulted even if local is not in the
* --auto-key-locate option list!
*
* This function returns 0 on success. Otherwise, an error code is
* returned. In particular, GPG_ERR_NO_PUBKEY or GPG_ERR_NO_SECKEY
* (if want_secret is set) is returned if the key is not found. */
int
get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
get_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
GETKEY_CTX * retctx, PKT_public_key * pk,
const char *name, KBNODE * ret_keyblock,
KEYDB_HANDLE * ret_kdbhd, int include_unusable, int no_akl)
KEYDB_HANDLE * ret_kdbhd, int include_unusable)
{
int rc;
strlist_t namelist = NULL;
@ -1035,7 +928,9 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
* Note: we only save the search context in RETCTX if the local
* method is the first method tried (either explicitly or
* implicitly). */
if (!no_akl)
if (mode == GET_PUBKEY_NO_LOCAL)
nodefault = 1; /* Auto-key-locate but ignore "local". */
else if (mode != GET_PUBKEY_NO_AKL)
{
/* auto-key-locate is enabled. */
@ -1064,7 +959,13 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
anylocalfirst = 1;
}
if (nodefault && is_mbox)
if (mode == GET_PUBKEY_NO_LOCAL)
{
/* Force using the AKL. If IS_MBOX is not set this is the final
* error code. */
rc = GPG_ERR_NO_PUBKEY;
}
else if (nodefault && is_mbox)
{
/* Either "nodefault" or "local" (explicitly) appeared in the
* auto key locate list and NAME appears to be an email address.
@ -1085,7 +986,9 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
/* If the requested name resembles a valid mailbox and automatic
retrieval has been enabled, we try to import the key. */
if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY && !no_akl && is_mbox)
if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY
&& mode != GET_PUBKEY_NO_AKL
&& is_mbox)
{
/* NAME wasn't present in the local keyring (or we didn't try
* the local keyring). Since the auto key locate feature is
@ -1104,22 +1007,30 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
{
case AKL_NODEFAULT:
/* This is a dummy mechanism. */
mechanism_string = "None";
mechanism_string = "";
rc = GPG_ERR_NO_PUBKEY;
break;
case AKL_LOCAL:
mechanism_string = "Local";
did_akl_local = 1;
if (retctx)
{
getkey_end (ctrl, *retctx);
*retctx = NULL;
}
add_to_strlist (&namelist, name);
rc = key_byname (ctrl, anylocalfirst ? retctx : NULL,
namelist, pk, 0,
include_unusable, ret_keyblock, ret_kdbhd);
if (mode == GET_PUBKEY_NO_LOCAL)
{
mechanism_string = "";
rc = GPG_ERR_NO_PUBKEY;
}
else
{
mechanism_string = "Local";
did_akl_local = 1;
if (retctx)
{
getkey_end (ctrl, *retctx);
*retctx = NULL;
}
add_to_strlist (&namelist, name);
rc = key_byname (ctrl, anylocalfirst ? retctx : NULL,
namelist, pk, 0,
include_unusable, ret_keyblock, ret_kdbhd);
}
break;
case AKL_CERT:
@ -1246,15 +1157,14 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
name, mechanism_string);
break;
}
if (gpg_err_code (rc) != GPG_ERR_NO_PUBKEY
|| opt.verbose || no_fingerprint)
if ((gpg_err_code (rc) != GPG_ERR_NO_PUBKEY
|| opt.verbose || no_fingerprint) && *mechanism_string)
log_info (_("error retrieving '%s' via %s: %s\n"),
name, mechanism_string,
no_fingerprint ? _("No fingerprint") : gpg_strerror (rc));
}
}
if (rc && retctx)
{
getkey_end (ctrl, *retctx);
@ -1315,7 +1225,7 @@ subkey_is_ok (const PKT_public_key *sub)
/* Return true if KEYBLOCK has only expired encryption subkyes. Note
* that the function returns false if the key has no encryption
* subkeys at all or the subkecys are revoked. */
* subkeys at all or the subkeys are revoked. */
static int
only_expired_enc_subkeys (kbnode_t keyblock)
{
@ -1407,7 +1317,8 @@ pubkey_cmp (ctrl_t ctrl, const char *name, struct pubkey_cmp_cookie *old,
* resembles a mail address, the results are ranked and only the best
* result is returned. */
gpg_error_t
get_best_pubkey_byname (ctrl_t ctrl, GETKEY_CTX *retctx, PKT_public_key *pk,
get_best_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
GETKEY_CTX *retctx, PKT_public_key *pk,
const char *name, KBNODE *ret_keyblock,
int include_unusable)
{
@ -1430,8 +1341,9 @@ get_best_pubkey_byname (ctrl_t ctrl, GETKEY_CTX *retctx, PKT_public_key *pk,
getkey_end (ctrl, ctx);
ctx = NULL;
}
err = get_pubkey_byname (ctrl, &ctx, pk, name, ret_keyblock,
NULL, include_unusable, 0);
err = get_pubkey_byname (ctrl, mode,
&ctx, pk, name, ret_keyblock,
NULL, include_unusable);
if (err)
{
getkey_end (ctrl, ctx);
@ -1493,15 +1405,14 @@ get_best_pubkey_byname (ctrl_t ctrl, GETKEY_CTX *retctx, PKT_public_key *pk,
/* Old key is better. */
release_public_key_parts (&new.key);
free_user_id (new.uid);
new.uid = NULL;
}
else
{
/* A tie. Keep the old key. */
release_public_key_parts (&new.key);
free_user_id (new.uid);
new.uid = NULL;
}
new.uid = NULL;
}
getkey_end (ctrl, ctx);
ctx = NULL;
@ -1637,7 +1548,7 @@ get_pubkey_fromfile (ctrl_t ctrl, PKT_public_key *pk, const char *fname)
*
* FPRINT is a byte array whose contents is the fingerprint to use as
* the search term. FPRINT_LEN specifies the length of the
* fingerprint (in bytes). Currently, only 16 and 20-byte
* fingerprint (in bytes). Currently, only 16, 20, and 32-byte
* fingerprints are supported.
*
* FIXME: We should replace this with the _byname function. This can
@ -3291,7 +3202,11 @@ merge_selfsigs (ctrl_t ctrl, kbnode_t keyblock)
memcpy (&pk->revoked, &rinfo, sizeof (rinfo));
}
if (main_pk->has_expired)
pk->has_expired = main_pk->has_expired;
{
pk->has_expired = main_pk->has_expired;
if (!pk->expiredate || pk->expiredate > main_pk->expiredate)
pk->expiredate = main_pk->expiredate;
}
}
}
return;
@ -3623,7 +3538,7 @@ finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact,
xfree (tempkeystr);
}
cache_user_id (keyblock);
cache_put_keyblock (keyblock);
return latest_key ? latest_key : keyblock; /* Found. */
}
@ -3836,67 +3751,40 @@ get_seckey_default_or_card (ctrl_t ctrl, PKT_public_key *pk,
* this string must be freed by xfree. If R_NOUID is not NULL it is
* set to true if a user id was not found; otherwise to false. */
static char *
get_user_id_string (ctrl_t ctrl, u32 * keyid, int mode, size_t *r_len,
int *r_nouid)
get_user_id_string (ctrl_t ctrl, u32 * keyid, int mode)
{
user_id_db_t r;
keyid_list_t a;
int pass = 0;
char *name;
unsigned int namelen;
char *p;
if (r_nouid)
*r_nouid = 0;
log_assert (mode != 2);
/* Try it two times; second pass reads from the database. */
do
name = cache_get_uid_bykid (keyid, &namelen);
if (!name)
{
for (r = user_id_db; r; r = r->next)
{
for (a = r->keyids; a; a = a->next)
{
if (a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1])
{
if (mode == 2)
{
/* An empty string as user id is possible. Make
sure that the malloc allocates one byte and
does not bail out. */
p = xmalloc (r->len? r->len : 1);
memcpy (p, r->name, r->len);
if (r_len)
*r_len = r->len;
}
else
{
if (mode)
p = xasprintf ("%08lX%08lX %.*s",
(ulong) keyid[0], (ulong) keyid[1],
r->len, r->name);
else
p = xasprintf ("%s %.*s", keystr (keyid),
r->len, r->name);
if (r_len)
*r_len = strlen (p);
}
return p;
}
}
}
/* Get it so that the cache will be filled. */
if (!get_pubkey (ctrl, NULL, keyid))
name = cache_get_uid_bykid (keyid, &namelen);
}
while (++pass < 2 && !get_pubkey (ctrl, NULL, keyid));
if (mode == 2)
p = xstrdup (user_id_not_found_utf8 ());
else if (mode)
p = xasprintf ("%08lX%08lX [?]", (ulong) keyid[0], (ulong) keyid[1]);
if (name)
{
if (mode)
p = xasprintf ("%08lX%08lX %.*s",
(ulong) keyid[0], (ulong) keyid[1], namelen, name);
else
p = xasprintf ("%s %.*s", keystr (keyid), namelen, name);
xfree (name);
}
else
p = xasprintf ("%s [?]", keystr (keyid));
{
if (mode)
p = xasprintf ("%08lX%08lX [?]", (ulong) keyid[0], (ulong) keyid[1]);
else
p = xasprintf ("%s [?]", keystr (keyid));
}
if (r_nouid)
*r_nouid = 1;
if (r_len)
*r_len = strlen (p);
return p;
}
@ -3904,7 +3792,7 @@ get_user_id_string (ctrl_t ctrl, u32 * keyid, int mode, size_t *r_len,
char *
get_user_id_string_native (ctrl_t ctrl, u32 * keyid)
{
char *p = get_user_id_string (ctrl, keyid, 0, NULL, NULL);
char *p = get_user_id_string (ctrl, keyid, 0);
char *p2 = utf8_to_native (p, strlen (p), 0);
xfree (p);
return p2;
@ -3914,7 +3802,7 @@ get_user_id_string_native (ctrl_t ctrl, u32 * keyid)
char *
get_long_user_id_string (ctrl_t ctrl, u32 * keyid)
{
return get_user_id_string (ctrl, keyid, 1, NULL, NULL);
return get_user_id_string (ctrl, keyid, 1);
}
@ -3922,7 +3810,31 @@ get_long_user_id_string (ctrl_t ctrl, u32 * keyid)
char *
get_user_id (ctrl_t ctrl, u32 *keyid, size_t *rn, int *r_nouid)
{
return get_user_id_string (ctrl, keyid, 2, rn, r_nouid);
char *name;
unsigned int namelen;
if (r_nouid)
*r_nouid = 0;
name = cache_get_uid_bykid (keyid, &namelen);
if (!name)
{
/* Get it so that the cache will be filled. */
if (!get_pubkey (ctrl, NULL, keyid))
name = cache_get_uid_bykid (keyid, &namelen);
}
if (!name)
{
name = xstrdup (user_id_not_found_utf8 ());
namelen = strlen (name);
if (r_nouid)
*r_nouid = 1;
}
if (rn && name)
*rn = namelen;
return name;
}
@ -3943,49 +3855,36 @@ get_user_id_native (ctrl_t ctrl, u32 *keyid)
returned string, which must be freed using xfree, may not be NUL
terminated. To determine the length of the string, you must use
*RN. */
char *
get_user_id_byfpr (ctrl_t ctrl, const byte *fpr, size_t *rn)
static char *
get_user_id_byfpr (ctrl_t ctrl, const byte *fpr, size_t fprlen, size_t *rn)
{
user_id_db_t r;
char *p;
int pass = 0;
char *name;
/* Try it two times; second pass reads from the database. */
do
name = cache_get_uid_byfpr (fpr, fprlen, rn);
if (!name)
{
for (r = user_id_db; r; r = r->next)
{
keyid_list_t a;
for (a = r->keyids; a; a = a->next)
{
if (!memcmp (a->fpr, fpr, MAX_FINGERPRINT_LEN))
{
/* An empty string as user id is possible. Make
sure that the malloc allocates one byte and does
not bail out. */
p = xmalloc (r->len? r->len : 1);
memcpy (p, r->name, r->len);
*rn = r->len;
return p;
}
}
}
/* Get it so that the cache will be filled. */
if (!get_pubkey_byfprint (ctrl, NULL, NULL, fpr, fprlen))
name = cache_get_uid_byfpr (fpr, fprlen, rn);
}
while (++pass < 2
&& !get_pubkey_byfprint (ctrl, NULL, NULL, fpr, MAX_FINGERPRINT_LEN));
p = xstrdup (user_id_not_found_utf8 ());
*rn = strlen (p);
return p;
if (!name)
{
name = xstrdup (user_id_not_found_utf8 ());
*rn = strlen (name);
}
return name;
}
/* Like get_user_id_byfpr, but convert the string to the native
encoding. The returned string needs to be freed. Unlike
get_user_id_byfpr, the returned string is NUL terminated. */
char *
get_user_id_byfpr_native (ctrl_t ctrl, const byte *fpr)
get_user_id_byfpr_native (ctrl_t ctrl, const byte *fpr, size_t fprlen)
{
size_t rn;
char *p = get_user_id_byfpr (ctrl, fpr, &rn);
char *p = get_user_id_byfpr (ctrl, fpr, fprlen, &rn);
char *p2 = utf8_to_native (p, rn, 0);
xfree (p);
return p2;

View File

@ -59,6 +59,7 @@
#include "../common/asshelp.h"
#include "call-dirmngr.h"
#include "tofu.h"
#include "objcache.h"
#include "../common/init.h"
#include "../common/mbox-util.h"
#include "../common/shareddefs.h"
@ -148,6 +149,7 @@ enum cmd_and_opt_values
aSendKeys,
aRecvKeys,
aLocateKeys,
aLocateExtKeys,
aSearchKeys,
aRefreshKeys,
aFetchKeys,
@ -502,6 +504,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_c (aRefreshKeys, "refresh-keys",
N_("update all keys from a keyserver")),
ARGPARSE_c (aLocateKeys, "locate-keys", "@"),
ARGPARSE_c (aLocateExtKeys, "locate-external-keys", "@"),
ARGPARSE_c (aFetchKeys, "fetch-keys" , "@" ),
ARGPARSE_c (aShowKeys, "show-keys" , "@" ),
ARGPARSE_c (aExportSecret, "export-secret-keys" , "@" ),
@ -2421,7 +2424,9 @@ main (int argc, char **argv)
opt.import_options = IMPORT_REPAIR_KEYS;
opt.export_options = EXPORT_ATTRIBUTES;
opt.keyserver_options.import_options = (IMPORT_REPAIR_KEYS
| IMPORT_REPAIR_PKS_SUBKEY_BUG);
| IMPORT_REPAIR_PKS_SUBKEY_BUG
| IMPORT_SELF_SIGS_ONLY
| IMPORT_CLEAN);
opt.keyserver_options.export_options = EXPORT_ATTRIBUTES;
opt.keyserver_options.options = KEYSERVER_HONOR_PKA_RECORD;
opt.verify_options = (LIST_SHOW_UID_VALIDITY
@ -2611,6 +2616,7 @@ main (int argc, char **argv)
#endif /* ENABLE_CARD_SUPPORT*/
case aListKeys:
case aLocateKeys:
case aLocateExtKeys:
case aListSigs:
case aExportSecret:
case aExportSecretSub:
@ -4511,7 +4517,7 @@ main (int argc, char **argv)
sl = NULL;
for( ; argc; argc--, argv++ )
add_to_strlist2( &sl, *argv, utf8_strings );
public_key_list (ctrl, sl, 0);
public_key_list (ctrl, sl, 0, 0);
free_strlist(sl);
break;
case aListSecretKeys:
@ -4522,10 +4528,11 @@ main (int argc, char **argv)
free_strlist(sl);
break;
case aLocateKeys:
case aLocateExtKeys:
sl = NULL;
for (; argc; argc--, argv++)
add_to_strlist2( &sl, *argv, utf8_strings );
public_key_list (ctrl, sl, 1);
public_key_list (ctrl, sl, 1, cmd == aLocateExtKeys);
free_strlist (sl);
break;
@ -5223,12 +5230,14 @@ g10_exit( int rc )
{
keydb_dump_stats ();
sig_check_dump_stats ();
objcache_dump_stats ();
gcry_control (GCRYCTL_DUMP_MEMORY_STATS);
gcry_control (GCRYCTL_DUMP_RANDOM_STATS);
}
if (opt.debug)
gcry_control (GCRYCTL_DUMP_SECMEM_STATS );
gnupg_block_all_signals ();
emergency_cleanup ();
rc = rc? rc : log_get_errorcount(0)? 2 : g10_errors_seen? 1 : 0;

View File

@ -1200,7 +1200,8 @@ sig_revocation_key (const char *option, int argc, char *argv[], void *cookie)
option, argv[0]);
pk.req_usage = PUBKEY_USAGE_SIG;
err = get_pubkey_byname (NULL, NULL, &pk, argv[1], NULL, NULL, 1, 1);
err = get_pubkey_byname (NULL, GET_PUBKEY_NO_AKL,
NULL, &pk, argv[1], NULL, NULL, 1);
if (err)
log_fatal ("looking up key %s: %s\n", argv[1], gpg_strerror (err));
@ -1799,12 +1800,19 @@ signature (const char *option, int argc, char *argv[], void *cookie)
keyid_copy (si.issuer_pk->keyid, pk_keyid (pripk));
}
/* The reuse of core gpg stuff by this tool is questionable when it
* requires adding extra code to the actual gpg code. It does not
* make sense to pass an extra parameter and in particular not given
* that gpg already has opt.cert_digest_algo to override it. */
if (si.digest_algo)
log_info ("note: digest algo can't be passed to make_keysig_packet\n");
/* Changing the issuer's key id is fragile. Check to make sure
make_keysig_packet didn't recompute the keyid. */
keyid_copy (keyid, si.issuer_pk->keyid);
err = make_keysig_packet (global_ctrl,
&sig, si.pk, si.uid, si.sk, si.issuer_pk,
si.class, si.digest_algo,
si.class,
si.timestamp, si.expiration,
mksubpkt_callback, &si, NULL);
log_assert (keyid_cmp (keyid, si.issuer_pk->keyid) == 0);
@ -2450,7 +2458,8 @@ pk_esk (const char *option, int argc, char *argv[], void *cookie)
memset (&pk, 0, sizeof (pk));
pk.req_usage = PUBKEY_USAGE_ENC;
err = get_pubkey_byname (NULL, NULL, &pk, pi.keyid, NULL, NULL, 1, 1);
err = get_pubkey_byname (NULL, GET_PUBKEY_NO_AKL,
NULL, &pk, pi.keyid, NULL, NULL, 1);
if (err)
log_fatal ("%s: looking up key %s: %s\n",
option, pi.keyid, gpg_strerror (err));

View File

@ -102,7 +102,7 @@ static int import (ctrl_t ctrl,
unsigned char **fpr, size_t *fpr_len, unsigned int options,
import_screener_t screener, void *screener_arg,
int origin, const char *url);
static int read_block (IOBUF a, int with_meta,
static int read_block (IOBUF a, unsigned int options,
PACKET **pending_pkt, kbnode_t *ret_root, int *r_v3keys);
static void revocation_present (ctrl_t ctrl, kbnode_t keyblock);
static gpg_error_t import_one (ctrl_t ctrl,
@ -129,6 +129,7 @@ static int delete_inv_parts (ctrl_t ctrl, kbnode_t keyblock,
u32 *keyid, unsigned int options);
static int any_uid_left (kbnode_t keyblock);
static int remove_all_uids (kbnode_t *keyblock);
static void remove_all_non_self_sigs (kbnode_t *keyblock, u32 *keyid);
static int merge_blocks (ctrl_t ctrl, unsigned int options,
kbnode_t keyblock_orig,
kbnode_t keyblock, u32 *keyid,
@ -190,7 +191,10 @@ parse_import_options(char *str,unsigned int *options,int noisy)
N_("remove as much as possible from key after import")},
{"import-drop-uids", IMPORT_DROP_UIDS, NULL,
N_("Do not import user id or attribute packets")},
N_("do not import user id or attribute packets")},
{"self-sigs-only", IMPORT_SELF_SIGS_ONLY, NULL,
N_("ignore key-signatures which are not self-signatures")},
{"import-export", IMPORT_EXPORT, NULL,
N_("run import filters and export key immediately")},
@ -589,8 +593,7 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct import_stats_s *stats,
release_armor_context (afx);
}
while (!(rc = read_block (inp, !!(options & IMPORT_RESTORE),
&pending_pkt, &keyblock, &v3keys)))
while (!(rc = read_block (inp, options, &pending_pkt, &keyblock, &v3keys)))
{
stats->v3keys += v3keys;
if (keyblock->pkt->pkttype == PKT_PUBLIC_KEY)
@ -669,6 +672,18 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct import_stats_s *stats,
if (!(++stats->count % 100) && !opt.quiet)
log_info (_("%lu keys processed so far\n"), stats->count );
if (origin == KEYORG_WKD && stats->count >= 5)
{
/* We limit the number of keys _received_ from the WKD to 5.
* In fact there should be only one key but some sites want
* to store a few expired keys there also. gpg's key
* selection will later figure out which key to use. Note
* that for WKD we always return the fingerprint of the
* first imported key. */
log_info ("import from WKD stopped after %d keys\n", 5);
break;
}
}
stats->v3keys += v3keys;
if (rc == -1)
@ -677,6 +692,13 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct import_stats_s *stats,
log_error (_("error reading '%s': %s\n"), fname, gpg_strerror (rc));
release_kbnode (secattic);
/* When read_block loop was stopped by error, we have PENDING_PKT left. */
if (pending_pkt)
{
free_packet (pending_pkt, NULL);
xfree (pending_pkt);
}
return rc;
}
@ -826,31 +848,39 @@ valid_keyblock_packet (int pkttype)
}
/****************
* Read the next keyblock from stream A.
* Meta data (ring trust packets) are only considered of WITH_META is set.
* PENDING_PKT should be initialized to NULL and not changed by the caller.
* Return: 0 = okay, -1 no more blocks or another errorcode.
* The int at R_V3KEY counts the number of unsupported v3
* keyblocks.
/* Read the next keyblock from stream A. Meta data (ring trust
* packets) are only considered if OPTIONS has the IMPORT_RESTORE flag
* set. PENDING_PKT should be initialized to NULL and not changed by
* the caller.
*
* Returns 0 for okay, -1 no more blocks, or any other errorcode. The
* integer at R_V3KEY counts the number of unsupported v3 keyblocks.
*/
static int
read_block( IOBUF a, int with_meta,
read_block( IOBUF a, unsigned int options,
PACKET **pending_pkt, kbnode_t *ret_root, int *r_v3keys)
{
int rc;
struct parse_packet_ctx_s parsectx;
PACKET *pkt;
kbnode_t root = NULL;
kbnode_t lastnode = NULL;
int in_cert, in_v3key, skip_sigs;
u32 keyid[2];
int got_keyid = 0;
unsigned int dropped_nonselfsigs = 0;
*r_v3keys = 0;
if (*pending_pkt)
{
root = new_kbnode( *pending_pkt );
root = lastnode = new_kbnode( *pending_pkt );
*pending_pkt = NULL;
log_assert (root->pkt->pkttype == PKT_PUBLIC_KEY
|| root->pkt->pkttype == PKT_SECRET_KEY);
in_cert = 1;
keyid_from_pk (root->pkt->pkt.public_key, keyid);
got_keyid = 1;
}
else
in_cert = 0;
@ -858,7 +888,7 @@ read_block( IOBUF a, int with_meta,
pkt = xmalloc (sizeof *pkt);
init_packet (pkt);
init_parse_packet (&parsectx, a);
if (!with_meta)
if (!(options & IMPORT_RESTORE))
parsectx.skip_meta = 1;
in_v3key = 0;
skip_sigs = 0;
@ -965,24 +995,59 @@ read_block( IOBUF a, int with_meta,
init_packet(pkt);
break;
case PKT_SIGNATURE:
if (!in_cert)
goto x_default;
if (!(options & IMPORT_SELF_SIGS_ONLY))
goto x_default;
log_assert (got_keyid);
if (pkt->pkt.signature->keyid[0] == keyid[0]
&& pkt->pkt.signature->keyid[1] == keyid[1])
{ /* This is likely a self-signature. We import this one.
* Eventually we should use the ISSUER_FPR to compare
* self-signatures, but that will work only for v5 keys
* which are currently not even deployed.
* Note that we do not do any crypto verify here because
* that would defeat this very mitigation of DoS by
* importing a key with a huge amount of faked
* key-signatures. A verification will be done later in
* the processing anyway. Here we want a cheap an early
* way to drop non-self-signatures. */
goto x_default;
}
/* Skip this signature. */
dropped_nonselfsigs++;
free_packet (pkt, &parsectx);
init_packet(pkt);
break;
case PKT_PUBLIC_KEY:
case PKT_SECRET_KEY:
if (in_cert ) /* Store this packet. */
if (!got_keyid)
{
keyid_from_pk (pkt->pkt.public_key, keyid);
got_keyid = 1;
}
if (in_cert) /* Store this packet. */
{
*pending_pkt = pkt;
pkt = NULL;
goto ready;
}
in_cert = 1;
/* fall through */
goto x_default;
default:
x_default:
if (in_cert && valid_keyblock_packet (pkt->pkttype))
{
if (!root )
root = new_kbnode (pkt);
root = lastnode = new_kbnode (pkt);
else
add_kbnode (root, new_kbnode (pkt));
{
lastnode->next = new_kbnode (pkt);
lastnode = lastnode->next;
}
pkt = xmalloc (sizeof *pkt);
}
else
@ -1003,6 +1068,10 @@ read_block( IOBUF a, int with_meta,
free_packet (pkt, &parsectx);
deinit_parse_packet (&parsectx);
xfree( pkt );
if (!rc && dropped_nonselfsigs && opt.verbose)
log_info ("key %s: number of dropped non-self-signatures: %u\n",
keystr (keyid), dropped_nonselfsigs);
return rc;
}
@ -1729,12 +1798,12 @@ update_key_origin (kbnode_t keyblock, u32 curtime, int origin, const char *url)
* has valid parts.
*/
static gpg_error_t
import_one (ctrl_t ctrl,
kbnode_t keyblock, struct import_stats_s *stats,
unsigned char **fpr, size_t *fpr_len, unsigned int options,
int from_sk, int silent,
import_screener_t screener, void *screener_arg,
int origin, const char *url, int *r_valid)
import_one_real (ctrl_t ctrl,
kbnode_t keyblock, struct import_stats_s *stats,
unsigned char **fpr, size_t *fpr_len, unsigned int options,
int from_sk, int silent,
import_screener_t screener, void *screener_arg,
int origin, const char *url, int *r_valid)
{
gpg_error_t err = 0;
PKT_public_key *pk;
@ -1817,6 +1886,13 @@ import_one (ctrl_t ctrl,
return 0;
}
/* Remove all non-self-sigs if requested. Noe that this is a NOP if
* that option has been globally set but we may also be called
* latter with the already parsed keyblock and a locally changed
* option. This is why we need to remove them here as well. */
if ((options & IMPORT_SELF_SIGS_ONLY))
remove_all_non_self_sigs (&keyblock, keyid);
/* Remove or collapse the user ids. */
if ((options & IMPORT_DROP_UIDS))
remove_all_uids (&keyblock);
@ -2026,22 +2102,25 @@ import_one (ctrl_t ctrl,
hd = NULL;
/* We are ready. */
if (!opt.quiet && !silent)
if (!err && !opt.quiet && !silent)
{
char *p = get_user_id_byfpr_native (ctrl, fpr2);
char *p = get_user_id_byfpr_native (ctrl, fpr2, fpr2len);
log_info (_("key %s: public key \"%s\" imported\n"),
keystr(keyid), p);
xfree(p);
}
if (is_status_enabled())
if (!err && is_status_enabled())
{
char *us = get_long_user_id_string (ctrl, keyid);
write_status_text( STATUS_IMPORTED, us );
xfree(us);
print_import_ok (pk, 1);
}
stats->imported++;
new_key = 1;
if (!err)
{
stats->imported++;
new_key = 1;
}
}
else /* Key already exists - merge. */
{
@ -2111,10 +2190,12 @@ import_one (ctrl_t ctrl,
keydb_release (hd);
hd = NULL;
/* We are ready. */
if (!opt.quiet && !silent)
/* We are ready. Print and update stats if we got no error.
* An error here comes from writing the keyblock and thus
* very likely means that no update happened. */
if (!err && !opt.quiet && !silent)
{
char *p = get_user_id_byfpr_native (ctrl, fpr2);
char *p = get_user_id_byfpr_native (ctrl, fpr2, fpr2len);
if (n_uids == 1 )
log_info( _("key %s: \"%s\" 1 new user ID\n"),
keystr(keyid),p);
@ -2148,14 +2229,17 @@ import_one (ctrl_t ctrl,
xfree(p);
}
stats->n_uids +=n_uids;
stats->n_sigs +=n_sigs;
stats->n_subk +=n_subk;
stats->n_sigs_cleaned +=n_sigs_cleaned;
stats->n_uids_cleaned +=n_uids_cleaned;
if (!err)
{
stats->n_uids +=n_uids;
stats->n_sigs +=n_sigs;
stats->n_subk +=n_subk;
stats->n_sigs_cleaned +=n_sigs_cleaned;
stats->n_uids_cleaned +=n_uids_cleaned;
if (is_status_enabled () && !silent)
print_import_ok (pk, ((n_uids?2:0)|(n_sigs?4:0)|(n_subk?8:0)));
if (is_status_enabled () && !silent)
print_import_ok (pk, ((n_uids?2:0)|(n_sigs?4:0)|(n_subk?8:0)));
}
}
else
{
@ -2175,7 +2259,7 @@ import_one (ctrl_t ctrl,
if (!opt.quiet && !silent)
{
char *p = get_user_id_byfpr_native (ctrl, fpr2);
char *p = get_user_id_byfpr_native (ctrl, fpr2, fpr2len);
log_info( _("key %s: \"%s\" not changed\n"),keystr(keyid),p);
xfree(p);
}
@ -2203,14 +2287,19 @@ import_one (ctrl_t ctrl,
fingerprint of the key in all cases. */
if (fpr)
{
xfree (*fpr);
/* Note that we need to compare against 0 here because
COUNT gets only incremented after returning from this
function. */
if (!stats->count)
*fpr = fingerprint_from_pk (pk, NULL, fpr_len);
else
*fpr = NULL;
{
xfree (*fpr);
*fpr = fingerprint_from_pk (pk, NULL, fpr_len);
}
else if (origin != KEYORG_WKD)
{
xfree (*fpr);
*fpr = NULL;
}
}
}
@ -2237,6 +2326,41 @@ import_one (ctrl_t ctrl,
}
/* Wrapper around import_one_real to retry the import in some cases. */
static gpg_error_t
import_one (ctrl_t ctrl,
kbnode_t keyblock, struct import_stats_s *stats,
unsigned char **fpr, size_t *fpr_len, unsigned int options,
int from_sk, int silent,
import_screener_t screener, void *screener_arg,
int origin, const char *url, int *r_valid)
{
gpg_error_t err;
err = import_one_real (ctrl, keyblock, stats, fpr, fpr_len, options,
from_sk, silent, screener, screener_arg,
origin, url, r_valid);
if (gpg_err_code (err) == GPG_ERR_TOO_LARGE
&& gpg_err_source (err) == GPG_ERR_SOURCE_KEYBOX
&& ((options & (IMPORT_SELF_SIGS_ONLY | IMPORT_CLEAN))
!= (IMPORT_SELF_SIGS_ONLY | IMPORT_CLEAN)))
{
/* We hit the maximum image length. Ask the wrapper to do
* everything again but this time with some extra options. */
u32 keyid[2];
keyid_from_pk (keyblock->pkt->pkt.public_key, keyid);
log_info ("key %s: keyblock too large, retrying with self-sigs-only\n",
keystr (keyid));
options |= IMPORT_SELF_SIGS_ONLY | IMPORT_CLEAN;
err = import_one_real (ctrl, keyblock, stats, fpr, fpr_len, options,
from_sk, silent, screener, screener_arg,
origin, url, r_valid);
}
return err;
}
/* Transfer all the secret keys in SEC_KEYBLOCK to the gpg-agent. The
* function prints diagnostics and returns an error code. If BATCH is
* true the secret keys are stored by gpg-agent in the transfer format
@ -2544,6 +2668,7 @@ sec_to_pub_keyblock (kbnode_t sec_keyblock)
kbnode_t pub_keyblock = NULL;
kbnode_t ctx = NULL;
kbnode_t secnode, pubnode;
kbnode_t lastnode = NULL;
unsigned int tag = 0;
/* Set a tag to all nodes. */
@ -2583,9 +2708,12 @@ sec_to_pub_keyblock (kbnode_t sec_keyblock)
pubnode->tag = secnode->tag;
if (!pub_keyblock)
pub_keyblock = pubnode;
pub_keyblock = lastnode = pubnode;
else
add_kbnode (pub_keyblock, pubnode);
{
lastnode->next = pubnode;
lastnode = pubnode;
}
}
return pub_keyblock;
@ -2915,7 +3043,7 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
/* The secret keyblock may not have nodes which are deleted in
* the public keyblock. Otherwise we would import just the
* secret key without having the public key. That would be
* surprising and clutters out private-keys-v1.d. */
* surprising and clutters our private-keys-v1.d. */
err = resync_sec_with_pub_keyblock (&keyblock, pub_keyblock, &attic);
if (err)
goto leave;
@ -3764,6 +3892,38 @@ remove_all_uids (kbnode_t *keyblock)
}
/* Delete all non-self-sigs from KEYBLOCK.
* Returns: True if the keyblock has changed. */
static void
remove_all_non_self_sigs (kbnode_t *keyblock, u32 *keyid)
{
kbnode_t node;
unsigned int dropped = 0;
for (node = *keyblock; node; node = node->next)
{
if (is_deleted_kbnode (node))
continue;
if (node->pkt->pkttype != PKT_SIGNATURE)
continue;
if (node->pkt->pkt.signature->keyid[0] == keyid[0]
&& node->pkt->pkt.signature->keyid[1] == keyid[1])
continue;
delete_kbnode (node);
dropped++;
}
if (dropped)
commit_kbnode (keyblock);
if (dropped && opt.verbose)
log_info ("key %s: number of dropped non-self-signatures: %u\n",
keystr (keyid), dropped);
}
/*
* It may happen that the imported keyblock has duplicated user IDs.
* We check this here and collapse those user IDs together with their

View File

@ -1,6 +1,6 @@
/* keydb.c - key database dispatcher
* Copyright (C) 2001-2013 Free Software Foundation, Inc.
* Coyrright (C) 2001-2015 Werner Koch
* Copyright (C) 2001-2015 Werner Koch
*
* This file is part of GnuPG.
*
@ -1076,7 +1076,7 @@ lock_all (KEYDB_HANDLE hd)
rc = keyring_lock (hd->active[i].u.kr, 1);
break;
case KEYDB_RESOURCE_TYPE_KEYBOX:
rc = keybox_lock (hd->active[i].u.kb, 1);
rc = keybox_lock (hd->active[i].u.kb, 1, -1);
break;
}
}
@ -1094,7 +1094,7 @@ lock_all (KEYDB_HANDLE hd)
keyring_lock (hd->active[i].u.kr, 0);
break;
case KEYDB_RESOURCE_TYPE_KEYBOX:
keybox_lock (hd->active[i].u.kb, 0);
keybox_lock (hd->active[i].u.kb, 0, 0);
break;
}
}
@ -1127,7 +1127,7 @@ unlock_all (KEYDB_HANDLE hd)
keyring_lock (hd->active[i].u.kr, 0);
break;
case KEYDB_RESOURCE_TYPE_KEYBOX:
keybox_lock (hd->active[i].u.kb, 0);
keybox_lock (hd->active[i].u.kb, 0, 0);
break;
}
}
@ -1242,8 +1242,15 @@ parse_keyblock_image (iobuf_t iobuf, int pk_no, int uid_no,
}
if (err)
{
es_fflush (es_stdout);
log_error ("parse_keyblock_image: read error: %s\n",
gpg_strerror (err));
if (gpg_err_code (err) == GPG_ERR_INV_PACKET)
{
free_packet (pkt, &parsectx);
init_packet (pkt);
continue;
}
err = gpg_error (GPG_ERR_INV_KEYRING);
break;
}

View File

@ -345,16 +345,25 @@ typedef struct pubkey_s *pubkey_t;
/* Free a list of public keys. */
void pubkeys_free (pubkey_t keys);
/* Mode flags for get_pubkey_byname. */
enum get_pubkey_modes
{
GET_PUBKEY_NORMAL = 0,
GET_PUBKEY_NO_AKL = 1,
GET_PUBKEY_NO_LOCAL = 2
};
/* Find a public key identified by NAME. */
int get_pubkey_byname (ctrl_t ctrl,
int get_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
GETKEY_CTX *retctx, PKT_public_key *pk,
const char *name,
KBNODE *ret_keyblock, KEYDB_HANDLE *ret_kdbhd,
int include_unusable, int no_akl );
int include_unusable);
/* Likewise, but only return the best match if NAME resembles a mail
* address. */
gpg_error_t get_best_pubkey_byname (ctrl_t ctrl,
gpg_error_t get_best_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
GETKEY_CTX *retctx, PKT_public_key *pk,
const char *name, KBNODE *ret_keyblock,
int include_unusable);
@ -436,8 +445,7 @@ char *get_user_id_string_native (ctrl_t ctrl, u32 *keyid);
char *get_long_user_id_string (ctrl_t ctrl, u32 *keyid);
char *get_user_id (ctrl_t ctrl, u32 *keyid, size_t *rn, int *r_nouid);
char *get_user_id_native (ctrl_t ctrl, u32 *keyid);
char *get_user_id_byfpr (ctrl_t ctrl, const byte *fpr, size_t *rn);
char *get_user_id_byfpr_native (ctrl_t ctrl, const byte *fpr);
char *get_user_id_byfpr_native (ctrl_t ctrl, const byte *fpr, size_t fprlen);
void release_akl(void);
int parse_auto_key_locate(const char *options);

View File

@ -1012,7 +1012,8 @@ sign_uids (ctrl_t ctrl, estream_t fp,
node->pkt->pkt.user_id,
NULL,
pk,
0x13, 0, 0, 0,
0x13,
0, 0,
keygen_add_std_prefs, primary_pk,
NULL);
else
@ -1020,7 +1021,7 @@ sign_uids (ctrl_t ctrl, estream_t fp,
node->pkt->pkt.user_id,
NULL,
pk,
class, 0,
class,
timestamp, duration,
sign_mk_attrib, &attrib,
NULL);
@ -1437,7 +1438,8 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
#endif
/* Get the public key */
err = get_pubkey_byname (ctrl, NULL, NULL, username, &keyblock, &kdbhd, 1, 1);
err = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL,
NULL, NULL, username, &keyblock, &kdbhd, 1);
if (err)
{
log_error (_("key \"%s\" not found: %s\n"), username, gpg_strerror (err));
@ -2570,7 +2572,8 @@ find_by_primary_fpr (ctrl_t ctrl, const char *fpr,
err = gpg_error (GPG_ERR_INV_NAME);
goto leave;
}
err = get_pubkey_byname (ctrl, NULL, NULL, fpr, &keyblock, &kdbhd, 1, 1);
err = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL,
NULL, NULL, fpr, &keyblock, &kdbhd, 1);
if (err)
{
log_error (_("key \"%s\" not found: %s\n"), fpr, gpg_strerror (err));
@ -3991,7 +3994,7 @@ menu_adduid (ctrl_t ctrl, kbnode_t pub_keyblock,
return 0;
}
err = make_keysig_packet (ctrl, &sig, pk, uid, NULL, pk, 0x13, 0, 0, 0,
err = make_keysig_packet (ctrl, &sig, pk, uid, NULL, pk, 0x13, 0, 0,
keygen_add_std_prefs, pk, NULL);
if (err)
{
@ -4289,7 +4292,8 @@ menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive)
primary keys only, but some casual testing shows that PGP and
GnuPG both can handle a designated revocation from a subkey. */
revoker_pk->req_usage = PUBKEY_USAGE_CERT;
rc = get_pubkey_byname (ctrl, NULL, revoker_pk, answer, NULL, NULL, 1, 1);
rc = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL,
NULL, revoker_pk, answer, NULL, NULL, 1);
if (rc)
{
log_error (_("key \"%s\" not found: %s\n"), answer,
@ -4355,7 +4359,7 @@ menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive)
continue;
}
print_pubkey_info (ctrl, NULL, revoker_pk);
print_key_info (ctrl, NULL, 0, revoker_pk, 0);
print_fingerprint (ctrl, NULL, revoker_pk, 2);
tty_printf ("\n");
@ -4374,7 +4378,7 @@ menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive)
break;
}
rc = make_keysig_packet (ctrl, &sig, pk, NULL, NULL, pk, 0x1F, 0, 0, 0,
rc = make_keysig_packet (ctrl, &sig, pk, NULL, NULL, pk, 0x1F, 0, 0,
keygen_add_revkey, &revkey, NULL);
if (rc)
{
@ -5898,7 +5902,7 @@ reloop: /* (must use this, because we are modifying the list) */
}
rc = make_keysig_packet (ctrl, &sig, primary_pk,
unode->pkt->pkt.user_id,
NULL, signerkey, 0x30, 0, 0, 0,
NULL, signerkey, 0x30, 0, 0,
sign_mk_attrib, &attrib, NULL);
free_public_key (signerkey);
if (rc)
@ -5977,11 +5981,11 @@ core_revuid (ctrl_t ctrl, kbnode_t keyblock, KBNODE node,
memset (&attrib, 0, sizeof attrib);
/* should not need to cast away const here; but
revocation_reason_build_cb needs to take a non-const
void* in order to meet the function signtuare for the
void* in order to meet the function signutare for the
mksubpkt argument to make_keysig_packet */
attrib.reason = (struct revocation_reason_info *)reason;
rc = make_keysig_packet (ctrl, &sig, pk, uid, NULL, pk, 0x30, 0,
rc = make_keysig_packet (ctrl, &sig, pk, uid, NULL, pk, 0x30,
timestamp, 0,
sign_mk_attrib, &attrib, NULL);
if (rc)
@ -6111,7 +6115,7 @@ menu_revkey (ctrl_t ctrl, kbnode_t pub_keyblock)
return 0;
rc = make_keysig_packet (ctrl, &sig, pk, NULL, NULL, pk,
0x20, 0, 0, 0,
0x20, 0, 0,
revocation_reason_build_cb, reason, NULL);
if (rc)
{
@ -6173,7 +6177,7 @@ menu_revsubkey (ctrl_t ctrl, kbnode_t pub_keyblock)
node->flag &= ~NODFLG_SELKEY;
rc = make_keysig_packet (ctrl, &sig, mainpk, NULL, subpk, mainpk,
0x28, 0, 0, 0, sign_mk_attrib, &attrib,
0x28, 0, 0, sign_mk_attrib, &attrib,
NULL);
if (rc)
{

View File

@ -227,18 +227,22 @@ print_status_key_not_created (const char *handle)
static void
write_uid( KBNODE root, const char *s )
static gpg_error_t
write_uid (kbnode_t root, const char *s)
{
PACKET *pkt = xmalloc_clear(sizeof *pkt );
size_t n = strlen(s);
PACKET *pkt = xmalloc_clear (sizeof *pkt);
size_t n = strlen (s);
pkt->pkttype = PKT_USER_ID;
pkt->pkt.user_id = xmalloc_clear (sizeof *pkt->pkt.user_id + n);
pkt->pkt.user_id->len = n;
pkt->pkt.user_id->ref = 1;
strcpy(pkt->pkt.user_id->name, s);
add_kbnode( root, new_kbnode( pkt ) );
if (n > MAX_UID_PACKET_LENGTH - 10)
return gpg_error (GPG_ERR_INV_USER_ID);
pkt->pkttype = PKT_USER_ID;
pkt->pkt.user_id = xmalloc_clear (sizeof *pkt->pkt.user_id + n);
pkt->pkt.user_id->len = n;
pkt->pkt.user_id->ref = 1;
strcpy (pkt->pkt.user_id->name, s);
add_kbnode (root, new_kbnode (pkt));
return 0;
}
static void
@ -1022,7 +1026,7 @@ make_backsig (ctrl_t ctrl, PKT_signature *sig, PKT_public_key *pk,
cache_public_key (sub_pk);
err = make_keysig_packet (ctrl, &backsig, pk, NULL, sub_pk, sub_psk, 0x19,
0, timestamp, 0, NULL, NULL, cache_nonce);
timestamp, 0, NULL, NULL, cache_nonce);
if (err)
log_error ("make_keysig_packet failed for backsig: %s\n",
gpg_strerror (err));
@ -1130,7 +1134,7 @@ write_direct_sig (ctrl_t ctrl, kbnode_t root, PKT_public_key *psk,
/* Make the signature. */
err = make_keysig_packet (ctrl, &sig, pk, NULL,NULL, psk, 0x1F,
0, timestamp, 0,
timestamp, 0,
keygen_add_revkey, revkey, cache_nonce);
if (err)
{
@ -1185,7 +1189,7 @@ write_selfsigs (ctrl_t ctrl, kbnode_t root, PKT_public_key *psk,
/* Make the signature. */
err = make_keysig_packet (ctrl, &sig, pk, uid, NULL, psk, 0x13,
0, timestamp, 0,
timestamp, 0,
keygen_add_std_prefs, pk, cache_nonce);
if (err)
{
@ -1245,7 +1249,7 @@ write_keybinding (ctrl_t ctrl, kbnode_t root,
oduap.usage = use;
oduap.pk = sub_pk;
err = make_keysig_packet (ctrl, &sig, pri_pk, NULL, sub_pk, pri_psk, 0x18,
0, timestamp, 0,
timestamp, 0,
keygen_add_key_flags_and_expire, &oduap,
cache_nonce);
if (err)
@ -1881,24 +1885,26 @@ print_key_flags(int flags)
/* Ask for the key flags and return them. CURRENT gives the current
* usage which should normally be given as 0. */
* usage which should normally be given as 0. MASK gives the allowed
* flags. */
unsigned int
ask_key_flags (int algo, int subkey, unsigned int current)
ask_key_flags_with_mask (int algo, int subkey, unsigned int current,
unsigned int mask)
{
/* TRANSLATORS: Please use only plain ASCII characters for the
translation. If this is not possible use single digits. The
string needs to 8 bytes long. Here is a description of the
functions:
s = Toggle signing capability
e = Toggle encryption capability
a = Toggle authentication capability
q = Finish
*/
* translation. If this is not possible use single digits. The
* string needs to 8 bytes long. Here is a description of the
* functions:
*
* s = Toggle signing capability
* e = Toggle encryption capability
* a = Toggle authentication capability
* q = Finish
*/
const char *togglers = _("SsEeAaQq");
char *answer = NULL;
const char *s;
unsigned int possible = openpgp_pk_algo_usage(algo);
unsigned int possible;
if ( strlen(togglers) != 8 )
{
@ -1907,22 +1913,26 @@ ask_key_flags (int algo, int subkey, unsigned int current)
togglers = "11223300";
}
/* Only primary keys may certify. */
if(subkey)
possible&=~PUBKEY_USAGE_CERT;
/* Mask the possible usage flags. This is for example used for a
* card based key. */
possible = (openpgp_pk_algo_usage (algo) & mask);
/* Preload the current set with the possible set, minus
authentication if CURRENT has been given as 0. If CURRENT has
been has non-zero we mask with all possible usages. */
/* However, only primary keys may certify. */
if (subkey)
possible &= ~PUBKEY_USAGE_CERT;
/* Preload the current set with the possible set, without
* authentication if CURRENT is 0. If CURRENT is non-zero we mask
* with all possible usages. */
if (current)
current &= possible;
else
current = (possible&~PUBKEY_USAGE_AUTH);
for(;;)
for (;;)
{
tty_printf("\n");
tty_printf(_("Possible actions for a %s key: "),
tty_printf(_("Possible actions for this %s key: "),
(algo == PUBKEY_ALGO_ECDSA
|| algo == PUBKEY_ALGO_EDDSA)
? "ECDSA/EdDSA" : openpgp_pk_algo_name (algo));
@ -2009,6 +2019,13 @@ ask_key_flags (int algo, int subkey, unsigned int current)
}
unsigned int
ask_key_flags (int algo, int subkey, unsigned int current)
{
return ask_key_flags_with_mask (algo, subkey, current, ~0);
}
/* Check whether we have a key for the key with HEXGRIP. Returns 0 if
there is no such key or the OpenPGP algo number for the key. */
static int
@ -2047,10 +2064,12 @@ static int
ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
char **r_keygrip)
{
gpg_error_t err;
char *keygrip = NULL;
char *answer = NULL;
int algo;
int dummy_algo;
char *p;
if (!r_subkey_algo)
r_subkey_algo = &dummy_algo;
@ -2101,6 +2120,8 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
if (opt.expert && r_keygrip)
tty_printf (_(" (%d) Existing key\n"), 13 );
if (r_keygrip)
tty_printf (_(" (%d) Existing key from card\n"), 14 );
for (;;)
{
@ -2221,9 +2242,130 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
*r_usage = ask_key_flags (algo, addmode, 0);
break;
}
else if ((algo == 14 || !strcmp (answer, "cardkey")) && r_keygrip)
{
char *serialno;
strlist_t keypairlist, sl;
int count, selection;
err = agent_scd_serialno (&serialno, NULL);
if (err)
{
tty_printf (_("error reading the card: %s\n"),
gpg_strerror (err));
goto ask_again;
}
tty_printf (_("Serial number of the card: %s\n"), serialno);
xfree (serialno);
err = agent_scd_keypairinfo (ctrl, NULL, &keypairlist);
if (err)
{
tty_printf (_("error reading the card: %s\n"),
gpg_strerror (err));
goto ask_again;
}
do
{
tty_printf (_("Available keys:\n"));
for (count=1,sl=keypairlist; sl; sl = sl->next, count++)
{
gcry_sexp_t s_pkey;
char *algostr = NULL;
enum gcry_pk_algos algoid = 0;
const char *keyref;
int any = 0;
keyref = strchr (sl->d, ' ');
if (keyref)
{
keyref++;
if (!agent_scd_readkey (keyref, &s_pkey))
{
algostr = pubkey_algo_string (s_pkey, &algoid);
gcry_sexp_release (s_pkey);
}
}
/* We use the flags also encode the algo for use
* below. We need to tweak the algo in case
* GCRY_PK_ECC is returned becuase pubkey_algo_string
* is not aware of the OpenPGP algo mapping.
* FIXME: This is an ugly hack. */
sl->flags &= 0xff;
if (algoid == GCRY_PK_ECC
&& algostr && !strncmp (algostr, "nistp", 5)
&& !(sl->flags & GCRY_PK_USAGE_ENCR))
sl->flags |= (PUBKEY_ALGO_ECDSA << 8);
else
sl->flags |= (map_pk_gcry_to_openpgp (algoid) << 8);
tty_printf (" (%d) %s %s", count, sl->d, algostr);
if ((sl->flags & GCRY_PK_USAGE_CERT))
{
tty_printf ("%scert", any?",":" (");
any = 1;
}
if ((sl->flags & GCRY_PK_USAGE_SIGN))
{
tty_printf ("%ssign", any?",":" (");
any = 1;
}
if ((sl->flags & GCRY_PK_USAGE_AUTH))
{
tty_printf ("%sauth", any?",":" (");
any = 1;
}
if ((sl->flags & GCRY_PK_USAGE_ENCR))
{
tty_printf ("%sencr", any?",":" (");
any = 1;
}
tty_printf ("%s\n", any?")":"");
xfree (algostr);
}
xfree (answer);
answer = cpr_get ("keygen.cardkey", _("Your selection? "));
cpr_kill_prompt ();
trim_spaces (answer);
selection = atoi (answer);
}
while (!(selection > 0 && selection < count));
for (count=1,sl=keypairlist; sl; sl = sl->next, count++)
if (count == selection)
break;
if (!sl)
{
/* Just in case COUNT is zero (no keys). */
free_strlist (keypairlist);
goto ask_again;
}
xfree (keygrip);
keygrip = xstrdup (sl->d);
if ((p = strchr (keygrip, ' ')))
*p = 0;
algo = (sl->flags >>8);
if (opt.expert)
*r_usage = ask_key_flags_with_mask (algo, addmode,
(sl->flags & 0xff),
(sl->flags & 0xff));
else
{
*r_usage = (sl->flags & 0xff);
if (addmode)
*r_usage &= ~GCRY_PK_USAGE_CERT;
}
free_strlist (keypairlist);
break;
}
else
tty_printf (_("Invalid selection.\n"));
ask_again:
;
}
xfree(answer);
@ -2507,14 +2649,25 @@ ask_curve (int *algo, int *subkey_algo, const char *current)
else
{
/* If the user selected a signing algorithm and Curve25519
we need to set the algo to EdDSA and update the curve name. */
if ((*algo == PUBKEY_ALGO_ECDSA || *algo == PUBKEY_ALGO_EDDSA)
&& curves[idx].eddsa_curve)
we need to set the algo to EdDSA and update the curve name.
If switching away from EdDSA, we need to set the algo back
to ECDSA. */
if (*algo == PUBKEY_ALGO_ECDSA || *algo == PUBKEY_ALGO_EDDSA)
{
if (subkey_algo && *subkey_algo == PUBKEY_ALGO_ECDSA)
*subkey_algo = PUBKEY_ALGO_EDDSA;
*algo = PUBKEY_ALGO_EDDSA;
result = curves[idx].eddsa_curve;
if (curves[idx].eddsa_curve)
{
if (subkey_algo && *subkey_algo == PUBKEY_ALGO_ECDSA)
*subkey_algo = PUBKEY_ALGO_EDDSA;
*algo = PUBKEY_ALGO_EDDSA;
result = curves[idx].eddsa_curve;
}
else
{
if (subkey_algo && *subkey_algo == PUBKEY_ALGO_EDDSA)
*subkey_algo = PUBKEY_ALGO_ECDSA;
*algo = PUBKEY_ALGO_ECDSA;
result = curves[idx].name;
}
}
else
result = curves[idx].name;
@ -4943,10 +5096,11 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
if (!err && (s = get_parameter_value (para, pUSERID)))
{
write_uid (pub_root, s );
err = write_selfsigs (ctrl, pub_root, pri_psk,
get_parameter_uint (para, pKEYUSAGE), timestamp,
cache_nonce);
err = write_uid (pub_root, s );
if (!err)
err = write_selfsigs (ctrl, pub_root, pri_psk,
get_parameter_uint (para, pKEYUSAGE), timestamp,
cache_nonce);
}
/* Write the auth key to the card before the encryption key. This

View File

@ -68,7 +68,7 @@ pubkey_letter( int algo )
}
/* Return a string describing the public key algorithm and the
keysize. For elliptic curves the functions prints the name of the
keysize. For elliptic curves the function prints the name of the
curve because the keysize is a property of the curve. The string
is copied to the supplied buffer up a length of BUFSIZE-1.
Examples for the output are:
@ -253,20 +253,6 @@ hash_public_key (gcry_md_hd_t md, PKT_public_key *pk)
}
static gcry_md_hd_t
do_fingerprint_md( PKT_public_key *pk )
{
gcry_md_hd_t md;
if (gcry_md_open (&md, pk->version == 5 ? GCRY_MD_SHA256 : GCRY_MD_SHA1, 0))
BUG ();
hash_public_key (md,pk);
gcry_md_final (md);
return md;
}
/* fixme: Check whether we can replace this function or if not
describe why we need it. */
u32
@ -520,6 +506,37 @@ keystr_from_desc(KEYDB_SEARCH_DESC *desc)
}
/* Compute the fingerprint and keyid and store it in PK. */
static void
compute_fingerprint (PKT_public_key *pk)
{
const byte *dp;
gcry_md_hd_t md;
size_t len;
if (gcry_md_open (&md, pk->version == 5 ? GCRY_MD_SHA256 : GCRY_MD_SHA1, 0))
BUG ();
hash_public_key (md, pk);
gcry_md_final (md);
dp = gcry_md_read (md, 0);
len = gcry_md_get_algo_dlen (gcry_md_get_algo (md));
log_assert (len <= MAX_FINGERPRINT_LEN);
memcpy (pk->fpr, dp, len);
pk->fprlen = len;
if (pk->version == 5)
{
pk->keyid[0] = buf32_to_u32 (dp);
pk->keyid[1] = buf32_to_u32 (dp+4);
}
else
{
pk->keyid[0] = buf32_to_u32 (dp+12);
pk->keyid[1] = buf32_to_u32 (dp+16);
}
gcry_md_close( md);
}
/*
* Get the keyid from the public key PK and store it at KEYID unless
* this is NULL. Returns the 32 bit short keyid.
@ -532,37 +549,11 @@ keyid_from_pk (PKT_public_key *pk, u32 *keyid)
if (!keyid)
keyid = dummy_keyid;
if( pk->keyid[0] || pk->keyid[1] )
{
keyid[0] = pk->keyid[0];
keyid[1] = pk->keyid[1];
}
else
{
const byte *dp;
gcry_md_hd_t md;
if (!pk->fprlen)
compute_fingerprint (pk);
md = do_fingerprint_md(pk);
if(md)
{
dp = gcry_md_read ( md, 0 );
if (pk->version == 5)
{
keyid[0] = buf32_to_u32 (dp);
keyid[1] = buf32_to_u32 (dp+4);
}
else
{
keyid[0] = buf32_to_u32 (dp+12);
keyid[1] = buf32_to_u32 (dp+16);
}
gcry_md_close (md);
pk->keyid[0] = keyid[0];
pk->keyid[1] = keyid[1];
}
else
pk->keyid[0] = pk->keyid[1] = keyid[0]= keyid[1] = 0xFFFFFFFF;
}
keyid[0] = pk->keyid[0];
keyid[1] = pk->keyid[1];
return keyid[1]; /*FIXME:shortkeyid ist different for v5*/
}
@ -805,6 +796,7 @@ colon_expirestr_from_sig (PKT_signature *sig)
}
/*
* Return a byte array with the fingerprint for the given PK/SK
* The length of the array is returned in ret_len. Caller must free
@ -813,31 +805,15 @@ colon_expirestr_from_sig (PKT_signature *sig)
byte *
fingerprint_from_pk (PKT_public_key *pk, byte *array, size_t *ret_len)
{
const byte *dp;
size_t len;
gcry_md_hd_t md;
if (!pk->fprlen)
compute_fingerprint (pk);
md = do_fingerprint_md (pk);
dp = gcry_md_read (md, 0);
len = gcry_md_get_algo_dlen (gcry_md_get_algo (md));
log_assert (len <= MAX_FINGERPRINT_LEN);
if (!array)
array = xmalloc ( len );
memcpy (array, dp, len );
if (pk->version == 5)
{
pk->keyid[0] = buf32_to_u32 (dp);
pk->keyid[1] = buf32_to_u32 (dp+4);
}
else
{
pk->keyid[0] = buf32_to_u32 (dp+12);
pk->keyid[1] = buf32_to_u32 (dp+16);
}
gcry_md_close( md);
array = xmalloc (pk->fprlen);
memcpy (array, pk->fpr, pk->fprlen);
if (ret_len)
*ret_len = len;
*ret_len = pk->fprlen;
return array;
}
@ -852,19 +828,19 @@ fingerprint_from_pk (PKT_public_key *pk, byte *array, size_t *ret_len)
char *
hexfingerprint (PKT_public_key *pk, char *buffer, size_t buflen)
{
unsigned char fpr[MAX_FINGERPRINT_LEN];
size_t len;
if (!pk->fprlen)
compute_fingerprint (pk);
fingerprint_from_pk (pk, fpr, &len);
if (!buffer)
{
buffer = xtrymalloc (2 * len + 1);
buffer = xtrymalloc (2 * pk->fprlen + 1);
if (!buffer)
return NULL;
}
else if (buflen < 2*len+1)
else if (buflen < 2 * pk->fprlen + 1)
log_fatal ("%s: buffer too short (%zu)\n", __func__, buflen);
bin2hex (fpr, len, buffer);
bin2hex (pk->fpr, pk->fprlen, buffer);
return buffer;
}

View File

@ -51,7 +51,7 @@
static void list_all (ctrl_t, int, int);
static void list_one (ctrl_t ctrl,
strlist_t names, int secret, int mark_secret);
static void locate_one (ctrl_t ctrl, strlist_t names);
static void locate_one (ctrl_t ctrl, strlist_t names, int no_local);
static void print_card_serialno (const char *serialno);
struct keylist_context
@ -83,10 +83,11 @@ keylist_context_release (struct keylist_context *listctx)
/* List the keys. If list is NULL, all available keys are listed.
With LOCATE_MODE set the locate algorithm is used to find a
key. */
* With LOCATE_MODE set the locate algorithm is used to find a key; if
* in addition NO_LOCAL is set the locate does not look into the local
* keyring. */
void
public_key_list (ctrl_t ctrl, strlist_t list, int locate_mode)
public_key_list (ctrl_t ctrl, strlist_t list, int locate_mode, int no_local)
{
#ifndef NO_TRUST_MODELS
if (opt.with_colons)
@ -140,7 +141,7 @@ public_key_list (ctrl_t ctrl, strlist_t list, int locate_mode)
#endif
if (locate_mode)
locate_one (ctrl, list);
locate_one (ctrl, list, no_local);
else if (!list)
list_all (ctrl, 0, opt.with_secret);
else
@ -165,43 +166,15 @@ secret_key_list (ctrl_t ctrl, strlist_t list)
list_one (ctrl, list, 1, 0);
}
char *
format_seckey_info (ctrl_t ctrl, PKT_public_key *pk)
{
u32 keyid[2];
char *p;
char pkstrbuf[PUBKEY_STRING_SIZE];
char *info;
keyid_from_pk (pk, keyid);
p = get_user_id_native (ctrl, keyid);
info = xtryasprintf ("sec %s/%s %s %s",
pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
keystr (keyid), datestr_from_pk (pk), p);
xfree (p);
return info;
}
void
print_seckey_info (ctrl_t ctrl, PKT_public_key *pk)
{
char *p = format_seckey_info (ctrl, pk);
tty_printf ("\n%s\n", p);
xfree (p);
}
/* Print information about the public key. With FP passed as NULL,
the tty output interface is used, otherwise output is directed to
the given stream. */
void
print_pubkey_info (ctrl_t ctrl, estream_t fp, PKT_public_key *pk)
/* Helper for print_key_info and print_key_info_log. */
static char *
format_key_info (ctrl_t ctrl, PKT_public_key *pk, int secret)
{
u32 keyid[2];
char *p;
char pkstrbuf[PUBKEY_STRING_SIZE];
char *result;
keyid_from_pk (pk, keyid);
@ -212,13 +185,59 @@ print_pubkey_info (ctrl_t ctrl, estream_t fp, PKT_public_key *pk)
else
p = get_user_id_native (ctrl, keyid);
if (!fp)
tty_printf ("\n");
tty_fprintf (fp, "%s %s/%s %s %s\n",
pk->flags.primary? "pub":"sub",
pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
keystr (keyid), datestr_from_pk (pk), p);
result = xtryasprintf ("%s %s/%s %s %s",
secret? (pk->flags.primary? "sec":"ssb")
/* */ : (pk->flags.primary? "pub":"sub"),
pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
keystr (keyid), datestr_from_pk (pk), p);
xfree (p);
return result;
}
/* Print basic information about a public or secret key. With FP
* passed as NULL, the tty output interface is used, otherwise output
* is directed to the given stream. INDENT gives the requested
* indentation; if that is a negative value indentation is suppressed
* for the first line. SECRET tells that the PK has a secret part.
* FIXME: This is similar in use to print_key_line and thus both
* functions should eventually be united.
*/
void
print_key_info (ctrl_t ctrl, estream_t fp,
int indent, PKT_public_key *pk, int secret)
{
int indentabs = indent >= 0? indent : -indent;
char *info;
/* Note: Negative values for INDENT are not yet needed. */
info = format_key_info (ctrl, pk, secret);
if (!fp && indent >= 0)
tty_printf ("\n"); /* (Backward compatibility to old code) */
tty_fprintf (fp, "%*s%s\n", indentabs, "",
info? info : "[Ooops - out of core]");
xfree (info);
}
/* Same as print_key_info put print using the log functions at
* LOGLEVEL. */
void
print_key_info_log (ctrl_t ctrl, int loglevel,
int indent, PKT_public_key *pk, int secret)
{
int indentabs = indent >= 0? indent : -indent;
char *info;
info = format_key_info (ctrl, pk, secret);
log_log (loglevel, "%*s%s\n", indentabs, "",
info? info : "[Ooops - out of core]");
xfree (info);
}
@ -640,7 +659,7 @@ list_one (ctrl_t ctrl, strlist_t names, int secret, int mark_secret)
static void
locate_one (ctrl_t ctrl, strlist_t names)
locate_one (ctrl_t ctrl, strlist_t names, int no_local)
{
int rc = 0;
strlist_t sl;
@ -654,7 +673,10 @@ locate_one (ctrl_t ctrl, strlist_t names)
for (sl = names; sl; sl = sl->next)
{
rc = get_best_pubkey_byname (ctrl, &ctx, NULL, sl->d, &keyblock, 1);
rc = get_best_pubkey_byname (ctrl,
no_local? GET_PUBKEY_NO_LOCAL
/* */: GET_PUBKEY_NORMAL,
&ctx, NULL, sl->d, &keyblock, 1);
if (rc)
{
if (gpg_err_code (rc) != GPG_ERR_NO_PUBKEY)

View File

@ -473,11 +473,14 @@ keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
}
in_cert = 1;
node = lastnode = new_kbnode (pkt);
node = new_kbnode (pkt);
if (!keyblock)
keyblock = node;
keyblock = lastnode = node;
else
add_kbnode (keyblock, node);
{
lastnode->next = node;
lastnode = node;
}
switch (pkt->pkttype)
{
case PKT_PUBLIC_KEY:

View File

@ -333,7 +333,7 @@ parse_keyserver_uri (const char *string,int require_scheme)
{
/* Three slashes means network path with a default host name.
This is a hack because it does not crok all possible
combiantions. We should better repalce all code bythe parser
combinations. We should better replace all code by the parser
from http.c. */
keyserver->path = xstrdup (uri+2);
}
@ -1519,9 +1519,7 @@ keyserver_search (ctrl_t ctrl, strlist_t tokens)
log_info (_("key not found on keyserver\n"));
}
if (gpg_err_code (err) == GPG_ERR_NO_KEYSERVER)
log_error (_("no keyserver known (use option --keyserver)\n"));
else if (gpg_err_code (err) == GPG_ERR_NO_DATA)
if (gpg_err_code (err) == GPG_ERR_NO_DATA)
err = gpg_error (GPG_ERR_NOT_FOUND);
else if (err)
log_error ("error searching keyserver: %s\n", gpg_strerror (err));
@ -2051,8 +2049,9 @@ keyserver_import_wkd (ctrl_t ctrl, const char *name, int quick,
int armor_status = opt.no_armor;
import_filter_t save_filt;
/* Keys returned via WKD are in binary format. */
opt.no_armor = 1;
/* Keys returned via WKD are in binary format. However, we
* relax that requirement and allow also for armored data. */
opt.no_armor = 0;
save_filt = save_and_clear_import_filter ();
if (!save_filt)
err = gpg_error_from_syserror ();

View File

@ -414,6 +414,8 @@ void export_print_stats (export_stats_t stats);
int parse_export_options(char *str,unsigned int *options,int noisy);
gpg_error_t parse_and_set_export_filter (const char *string);
int exact_subkey_match_p (KEYDB_SEARCH_DESC *desc, kbnode_t node);
int export_pubkeys (ctrl_t ctrl, strlist_t users, unsigned int options,
export_stats_t stats);
int export_seckeys (ctrl_t ctrl, strlist_t users, unsigned int options,
@ -456,7 +458,8 @@ struct revocation_reason_info * get_default_uid_revocation_reason(void);
void release_revocation_reason_info( struct revocation_reason_info *reason );
/*-- keylist.c --*/
void public_key_list (ctrl_t ctrl, strlist_t list, int locate_mode );
void public_key_list (ctrl_t ctrl, strlist_t list,
int locate_mode, int no_local);
void secret_key_list (ctrl_t ctrl, strlist_t list );
void print_subpackets_colon(PKT_signature *sig);
void reorder_keyblock (KBNODE keyblock);
@ -470,9 +473,10 @@ void show_keyserver_url(PKT_signature *sig,int indent,int mode);
void show_notation(PKT_signature *sig,int indent,int mode,int which);
void dump_attribs (const PKT_user_id *uid, PKT_public_key *pk);
void set_attrib_fd(int fd);
char *format_seckey_info (ctrl_t ctrl, PKT_public_key *pk);
void print_seckey_info (ctrl_t ctrl, PKT_public_key *pk);
void print_pubkey_info (ctrl_t ctrl, estream_t fp, PKT_public_key *pk);
void print_key_info (ctrl_t ctrl, estream_t fp, int indent,
PKT_public_key *pk, int secret);
void print_key_info_log (ctrl_t ctrl, int loglevel, int indent,
PKT_public_key *pk, int secret);
void print_card_key_info (estream_t fp, KBNODE keyblock);
void print_key_line (ctrl_t ctrl, estream_t fp, PKT_public_key *pk, int secret);

View File

@ -506,19 +506,18 @@ print_pkenc_list (ctrl_t ctrl, struct pubkey_enc_list *list)
for (; list; list = list->next)
{
PKT_public_key *pk;
const char *algstr;
char pkstrbuf[PUBKEY_STRING_SIZE];
char *p;
algstr = openpgp_pk_algo_name (list->pubkey_algo);
pk = xmalloc_clear (sizeof *pk);
if (!algstr)
algstr = "[?]";
pk->pubkey_algo = list->pubkey_algo;
if (!get_pubkey (ctrl, pk, list->keyid))
{
char *p;
log_info (_("encrypted with %u-bit %s key, ID %s, created %s\n"),
nbits_from_pk (pk), algstr, keystr_from_pk(pk),
pubkey_string (pk, pkstrbuf, sizeof pkstrbuf);
log_info (_("encrypted with %s key, ID %s, created %s\n"),
pkstrbuf, keystr_from_pk (pk),
strtimestamp (pk->timestamp));
p = get_user_id_native (ctrl, list->keyid);
log_printf (_(" \"%s\"\n"), p);
@ -526,7 +525,8 @@ print_pkenc_list (ctrl_t ctrl, struct pubkey_enc_list *list)
}
else
log_info (_("encrypted with %s key, ID %s\n"),
algstr, keystr(list->keyid));
openpgp_pk_algo_name (list->pubkey_algo),
keystr(list->keyid));
free_public_key (pk);
}
@ -574,7 +574,7 @@ proc_encrypted (CTX c, PACKET *pkt)
write_status_error ("pkdecrypt_failed", result);
}
}
else
else if (c->pkenc_list)
{
c->dek = xmalloc_secure_clear (sizeof *c->dek);
result = get_session_key (c->ctrl, c->pkenc_list, c->dek);
@ -583,7 +583,7 @@ proc_encrypted (CTX c, PACKET *pkt)
struct pubkey_enc_list *list;
for (list = c->pkenc_list; list; list = list->next)
if (list->result == GPG_ERR_NO_SECKEY)
if (list->result != -1)
{
char buf[20];
snprintf (buf, sizeof buf, "%08lX%08lX",
@ -668,7 +668,13 @@ proc_encrypted (CTX c, PACKET *pkt)
}
}
else if (!c->dek)
result = GPG_ERR_NO_SECKEY;
{
if (c->symkeys && !c->pkenc_list)
result = gpg_error (GPG_ERR_BAD_KEY);
if (!result)
result = gpg_error (GPG_ERR_NO_SECKEY);
}
/* Compute compliance with CO_DE_VS. */
if (!result && is_status_enabled ()
@ -780,7 +786,7 @@ proc_encrypted (CTX c, PACKET *pkt)
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')
&& c->dek && *c->dek->s2k_cacheid != '\0')
{
if (opt.debug)
log_debug ("cleared passphrase cached with ID: %s\n",
@ -1840,7 +1846,6 @@ check_sig_and_print (CTX c, kbnode_t node)
int is_revkey = 0;
char *issuer_fpr = NULL;
PKT_public_key *pk = NULL; /* The public key for the signature or NULL. */
int tried_ks_by_fpr;
const void *extrahash = NULL;
size_t extrahashlen = 0;
@ -1999,12 +2004,17 @@ check_sig_and_print (CTX c, kbnode_t node)
rc = do_check_sig (c, node, extrahash, extrahashlen,
NULL, &is_expkey, &is_revkey, &pk);
/* If the key isn't found, check for a preferred keyserver. */
if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY && sig->flags.pref_ks)
/* If the key isn't found, check for a preferred keyserver. Note
* that this is only done if honor-keyserver-url has been set. We
* test for this in the loop so that we can show info about the
* preferred keyservers. */
if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY
&& sig->flags.pref_ks)
{
const byte *p;
int seq = 0;
size_t n;
int any_pref_ks = 0;
while ((p=enum_sig_subpkt (sig->hashed,SIGSUBPKT_PREF_KS,&n,&seq,NULL)))
{
@ -2015,9 +2025,10 @@ check_sig_and_print (CTX c, kbnode_t node)
log_info(_("Key available at: ") );
print_utf8_buffer (log_get_stream(), p, n);
log_printf ("\n");
any_pref_ks = 1;
if (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE
&& opt.keyserver_options.options&KEYSERVER_HONOR_KEYSERVER_URL)
if ((opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE)
&& (opt.keyserver_options.options&KEYSERVER_HONOR_KEYSERVER_URL))
{
struct keyserver_spec *spec;
@ -2026,6 +2037,10 @@ check_sig_and_print (CTX c, kbnode_t node)
{
int res;
if (DBG_LOOKUP)
log_debug ("trying auto-key-retrieve method %s\n",
"Pref-KS");
free_public_key (pk);
pk = NULL;
glo_ctrl.in_auto_key_retrieve++;
@ -2034,6 +2049,9 @@ check_sig_and_print (CTX c, kbnode_t node)
if (!res)
rc = do_check_sig (c, node, extrahash, extrahashlen,
NULL, &is_expkey, &is_revkey, &pk);
else if (DBG_LOOKUP)
log_debug ("lookup via %s failed: %s\n", "Pref-KS",
gpg_strerror (res));
free_keyserver_spec (spec);
if (!rc)
@ -2041,10 +2059,44 @@ check_sig_and_print (CTX c, kbnode_t node)
}
}
}
if (any_pref_ks
&& (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE)
&& !(opt.keyserver_options.options&KEYSERVER_HONOR_KEYSERVER_URL))
log_info (_("Note: Use '%s' to make use of this info\n"),
"--keyserver-option honor-keyserver-url");
}
/* If the above methods didn't work, our next try is to retrieve the
* key from the WKD. This requires that WKD is in the AKL and the
* Signer's UID is in the signature. */
if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY
&& (opt.keyserver_options.options & KEYSERVER_AUTO_KEY_RETRIEVE)
&& !opt.flags.disable_signer_uid
&& akl_has_wkd_method ()
&& sig->signers_uid)
{
int res;
if (DBG_LOOKUP)
log_debug ("trying auto-key-retrieve method %s\n", "WKD");
free_public_key (pk);
pk = NULL;
glo_ctrl.in_auto_key_retrieve++;
res = keyserver_import_wkd (c->ctrl, sig->signers_uid, 1, NULL, NULL);
glo_ctrl.in_auto_key_retrieve--;
/* Fixme: If the fingerprint is embedded in the signature,
* compare it to the fingerprint of the returned key. */
if (!res)
rc = do_check_sig (c, node, extrahash, extrahashlen,
NULL, &is_expkey, &is_revkey, &pk);
else if (DBG_LOOKUP)
log_debug ("lookup via %s failed: %s\n", "WKD", gpg_strerror (res));
}
/* If the avove methods didn't work, our next try is to use the URI
* from a DNS PKA record. */
* from a DNS PKA record. This is a legacy method which will
* eventually be removed. */
if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY
&& (opt.keyserver_options.options & KEYSERVER_AUTO_KEY_RETRIEVE)
&& (opt.keyserver_options.options & KEYSERVER_HONOR_PKA_RECORD))
@ -2061,6 +2113,9 @@ check_sig_and_print (CTX c, kbnode_t node)
spec = parse_keyserver_uri (uri, 1);
if (spec)
{
if (DBG_LOOKUP)
log_debug ("trying auto-key-retrieve method %s\n", "PKA");
free_public_key (pk);
pk = NULL;
glo_ctrl.in_auto_key_retrieve++;
@ -2070,16 +2125,16 @@ check_sig_and_print (CTX c, kbnode_t node)
if (!res)
rc = do_check_sig (c, node, extrahash, extrahashlen,
NULL, &is_expkey, &is_revkey, &pk);
else if (DBG_LOOKUP)
log_debug ("lookup via %s failed: %s\n", "PKA",
gpg_strerror (res));
}
}
}
/* If the above methods didn't work, our next try is to locate
* the key via its fingerprint from a keyserver. This requires
* that the signers fingerprint is encoded in the signature. We
* favor this over the WKD method (to be tried next), because an
* arbitrary keyserver is less subject to web bug like monitoring. */
tried_ks_by_fpr = 0;
* that the signers fingerprint is encoded in the signature. */
if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY
&& (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE)
&& keyserver_any_configured (c->ctrl))
@ -2091,60 +2146,23 @@ check_sig_and_print (CTX c, kbnode_t node)
p = issuer_fpr_raw (sig, &n);
if (p)
{
if (DBG_LOOKUP)
log_debug ("trying auto-key-retrieve method %s\n", "KS");
/* v4 or v5 packet with a SHA-1/256 fingerprint. */
free_public_key (pk);
pk = NULL;
glo_ctrl.in_auto_key_retrieve++;
res = keyserver_import_fprint (c->ctrl, p, n, opt.keyserver, 1);
tried_ks_by_fpr = 1;
glo_ctrl.in_auto_key_retrieve--;
if (!res)
rc = do_check_sig (c, node, extrahash, extrahashlen,
NULL, &is_expkey, &is_revkey, &pk);
else if (DBG_LOOKUP)
log_debug ("lookup via %s failed: %s\n", "KS", gpg_strerror (res));
}
}
/* If the above methods didn't work, our next try is to retrieve the
* key from the WKD. */
if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY
&& (opt.keyserver_options.options & KEYSERVER_AUTO_KEY_RETRIEVE)
&& !opt.flags.disable_signer_uid
&& akl_has_wkd_method ()
&& sig->signers_uid)
{
int res;
free_public_key (pk);
pk = NULL;
glo_ctrl.in_auto_key_retrieve++;
res = keyserver_import_wkd (c->ctrl, sig->signers_uid, 1, NULL, NULL);
glo_ctrl.in_auto_key_retrieve--;
/* Fixme: If the fingerprint is embedded in the signature,
* compare it to the fingerprint of the returned key. */
if (!res)
rc = do_check_sig (c, node, extrahash, extrahashlen,
NULL, &is_expkey, &is_revkey, &pk);
}
/* If the above methods did't work, our next try is to use a
* keyserver. */
if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY
&& (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE)
&& !tried_ks_by_fpr
&& keyserver_any_configured (c->ctrl))
{
int res;
free_public_key (pk);
pk = NULL;
glo_ctrl.in_auto_key_retrieve++;
res = keyserver_import_keyid (c->ctrl, sig->keyid, opt.keyserver, 1);
glo_ctrl.in_auto_key_retrieve--;
if (!res)
rc = do_check_sig (c, node, extrahash, extrahashlen,
NULL, &is_expkey, &is_revkey, &pk);
}
if (!rc || gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE)
{
kbnode_t un, keyblock;

689
g10/objcache.c Normal file
View File

@ -0,0 +1,689 @@
/* objcache.c - Caching functions for keys and user ids.
* Copyright (C) 2019 g10 Code GmbH
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "gpg.h"
#include "../common/util.h"
#include "packet.h"
#include "keydb.h"
#include "options.h"
#include "objcache.h"
/* Note that max value for uid_items is actually a the threshold when
* we start to look for ietms which can be removed. */
#define NO_OF_UID_ITEM_BUCKETS 107
#define MAX_UID_ITEMS_PER_BUCKET 20
#define NO_OF_KEY_ITEM_BUCKETS 383
#define MAX_KEY_ITEMS_PER_BUCKET 20
/* An object to store a user id. This describes an item in the linked
* lists of a bucket in hash table. The reference count will
* eventually be used to remove items from the table. */
typedef struct uid_item_s
{
struct uid_item_s *next;
unsigned int refcount; /* The reference count for this item. */
unsigned int namelen; /* The length of the UID sans the nul. */
char name[1];
} *uid_item_t;
static uid_item_t *uid_table; /* Hash table for with user ids. */
static size_t uid_table_size; /* Number of allocated buckets. */
static unsigned int uid_table_max; /* Max. # of items in a bucket. */
static unsigned int uid_table_added; /* # of items added. */
static unsigned int uid_table_dropped;/* # of items dropped. */
/* An object to store properties of a key. Note that this can be used
* for a primary or a subkey. The key is linked to a user if that
* exists. */
typedef struct key_item_s
{
struct key_item_s *next;
unsigned int usecount;
byte fprlen;
char fpr[MAX_FINGERPRINT_LEN];
u32 keyid[2];
uid_item_t ui; /* NULL of a ref'ed user id item. */
} *key_item_t;
static key_item_t *key_table; /* Hash table with the keys. */
static size_t key_table_size; /* Number of allocated buckents. */
static unsigned int key_table_max; /* Max. # of items in a bucket. */
static unsigned int key_table_added; /* # of items added. */
static unsigned int key_table_dropped;/* # of items dropped. */
static key_item_t key_item_attic; /* List of freed items. */
/* Dump stats. */
void
objcache_dump_stats (void)
{
unsigned int idx;
int len, minlen, maxlen;
unsigned int count, attic, empty;
key_item_t ki;
uid_item_t ui;
count = empty = 0;
minlen = -1;
maxlen = 0;
for (idx = 0; idx < key_table_size; idx++)
{
len = 0;
for (ki = key_table[idx]; ki; ki = ki->next)
{
count++;
len++;
/* log_debug ("key bucket %u: kid=%08lX used=%u ui=%p\n", */
/* idx, (ulong)ki->keyid[0], ki->usecount, ki->ui); */
}
if (len > maxlen)
maxlen = len;
if (!len)
empty++;
else if (minlen == -1 || len < minlen)
minlen = len;
}
for (attic=0, ki = key_item_attic; ki; ki = ki->next)
attic++;
log_info ("objcache: keys=%u/%u/%u chains=%u,%d..%d buckets=%zu/%u"
" attic=%u\n",
count, key_table_added, key_table_dropped,
empty, minlen > 0? minlen : 0, maxlen,
key_table_size, key_table_max, attic);
count = empty = 0;
minlen = -1;
maxlen = 0;
for (idx = 0; idx < uid_table_size; idx++)
{
len = 0;
for (ui = uid_table[idx]; ui; ui = ui->next)
{
count++;
len++;
/* log_debug ("uid bucket %u: %p ref=%u l=%u (%.20s)\n", */
/* idx, ui, ui->refcount, ui->namelen, ui->name); */
}
if (len > maxlen)
maxlen = len;
if (!len)
empty++;
else if (minlen == -1 || len < minlen)
minlen = len;
}
log_info ("objcache: uids=%u/%u/%u chains=%u,%d..%d buckets=%zu/%u\n",
count, uid_table_added, uid_table_dropped,
empty, minlen > 0? minlen : 0, maxlen,
uid_table_size, uid_table_max);
}
/* The hash function we use for the uid_table. Must not call a system
* function. */
static inline unsigned int
uid_table_hasher (const char *name, unsigned namelen)
{
const unsigned char *s = (const unsigned char*)name;
unsigned int hashval = 0;
unsigned int carry;
for (; namelen; namelen--, s++)
{
hashval = (hashval << 4) + *s;
if ((carry = (hashval & 0xf0000000)))
{
hashval ^= (carry >> 24);
hashval ^= carry;
}
}
return hashval % uid_table_size;
}
/* Run time allocation of the uid table. This allows us to eventually
* add an option to gpg to control the size. */
static void
uid_table_init (void)
{
if (uid_table)
return;
uid_table_size = NO_OF_UID_ITEM_BUCKETS;
uid_table_max = MAX_UID_ITEMS_PER_BUCKET;
uid_table = xcalloc (uid_table_size, sizeof *uid_table);
}
static uid_item_t
uid_item_ref (uid_item_t ui)
{
if (ui)
ui->refcount++;
return ui;
}
static void
uid_item_unref (uid_item_t uid)
{
if (!uid)
return;
if (!uid->refcount)
log_fatal ("too many unrefs for uid_item\n");
uid->refcount--;
/* We do not release the item here because that would require that
* we locate the head of the list which has this item. This will
* take too long and thus the item is removed when we need to purge
* some items for the list during uid_item_put. */
}
/* Put (NAME,NAMELEN) into the UID_TABLE and return the item. The
* reference count for that item is incremented. NULL is return on an
* allocation error. The caller should release the returned item
* using uid_item_unref. */
static uid_item_t
uid_table_put (const char *name, unsigned int namelen)
{
unsigned int hash;
uid_item_t ui;
unsigned int count;
if (!uid_table)
uid_table_init ();
hash = uid_table_hasher (name, namelen);
for (ui = uid_table[hash], count = 0; ui; ui = ui->next, count++)
if (ui->namelen == namelen && !memcmp (ui->name, name, namelen))
return uid_item_ref (ui); /* Found. */
/* If the bucket is full remove all unrefed items. */
if (count >= uid_table_max)
{
uid_item_t ui_next, ui_prev, list_head, drop_head;
/* No syscalls from here .. */
list_head = uid_table[hash];
drop_head = NULL;
while (list_head && !list_head->refcount)
{
ui = list_head;
list_head = ui->next;
ui->next = drop_head;
drop_head = ui;
}
if ((ui_prev = list_head))
for (ui = ui_prev->next; ui; ui = ui_next)
{
ui_next = ui->next;
if (!ui->refcount)
{
ui->next = drop_head;
drop_head = ui;
ui_prev->next = ui_next;
}
else
ui_prev = ui;
}
uid_table[hash] = list_head;
/* ... to here */
for (ui = drop_head; ui; ui = ui_next)
{
ui_next = ui->next;
xfree (ui);
uid_table_dropped++;
}
}
count = uid_table_added + uid_table_dropped;
ui = xtrycalloc (1, sizeof *ui + namelen);
if (!ui)
return NULL; /* Out of core. */
if (count != uid_table_added + uid_table_dropped)
{
/* During the malloc another thread added an item. Thus we need
* to check again. */
uid_item_t ui_new = ui;
for (ui = uid_table[hash]; ui; ui = ui->next)
if (ui->namelen == namelen && !memcmp (ui->name, name, namelen))
{
/* Found. */
xfree (ui_new);
return uid_item_ref (ui);
}
ui = ui_new;
}
memcpy (ui->name, name, namelen);
ui->name[namelen] = 0; /* Extra Nul so we can use it as a string. */
ui->namelen = namelen;
ui->refcount = 1;
ui->next = uid_table[hash];
uid_table[hash] = ui;
uid_table_added++;
return ui;
}
/* The hash function we use for the key_table. Must not call a system
* function. */
static inline unsigned int
key_table_hasher (u32 *keyid)
{
/* A fingerprint could be used directly as a hash value. However,
* we use the keyid here because it is used in encrypted packets and
* older signatures to identify a key. Since v4 keys the keyid is
* anyway a part of the fingerprint so it quickly extracted from a
* fingerprint. Note that v3 keys are not supported by gpg. */
return keyid[0] % key_table_size;
}
/* Run time allocation of the key table. This allows us to eventually
* add an option to gpg to control the size. */
static void
key_table_init (void)
{
if (key_table)
return;
key_table_size = NO_OF_KEY_ITEM_BUCKETS;
key_table_max = MAX_KEY_ITEMS_PER_BUCKET;
key_table = xcalloc (key_table_size, sizeof *key_table);
}
static void
key_item_free (key_item_t ki)
{
if (!ki)
return;
uid_item_unref (ki->ui);
ki->ui = NULL;
ki->next = key_item_attic;
key_item_attic = ki;
}
/* Get a key item from PK or if that is NULL from KEYID. The
* reference count for that item is incremented. NULL is return if it
* was not found. */
static key_item_t
key_table_get (PKT_public_key *pk, u32 *keyid)
{
unsigned int hash;
key_item_t ki, ki2;
if (!key_table)
key_table_init ();
if (pk)
{
byte fpr[MAX_FINGERPRINT_LEN];
size_t fprlen;
u32 tmpkeyid[2];
fingerprint_from_pk (pk, fpr, &fprlen);
keyid_from_pk (pk, tmpkeyid);
hash = key_table_hasher (tmpkeyid);
for (ki = key_table[hash]; ki; ki = ki->next)
if (ki->fprlen == fprlen && !memcmp (ki->fpr, fpr, fprlen))
return ki; /* Found */
}
else if (keyid)
{
hash = key_table_hasher (keyid);
for (ki = key_table[hash]; ki; ki = ki->next)
if (ki->keyid[0] == keyid[0] && ki->keyid[1] == keyid[1])
{
/* Found. We need to check for dups. */
for (ki2 = ki->next; ki2; ki2 = ki2->next)
if (ki2->keyid[0] == keyid[0] && ki2->keyid[1] == keyid[1])
return NULL; /* Duplicated keyid - retrun NULL. */
/* This is the only one - return it. */
return ki;
}
}
return NULL;
}
/* Helper for the qsort in key_table_put. */
static int
compare_key_items (const void *arg_a, const void *arg_b)
{
const key_item_t a = *(const key_item_t *)arg_a;
const key_item_t b = *(const key_item_t *)arg_b;
/* Reverse sort on the usecount. */
if (a->usecount > b->usecount)
return -1;
else if (a->usecount == b->usecount)
return 0;
else
return 1;
}
/* Put PK into the KEY_TABLE and return a key item. The reference
* count for that item is incremented. If UI is given it is put into
* the entry. NULL is return on an allocation error. */
static key_item_t
key_table_put (PKT_public_key *pk, uid_item_t ui)
{
unsigned int hash;
key_item_t ki;
u32 keyid[2];
byte fpr[MAX_FINGERPRINT_LEN];
size_t fprlen;
unsigned int count, n;
if (!key_table)
key_table_init ();
fingerprint_from_pk (pk, fpr, &fprlen);
keyid_from_pk (pk, keyid);
hash = key_table_hasher (keyid);
for (ki = key_table[hash], count=0; ki; ki = ki->next, count++)
if (ki->fprlen == fprlen && !memcmp (ki->fpr, fpr, fprlen))
return ki; /* Found */
/* If the bucket is full remove a couple of items. */
if (count >= key_table_max)
{
key_item_t list_head, *list_tailp, ki_next;
key_item_t *array;
int narray, idx;
/* Unlink from the global list so that other threads don't
* disturb us. If another thread adds or removes something only
* one will be the winner. Bad luck for the drooped cache items
* but after all it is just a cache. */
list_head = key_table[hash];
key_table[hash] = NULL;
/* Put all items into an array for sorting. */
array = xtrycalloc (count, sizeof *array);
if (!array)
{
/* That's bad; give up all items of the bucket. */
log_info ("Note: malloc failed while purging from the key_tabe: %s\n",
gpg_strerror (gpg_error_from_syserror ()));
goto leave_drop;
}
narray = 0;
for (ki = list_head; ki; ki = ki_next)
{
ki_next = ki->next;
array[narray++] = ki;
ki->next = NULL;
}
log_assert (narray == count);
/* Sort the array and put half of it onto a new list. */
qsort (array, narray, sizeof *array, compare_key_items);
list_head = NULL;
list_tailp = &list_head;
for (idx=0; idx < narray/2; idx++)
{
*list_tailp = array[idx];
list_tailp = &array[idx]->next;
}
/* Put the new list into the bucket. */
ki = key_table[hash];
key_table[hash] = list_head;
list_head = ki;
/* Free the remaining items and the array. */
for (; idx < narray; idx++)
{
key_item_free (array[idx]);
key_table_dropped++;
}
xfree (array);
leave_drop:
/* Free any items added in the meantime by other threads. This
* is also used in case of a malloc problem (which won't update
* the counters, though). */
for ( ; list_head; list_head = ki_next)
{
ki_next = list_head->next;
key_item_free (list_head);
}
}
/* Add an item to the bucket. We allocate a whole block of items
* for cache performace reasons. */
if (!key_item_attic)
{
key_item_t kiblock;
int kiblocksize = 256;
kiblock = xtrymalloc (kiblocksize * sizeof *kiblock);
if (!kiblock)
return NULL; /* Out of core. */
for (n = 0; n < kiblocksize; n++)
{
ki = kiblock + n;
ki->next = key_item_attic;
key_item_attic = ki;
}
/* During the malloc another thread may have changed the bucket.
* Thus we need to check again. */
for (ki = key_table[hash]; ki; ki = ki->next)
if (ki->fprlen == fprlen && !memcmp (ki->fpr, fpr, fprlen))
return ki; /* Found */
}
/* We now know that there is an item in the attic. */
ki = key_item_attic;
key_item_attic = ki->next;
ki->next = NULL;
memcpy (ki->fpr, fpr, fprlen);
ki->fprlen = fprlen;
ki->keyid[0] = keyid[0];
ki->keyid[1] = keyid[1];
ki->ui = uid_item_ref (ui);
ki->usecount = 0;
ki->next = key_table[hash];
key_table[hash] = ki;
key_table_added++;
return ki;
}
/* Return the user ID from the given keyblock. We use the primary uid
* flag which should have already been set. The returned value is
* only valid as long as the given keyblock is not changed. */
static const char *
primary_uid_from_keyblock (kbnode_t keyblock, size_t *uidlen)
{
kbnode_t k;
for (k = keyblock; k; k = k->next)
{
if (k->pkt->pkttype == PKT_USER_ID
&& !k->pkt->pkt.user_id->attrib_data
&& k->pkt->pkt.user_id->flags.primary)
{
*uidlen = k->pkt->pkt.user_id->len;
return k->pkt->pkt.user_id->name;
}
}
return NULL;
}
/* Store the associations of keyid/fingerprint and userid. Only
* public keys should be fed to this function. */
void
cache_put_keyblock (kbnode_t keyblock)
{
uid_item_t ui = NULL;
kbnode_t k;
restart:
for (k = keyblock; k; k = k->next)
{
if (k->pkt->pkttype == PKT_PUBLIC_KEY
|| k->pkt->pkttype == PKT_PUBLIC_SUBKEY)
{
if (!ui)
{
/* Initially we just test for an entry to avoid the need
* to create a user id item for a put. Only if we miss
* key in the cache we create a user id and restart. */
if (!key_table_get (k->pkt->pkt.public_key, NULL))
{
const char *uid;
size_t uidlen;
uid = primary_uid_from_keyblock (keyblock, &uidlen);
if (uid)
{
ui = uid_table_put (uid, uidlen);
if (!ui)
{
log_info ("Note: failed to cache a user id: %s\n",
gpg_strerror (gpg_error_from_syserror ()));
goto leave;
}
goto restart;
}
}
}
else /* With a UID we use the update cache mode. */
{
if (!key_table_put (k->pkt->pkt.public_key, ui))
{
log_info ("Note: failed to cache a key: %s\n",
gpg_strerror (gpg_error_from_syserror ()));
goto leave;
}
}
}
}
leave:
uid_item_unref (ui);
}
/* Return the user id string for KEYID. If a user id is not found (or
* on malloc error) NULL is returned. If R_LENGTH is not NULL the
* length of the user id is stored there; this does not included the
* always appended nul. Note that a user id may include an internal
* nul which can be detected by the caller by comparing to the
* returned length. */
char *
cache_get_uid_bykid (u32 *keyid, unsigned int *r_length)
{
key_item_t ki;
char *p;
if (r_length)
*r_length = 0;
ki = key_table_get (NULL, keyid);
if (!ki)
return NULL; /* Not found or duplicate keyid. */
if (!ki->ui)
p = NULL; /* No user id known for key. */
else
{
p = xtrymalloc (ki->ui->namelen + 1);
if (p)
{
memcpy (p, ki->ui->name, ki->ui->namelen + 1);
if (r_length)
*r_length = ki->ui->namelen;
ki->usecount++;
}
}
return p;
}
/* Return the user id string for FPR with FPRLEN. If a user id is not
* found (or on malloc error) NULL is returned. If R_LENGTH is not
* NULL the length of the user id is stored there; this does not
* included the always appended nul. Note that a user id may include
* an internal nul which can be detected by the caller by comparing to
* the returned length. */
char *
cache_get_uid_byfpr (const byte *fpr, size_t fprlen, size_t *r_length)
{
char *p;
unsigned int hash;
u32 keyid[2];
key_item_t ki;
if (r_length)
*r_length = 0;
if (!key_table)
return NULL;
keyid_from_fingerprint (NULL, fpr, fprlen, keyid);
hash = key_table_hasher (keyid);
for (ki = key_table[hash]; ki; ki = ki->next)
if (ki->fprlen == fprlen && !memcmp (ki->fpr, fpr, fprlen))
break; /* Found */
if (!ki)
return NULL; /* Not found. */
if (!ki->ui)
p = NULL; /* No user id known for key. */
else
{
p = xtrymalloc (ki->ui->namelen + 1);
if (p)
{
memcpy (p, ki->ui->name, ki->ui->namelen + 1);
if (r_length)
*r_length = ki->ui->namelen;
ki->usecount++;
}
}
return p;
}

29
g10/objcache.h Normal file
View File

@ -0,0 +1,29 @@
/* objcache.h - Caching functions for keys and user ids.
* Copyright (C) 2019 g10 Code GmbH
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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
*/
#ifndef GNUPG_G10_OBJCACHE_H
#define GNUPG_G10_OBJCACHE_H
void objcache_dump_stats (void);
void cache_put_keyblock (kbnode_t keyblock);
char *cache_get_uid_bykid (u32 *keyid, unsigned int *r_length);
char *cache_get_uid_byfpr (const byte *fpr, size_t fprlen, size_t *r_length);
#endif /*GNUPG_G10_OBJCACHE_H*/

View File

@ -249,6 +249,8 @@ struct
unsigned int disable_signer_uid:1;
/* Flag to enable experimental features from RFC4880bis. */
unsigned int rfc4880bis:1;
/* Hack: --output is not given but OUTFILE was temporary set to "-". */
unsigned int dummy_outfile:1;
} flags;
/* Linked list of ways to find a key if the key isn't on the local
@ -361,6 +363,7 @@ EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode;
#define IMPORT_REPAIR_KEYS (1<<11)
#define IMPORT_DRY_RUN (1<<12)
#define IMPORT_DROP_UIDS (1<<13)
#define IMPORT_SELF_SIGS_ONLY (1<<14)
#define EXPORT_LOCAL_SIGS (1<<0)
#define EXPORT_ATTRIBUTES (1<<1)

View File

@ -33,6 +33,11 @@
#define DEBUG_PARSE_PACKET 1
/* Maximum length of packets to avoid excessive memory allocation. */
#define MAX_KEY_PACKET_LENGTH (256 * 1024)
#define MAX_UID_PACKET_LENGTH ( 2 * 1024)
#define MAX_COMMENT_PACKET_LENGTH ( 64 * 1024)
#define MAX_ATTR_PACKET_LENGTH ( 16 * 1024*1024)
/* Constants to allocate static MPI arrays. */
#define PUBKEY_MAX_NPKEY OPENPGP_MAX_NPKEY
@ -394,6 +399,7 @@ typedef struct
byte pubkey_algo;
byte pubkey_usage; /* for now only used to pass it to getkey() */
byte req_usage; /* hack to pass a request to getkey() */
byte fprlen; /* 0 or length of FPR. */
u32 has_expired; /* set to the expiration date if expired */
/* keyid of the primary key. Never access this value directly.
Instead, use pk_main_keyid(). */
@ -401,6 +407,8 @@ typedef struct
/* keyid of this key. Never access this value directly! Instead,
use pk_keyid(). */
u32 keyid[2];
/* Fingerprint of the key. Only valid if FPRLEN is not 0. */
byte fpr[MAX_FINGERPRINT_LEN];
prefitem_t *prefs; /* list of preferences (may be NULL) */
struct
{
@ -928,7 +936,7 @@ int ask_for_detached_datafile( gcry_md_hd_t md, gcry_md_hd_t md2,
int make_keysig_packet (ctrl_t ctrl,
PKT_signature **ret_sig, PKT_public_key *pk,
PKT_user_id *uid, PKT_public_key *subpk,
PKT_public_key *pksk, int sigclass, int digest_algo,
PKT_public_key *pksk, int sigclass,
u32 timestamp, u32 duration,
int (*mksubpkt)(PKT_signature *, void *),
void *opaque,

View File

@ -35,14 +35,9 @@
#include "main.h"
#include "../common/i18n.h"
#include "../common/host2net.h"
#include "../common/mbox-util.h"
/* Maximum length of packets to avoid excessive memory allocation. */
#define MAX_KEY_PACKET_LENGTH (256 * 1024)
#define MAX_UID_PACKET_LENGTH ( 2 * 1024)
#define MAX_COMMENT_PACKET_LENGTH ( 64 * 1024)
#define MAX_ATTR_PACKET_LENGTH ( 16 * 1024*1024)
static int mpi_print_mode;
static int list_mode;
static estream_t listfp;
@ -2118,12 +2113,20 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIGNERS_UID, &len);
if (p && len)
{
char *mbox;
sig->signers_uid = try_make_printable_string (p, len, 0);
if (!sig->signers_uid)
{
rc = gpg_error_from_syserror ();
goto leave;
}
mbox = mailbox_from_userid (sig->signers_uid, 0);
if (mbox)
{
xfree (sig->signers_uid);
sig->signers_uid = mbox;
}
}
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_NOTATION, NULL);

View File

@ -262,7 +262,8 @@ char *image_type_to_string(byte type,int style)
}
#if !defined(FIXED_PHOTO_VIEWER) && !defined(DISABLE_PHOTO_VIEWER)
static const char *get_default_photo_command(void)
static const char *
get_default_photo_command(void)
{
#if defined(_WIN32)
OSVERSIONINFO osvi;
@ -274,14 +275,21 @@ static const char *get_default_photo_command(void)
if(osvi.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS)
return "start /w %i";
else
return "cmd /c start /w %i";
return "!ShellExecute 400 %i";
#elif defined(__APPLE__)
/* OS X. This really needs more than just __APPLE__. */
return "open %I";
#elif defined(__riscos__)
return "Filer_Run %I";
#else
return "xloadimage -fork -quiet -title 'KeyID 0x%k' stdin";
if (!path_access ("xloadimage", X_OK))
return "xloadimage -fork -quiet -title 'KeyID 0x%k' stdin";
else if (!path_access ("display",X_OK))
return "display -title 'KeyID 0x%k' %i";
else if (getuid () && !path_access ("xdg-open", X_OK))
return "xdg-open %i";
else
return "/bin/true";
#endif
}
#endif
@ -312,6 +320,8 @@ show_photos (ctrl_t ctrl, const struct user_attribute *attrs, int count,
if (pk)
keyid_from_pk (pk, kid);
es_fflush (es_stdout);
for(i=0;i<count;i++)
if(attrs[i].type==ATTRIB_IMAGE &&
parse_image_header(&attrs[i],&args.imagetype,&len))

View File

@ -475,7 +475,7 @@ do_we_trust_pre (ctrl_t ctrl, PKT_public_key *pk, unsigned int trustlevel )
if( !opt.batch && !rc )
{
print_pubkey_info (ctrl, NULL,pk);
print_key_info (ctrl, NULL, 0, pk, 0);
print_fingerprint (ctrl, NULL, pk, 2);
tty_printf("\n");
@ -834,7 +834,8 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
if (from_file)
rc = get_pubkey_fromfile (ctrl, pk, name);
else
rc = get_best_pubkey_byname (ctrl, NULL, pk, name, &keyblock, 0);
rc = get_best_pubkey_byname (ctrl, GET_PUBKEY_NORMAL,
NULL, pk, name, &keyblock, 0);
if (rc)
{
int code;
@ -975,8 +976,8 @@ build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list)
r->pk = xmalloc_clear (sizeof *r->pk);
r->pk->req_usage = PUBKEY_USAGE_ENC;
rc = get_pubkey_byname (ctrl, NULL, r->pk, default_key,
NULL, NULL, 0, 1);
rc = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL,
NULL, r->pk, default_key, NULL, NULL, 0);
if (rc)
{
xfree (r->pk);
@ -1041,8 +1042,8 @@ build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list)
/* We explicitly allow encrypt-to to an disabled key; thus
we pass 1 for the second last argument and 1 as the last
argument to disable AKL. */
if ( (rc = get_pubkey_byname (ctrl,
NULL, pk, rov->d, NULL, NULL, 1, 1)) )
if ((rc = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL,
NULL, pk, rov->d, NULL, NULL, 1)))
{
free_public_key ( pk ); pk = NULL;
log_error (_("%s: skipped: %s\n"), rov->d, gpg_strerror (rc) );
@ -1179,7 +1180,8 @@ build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list)
free_public_key (pk);
pk = xmalloc_clear( sizeof *pk );
pk->req_usage = PUBKEY_USAGE_ENC;
rc = get_pubkey_byname (ctrl, NULL, pk, answer, NULL, NULL, 0, 0 );
rc = get_pubkey_byname (ctrl, GET_PUBKEY_NORMAL,
NULL, pk, answer, NULL, NULL, 0);
if (rc)
tty_printf(_("No such user ID.\n"));
else if ( !(rc=openpgp_pk_test_algo2 (pk->pubkey_algo,
@ -1257,7 +1259,8 @@ build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list)
/* The default recipient is allowed to be disabled; thus pass 1
as second last argument. We also don't want an AKL. */
rc = get_pubkey_byname (ctrl, NULL, pk, def_rec, NULL, NULL, 1, 1);
rc = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL,
NULL, pk, def_rec, NULL, NULL, 1);
if (rc)
log_error(_("unknown default recipient \"%s\"\n"), def_rec );
else if ( !(rc=openpgp_pk_test_algo2(pk->pubkey_algo,

View File

@ -70,7 +70,8 @@ get_output_file (const byte *embedded_name, int embedded_namelen,
goto leave;
}
}
else if (opt.outfile)
else if (opt.outfile
&& !(opt.flags.use_embedded_filename && opt.flags.dummy_outfile))
{
fname = xtrystrdup (opt.outfile);
if (!fname)

View File

@ -75,25 +75,21 @@ gpg_error_t
get_session_key (ctrl_t ctrl, struct pubkey_enc_list *list, DEK *dek)
{
PKT_public_key *sk = NULL;
int rc;
gpg_error_t err;
void *enum_context = NULL;
u32 keyid[2];
int search_for_secret_keys = 1;
struct pubkey_enc_list *k;
if (DBG_CLOCK)
log_clock ("get_session_key enter");
while (search_for_secret_keys)
{
struct pubkey_enc_list *k;
sk = xmalloc_clear (sizeof *sk);
rc = enum_secret_keys (ctrl, &enum_context, sk);
if (rc)
{
rc = GPG_ERR_NO_SECKEY;
break;
}
err = enum_secret_keys (ctrl, &enum_context, sk);
if (err)
break;
if (!(sk->pubkey_usage & PUBKEY_USAGE_ENC))
continue;
@ -132,8 +128,6 @@ get_session_key (ctrl_t ctrl, struct pubkey_enc_list *list, DEK *dek)
if (openpgp_pk_test_algo2 (k->pubkey_algo, PUBKEY_USAGE_ENC))
continue;
k->result = GPG_ERR_NO_SECKEY;
if (sk->pubkey_algo != k->pubkey_algo)
continue;
@ -154,16 +148,16 @@ get_session_key (ctrl_t ctrl, struct pubkey_enc_list *list, DEK *dek)
else
continue;
rc = get_it (ctrl, k, dek, sk, keyid);
if (!rc)
err = get_it (ctrl, k, dek, sk, keyid);
k->result = err;
if (!err)
{
k->result = 0;
if (!opt.quiet && !k->keyid[0] && !k->keyid[1])
log_info (_("okay, we are the anonymous recipient.\n"));
search_for_secret_keys = 0;
break;
}
else if (gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED)
else if (gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
{
search_for_secret_keys = 0;
break; /* Don't try any more secret keys. */
@ -172,9 +166,19 @@ get_session_key (ctrl_t ctrl, struct pubkey_enc_list *list, DEK *dek)
}
enum_secret_keys (ctrl, &enum_context, NULL); /* free context */
if (gpg_err_code (err) == GPG_ERR_EOF)
{
err = gpg_error (GPG_ERR_NO_SECKEY);
/* Return the last specific error, if any. */
for (k = list; k; k = k->next)
if (k->result != -1)
err = k->result;
}
if (DBG_CLOCK)
log_clock ("get_session_key leave");
return rc;
return err;
}
@ -319,6 +323,16 @@ get_it (ctrl_t ctrl,
err = gpg_error (GPG_ERR_WRONG_SECKEY);
goto leave;
}
/* FIXME: Actually the leading zero is required but due to
* the way we encode the output in libgcrypt as an MPI we
* are not able to encode that leading zero. However, when
* using a Smartcard we are doing it the right way and
* therefore we have to skip the zero. This should be fixed
* in gpg-agent of course. */
if (!frame[n])
n++;
if (frame[n] == 1 && frame[nframe - 1] == 2)
{
log_info (_("old encoding of the DEK is not supported\n"));

View File

@ -305,11 +305,11 @@ gen_desig_revoke (ctrl_t ctrl, const char *uname, strlist_t locusr)
any = 1;
print_pubkey_info (ctrl, NULL, pk);
print_key_info (ctrl, NULL, 0, pk, 0);
tty_printf ("\n");
tty_printf (_("To be revoked by:\n"));
print_seckey_info (ctrl, pk2);
print_key_info (ctrl, NULL, 0, pk2, 1);
if(pk->revkey[i].class&0x40)
tty_printf(_("(This is a sensitive revocation key)\n"));
@ -343,7 +343,7 @@ gen_desig_revoke (ctrl_t ctrl, const char *uname, strlist_t locusr)
push_armor_filter (afx, out);
/* create it */
rc = make_keysig_packet (ctrl, &sig, pk, NULL, NULL, pk2, 0x20, 0,
rc = make_keysig_packet (ctrl, &sig, pk, NULL, NULL, pk2, 0x20,
0, 0,
revocation_reason_build_cb, reason,
NULL);
@ -474,7 +474,7 @@ create_revocation (ctrl_t ctrl,
afx->hdrlines = "Comment: This is a revocation certificate\n";
push_armor_filter (afx, out);
rc = make_keysig_packet (ctrl, &sig, psk, NULL, NULL, psk, 0x20, 0,
rc = make_keysig_packet (ctrl, &sig, psk, NULL, NULL, psk, 0x20,
0, 0,
revocation_reason_build_cb, reason, cache_nonce);
if (rc)
@ -669,30 +669,26 @@ gen_revoke (ctrl_t ctrl, const char *uname)
rc = keydb_search (kdbhd, &desc, 1, NULL);
if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
/* Not ambiguous. */
{
/* Not ambiguous. */
}
else if (rc == 0)
/* Ambiguous. */
{
char *info;
/* Ambiguous. */
/* TRANSLATORS: The %s prints a key specification which
for example has been given at the command line. Several lines
lines with secret key infos are printed after this message. */
log_error (_("'%s' matches multiple secret keys:\n"), uname);
info = format_seckey_info (ctrl, keyblock->pkt->pkt.public_key);
log_error (" %s\n", info);
xfree (info);
print_key_info_log (ctrl, GPGRT_LOGLVL_ERROR, 2,
keyblock->pkt->pkt.public_key, 1);
release_kbnode (keyblock);
rc = keydb_get_keyblock (kdbhd, &keyblock);
while (! rc)
{
info = format_seckey_info (ctrl, keyblock->pkt->pkt.public_key);
log_info (" %s\n", info);
xfree (info);
print_key_info_log (ctrl, GPGRT_LOGLVL_INFO, 2,
keyblock->pkt->pkt.public_key, 1);
release_kbnode (keyblock);
keyblock = NULL;
@ -726,7 +722,7 @@ gen_revoke (ctrl_t ctrl, const char *uname)
}
keyid_from_pk (psk, keyid );
print_seckey_info (ctrl, psk);
print_key_info (ctrl, NULL, 0, psk, 1);
tty_printf("\n");
if (!cpr_get_answer_is_yes ("gen_revoke.okay",

View File

@ -1076,7 +1076,7 @@ check_signature_over_key_or_uid (ctrl_t ctrl, PKT_public_key *signer,
* signature packet's data structure.
*
* TODO: add r_revoked here as well. It has the same problems as
* r_expiredate and r_expired and the cache. */
* r_expiredate and r_expired and the cache [nw]. Which problems [wk]? */
int
check_key_signature2 (ctrl_t ctrl,
kbnode_t root, kbnode_t node, PKT_public_key *check_pk,

View File

@ -1593,7 +1593,7 @@ make_keysig_packet (ctrl_t ctrl,
PKT_signature **ret_sig, PKT_public_key *pk,
PKT_user_id *uid, PKT_public_key *subpk,
PKT_public_key *pksk,
int sigclass, int digest_algo,
int sigclass,
u32 timestamp, u32 duration,
int (*mksubpkt)(PKT_signature *, void *), void *opaque,
const char *cache_nonce)
@ -1601,6 +1601,7 @@ make_keysig_packet (ctrl_t ctrl,
PKT_signature *sig;
int rc = 0;
int sigversion;
int digest_algo;
gcry_md_hd_t md;
log_assert ((sigclass >= 0x10 && sigclass <= 0x13) || sigclass == 0x1F
@ -1612,31 +1613,22 @@ make_keysig_packet (ctrl_t ctrl,
else
sigversion = 4;
if (!digest_algo)
/* Select the digest algo to use. */
if (opt.cert_digest_algo) /* Forceful override by the user. */
digest_algo = opt.cert_digest_algo;
else if (pksk->pubkey_algo == PUBKEY_ALGO_DSA) /* Meet DSA requirements. */
digest_algo = match_dsa_hash (gcry_mpi_get_nbits (pksk->pkey[1])/8);
else if (pksk->pubkey_algo == PUBKEY_ALGO_ECDSA /* Meet ECDSA requirements. */
|| pksk->pubkey_algo == PUBKEY_ALGO_EDDSA)
{
/* Basically, this means use SHA1 always unless the user
* specified something (use whatever they said), or it's DSA
* (use the best match). They still can't pick an inappropriate
* hash for DSA or the signature will fail. Note that this
* still allows the caller of make_keysig_packet to override the
* user setting if it must. */
if (opt.cert_digest_algo)
digest_algo = opt.cert_digest_algo;
else if (pksk->pubkey_algo == PUBKEY_ALGO_DSA)
digest_algo = match_dsa_hash (gcry_mpi_get_nbits (pksk->pkey[1])/8);
else if (pksk->pubkey_algo == PUBKEY_ALGO_ECDSA
|| pksk->pubkey_algo == PUBKEY_ALGO_EDDSA)
{
if (openpgp_oid_is_ed25519 (pksk->pkey[0]))
digest_algo = DIGEST_ALGO_SHA256;
else
digest_algo = match_dsa_hash
(ecdsa_qbits_from_Q (gcry_mpi_get_nbits (pksk->pkey[1]))/8);
}
if (openpgp_oid_is_ed25519 (pksk->pkey[0]))
digest_algo = DIGEST_ALGO_SHA256;
else
digest_algo = DEFAULT_DIGEST_ALGO;
digest_algo = match_dsa_hash
(ecdsa_qbits_from_Q (gcry_mpi_get_nbits (pksk->pkey[1]))/8);
}
else /* Use the default. */
digest_algo = DEFAULT_DIGEST_ALGO;
if (gcry_md_open (&md, digest_algo, 0))
BUG ();
@ -1722,8 +1714,19 @@ update_keysig_packet (ctrl_t ctrl,
|| (orig_sig->sig_class == 0x18 && !subpk))
return GPG_ERR_GENERAL;
/* Either use the override digest algo or in the normal case the
* original digest algorithm. However, iff the original digest
* algorithms is SHA-1 and we are in gnupg or de-vs compliance mode
* we switch to SHA-256 (done by the macro). */
if (opt.cert_digest_algo)
digest_algo = opt.cert_digest_algo;
else if (pksk->pubkey_algo == PUBKEY_ALGO_DSA
|| pksk->pubkey_algo == PUBKEY_ALGO_ECDSA
|| pksk->pubkey_algo == PUBKEY_ALGO_EDDSA)
digest_algo = orig_sig->digest_algo;
else if (orig_sig->digest_algo == DIGEST_ALGO_SHA1
|| orig_sig->digest_algo == DIGEST_ALGO_RMD160)
digest_algo = DEFAULT_DIGEST_ALGO;
else
digest_algo = orig_sig->digest_algo;

View File

@ -340,6 +340,10 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk)
SK_LIST results;
} *c = *context;
#if MAX_FINGERPRINT_LEN < KEYGRIP_LEN
# error buffer too short for this configuration
#endif
if (!c)
{
/* Make a new context. */
@ -423,23 +427,58 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk)
if (opt.verbose)
log_info (_("error getting serial number of card: %s\n"),
gpg_strerror (err));
c->sl = c->sl->next;
continue;
}
xfree (serialno);
c->info.fpr2len = 0;
err = agent_scd_getattr ("KEY-FPR", &c->info);
if (!err)
{
if (c->info.fpr2len)
{
c->fpr2[0] = '0';
c->fpr2[1] = 'x';
bin2hex (c->info.fpr2, sizeof c->info.fpr2,
c->fpr2 + 2);
name = c->fpr2;
}
}
else if (gpg_err_code (err) == GPG_ERR_INV_NAME)
{
/* KEY-FPR not supported by the card - get
* the key using the keygrip. */
char *keyref;
strlist_t kplist;
const char *s;
int i;
err = agent_scd_getattr_one ("$ENCRKEYID", &keyref);
if (!err)
{
err = agent_scd_keypairinfo (ctrl, keyref,
&kplist);
if (!err)
{
c->fpr2[0] = '&';
for (i=1, s=kplist->d;
(*s && *s != ' '
&& i < sizeof c->fpr2 - 3);
s++, i++)
c->fpr2[i] = *s;
c->fpr2[i] = 0;
name = c->fpr2;
free_strlist (kplist);
}
xfree (keyref);
}
}
if (err)
log_error ("error retrieving key fingerprint from card: %s\n",
log_error ("error retrieving key from card: %s\n",
gpg_strerror (err));
if (c->info.fpr2len)
{
c->fpr2[0] = '0';
c->fpr2[1] = 'x';
bin2hex (c->info.fpr2, sizeof c->info.fpr2,c->fpr2+2);
name = c->fpr2;
}
c->sl = c->sl->next;
}
else

View File

@ -534,7 +534,7 @@ check_utks (sqlite3 *db)
NULL, NULL, &err);
if (rc)
{
log_error (_("error creating 'ultimately_trusted_keys' TOFU table: %s\n"),
log_error ("error creating 'ultimately_trusted_keys' TOFU table: %s\n",
err);
sqlite3_free (err);
goto out;
@ -840,7 +840,7 @@ initdb (sqlite3 *db)
NULL, NULL, &err);
if (rc)
{
log_error (_("error creating 'encryptions' TOFU table: %s\n"),
log_error ("error creating 'encryptions' TOFU table: %s\n",
err);
sqlite3_free (err);
}
@ -870,7 +870,7 @@ initdb (sqlite3 *db)
* safely ignore. */
rc = 0;
else
log_error (_("adding column effective_policy to bindings DB: %s\n"),
log_error ("adding column effective_policy to bindings DB: %s\n",
err);
sqlite3_free (err);
}
@ -2146,8 +2146,7 @@ build_conflict_set (ctrl_t ctrl, tofu_dbs_t dbs,
rc = keydb_search_reset (hd);
if (rc)
{
log_error (_("resetting keydb: %s\n"),
gpg_strerror (rc));
log_error ("resetting keydb failed: %s\n", gpg_strerror (rc));
continue;
}
@ -2614,8 +2613,8 @@ get_policy (ctrl_t ctrl, tofu_dbs_t dbs, PKT_public_key *pk,
if (record_binding (dbs, fingerprint, email, user_id,
policy == TOFU_POLICY_NONE ? TOFU_POLICY_AUTO : policy,
effective_policy, conflict, 1, 0, now) != 0)
log_error (_("error setting TOFU binding's policy"
" to %s\n"), tofu_policy_str (policy));
log_error ("error setting TOFU binding's policy"
" to %s\n", tofu_policy_str (policy));
}
/* If the caller wants the set of conflicts, return it. */
@ -3152,14 +3151,10 @@ show_statistics (tofu_dbs_t dbs,
es_fprintf (fp, _("%s: Verified 0 signatures."), email);
else
{
/* TRANSLATORS: The final %s is replaced by a string like
"7~months". */
/* Note: Translation not possible with that wording. */
char *ago_str = time_ago_str (now - signature_first_seen);
es_fprintf
(fp,
ngettext("%s: Verified %ld~signature in the past %s.",
"%s: Verified %ld~signatures in the past %s.",
signature_count),
(fp, "%s: Verified %ld~signatures in the past %s.",
email, signature_count, ago_str);
xfree (ago_str);
}
@ -3172,12 +3167,9 @@ show_statistics (tofu_dbs_t dbs,
{
char *ago_str = time_ago_str (now - encryption_first_done);
/* TRANSLATORS: The final %s is replaced by a string like
"7~months". */
es_fprintf (fp,
ngettext("Encrypted %ld~message in the past %s.",
"Encrypted %ld~messages in the past %s.",
encryption_count),
/* Note: Translation not possible with this kind of
* composition. */
es_fprintf (fp, "Encrypted %ld~messages in the past %s.",
encryption_count, ago_str);
xfree (ago_str);
}
@ -3944,7 +3936,7 @@ tofu_set_policy (ctrl_t ctrl, kbnode_t kb, enum tofu_policy policy)
policy, TOFU_POLICY_NONE, NULL, 0, 1, now);
if (err)
{
log_error (_("error setting policy for key %s, user id \"%s\": %s"),
log_error ("error setting policy for key %s, user id \"%s\": %s",
fingerprint, email, gpg_strerror (err));
xfree (email);
break;

View File

@ -530,7 +530,7 @@ cmd_getinfo (assuan_context_t ctx, char *line)
{
cmdopt = line;
if (!command_has_option (cmd, cmdopt))
err = gpg_error (GPG_ERR_GENERAL);
err = gpg_error (GPG_ERR_FALSE);
}
}
}

View File

@ -134,7 +134,7 @@
Note that this value matches TRUST_FLAG_REVOKED
- u16 RFU
- u32 Recheck_after
- u32 Latest timestamp in the keyblock (useful for KS syncronsiation?)
- u32 Latest timestamp in the keyblock (useful for KS synchronization?)
- u32 Blob created at
- u32 [NRES] Size of reserved space (not including this field)
- bN Reserved space of size NRES for future use.
@ -144,7 +144,7 @@
- bN Space for the keyblock or certificate.
- bN RFU. This is the remaining space after keyblock and before
the checksum. It is not covered by the checksum.
- b20 SHA-1 checksum (useful for KS syncronisation?)
- b20 SHA-1 checksum (useful for KS synchronization?)
Note, that KBX versions before GnuPG 2.1 used an MD5
checksum. However it was only created but never checked.
Thus we do not expect problems if we switch to SHA-1. If

View File

@ -261,10 +261,12 @@ _keybox_close_file (KEYBOX_HANDLE hd)
/*
* Lock the keybox at handle HD, or unlock if YES is false.
* Lock the keybox at handle HD, or unlock if YES is false. TIMEOUT
* is the value used for dotlock_take. In general -1 should be used
* when taking a lock; use 0 when releasing a lock.
*/
gpg_error_t
keybox_lock (KEYBOX_HANDLE hd, int yes)
keybox_lock (KEYBOX_HANDLE hd, int yes, long timeout)
{
gpg_error_t err = 0;
KB_NAME kb = hd->kb;
@ -289,23 +291,22 @@ keybox_lock (KEYBOX_HANDLE hd, int yes)
if (!kb->is_locked)
{
#ifdef HAVE_W32_SYSTEM
/* Under Windows we need to close the file before we try
* to lock it. This is because another process might have
* taken the lock and is using keybox_file_rename to
* rename the base file. How if our dotlock_take below is
* waiting for the lock but we have the base file still
* open, keybox_file_rename will never succeed as we are
* in a deadlock. */
if (hd->fp)
{
fclose (hd->fp);
hd->fp = NULL;
}
/* Under Windows we need to close the file before we try
* to lock it. This is because another process might have
* taken the lock and is using keybox_file_rename to
* rename the base file. Now if our dotlock_take below is
* waiting for the lock but we have the base file still
* open, keybox_file_rename will never succeed as we are
* in a deadlock. */
_keybox_close_file (hd);
#endif /*HAVE_W32_SYSTEM*/
if (dotlock_take (kb->lockhd, -1))
if (dotlock_take (kb->lockhd, timeout))
{
err = gpg_error_from_syserror ();
log_info ("can't lock '%s'\n", kb->fname );
if (!timeout && gpg_err_code (err) == GPG_ERR_EACCES)
; /* No diagnostic if we only tried to lock. */
else
log_info ("can't lock '%s'\n", kb->fname );
}
else
kb->is_locked = 1;

View File

@ -873,16 +873,21 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc,
KEYBOXBLOB blob = NULL;
struct sn_array_s *sn_array = NULL;
int pk_no, uid_no;
off_t lastfoundoff;
if (!hd)
return gpg_error (GPG_ERR_INV_VALUE);
/* clear last found result */
/* Clear last found result but reord the offset of the last found
* blob which we may need later. */
if (hd->found.blob)
{
lastfoundoff = _keybox_get_blob_fileoffset (hd->found.blob);
_keybox_release_blob (hd->found.blob);
hd->found.blob = NULL;
}
else
lastfoundoff = 0;
if (hd->error)
return hd->error; /* still in error state */
@ -901,6 +906,7 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc,
case KEYDB_SEARCH_MODE_FIRST:
/* always restart the search in this mode */
keybox_search_reset (hd);
lastfoundoff = 0;
break;
default:
break;
@ -925,6 +931,32 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc,
xfree (sn_array);
return rc;
}
/* log_debug ("%s: re-opened file\n", __func__); */
if (ndesc && desc[0].mode != KEYDB_SEARCH_MODE_FIRST && lastfoundoff)
{
/* Search mode is not first and the last search operation
* returned a blob which also was not the first one. We now
* need to skip over that blob and hope that the file has
* not changed. */
if (fseeko (hd->fp, lastfoundoff, SEEK_SET))
{
rc = gpg_error_from_syserror ();
log_debug ("%s: seeking to last found offset failed: %s\n",
__func__, gpg_strerror (rc));
xfree (sn_array);
return gpg_error (GPG_ERR_NOTHING_FOUND);
}
/* log_debug ("%s: re-opened file and sought to last offset\n", */
/* __func__); */
rc = _keybox_read_blob (NULL, hd->fp, NULL);
if (rc)
{
log_debug ("%s: skipping last found blob failed: %s\n",
__func__, gpg_strerror (rc));
xfree (sn_array);
return gpg_error (GPG_ERR_NOTHING_FOUND);
}
}
}
/* Kludge: We need to convert an SN given as hexstring to its binary

View File

@ -423,7 +423,7 @@ keybox_update_keyblock (KEYBOX_HANDLE hd, const void *image, size_t imagelen)
if (off == (off_t)-1)
return gpg_error (GPG_ERR_GENERAL);
/* Close this the file so that we do no mess up the position for a
/* Close the file so that we do no mess up the position for a
next search. */
_keybox_close_file (hd);

View File

@ -76,7 +76,7 @@ void keybox_pop_found_state (KEYBOX_HANDLE hd);
const char *keybox_get_resource_name (KEYBOX_HANDLE hd);
int keybox_set_ephemeral (KEYBOX_HANDLE hd, int yes);
gpg_error_t keybox_lock (KEYBOX_HANDLE hd, int yes);
gpg_error_t keybox_lock (KEYBOX_HANDLE hd, int yes, long timeout);
/*-- keybox-file.c --*/
/* Fixme: This function does not belong here: Provide a better

View File

@ -1,5 +1,6 @@
# iconv.m4 serial AM6 (gettext-0.17)
dnl Copyright (C) 2000-2002, 2007 Free Software Foundation, Inc.
# iconv.m4 serial 21
dnl Copyright (C) 2000-2002, 2007-2014, 2016-2019 Free Software Foundation,
dnl Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.
@ -30,61 +31,118 @@ AC_DEFUN([AM_ICONV_LINK],
dnl Add $INCICONV to CPPFLAGS before performing the following checks,
dnl because if the user has installed libiconv and not disabled its use
dnl via --without-libiconv-prefix, he wants to use it. The first
dnl AC_TRY_LINK will then fail, the second AC_TRY_LINK will succeed.
dnl AC_LINK_IFELSE will then fail, the second AC_LINK_IFELSE will succeed.
am_save_CPPFLAGS="$CPPFLAGS"
AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCICONV])
AC_CACHE_CHECK([for iconv], am_cv_func_iconv, [
AC_CACHE_CHECK([for iconv], [am_cv_func_iconv], [
am_cv_func_iconv="no, consider installing GNU libiconv"
am_cv_lib_iconv=no
AC_TRY_LINK([#include <stdlib.h>
#include <iconv.h>],
[iconv_t cd = iconv_open("","");
iconv(cd,NULL,NULL,NULL,NULL);
iconv_close(cd);],
am_cv_func_iconv=yes)
AC_LINK_IFELSE(
[AC_LANG_PROGRAM(
[[
#include <stdlib.h>
#include <iconv.h>
]],
[[iconv_t cd = iconv_open("","");
iconv(cd,NULL,NULL,NULL,NULL);
iconv_close(cd);]])],
[am_cv_func_iconv=yes])
if test "$am_cv_func_iconv" != yes; then
am_save_LIBS="$LIBS"
LIBS="$LIBS $LIBICONV"
AC_TRY_LINK([#include <stdlib.h>
#include <iconv.h>],
[iconv_t cd = iconv_open("","");
iconv(cd,NULL,NULL,NULL,NULL);
iconv_close(cd);],
am_cv_lib_iconv=yes
am_cv_func_iconv=yes)
AC_LINK_IFELSE(
[AC_LANG_PROGRAM(
[[
#include <stdlib.h>
#include <iconv.h>
]],
[[iconv_t cd = iconv_open("","");
iconv(cd,NULL,NULL,NULL,NULL);
iconv_close(cd);]])],
[am_cv_lib_iconv=yes]
[am_cv_func_iconv=yes])
LIBS="$am_save_LIBS"
fi
])
if test "$am_cv_func_iconv" = yes; then
AC_CACHE_CHECK([for working iconv], am_cv_func_iconv_works, [
dnl This tests against bugs in AIX 5.1 and HP-UX 11.11.
AC_CACHE_CHECK([for working iconv], [am_cv_func_iconv_works], [
dnl This tests against bugs in AIX 5.1, AIX 6.1..7.1, HP-UX 11.11,
dnl Solaris 10.
am_save_LIBS="$LIBS"
if test $am_cv_lib_iconv = yes; then
LIBS="$LIBS $LIBICONV"
fi
AC_TRY_RUN([
am_cv_func_iconv_works=no
for ac_iconv_const in '' 'const'; do
AC_RUN_IFELSE(
[AC_LANG_PROGRAM(
[[
#include <iconv.h>
#include <string.h>
int main ()
{
#ifndef ICONV_CONST
# define ICONV_CONST $ac_iconv_const
#endif
]],
[[int result = 0;
/* Test against AIX 5.1 bug: Failures are not distinguishable from successful
returns. */
{
iconv_t cd_utf8_to_88591 = iconv_open ("ISO8859-1", "UTF-8");
if (cd_utf8_to_88591 != (iconv_t)(-1))
{
static const char input[] = "\342\202\254"; /* EURO SIGN */
static ICONV_CONST char input[] = "\342\202\254"; /* EURO SIGN */
char buf[10];
const char *inptr = input;
ICONV_CONST char *inptr = input;
size_t inbytesleft = strlen (input);
char *outptr = buf;
size_t outbytesleft = sizeof (buf);
size_t res = iconv (cd_utf8_to_88591,
(char **) &inptr, &inbytesleft,
&inptr, &inbytesleft,
&outptr, &outbytesleft);
if (res == 0)
return 1;
result |= 1;
iconv_close (cd_utf8_to_88591);
}
}
/* Test against Solaris 10 bug: Failures are not distinguishable from
successful returns. */
{
iconv_t cd_ascii_to_88591 = iconv_open ("ISO8859-1", "646");
if (cd_ascii_to_88591 != (iconv_t)(-1))
{
static ICONV_CONST char input[] = "\263";
char buf[10];
ICONV_CONST char *inptr = input;
size_t inbytesleft = strlen (input);
char *outptr = buf;
size_t outbytesleft = sizeof (buf);
size_t res = iconv (cd_ascii_to_88591,
&inptr, &inbytesleft,
&outptr, &outbytesleft);
if (res == 0)
result |= 2;
iconv_close (cd_ascii_to_88591);
}
}
/* Test against AIX 6.1..7.1 bug: Buffer overrun. */
{
iconv_t cd_88591_to_utf8 = iconv_open ("UTF-8", "ISO-8859-1");
if (cd_88591_to_utf8 != (iconv_t)(-1))
{
static ICONV_CONST char input[] = "\304";
static char buf[2] = { (char)0xDE, (char)0xAD };
ICONV_CONST char *inptr = input;
size_t inbytesleft = 1;
char *outptr = buf;
size_t outbytesleft = 1;
size_t res = iconv (cd_88591_to_utf8,
&inptr, &inbytesleft,
&outptr, &outbytesleft);
if (res != (size_t)(-1) || outptr - buf > 1 || buf[1] != (char)0xAD)
result |= 4;
iconv_close (cd_88591_to_utf8);
}
}
#if 0 /* This bug could be worked around by the caller. */
@ -93,37 +151,53 @@ int main ()
iconv_t cd_88591_to_utf8 = iconv_open ("utf8", "iso88591");
if (cd_88591_to_utf8 != (iconv_t)(-1))
{
static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
static ICONV_CONST char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
char buf[50];
const char *inptr = input;
ICONV_CONST char *inptr = input;
size_t inbytesleft = strlen (input);
char *outptr = buf;
size_t outbytesleft = sizeof (buf);
size_t res = iconv (cd_88591_to_utf8,
(char **) &inptr, &inbytesleft,
&inptr, &inbytesleft,
&outptr, &outbytesleft);
if ((int)res > 0)
return 1;
result |= 8;
iconv_close (cd_88591_to_utf8);
}
}
#endif
/* Test against HP-UX 11.11 bug: No converter from EUC-JP to UTF-8 is
provided. */
if (/* Try standardized names. */
iconv_open ("UTF-8", "EUC-JP") == (iconv_t)(-1)
/* Try IRIX, OSF/1 names. */
&& iconv_open ("UTF-8", "eucJP") == (iconv_t)(-1)
/* Try AIX names. */
&& iconv_open ("UTF-8", "IBM-eucJP") == (iconv_t)(-1)
/* Try HP-UX names. */
&& iconv_open ("utf8", "eucJP") == (iconv_t)(-1))
return 1;
return 0;
}], [am_cv_func_iconv_works=yes], [am_cv_func_iconv_works=no],
[case "$host_os" in
aix* | hpux*) am_cv_func_iconv_works="guessing no" ;;
*) am_cv_func_iconv_works="guessing yes" ;;
esac])
{
/* Try standardized names. */
iconv_t cd1 = iconv_open ("UTF-8", "EUC-JP");
/* Try IRIX, OSF/1 names. */
iconv_t cd2 = iconv_open ("UTF-8", "eucJP");
/* Try AIX names. */
iconv_t cd3 = iconv_open ("UTF-8", "IBM-eucJP");
/* Try HP-UX names. */
iconv_t cd4 = iconv_open ("utf8", "eucJP");
if (cd1 == (iconv_t)(-1) && cd2 == (iconv_t)(-1)
&& cd3 == (iconv_t)(-1) && cd4 == (iconv_t)(-1))
result |= 16;
if (cd1 != (iconv_t)(-1))
iconv_close (cd1);
if (cd2 != (iconv_t)(-1))
iconv_close (cd2);
if (cd3 != (iconv_t)(-1))
iconv_close (cd3);
if (cd4 != (iconv_t)(-1))
iconv_close (cd4);
}
return result;
]])],
[am_cv_func_iconv_works=yes], ,
[case "$host_os" in
aix* | hpux*) am_cv_func_iconv_works="guessing no" ;;
*) am_cv_func_iconv_works="guessing yes" ;;
esac])
test "$am_cv_func_iconv_works" = no || break
done
LIBS="$am_save_LIBS"
])
case "$am_cv_func_iconv_works" in
@ -134,7 +208,7 @@ int main ()
am_func_iconv=no am_cv_lib_iconv=no
fi
if test "$am_func_iconv" = yes; then
AC_DEFINE(HAVE_ICONV, 1,
AC_DEFINE([HAVE_ICONV], [1],
[Define if you have the iconv() function and it works.])
fi
if test "$am_cv_lib_iconv" = yes; then
@ -147,34 +221,68 @@ int main ()
LIBICONV=
LTLIBICONV=
fi
AC_SUBST(LIBICONV)
AC_SUBST(LTLIBICONV)
AC_SUBST([LIBICONV])
AC_SUBST([LTLIBICONV])
])
AC_DEFUN([AM_ICONV],
dnl Define AM_ICONV using AC_DEFUN_ONCE for Autoconf >= 2.64, in order to
dnl avoid warnings like
dnl "warning: AC_REQUIRE: `AM_ICONV' was expanded before it was required".
dnl This is tricky because of the way 'aclocal' is implemented:
dnl - It requires defining an auxiliary macro whose name ends in AC_DEFUN.
dnl Otherwise aclocal's initial scan pass would miss the macro definition.
dnl - It requires a line break inside the AC_DEFUN_ONCE and AC_DEFUN expansions.
dnl Otherwise aclocal would emit many "Use of uninitialized value $1"
dnl warnings.
m4_define([gl_iconv_AC_DEFUN],
m4_version_prereq([2.64],
[[AC_DEFUN_ONCE(
[$1], [$2])]],
[m4_ifdef([gl_00GNULIB],
[[AC_DEFUN_ONCE(
[$1], [$2])]],
[[AC_DEFUN(
[$1], [$2])]])]))
gl_iconv_AC_DEFUN([AM_ICONV],
[
AM_ICONV_LINK
if test "$am_cv_func_iconv" = yes; then
AC_MSG_CHECKING([for iconv declaration])
AC_CACHE_VAL(am_cv_proto_iconv, [
AC_TRY_COMPILE([
AC_CACHE_VAL([am_cv_proto_iconv], [
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM(
[[
#include <stdlib.h>
#include <iconv.h>
extern
#ifdef __cplusplus
"C"
#endif
#if defined(__STDC__) || defined(__cplusplus)
#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus)
size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);
#else
size_t iconv();
#endif
], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const")
]],
[[]])],
[am_cv_proto_iconv_arg1=""],
[am_cv_proto_iconv_arg1="const"])
am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"])
am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'`
AC_MSG_RESULT([$]{ac_t:-
}[$]am_cv_proto_iconv)
AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1,
[Define as const if the declaration of iconv() needs const.])
AC_MSG_RESULT([
$am_cv_proto_iconv])
else
dnl When compiling GNU libiconv on a system that does not have iconv yet,
dnl pick the POSIX compliant declaration without 'const'.
am_cv_proto_iconv_arg1=""
fi
AC_DEFINE_UNQUOTED([ICONV_CONST], [$am_cv_proto_iconv_arg1],
[Define as const if the declaration of iconv() needs const.])
dnl Also substitute ICONV_CONST in the gnulib generated <iconv.h>.
m4_ifdef([gl_ICONV_H_DEFAULTS],
[AC_REQUIRE([gl_ICONV_H_DEFAULTS])
if test -n "$am_cv_proto_iconv_arg1"; then
ICONV_CONST="const"
fi
])
])

541
po/ja.po
View File

@ -4,13 +4,13 @@
# IIDA Yosiaki <iida@gnu.org>, 1999, 2000, 2002, 2003, 2004.
# Yoshihiro Kajiki <kajiki@ylug.org>, 1999.
# Takashi P.KATOH, 2002.
# NIIBE Yutaka <gniibe@fsij.org>, 2013, 2014, 2015, 2016, 2017, 2018.
# NIIBE Yutaka <gniibe@fsij.org>, 2013, 2014, 2015, 2016, 2017, 2018, 2019.
#
msgid ""
msgstr ""
"Project-Id-Version: gnupg 2.2.6\n"
"Project-Id-Version: gnupg 2.2.16\n"
"Report-Msgid-Bugs-To: translations@gnupg.org\n"
"PO-Revision-Date: 2018-04-12 10:51+0900\n"
"PO-Revision-Date: 2019-06-27 08:29+0900\n"
"Last-Translator: NIIBE Yutaka <gniibe@fsij.org>\n"
"Language-Team: none\n"
"Language: ja\n"
@ -23,12 +23,12 @@ msgstr ""
msgid "failed to acquire the pinentry lock: %s\n"
msgstr "pinentryのロックの獲得に失敗しました: %s\n"
#. TRANSLATORS: These are labels for buttons etc used in
#. Pinentries. An underscore indicates that the next letter
#. should be used as an accelerator. Double the underscore for
#. a literal one. The actual to be translated text starts after
#. the second vertical bar. Note that gpg-agent has been set to
#. utf-8 so that the strings are in the expected encoding.
#. TRANSLATORS: These are labels for buttons etc as used in
#. * Pinentries. In your translation copy the text before the
#. * second vertical bar verbatim; translate only the following
#. * text. An underscore indicates that the next letter should be
#. * used as an accelerator. Double the underscore to have
#. * pinentry display a literal underscore.
msgid "|pinentry-label|_OK"
msgstr "|pinentry-label|_OK"
@ -203,9 +203,11 @@ msgstr "PUK"
msgid "Reset Code"
msgstr "リセット・コード"
#, c-format
msgid "%s%%0A%%0AUse the reader's pinpad for input."
msgstr "%s%%0A%%0Aリーダーのピンパッドを入力に使ってください。"
msgid "Push ACK button on card/token."
msgstr "カード/トークンのACKボタンを押してください。"
msgid "Use the reader's pinpad for input."
msgstr "リーダーのピンパッドを入力に使ってください。"
msgid "Repeat this Reset Code"
msgstr "このリセット・コードをもう一度入力してください"
@ -240,9 +242,6 @@ msgstr "一時ファイルの書き込みエラー: %s\n"
msgid "Enter new passphrase"
msgstr "新しいパスフレーズを入力してください"
msgid "Take this one anyway"
msgstr "それでもこれを使います"
#, c-format
msgid ""
"You have not entered a passphrase!%0AAn empty passphrase is not allowed."
@ -280,6 +279,9 @@ msgstr ""
msgid "Warning: You have entered an insecure passphrase."
msgstr "警告: 安全とは言えないパスフレーズが入力されました。"
msgid "Take this one anyway"
msgstr "それでもこれを使います"
#, c-format
msgid "Please enter the passphrase to%0Aprotect your new key"
msgstr "新しい鍵を保護するために、%0Aパスフレーズを入力してください。"
@ -577,7 +579,7 @@ msgid "error reading '%s', line %d: %s\n"
msgstr "'%s'の読み込みエラー(行 %d): %s\n"
msgid "error reading list of trusted root certificates\n"
msgstr "信用されたルート証明書のリストの読み込みエラ\n"
msgstr "信用されたルート証明書のリストの読み込みエラ\n"
#. TRANSLATORS: This prompt is shown by the Pinentry
#. and has one special property: A "%%0A" is used by
@ -674,7 +676,7 @@ msgid "checking created signature failed: %s\n"
msgstr "作成された署名の検査に失敗しました: %s\n"
msgid "secret key parts are not available\n"
msgstr "秘密部分が得られません\n"
msgstr "秘密鍵部分が利用できません\n"
#, c-format
msgid "public key algorithm %d (%s) is not supported\n"
@ -729,7 +731,7 @@ msgid "can't connect to '%s': %s\n"
msgstr "'%s'へ接続できません: %s\n"
msgid "problem setting the gpg-agent options\n"
msgstr "gpg-agentオプション設定の問題\n"
msgstr "gpg-agentオプション設定の問題\n"
#, c-format
msgid "can't disable core dumps: %s\n"
@ -813,30 +815,30 @@ msgid "unknown debug flag '%s' ignored\n"
msgstr "未知のdebugフラグ'%s'は無視されました\n"
#, c-format
msgid "no running gpg-agent - starting '%s'\n"
msgstr "gpg-agentが実行されていません - '%s'を開始します\n"
msgid "waiting for the dirmngr to come up ... (%ds)\n"
msgstr "dirmngrの起動のため、%d秒待ちます\n"
#, c-format
msgid "waiting for the agent to come up ... (%ds)\n"
msgstr "agentの起動のため、%d秒待ちます\n"
msgid "connection to agent established\n"
msgid "connection to the dirmngr established\n"
msgstr "dirmngrへの接続が確立しました\n"
msgid "connection to the agent established\n"
msgstr "エージェントへの接続が確立しました。\n"
msgid "connection to agent is in restricted mode\n"
#, c-format
msgid "no running gpg-agent - starting '%s'\n"
msgstr "gpg-agentが実行されていません - '%s'を開始します\n"
msgid "connection to the agent is in restricted mode\n"
msgstr "エージェントへの接続は制限モードです。\n"
#, c-format
msgid "no running Dirmngr - starting '%s'\n"
msgid "no running dirmngr - starting '%s'\n"
msgstr "dirmngrが動いていません - 開始します'%s'\n"
#, c-format
msgid "waiting for the dirmngr to come up ... (%ds)\n"
msgstr "dirmngrの起動のため、%d秒待ちます\n"
msgid "connection to the dirmngr established\n"
msgstr "dirmngrへの接続が確立しました\n"
#. TRANSLATORS: Copy the prefix between the vertical bars
#. verbatim. It will not be printed.
msgid "|audit-log-result|Good"
@ -1128,7 +1130,7 @@ msgid "CRC error; %06lX - %06lX\n"
msgstr "CRCエラー。%06lX - %06lX\n"
msgid "premature eof (in trailer)\n"
msgstr "ファイル末尾が早すぎます (後尾部の中にあります)\n"
msgstr "ファイル終端が早すぎます (後尾部の中にあります)\n"
msgid "error in trailer line\n"
msgstr "後尾の行にエラーがあります\n"
@ -1205,6 +1207,10 @@ msgstr "注意: \"%s\"コマンドを使って再起動してください。\n"
msgid "%s is not compliant with %s mode\n"
msgstr "%sは%sモードに準拠しません\n"
#, c-format
msgid "problem with the agent: %s\n"
msgstr "エージェントに問題: %s\n"
#, c-format
msgid "OpenPGP card not available: %s\n"
msgstr "OpenPGPカードが利用できません: %s\n"
@ -1228,14 +1234,11 @@ msgstr "あなたの選択は? "
msgid "[not set]"
msgstr "[未設定]"
msgid "male"
msgstr ""
msgid "Mr."
msgstr "Mr."
msgid "female"
msgstr "女"
msgid "unspecified"
msgstr "無指定"
msgid "Mrs."
msgstr "Mrs"
msgid "not forced"
msgstr "強制なし"
@ -1288,8 +1291,8 @@ msgstr "エラー: 優先指定の文字列の長さが無効です。\n"
msgid "Error: invalid characters in preference string.\n"
msgstr "エラー: 優先指定の文字列に無効な文字があります。\n"
msgid "Sex ((M)ale, (F)emale or space): "
msgstr "性別 ((M)男、(F)女、または空白): "
msgid "Salutation (M = Mr., F = Mrs., or space): "
msgstr "敬称 (M = Mr., F = Mrs, あるいは空白): "
msgid "Error: invalid response.\n"
msgstr "エラー: 無効な応答。\n"
@ -1315,13 +1318,15 @@ msgid "Replace existing key? (y/N) "
msgstr "既存の鍵を置き換えしますか? (y/N) "
msgid ""
"Note: There is no guarantee that the card supports the requested size.\n"
" If the key generation does not succeed, please check the\n"
" documentation of your card to see what sizes are allowed.\n"
"Note: There is no guarantee that the card supports the requested\n"
" key type or size. If the key generation does not succeed,\n"
" please check the documentation of your card to see which\n"
" key types and sizes are supported.\n"
msgstr ""
"注意: カードが要求された鍵長をサポートしているという保証はありません。\n"
" 鍵生成が成功しない場合、あなたのカードに関する技術文書を確認し、\n"
" 利用できる鍵長について確認ください。\n"
"注意: カードが要求された鍵のタイプもしくは鍵長をサポートしている保証は\n"
" ありません。鍵生成が成功しない場合、あなたのカードに関する技術文書を\n"
" 確認し、どの鍵のタイプと鍵長がサポートされているかについて確認して\n"
" ください。\n"
#, c-format
msgid "What keysize do you want? (%u) "
@ -1432,6 +1437,10 @@ msgstr "工場出荷リセットを行いますか? (本当なら \"yes\" と入
msgid "error for setup KDF: %s\n"
msgstr "KDF設定のエラー: %s\n"
#, c-format
msgid "error for setup UIF: %s\n"
msgstr "UIF設定のエラー: %s\n"
msgid "quit this menu"
msgstr "このメニューを終了"
@ -1459,8 +1468,8 @@ msgstr "ログイン名の変更"
msgid "change the language preferences"
msgstr "言語の優先指定の変更"
msgid "change card holder's sex"
msgstr "カード所有者の性別の変更"
msgid "change card holder's salutation"
msgstr "カード所有者の敬称の変更"
msgid "change a CA fingerprint"
msgstr "CAフィンガープリントの変更"
@ -1489,6 +1498,9 @@ msgstr "PIN認証のKDFを設定する"
msgid "change the key attribute"
msgstr "鍵の属性の変更"
msgid "change the User Interaction Flag"
msgstr "ユーザ・インタラクション・フラグの変更"
msgid "gpg/card> "
msgstr "gpg/card> "
@ -1527,7 +1539,19 @@ msgid "(unless you specify the key by fingerprint)\n"
msgstr "(フィンガー・プリントで鍵を指定してない限り)\n"
msgid "can't do this in batch mode without \"--yes\"\n"
msgstr "\"--yes\"なしでバッチ・モードではできません\n"
msgstr "これは\"--yes\"なしでバッチ・モードではできません\n"
msgid "Note: The public primary key and all its subkeys will be deleted.\n"
msgstr "注意: 主鍵とすべての副鍵の公開鍵が削除されます。\n"
msgid "Note: Only the shown public subkey will be deleted.\n"
msgstr "注意: 表示されている副鍵の公開鍵だけが削除されます。\n"
msgid "Note: Only the secret part of the shown primary key will be deleted.\n"
msgstr "注意: 表示されている主鍵の秘密鍵だけが削除されます。\n"
msgid "Note: Only the secret part of the shown subkey will be deleted.\n"
msgstr "注意: 表示されている副鍵の秘密鍵だけが削除されます。\n"
msgid "Delete this key from the keyring? (y/N) "
msgstr "この鍵を鍵リングから削除しますか? (y/N) "
@ -1545,6 +1569,10 @@ msgstr "鍵"
msgid "subkey"
msgstr "副鍵: "
#, c-format
msgid "update failed: %s\n"
msgstr "更新に失敗しました: %s\n"
#, c-format
msgid "deleting keyblock failed: %s\n"
msgstr "鍵ブロックの削除に失敗しました: %s\n"
@ -1567,8 +1595,8 @@ msgid "can't use a symmetric ESK packet due to the S2K mode\n"
msgstr "S2Kモードのため、共通鍵ESKパケットを使えません\n"
#, c-format
msgid "using cipher %s\n"
msgstr "暗号方式 %s を使います\n"
msgid "using cipher %s.%s\n"
msgstr "暗号方式 %s.%s を使います\n"
#, c-format
msgid "'%s' already compressed\n"
@ -1608,16 +1636,16 @@ msgid "forcing symmetric cipher %s (%d) violates recipient preferences\n"
msgstr "共通鍵暗号方式 %s (%d) の強制が、受取人の優先指定をそむきます\n"
#, c-format
msgid "%s/%s encrypted for: \"%s\"\n"
msgstr "%s/%s暗号化 受信者:\"%s\"\n"
msgid "%s/%s.%s encrypted for: \"%s\"\n"
msgstr "%s/%s.%s 暗号化 受信者:\"%s\"\n"
#, c-format
msgid "option '%s' may not be used in %s mode\n"
msgstr "オプション'%s'を%sモードで使うことはできません\n"
#, c-format
msgid "%s encrypted data\n"
msgstr "%s暗号化済みデータ\n"
msgid "%s.%s encrypted data\n"
msgstr "%s.%s 暗号化データ\n"
#, c-format
msgid "encrypted with unknown algorithm %d\n"
@ -1688,6 +1716,9 @@ msgstr "エクスポートの際、利用できない部分を除去する"
msgid "remove as much as possible from key during export"
msgstr "エクスポートの際、できるだけ除去する"
msgid "Do not export user id or attribute packets"
msgstr "ユーザIDもしくは属性パケットをエクスポートしない"
msgid "use the GnuPG key backup format"
msgstr "GnuPGの鍵のバックアップフォーマットを使います"
@ -1719,22 +1750,6 @@ msgstr "'%s'の作成エラー: %s\n"
msgid "[User ID not found]"
msgstr "[ユーザIDが見つかりません]"
#, c-format
msgid "(check argument of option '%s')\n"
msgstr "(オプション'%s'の引数を確認ください)\n"
#, c-format
msgid "Warning: '%s' should be a long key ID or a fingerprint\n"
msgstr "警告: '%s'は長い鍵IDかフィンガープリントであるべきです。\n"
#, c-format
msgid "error looking up: %s\n"
msgstr "検索のエラー: %s\n"
#, c-format
msgid "Warning: %s appears in the keyring %d times\n"
msgstr "警告: %sは鍵リングに%d回出現します\n"
#, c-format
msgid "automatically retrieved '%s' via %s\n"
msgstr "'%s'を %s から自動取得\n"
@ -1746,10 +1761,18 @@ msgstr "'%s'を %s から取得する際のエラー: %s\n"
msgid "No fingerprint"
msgstr "フィンガープリントがありません"
#, c-format
msgid "checking for a fresh copy of an expired key via %s\n"
msgstr "%s から失効した鍵の新しいコピーを確認します。\n"
#, c-format
msgid "secret key \"%s\" not found: %s\n"
msgstr "秘密鍵\"%s\"が見つかりません: %s\n"
#, c-format
msgid "(check argument of option '%s')\n"
msgstr "(オプション'%s'の引数を確認ください)\n"
#, c-format
msgid "Warning: not using '%s' as default key: %s\n"
msgstr "警告: デフォルトの秘密鍵として '%s' を用いません: %s\n"
@ -2225,7 +2248,10 @@ msgid "will not run with insecure memory due to %s\n"
msgstr "%s のため、セキュアでないメモリで実行しません\n"
msgid "selected cipher algorithm is invalid\n"
msgstr "選択された暗号アルゴリズムは、無効です\n"
msgstr "選択された暗号アルゴリズムは無効です\n"
msgid "selected AEAD algorithm is invalid\n"
msgstr "選択された AEAD アルゴリズムは無効です\n"
msgid "selected compression algorithm is invalid\n"
msgstr "選択された圧縮アルゴリズムは、無効です\n"
@ -2260,16 +2286,27 @@ msgstr "無効なデフォルトの優先指定\n"
msgid "invalid personal cipher preferences\n"
msgstr "無効な個人用暗号方式の優先指定\n"
msgid "invalid personal AEAD preferences\n"
msgstr "無効な個人用 AEAD 方式の優先指定\n"
msgid "invalid personal digest preferences\n"
msgstr "無効な個人用ダイジェストの優先指定\n"
msgid "invalid personal compress preferences\n"
msgstr "無効な個人用圧縮の優先指定\n"
#, c-format
msgid "chunk size invalid - using %d\n"
msgstr "無効なチャンク長です - %dにします\n"
#, c-format
msgid "%s does not yet work with %s\n"
msgstr "%sは%sではまだ機能しません\n"
#, c-format
msgid "AEAD algorithm '%s' may not be used in %s mode\n"
msgstr "AEAD アルゴリズム'%s'を%sモードで使うことはできません\n"
#, c-format
msgid "digest algorithm '%s' may not be used in %s mode\n"
msgstr "ダイジェスト・アルゴリズム'%s'を%sモードで使うことはできません\n"
@ -2417,6 +2454,9 @@ msgstr "インポート後、利用できない部分を鍵から除去します
msgid "remove as much as possible from key after import"
msgstr "インポート後、できるだけ除去します"
msgid "Do not import user id or attribute packets"
msgstr "ユーザIDもしくは属性パケットをインポートしない"
msgid "run import filters and export key immediately"
msgstr "インポート・フィルタを実行し鍵をすぐにエクスポートします"
@ -2510,6 +2550,10 @@ msgstr ""
msgid " \"%s\": preference for cipher algorithm %s\n"
msgstr " \"%s\": 暗号アルゴリズムの優先指定 %s\n"
#, c-format
msgid " \"%s\": preference for AEAD algorithm %s\n"
msgstr " \"%s\": AEADアルゴリズムの優先指定 %s\n"
#, c-format
msgid " \"%s\": preference for digest algorithm %s\n"
msgstr " \"%s\": ダイジェスト・アルゴリズムの優先指定 %s\n"
@ -2634,6 +2678,18 @@ msgstr "鍵 %s: 秘密鍵はもうあります\n"
msgid "key %s: error sending to agent: %s\n"
msgstr "鍵 %s: エージェントへの送信エラー: %s\n"
#. TRANSLATORS: For a smartcard, each private key on host has a
#. * reference (stub) to a smartcard and actual private key data
#. * is stored on the card. A single smartcard can have up to
#. * three private key data. Importing private key stub is always
#. * skipped in 2.1, and it returns GPG_ERR_NOT_PROCESSED.
#. * Instead, user should be suggested to run 'gpg --card-status',
#. * then, references to a card will be automatically created
#. * again.
#, c-format
msgid "To migrate '%s', with each smartcard, run: %s\n"
msgstr "'%s'の移行には、スマードカードそれぞれで、以下を実行してください: %s\n"
#, c-format
msgid "secret key %s: %s\n"
msgstr "秘密鍵 %s: %s\n"
@ -2645,19 +2701,26 @@ msgstr "秘密鍵のインポートは禁止です\n"
msgid "key %s: secret key with invalid cipher %d - skipped\n"
msgstr "鍵%s: 無効な暗号方式%dの秘密鍵です - スキップします\n"
#. TRANSLATORS: For smartcard, each private key on
#. host has a reference (stub) to a smartcard and
#. actual private key data is stored on the card. A
#. single smartcard can have up to three private key
#. data. Importing private key stub is always
#. skipped in 2.1, and it returns
#. GPG_ERR_NOT_PROCESSED. Instead, user should be
#. suggested to run 'gpg --card-status', then,
#. references to a card will be automatically
#. created again.
#, c-format
msgid "To migrate '%s', with each smartcard, run: %s\n"
msgstr "'%s'の移行には、スマードカードそれぞれで、以下を実行してください: %s\n"
msgid "No reason specified"
msgstr "理由は指定されていません"
msgid "Key is superseded"
msgstr "鍵がとりかわっています"
msgid "Key has been compromised"
msgstr "鍵(の信頼性)が損なわれています"
msgid "Key is no longer used"
msgstr "鍵はもはや使われていません"
msgid "User ID is no longer valid"
msgstr "ユーザIDがもはや有効でありません"
msgid "reason for revocation: "
msgstr "失効理由: "
msgid "revocation comment: "
msgstr "失効のコメント: "
#, c-format
msgid "key %s: no public key - can't apply revocation certificate\n"
@ -3227,10 +3290,6 @@ msgstr "変更を保存しますか? (y/N) "
msgid "Quit without saving? (y/N) "
msgstr "保存せずに終了しますか? (y/N) "
#, c-format
msgid "update failed: %s\n"
msgstr "更新に失敗しました: %s\n"
msgid "Key not changed so no update needed.\n"
msgstr "鍵は無変更なので更新は不要です。\n"
@ -3269,12 +3328,15 @@ msgstr "'%s'は、有効な有効期限ではありません\n"
#, c-format
msgid "\"%s\" is not a proper fingerprint\n"
msgstr "\"%s\"は正しいィンガープリントではありません\n"
msgstr "\"%s\"は正しいィンガープリントではありません\n"
#, c-format
msgid "subkey \"%s\" not found\n"
msgstr "副鍵\"%s\"が見つかりません\n"
msgid "AEAD: "
msgstr "AEAD: "
msgid "Digest: "
msgstr "ダイジェスト: "
@ -3607,6 +3669,9 @@ msgstr "ダイジェストの優先指定が多すぎます\n"
msgid "too many compression preferences\n"
msgstr "圧縮の優先指定が多すぎます\n"
msgid "too many AEAD preferences\n"
msgstr "AEAD方式の優先指定が多すぎます\n"
#, c-format
msgid "invalid item '%s' in preference string\n"
msgstr "優先指定の文字列に無効な項目'%s'があります\n"
@ -3647,21 +3712,21 @@ msgid "Authenticate"
msgstr "Authenticate"
#. TRANSLATORS: Please use only plain ASCII characters for the
#. translation. If this is not possible use single digits. The
#. string needs to 8 bytes long. Here is a description of the
#. functions:
#.
#. s = Toggle signing capability
#. e = Toggle encryption capability
#. a = Toggle authentication capability
#. q = Finish
#. * translation. If this is not possible use single digits. The
#. * string needs to 8 bytes long. Here is a description of the
#. * functions:
#. *
#. * s = Toggle signing capability
#. * e = Toggle encryption capability
#. * a = Toggle authentication capability
#. * q = Finish
#.
msgid "SsEeAaQq"
msgstr "SsEeAaQq"
#, c-format
msgid "Possible actions for a %s key: "
msgstr "鍵%sに認められた操作: "
msgid "Possible actions for this %s key: "
msgstr "この鍵%sにありうる操作: "
msgid "Current allowed actions: "
msgstr "現在の認められた操作: "
@ -3734,6 +3799,10 @@ msgstr " (%d) ECC (暗号化のみ)\n"
msgid " (%d) Existing key\n"
msgstr " (%d) 既存の鍵\n"
#, c-format
msgid " (%d) Existing key from card\n"
msgstr " (%d) カードに存在する鍵\n"
msgid "Enter the keygrip: "
msgstr "keygripを入力: "
@ -3743,6 +3812,17 @@ msgstr "有効なkeygrip (40桁の16進数字)ではありません\n"
msgid "No key with this keygrip\n"
msgstr "このkeygripの鍵はありません\n"
#, c-format
msgid "error reading the card: %s\n"
msgstr "カードの読み込みエラー: %s\n"
#, c-format
msgid "Serial number of the card: %s\n"
msgstr "カードのシリアル番号: %s\n"
msgid "Available keys:\n"
msgstr "利用可能な鍵:\n"
#, c-format
msgid "rounded to %u bits\n"
msgstr "%uビットに切り上げます\n"
@ -4164,9 +4244,6 @@ msgstr "鍵\"%s\"が鍵サーバに見つかりません\n"
msgid "key not found on keyserver\n"
msgstr "鍵が鍵サーバに見つかりません\n"
msgid "no keyserver known (use option --keyserver)\n"
msgstr "既知の鍵サーバがありません (オプション--keyserverを使いましょう)\n"
#, c-format
msgid "requesting key %s from %s server %s\n"
msgstr "鍵%sを%sからサーバ%sに要求\n"
@ -4196,11 +4273,15 @@ msgstr "*警告*: URI %s からデータを取れません: %s\n"
#, c-format
msgid "weird size for an encrypted session key (%d)\n"
msgstr "変な長さの暗号化済みセッション鍵 (%d)\n"
msgstr "変な長さの暗号化セッション鍵 (%d)\n"
#, c-format
msgid "%s encrypted session key\n"
msgstr "%s 暗号化済みセッション鍵\n"
msgid "%s.%s encrypted session key\n"
msgstr "%s.%s 暗号化セッション鍵\n"
#, c-format
msgid "encrypted with unknown algorithm %d.%s\n"
msgstr "不明のアルゴリズム%d.%sによる暗号化\n"
#, c-format
msgid "passphrase generated with unknown digest algorithm %d\n"
@ -4210,12 +4291,9 @@ msgstr "不明のダイジェスト・アルゴリズムで生成されたパス
msgid "public key is %s\n"
msgstr "公開鍵は%sです\n"
msgid "public key encrypted data: good DEK\n"
msgstr "公開鍵による暗号化済みデータ: 正しいDEKです\n"
#, c-format
msgid "encrypted with %u-bit %s key, ID %s, created %s\n"
msgstr "%u-ビット%s鍵, ID %s, 日付%sに暗号化されました\n"
msgid "encrypted with %s key, ID %s, created %s\n"
msgstr "%s鍵, ID %s, 作成日付%s により暗号化されました\n"
#, c-format
msgid " \"%s\"\n"
@ -4225,9 +4303,8 @@ msgstr " \"%s\"\n"
msgid "encrypted with %s key, ID %s\n"
msgstr "%s鍵, ID %sで暗号化されました\n"
#, c-format
msgid "public key decryption failed: %s\n"
msgstr "公開鍵の復号に失敗しました: %s\n"
msgid "WARNING: multiple plaintexts seen\n"
msgstr "*警告*: 複数のプレインテクストが見られます\n"
#, c-format
msgid "encrypted with %lu passphrases\n"
@ -4236,9 +4313,16 @@ msgstr "%lu 個のパスフレーズで暗号化\n"
msgid "encrypted with 1 passphrase\n"
msgstr "1 個のパスフレーズで暗号化\n"
#, c-format
msgid "public key decryption failed: %s\n"
msgstr "公開鍵の復号に失敗しました: %s\n"
msgid "public key encrypted data: good DEK\n"
msgstr "公開鍵による暗号化データ: 正しいDEKです\n"
#, c-format
msgid "assuming %s encrypted data\n"
msgstr "%s暗号化済みデータを仮定\n"
msgstr "%s暗号化データを仮定\n"
#, c-format
msgid "IDEA cipher unavailable, optimistically attempting to use %s instead\n"
@ -4247,6 +4331,22 @@ msgstr "IDEA暗号方式は利用不能なので、楽天的ですが%sで代用
msgid "WARNING: message was not integrity protected\n"
msgstr "*警告*: メッセージの完全性は保護されていません\n"
msgid ""
"Hint: If this message was created before the year 2003 it is\n"
"likely that this message is legitimate. This is because back\n"
"then integrity protection was not widely used.\n"
msgstr ""
"ヒント: もし、このメッセージが2003年以前に作成されたのであれば、\n"
"このメッセージはおそらく正当でしょう。当時、整合性の保護機能は\n"
"広く使われてはいなかったためです。\n"
#, c-format
msgid "Use the option '%s' to decrypt anyway.\n"
msgstr "それでも復号するにはオプション '%s' を使います。\n"
msgid "decryption forced to fail!\n"
msgstr "復号は強制的に失敗とされました!\n"
msgid "decryption okay\n"
msgstr "復号に成功\n"
@ -4264,9 +4364,6 @@ msgstr "注意: 送信者は\"極秘とする\"ように求めています\n"
msgid "original file name='%.*s'\n"
msgstr "元のファイル名='%.*s'\n"
msgid "WARNING: multiple plaintexts seen\n"
msgstr "*警告*: 複数のプレインテクストが見られます\n"
msgid "standalone revocation - use \"gpg --import\" to apply\n"
msgstr "スタンドアロン失効 - \"gpg --import\"を使って適用してください\n"
@ -4493,14 +4590,13 @@ msgstr "公開鍵のアルゴリズム%dは、取り扱えません\n"
msgid "WARNING: potentially insecure symmetrically encrypted session key\n"
msgstr "*警告*: 潜在的にセキュアでない共通鍵暗号化セッション鍵です\n"
msgid "Unknown critical signature notation: "
msgstr "不明なクリティカルな署名注釈: "
#, c-format
msgid "subpacket of type %d has critical bit set\n"
msgstr "型%dの下位パケットにクリティカル・ビットを発見\n"
#, c-format
msgid "problem with the agent: %s\n"
msgstr "エージェントに問題: %s\n"
msgid "Enter passphrase\n"
msgstr "パスフレーズを入力\n"
@ -4581,27 +4677,6 @@ msgstr "この写真は正しいですか (y/N/q)? "
msgid "unable to display photo ID!\n"
msgstr "フォトIDが表示不能!\n"
msgid "No reason specified"
msgstr "理由は指定されていません"
msgid "Key is superseded"
msgstr "鍵がとりかわっています"
msgid "Key has been compromised"
msgstr "鍵(の信頼性)が損なわれています"
msgid "Key is no longer used"
msgstr "鍵はもはや使われていません"
msgid "User ID is no longer valid"
msgstr "ユーザIDがもはや有効でありません"
msgid "reason for revocation: "
msgstr "失効理由: "
msgid "revocation comment: "
msgstr "失効のコメント: "
#. TRANSLATORS: These are the allowed answers in lower and
#. uppercase. Below you will find the matching strings which
#. should be translated accordingly and the letter changed to
@ -5080,6 +5155,10 @@ msgstr "注意: 鍵 %s は失効済みです\n"
msgid "bad key signature from key %s: %s (0x%02x, 0x%x)\n"
msgstr "鍵%sによる不正な鍵への署名: %s (0x%02x, 0x%x)\n"
#, c-format
msgid "bad data signature from key %s: %s (0x%02x, 0x%x)\n"
msgstr "鍵%sによる不正なデータへの署名: %s (0x%02x, 0x%x)\n"
#, c-format
msgid "assuming bad signature from key %s due to an unknown critical bit\n"
msgstr "不明のクリティカル・ビットのため、鍵%sによる署名を不正とみなします\n"
@ -5122,8 +5201,8 @@ msgid "signing:"
msgstr "署名:"
#, c-format
msgid "%s encryption will be used\n"
msgstr "%s暗号化を使用します\n"
msgid "%s.%s encryption will be used\n"
msgstr "%s.%s 暗号化を使用します\n"
msgid "key is not flagged as insecure - can't use it with the faked RNG!\n"
msgstr ""
@ -5306,9 +5385,6 @@ msgid "unsupported TOFU database version: %s\n"
msgstr "サポートされていないTOFUデータベースバージョン: %s\n"
#, c-format
msgid "error creating 'ultimately_trusted_keys' TOFU table: %s\n"
msgstr "'ultimately_trusted_keys' TOFUテーブル作成エラー: %s\n"
msgid "TOFU DB error"
msgstr "TOFU DBエラー"
@ -5324,14 +5400,6 @@ msgstr "TOFUデータベースのバージョン判定エラー: %s\n"
msgid "error initializing TOFU database: %s\n"
msgstr "TOFUデータベースの初期化エラー: %s\n"
#, c-format
msgid "error creating 'encryptions' TOFU table: %s\n"
msgstr "'encryptions' TOFUデータベースの作成エラー: %s\n"
#, c-format
msgid "adding column effective_policy to bindings DB: %s\n"
msgstr "バインディングDBにカラムeffective_policyを追加: %s\n"
#, c-format
msgid "error opening TOFU database '%s': %s\n"
msgstr "TOFUデータベースのオープンでエラー '%s': %s\n"
@ -5470,14 +5538,6 @@ msgstr "不明をデフォルトとします。\n"
msgid "TOFU db corruption detected.\n"
msgstr "TOFU dbが壊れていることが検出されました。\n"
#, c-format
msgid "resetting keydb: %s\n"
msgstr "keydbをリセット: %s\n"
#, c-format
msgid "error setting TOFU binding's policy to %s\n"
msgstr "TOFUバインディングのポリシーを %s に設定エラー\n"
#, c-format
msgid "error changing TOFU policy: %s\n"
msgstr "TOFUポリシーの作成エラー: %s\n"
@ -5525,19 +5585,9 @@ msgstr "%s: 0個の署名を検証、0個のメッセージを暗号化しまし
msgid "%s: Verified 0 signatures."
msgstr "%s: 0個の署名を検証しました。"
#, c-format
msgid "%s: Verified %ld~signature in the past %s."
msgid_plural "%s: Verified %ld~signatures in the past %s."
msgstr[0] "%s: 署名を%ld個検証しました(これまで %s に)。"
msgid "Encrypted 0 messages."
msgstr "0 個のメッセージを暗号化しました。"
#, c-format
msgid "Encrypted %ld~message in the past %s."
msgid_plural "Encrypted %ld~messages in the past %s."
msgstr[0] "メッセージを%ld個暗号化しました(これまで %s に)。"
#, c-format
msgid "(policy: %s)"
msgstr "(ポリシー: %s)"
@ -5585,10 +5635,6 @@ msgid "WARNING: Encrypting to %s, which has no non-revoked user ids\n"
msgstr ""
"*警告*: %s に暗号化します。失効していないユーザIDが一つもないものです\n"
#, c-format
msgid "error setting policy for key %s, user id \"%s\": %s"
msgstr "鍵%s, ユーザID \"%s\"のポリシーの設定エラー: %s"
#, c-format
msgid "'%s' is not a valid long keyID\n"
msgstr "'%s'は、有効な大型鍵IDでありません\n"
@ -5751,6 +5797,13 @@ msgstr "入力の%u行目が長すぎるか、LFがないようです\n"
msgid "can't open fd %d: %s\n"
msgstr "fd %dが開けません: %s\n"
msgid "WARNING: encrypting without integrity protection is dangerous\n"
msgstr "*警告*: 完全性保護なしでの暗号化は危険です\n"
#, c-format
msgid "Hint: Do not use option %s\n"
msgstr "ヒント: オプション %s を使わない\n"
msgid "set debugging flags"
msgstr "デバッグ・フラグを設定"
@ -6030,6 +6083,9 @@ msgstr "リーダのピンパッドを使わない"
msgid "deny the use of admin card commands"
msgstr "管理カード・コマンドの使用を拒否"
msgid "|LIST|Change the application priority to LIST"
msgstr "|LIST|アプリケーションの優先順位をLISTに変更します"
msgid "use variable length input for pinpad"
msgstr "ピンパッドの可変長入力を使う"
@ -6298,6 +6354,9 @@ msgstr "証明書は暗号化のために使えません\n"
msgid "certificate is not usable for signing\n"
msgstr "証明書は署名のために使えません\n"
msgid "looking for another certificate\n"
msgstr "別の証明書を探索する\n"
#, c-format
msgid "line %d: invalid algorithm\n"
msgstr "行 %d: 無効なアルゴリズムです\n"
@ -6385,17 +6444,6 @@ msgstr " (%d) 既存の鍵\n"
msgid " (%d) Existing key from card\n"
msgstr " (%d) カードに存在する鍵\n"
#, c-format
msgid "error reading the card: %s\n"
msgstr "カードの読み込みエラー: %s\n"
#, c-format
msgid "Serial number of the card: %s\n"
msgstr "カードのシリアル番号: %s\n"
msgid "Available keys:\n"
msgstr "利用可能な鍵:\n"
#, c-format
msgid "Possible actions for a %s key:\n"
msgstr "%s鍵に可能な操作:\n"
@ -7641,6 +7689,17 @@ msgstr "'%s' は無効なLDAP URLです\n"
msgid "error accessing '%s': http status %u\n"
msgstr "'%s'へアクセスのエラー: httpステイタス %u\n"
#, c-format
msgid "URL '%s' redirected to '%s' (%u)\n"
msgstr "URL'%s' は '%s' (%u) へリダイレクトされました\n"
msgid "too many redirections\n"
msgstr "リダイレクトが多すぎます\n"
#, c-format
msgid "redirection changed to '%s'\n"
msgstr "リダイレクトが'%s'に変更されました\n"
#, c-format
msgid "error allocating memory: %s\n"
msgstr "メモリの確保のエラー: %s\n"
@ -7736,13 +7795,6 @@ msgstr "'%s'の接続エラー: %s\n"
msgid "error reading HTTP response for '%s': %s\n"
msgstr "'%s'のHTTP応答の読み込みエラー: %s\n"
#, c-format
msgid "URL '%s' redirected to '%s' (%u)\n"
msgstr "URL'%s' は '%s' (%u) へリダイレクトされました\n"
msgid "too many redirections\n"
msgstr "リダイレクトが多すぎます\n"
#, c-format
msgid "error parsing OCSP response for '%s': %s\n"
msgstr "'%s'に対するOCSP応答構文解析エラー: %s\n"
@ -7751,6 +7803,10 @@ msgstr "'%s'に対するOCSP応答構文解析エラー: %s\n"
msgid "OCSP responder at '%s' status: %s\n"
msgstr "OSCP応答が '%s' でステイタス: %s\n"
#, c-format
msgid "failed to establish a hashing context for OCSP: %s\n"
msgstr "OCSPのハッシュ・コンテクストを確立するのに失敗しました: %s\n"
#, c-format
msgid "hashing the OCSP response for '%s' failed: %s\n"
msgstr "'%s'に対するOCSP応答のハッシングに失敗しました: %s\n"
@ -7758,9 +7814,6 @@ msgstr "'%s'に対するOCSP応答のハッシングに失敗しました: %s\n"
msgid "not signed by a default OCSP signer's certificate"
msgstr "デフォルトOCSP署名者の証明で署名されていません"
msgid "only SHA-1 is supported for OCSP responses\n"
msgstr "SHA-1だけがOCSPレスポンスとしてサポートされています\n"
#, c-format
msgid "allocating list item failed: %s\n"
msgstr "リスト項目の確保に失敗しました: %s\n"
@ -7804,10 +7857,6 @@ msgstr "デフォルトOCSP応答'%s'を使います\n"
msgid "using OCSP responder '%s'\n"
msgstr "OCSP応答'%s'を使います\n"
#, c-format
msgid "failed to establish a hashing context for OCSP: %s\n"
msgstr "OCSPのハッシュ・コンテクストを確立するのに失敗しました: %s\n"
#, c-format
msgid "error getting OCSP status for target certificate: %s\n"
msgstr "対象の証明書のOCSPステイタスの取得エラー: %s\n"
@ -8106,6 +8155,14 @@ msgstr "パスフレーズ入力"
msgid "Component not suitable for launching"
msgstr "コンポーネントが起動するために適切ではありません"
#, c-format
msgid "Configuration file of component %s is broken\n"
msgstr "コンポーネント%sのコンフィグレーション・ファイルが壊れています\n"
#, c-format
msgid "Note: Use the command \"%s%s\" to get details.\n"
msgstr "注意: \"%s%s\"コマンドを使って詳細を得てください。\n"
#, c-format
msgid "External verification of component %s failed"
msgstr "コンポーネント%sの外部の検証が失敗しました"
@ -8332,6 +8389,84 @@ msgstr ""
"形式: gpg-check-pattern [オプション] パターンファイル\n"
"パターンファイルに対して標準入力のパスフレーズを確認する\n"
#, c-format
msgid "%s card no. %s detected\n"
msgstr "%s カード番号 %sを検出しました\n"
msgid "authenticate to the card"
msgstr "カードに対して認証します"
msgid "send a reset to the card daemon"
msgstr "リセットをカードデーモンに送ります"
msgid "change a private data object"
msgstr "プライベート・データオブジェクトを変更します"
msgid "read a certificate from a data object"
msgstr "証明書をデータオブジェクトから読み出します"
msgid "store a certificate to a data object"
msgstr "証明書をデータオブジェクトに保管します"
msgid "store a private key to a data object"
msgstr "プライベート鍵をデータオブジェクトに保管します"
msgid "Yubikey management commands"
msgstr "Yubikey管理コマンド"
#~ msgid "no keyserver known (use option --keyserver)\n"
#~ msgstr "既知の鍵サーバがありません (オプション--keyserverを使いましょう)\n"
#~ msgid "error creating 'ultimately_trusted_keys' TOFU table: %s\n"
#~ msgstr "'ultimately_trusted_keys' TOFUテーブル作成エラー: %s\n"
#~ msgid "error creating 'encryptions' TOFU table: %s\n"
#~ msgstr "'encryptions' TOFUデータベースの作成エラー: %s\n"
#~ msgid "adding column effective_policy to bindings DB: %s\n"
#~ msgstr "バインディングDBにカラムeffective_policyを追加: %s\n"
#~ msgid "resetting keydb: %s\n"
#~ msgstr "keydbをリセット: %s\n"
#~ msgid "error setting TOFU binding's policy to %s\n"
#~ msgstr "TOFUバインディングのポリシーを %s に設定エラー\n"
#~ msgid "%s: Verified %ld~signature in the past %s."
#~ msgid_plural "%s: Verified %ld~signatures in the past %s."
#~ msgstr[0] "%s: 署名を%ld個検証しました(これまで %s に)。"
#~ msgid "Encrypted %ld~message in the past %s."
#~ msgid_plural "Encrypted %ld~messages in the past %s."
#~ msgstr[0] "メッセージを%ld個暗号化しました(これまで %s に)。"
#~ msgid "error setting policy for key %s, user id \"%s\": %s"
#~ msgstr "鍵%s, ユーザID \"%s\"のポリシーの設定エラー: %s"
#~ msgid "only SHA-1 is supported for OCSP responses\n"
#~ msgstr "SHA-1だけがOCSPレスポンスとしてサポートされています\n"
#~ msgid "male"
#~ msgstr "男"
#~ msgid "female"
#~ msgstr "女"
#~ msgid "unspecified"
#~ msgstr "無指定"
#~ msgid "Sex ((M)ale, (F)emale or space): "
#~ msgstr "性別 ((M)男、(F)女、または空白): "
#~ msgid "Warning: '%s' should be a long key ID or a fingerprint\n"
#~ msgstr "警告: '%s'は長い鍵IDかフィンガープリントであるべきです。\n"
#~ msgid "error looking up: %s\n"
#~ msgstr "検索のエラー: %s\n"
#~ msgid "Warning: %s appears in the keyring %d times\n"
#~ msgstr "警告: %sは鍵リングに%d回出現します\n"
#~ msgid "using \"http\" instead of \"https\"\n"
#~ msgstr "\"http\" を \"https\" の代わりに使います\n"

View File

@ -42,23 +42,11 @@
#include "rapdu.h"
#endif /*USE_G10CODE_RAPDU*/
#if defined(GNUPG_SCD_MAIN_HEADER)
#include GNUPG_SCD_MAIN_HEADER
#elif GNUPG_MAJOR_VERSION == 1
/* This is used with GnuPG version < 1.9. The code has been source
copied from the current GnuPG >= 1.9 and is maintained over
there. */
#include "../common/options.h"
#include "errors.h"
#include "memory.h"
#include "../common/util.h"
#include "../common/i18n.h"
#include "dynload.h"
#include "cardglue.h"
#else /* GNUPG_MAJOR_VERSION != 1 */
#include "scdaemon.h"
#include "../common/exechelp.h"
#endif /* GNUPG_MAJOR_VERSION != 1 */
#if defined(GNUPG_MAJOR_VERSION)
# include "scdaemon.h"
# include "../common/exechelp.h"
#endif /*GNUPG_MAJOR_VERSION*/
#include "../common/host2net.h"
#include "iso7816.h"
@ -266,8 +254,13 @@ static npth_mutex_t reader_table_lock;
struct pcsc_io_request_s
{
#if defined(_WIN32) || defined(__CYGWIN__)
pcsc_dword_t protocol;
pcsc_dword_t pci_len;
#else
unsigned long protocol;
unsigned long pci_len;
#endif
};
typedef struct pcsc_io_request_s *pcsc_io_request_t;

View File

@ -36,35 +36,95 @@
/* Flags used with app_writekey. */
#define APP_WRITEKEY_FLAG_FORCE 1 /* Force overwriting existing key. */
/* Flags used with app_readkey. */
#define APP_READKEY_FLAG_INFO 1 /* Send also a KEYPAIRINFO line. */
/* Bit flags set by the decipher function into R_INFO. */
#define APP_DECIPHER_INFO_NOPAD 1 /* Padding has been removed. */
/* List of supported card types. Generic is the usual ISO7817-4
* compliant card. More specific card or token versions can be given
* here. Use strcardtype() to map them to a string. */
typedef enum
{
CARDTYPE_GENERIC = 0,
CARDTYPE_YUBIKEY
} cardtype_t;
/* List of supported card applications. The source code for each
* application can usually be found in an app-NAME.c file. Use
* strapptype() to map them to a string. */
typedef enum
{
APPTYPE_NONE = 0,
APPTYPE_UNDEFINED,
APPTYPE_OPENPGP,
APPTYPE_PIV,
APPTYPE_NKS,
APPTYPE_P15,
APPTYPE_GELDKARTE,
APPTYPE_DINSIG,
APPTYPE_SC_HSM
} apptype_t;
/* Forward declarations. */
struct card_ctx_s;
struct app_ctx_s;
struct app_local_s; /* Defined by all app-*.c. */
struct app_ctx_s {
struct app_ctx_s *next;
typedef struct card_ctx_s *card_t;
typedef struct app_ctx_s *app_t;
/* The object describing a card. */
struct card_ctx_s {
card_t next;
npth_mutex_t lock;
/* Number of connections currently using this application context.
If this is not 0 the application has been initialized and the
function pointers may be used. Note that for unsupported
operations the particular function pointer is set to NULL */
/* Number of connections currently using this application context. */
unsigned int ref_count;
/* Used reader slot. */
int slot;
cardtype_t cardtype; /* The token's type. */
unsigned int cardversion;/* Firmware version of the token or 0. */
unsigned int card_status;
/* The serial number is associated with the card and not with a
* specific app. If a card uses different serial numbers for its
* applications, our code picks the serial number of a specific
* application and uses that. */
unsigned char *serialno; /* Serialnumber in raw form, allocated. */
size_t serialnolen; /* Length in octets of serialnumber. */
const char *cardtype; /* NULL or string with the token's type. */
const char *apptype;
unsigned int cardversion;/* Firmware version of the token or 0. */
unsigned int appversion; /* Version of the application or 0. */
unsigned int card_status;
/* A linked list of applications used on this card. The app at the
* head of the list is the currently active app; To work with the
* other apps, switching to that app might be needed. Switching will
* put the active app at the head of the list. */
app_t app;
/* Various flags. */
unsigned int reset_requested:1;
unsigned int periodical_check_needed:1;
};
/* The object describing a card's applications. A card may have
* several applications and it is usuallay required to explicity
* switch between applications. */
struct app_ctx_s {
app_t next;
card_t card; /* Link back to the card. */
apptype_t apptype; /* The type of the application. */
unsigned int appversion; /* Version of the application or 0. */
unsigned int did_chv1:1;
unsigned int force_chv1:1; /* True if the card does not cache CHV1. */
unsigned int did_chv2:1;
@ -72,11 +132,13 @@ struct app_ctx_s {
struct app_local_s *app_local; /* Local to the application. */
struct {
void (*deinit) (app_t app);
gpg_error_t (*reselect) (app_t app, ctrl_t ctrl);
gpg_error_t (*learn_status) (app_t app, ctrl_t ctrl, unsigned int flags);
gpg_error_t (*readcert) (app_t app, const char *certid,
unsigned char **cert, size_t *certlen);
gpg_error_t (*readkey) (app_t app, const char *certid,
unsigned char **pk, size_t *pklen);
gpg_error_t (*readkey) (app_t app, ctrl_t ctrl,
const char *certid, unsigned int flags,
unsigned char **pk, size_t *pklen);
gpg_error_t (*getattr) (app_t app, ctrl_t ctrl, const char *name);
gpg_error_t (*setattr) (app_t app, const char *name,
gpg_error_t (*pincb)(void*, const char *, char **),
@ -121,11 +183,35 @@ struct app_ctx_s {
gpg_error_t (*check_pin) (app_t app, const char *keyidstr,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg);
gpg_error_t (*with_keygrip) (app_t app, ctrl_t ctrl, int action,
const char *keygrip_str);
} fnc;
};
/* Action values for app_do_with_keygrip. */
enum
{
KEYGRIP_ACTION_SEND_DATA,
KEYGRIP_ACTION_WRITE_STATUS,
KEYGRIP_ACTION_LOOKUP
};
/* Helper to get the slot from an APP object. */
static inline int
app_get_slot (app_t app)
{
if (app && app->card)
return app->card->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_pk (const void *pk, size_t pklen,
char *hexkeygrip);
gpg_error_t app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip);
gpg_error_t app_help_pubkey_from_cert (const void *cert, size_t certlen,
unsigned char **r_pk, size_t *r_pklen);
@ -133,70 +219,85 @@ size_t app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff);
/*-- app.c --*/
void app_send_card_list (ctrl_t ctrl);
const char *strcardtype (cardtype_t t);
const char *strapptype (apptype_t t);
void app_update_priority_list (const char *arg);
gpg_error_t app_send_card_list (ctrl_t ctrl);
char *card_get_serialno (card_t card);
char *app_get_serialno (app_t app);
void app_dump_state (void);
void application_notify_card_reset (int slot);
gpg_error_t check_application_conflict (const char *name, app_t app);
gpg_error_t app_reset (app_t app, ctrl_t ctrl, int send_reset);
gpg_error_t select_application (ctrl_t ctrl, const char *name, app_t *r_app,
gpg_error_t check_application_conflict (card_t card, const char *name,
const unsigned char *serialno_bin,
size_t serialno_bin_len);
gpg_error_t card_reset (card_t card, ctrl_t ctrl, int send_reset);
gpg_error_t select_application (ctrl_t ctrl, const char *name, card_t *r_app,
int scan, const unsigned char *serialno_bin,
size_t serialno_bin_len);
gpg_error_t select_additional_application (ctrl_t ctrl, const char *name);
char *get_supported_applications (void);
void release_application (app_t app, int locked_already);
gpg_error_t app_munge_serialno (app_t app);
gpg_error_t app_write_learn_status (app_t app, ctrl_t ctrl,
card_t card_ref (card_t card);
void card_unref (card_t card);
void card_unref_locked (card_t card);
gpg_error_t app_munge_serialno (card_t card);
gpg_error_t app_write_learn_status (card_t card, ctrl_t ctrl,
unsigned int flags);
gpg_error_t app_readcert (app_t app, ctrl_t ctrl, const char *certid,
gpg_error_t app_readcert (card_t card, ctrl_t ctrl, const char *certid,
unsigned char **cert, size_t *certlen);
gpg_error_t app_readkey (app_t app, ctrl_t ctrl,
const char *keyid, unsigned char **pk, size_t *pklen);
gpg_error_t app_getattr (app_t app, ctrl_t ctrl, const char *name);
gpg_error_t app_setattr (app_t app, ctrl_t ctrl, const char *name,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg,
const unsigned char *value, size_t valuelen);
gpg_error_t app_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg,
const void *indata, size_t indatalen,
unsigned char **outdata, size_t *outdatalen );
gpg_error_t app_auth (app_t app, ctrl_t ctrl, const char *keyidstr,
gpg_error_t app_readkey (card_t card, ctrl_t ctrl,
const char *keyid, unsigned int flags,
unsigned char **pk, size_t *pklen);
gpg_error_t app_getattr (card_t card, ctrl_t ctrl, const char *name);
gpg_error_t app_setattr (card_t card, ctrl_t ctrl, const char *name,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg,
const unsigned char *value, size_t valuelen);
gpg_error_t app_sign (card_t card, ctrl_t ctrl,
const char *keyidstr, int hashalgo,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg,
const void *indata, size_t indatalen,
unsigned char **outdata, size_t *outdatalen);
gpg_error_t app_decipher (app_t app, ctrl_t ctrl, const char *keyidstr,
gpg_error_t app_auth (card_t card, ctrl_t ctrl, 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);
gpg_error_t app_decipher (card_t card, ctrl_t ctrl, 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 app_writecert (app_t app, ctrl_t ctrl,
gpg_error_t app_writecert (card_t card, ctrl_t ctrl,
const char *certidstr,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg,
const unsigned char *keydata, size_t keydatalen);
gpg_error_t app_writekey (app_t app, ctrl_t ctrl,
gpg_error_t app_writekey (card_t card, ctrl_t ctrl,
const char *keyidstr, unsigned int flags,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg,
const unsigned char *keydata, size_t keydatalen);
gpg_error_t app_genkey (app_t app, ctrl_t ctrl,
gpg_error_t app_genkey (card_t card, ctrl_t ctrl,
const char *keynostr, const char *keytype,
unsigned int flags, time_t createtime,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg);
gpg_error_t app_get_challenge (app_t app, ctrl_t ctrl, size_t nbytes,
gpg_error_t app_get_challenge (card_t card, ctrl_t ctrl, size_t nbytes,
unsigned char *buffer);
gpg_error_t app_change_pin (app_t app, ctrl_t ctrl,
gpg_error_t app_change_pin (card_t card, ctrl_t ctrl,
const char *chvnostr, unsigned int flags,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg);
gpg_error_t app_check_pin (app_t app, ctrl_t ctrl, const char *keyidstr,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg);
gpg_error_t app_check_pin (card_t card, ctrl_t ctrl, const char *keyidstr,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg);
card_t app_do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str);
/*-- app-openpgp.c --*/

View File

@ -81,7 +81,6 @@
#include "../common/i18n.h"
#include "iso7816.h"
#include "app-common.h"
#include "../common/tlv.h"
@ -101,7 +100,7 @@ do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
/* Return the certificate of the card holder. */
fid = 0xC000;
len = app_help_read_length_of_cert (app->slot, fid, &certoff);
len = app_help_read_length_of_cert (app_get_slot (app), fid, &certoff);
if (!len)
return 0; /* Card has not been personalized. */
@ -114,7 +113,8 @@ do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
/* Now we need to read the certificate, so that we can get the
public key out of it. */
err = iso7816_read_binary (app->slot, certoff, len-certoff, &der, &derlen);
err = iso7816_read_binary (app_get_slot (app), certoff, len-certoff,
&der, &derlen);
if (err)
{
log_info ("error reading entire certificate from FID 0x%04X: %s\n",
@ -193,14 +193,14 @@ do_readcert (app_t app, const char *certid,
/* Read the entire file. fixme: This could be optimized by first
reading the header to figure out how long the certificate
actually is. */
err = iso7816_select_file (app->slot, fid, 0);
err = iso7816_select_file (app_get_slot (app), fid, 0);
if (err)
{
log_error ("error selecting FID 0x%04X: %s\n", fid, gpg_strerror (err));
return err;
}
err = iso7816_read_binary (app->slot, 0, 0, &buffer, &buflen);
err = iso7816_read_binary (app_get_slot (app), 0, 0, &buffer, &buflen);
if (err)
{
log_error ("error reading certificate from FID 0x%04X: %s\n",
@ -293,7 +293,7 @@ verify_pin (app_t app,
pininfo.maxlen = 8;
if (!opt.disable_pinpad
&& !iso7816_check_pinpad (app->slot, ISO7816_VERIFY, &pininfo) )
&& !iso7816_check_pinpad (app_get_slot (app), ISO7816_VERIFY, &pininfo) )
{
rc = pincb (pincb_arg,
_("||Please enter your PIN at the reader's pinpad"),
@ -304,7 +304,7 @@ verify_pin (app_t app,
gpg_strerror (rc));
return rc;
}
rc = iso7816_verify_kp (app->slot, 0x81, &pininfo);
rc = iso7816_verify_kp (app_get_slot (app), 0x81, &pininfo);
/* Dismiss the prompt. */
pincb (pincb_arg, NULL, NULL);
}
@ -345,7 +345,8 @@ verify_pin (app_t app,
return gpg_error (GPG_ERR_BAD_PIN);
}
rc = iso7816_verify (app->slot, 0x81, pinvalue, strlen (pinvalue));
rc = iso7816_verify (app_get_slot (app), 0x81,
pinvalue, strlen (pinvalue));
if (gpg_err_code (rc) == GPG_ERR_INV_VALUE)
{
/* We assume that ISO 9564-1 encoding is used and we failed
@ -366,7 +367,8 @@ verify_pin (app_t app,
paddedpin[i++] = (((*s - '0') << 4) | 0x0f);
while (i < sizeof paddedpin)
paddedpin[i++] = 0xff;
rc = iso7816_verify (app->slot, 0x81, paddedpin, sizeof paddedpin);
rc = iso7816_verify (app_get_slot (app), 0x81,
paddedpin, sizeof paddedpin);
}
xfree (pinvalue);
}
@ -482,7 +484,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
rc = verify_pin (app, pincb, pincb_arg);
if (!rc)
rc = iso7816_compute_ds (app->slot, 0, data, datalen, 0,
rc = iso7816_compute_ds (app_get_slot (app), 0, data, datalen, 0,
outdata, outdatalen);
return rc;
}
@ -532,7 +534,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
return err;
}
err = iso7816_change_reference_data (app->slot, 0x81,
err = iso7816_change_reference_data (app_get_slot (app), 0x81,
oldpin, oldpinlen,
pinvalue, strlen (pinvalue));
xfree (pinvalue);
@ -547,14 +549,15 @@ gpg_error_t
app_select_dinsig (app_t app)
{
static char const aid[] = { 0xD2, 0x76, 0x00, 0x00, 0x66, 0x01 };
int slot = app->slot;
int slot = app_get_slot (app);
int rc;
rc = iso7816_select_application (slot, aid, sizeof aid, 0);
if (!rc)
{
app->apptype = "DINSIG";
app->apptype = APPTYPE_DINSIG;
app->fnc.reselect = NULL;
app->fnc.learn_status = do_learn_status;
app->fnc.readcert = do_readcert;
app->fnc.getattr = NULL;

Some files were not shown because too many files have changed in this diff Show More