1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-12-21 10:09:57 +01:00

Merge branch 'STABLE-BRANCH-2-4'

--
Fixed conflicts:
	NEWS
	configure.ac
	doc/gpg.texi
This commit is contained in:
Werner Koch 2024-01-26 09:41:00 +01:00
commit dfa60c09f5
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
88 changed files with 2655 additions and 1419 deletions

View File

@ -16,7 +16,7 @@ List of Copyright holders
=========================
Copyright (C) 1997-2019 Werner Koch
Copyright (C) 2003-2023 g10 Code GmbH
Copyright (C) 2003-2024 g10 Code GmbH
Copyright (C) 1994-2021 Free Software Foundation, Inc.
Copyright (C) 2002 Klarälvdalens Datakonsult AB
Copyright (C) 1995-1997, 2000-2007 Ulrich Drepper <drepper@gnu.ai.mit.edu>

View File

@ -191,7 +191,7 @@ endif
gen_start_date = 2011-12-01T06:00:00
.PHONY: gen-ChangeLog
.PHONY: gen-ChangeLog stowinstall speedo
gen-ChangeLog:
if test -e $(top_srcdir)/.git; then \
(cd $(top_srcdir) && \
@ -207,6 +207,11 @@ gen-ChangeLog:
stowinstall:
$(MAKE) $(AM_MAKEFLAGS) install prefix=/usr/local/stow/gnupg
speedo:
$(MAKE) -f $(top_srcdir)/build-aux/speedo.mk native SELFCHECK=0
TESTS_ENVIRONMENT = \
LC_ALL=C \
EXEEXT=$(EXEEXT) \

107
NEWS
View File

@ -3,9 +3,104 @@ Noteworthy changes in version 2.5.0 (unreleased)
Changes also found in 2.4.4:
* gpgsm: Support ECDSA in de-vs compliance mode. [T6802]
* gpg: Do not keep an unprotected smartcard backup key on disk. See
https://gnupg.org/blog/20240125-smartcard-backup-key.html for a
security advisory. [T6944]
* gpg: Allow to specify seconds since Epoch beyond 2038 on 32-bit
platforms. [T6736]
* gpg: Fix expiration time when Creation-Date is specified. [T5252]
* gpg: Add support for Subkey-Expire-Date. [rG96b69c1866]
* gpg: Add option --with-v5-fingerprint. [T6705]
* gpg: Add sub-option ignore-attributes to --import-options.
[rGd4976e35d2]
* gpg: Add --list-filter properties sig_expires/sig_expires_d.
[rGbf662d0f93af]
* gpg: Fix validity of re-imported keys. [T6399]
* gpg: Report BEGIN_ status before examining the input. [T6481]
* gpg: Don't try to compress a read-only keybox. [T6811]
* gpg: Choose key from inserted card over a non-inserted
card. [T6831]
* gpg: Allow to create revocations even with non-compliant algos.
[T6929]
* gpg: Fix regression in the Revoker keyword of the parameter file.
[T6923]
* gpg: Improve error message for expired default keys. [T4704]
* gpgsm: Add --always-trust feature. [T6559]
* gpgsm: Support ECC certificates in de-vs mode. [T6802]
* gpgsm: Major rewrite of the PKCS#12 parser. [T6536]
* gpgsm: No not show the pkcs#12 passphrase in debug output. [T6654]
* keyboxd: Timeout on failure to get the database lock. [T6838]
* agent: Update the key stubs only if really modified. [T6829]
* scd: Add support for certain Starcos 3.2 cards. [rG5304c9b080]
* scd: Add support for CardOS 5.4 cards. [rG812f988059]
* scd: Add support for D-Trust 4.1/4.4 cards. [rG0b85a9ac09]
* scd: Add support for Smartcafe Expert 7.0 cards. [T6919]
* scd: Add a length check for a new PIN. [T6843]
* tpm: Fix keytotpm handling in the agent. [rG9909f622f6]
* tpm: Fixes for the TPM test suite. [T6052]
* dirmngr: Avoid starting a second instance on Windows via GPGME
based launching. [T6833]
* dirmngr: New option --ignore-crl-extensions. [T6545]
* dirmngr: Support config value "none" to disable the default
keyserver. [T6708]
* dirmngr: Implement automatic proxy detection on Windows. [T5768]
* dirmngr: Fix handling of the HTTP Content-Length. [rGa5e33618f4]
* dirmngr: Add code to support proxy authentication using the
Negotiation method on Windows. [T6719]
* gpgconf: Add commands --lock and --unlock. [rG93b5ba38dc]
* gpgconf: Add keyword socketdir to gpgconf.ctl. [rG239c1fdc28]
* gpgconf: Adjust the -X command for the new VERSION file format.
[T6918]
* wkd: Use export-clean for gpg-wks-client's --mirror and --create
commands. [rG2c7f7a5a278c]
* wkd: Make --add-revocs the default in gpg-wks-client. New option
--no-add-revocs. [rG10c937ee68]
* Remove duplicated backslashes when setting the homedir. [T6833]
* Ignore attempts to remove the /dev/null device. [T6556]
* Improve advisory file lock retry strategy. [T3380]
* Improve the speedo build system for Unix. [T6710]
* Fix garbled time output in non-English Windows. [T6741]
Changes also found in 2.4.3:
@ -21,6 +116,8 @@ Noteworthy changes in version 2.5.0 (unreleased)
* gpg: New option --no-compress as alias for -z0.
* gpg: Show better error messages for blocked PINs. [T6425]
* gpgsm: Print PROGRESS status lines. Add new --input-size-hint.
[T6534]
@ -52,6 +149,9 @@ Noteworthy changes in version 2.5.0 (unreleased)
* scd: Fix authentication with Administration Key for PIV.
[rG25b59cf6ce]
* Fix garbled time output in non-English Windows. [T6741]
Changes also found in 2.4.2:
* gpg: Print a warning if no more encryption subkeys are left over
@ -78,7 +178,7 @@ Noteworthy changes in version 2.5.0 (unreleased)
Release dates of 2.4 versions
-----------------------------
Version 2.4.4 (unreleased) https://dev.gnupg.org/T6578
Version 2.4.4 (2024-01-25) https://dev.gnupg.org/T6578
Version 2.4.3 (2023-07-04) https://dev.gnupg.org/T6509
Version 2.4.2 (2023-05-30) https://dev.gnupg.org/T6506
Version 2.4.1 (2023-04-28) https://dev.gnupg.org/T6454
@ -1678,6 +1778,7 @@ Noteworthy changes in version 2.3.0 (2021-04-07)
Release dates of 2.2 versions
-----------------------------
Version 2.2.42 (2023-11-28) https://dev.gnupg.org/T6307
Version 2.2.41 (2022-12-09) https://dev.gnupg.org/T6280
Version 2.2.40 (2022-10-10) https://dev.gnupg.org/T6181
Version 2.2.39 (2022-09-02) https://dev.gnupg.org/T6175

25
README
View File

@ -4,7 +4,7 @@
Copyright 1997-2019 Werner Koch
Copyright 1998-2021 Free Software Foundation, Inc.
Copyright 2003-2023 g10 Code GmbH
Copyright 2003-2024 g10 Code GmbH
* INTRODUCTION
@ -40,7 +40,7 @@
Several other standard libraries are also required. The configure
script prints diagnostic messages if one of these libraries is not
available and a feature will not be available..
available and a feature will not be available.
You also need the Pinentry package for most functions of GnuPG;
however it is not a build requirement. Pinentry is available at
@ -80,15 +80,24 @@
to view the directories used by GnuPG.
** Quick build method on Unix
To quickly build all required software without installing it, the
Speedo method may be used:
Speedo target may be used:
cd build
make -f ../build-aux/speedo.mk native
make -f build-aux/speedo.mk native
This target downloads all required libraries and does a native build
of GnuPG to PLAY/inst/. GNU make and the patchelf tool are
required. After the build the entire software including all
libraries can be installed into an arbitrary location using for
example:
make -f build-aux/speedo.mk install SYSROOT=/usr/local/gnupg24
ldconfig -n /usr/local/gnupg24/lib
and adding /usr/local/gnupg24/bin to PATH.
This method downloads all required libraries and does a native build
of GnuPG to PLAY/inst/. GNU make is required and you need to set
LD_LIBRARY_PATH to $(pwd)/PLAY/inst/lib to test the binaries.
** Specific build problems on some machines:

View File

@ -225,6 +225,17 @@ typedef struct ssh_control_file_s *ssh_control_file_t;
/* Forward reference for local definitions in call-scd.c. */
struct daemon_local_s;
/* Object to hold ephemeral secret keys. */
struct ephemeral_private_key_s
{
struct ephemeral_private_key_s *next;
unsigned char grip[KEYGRIP_LEN];
unsigned char *keybuf; /* Canon-s-exp with the private key (malloced). */
size_t keybuflen;
};
typedef struct ephemeral_private_key_s *ephemeral_private_key_t;
/* Collection of data per session (aka connection). */
struct server_control_s
{
@ -246,6 +257,12 @@ struct server_control_s
/* Private data of the daemon (call-XXX.c). */
struct daemon_local_s *d_local[DAEMON_MAX_TYPE];
/* Linked list with ephemeral stored private keys. */
ephemeral_private_key_t ephemeral_keys;
/* If set functions will lookup keys in the ephemeral_keys list. */
int ephemeral_mode;
/* Environment settings for the connection. */
session_env_t session_env;
char *lc_ctype;
@ -453,7 +470,8 @@ void start_command_handler_ssh (ctrl_t, gnupg_fd_t);
/*-- findkey.c --*/
gpg_error_t agent_modify_description (const char *in, const char *comment,
const gcry_sexp_t key, char **result);
gpg_error_t agent_write_private_key (const unsigned char *grip,
gpg_error_t agent_write_private_key (ctrl_t ctrl,
const unsigned char *grip,
const void *buffer, size_t length,
int force,
const char *serialno, const char *keyref,
@ -478,7 +496,7 @@ gpg_error_t agent_ssh_key_from_file (ctrl_t ctrl,
gcry_sexp_t *result, int *r_order);
int agent_pk_get_algo (gcry_sexp_t s_key);
int agent_is_tpm2_key(gcry_sexp_t s_key);
int agent_key_available (const unsigned char *grip);
int agent_key_available (ctrl_t ctrl, const unsigned char *grip);
gpg_error_t agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
int *r_keytype,
unsigned char **r_shadow_info,
@ -486,7 +504,8 @@ gpg_error_t agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
gpg_error_t agent_delete_key (ctrl_t ctrl, const char *desc_text,
const unsigned char *grip,
int force, int only_stubs);
gpg_error_t agent_update_private_key (const unsigned char *grip, nvc_t pk);
gpg_error_t agent_update_private_key (ctrl_t ctrl,
const unsigned char *grip, nvc_t pk);
/*-- call-pinentry.c --*/
void initialize_module_call_pinentry (void);
@ -542,15 +561,21 @@ gpg_error_t agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
#define CHECK_CONSTRAINTS_NOT_EMPTY 1
#define CHECK_CONSTRAINTS_NEW_SYMKEY 2
#define GENKEY_FLAG_NO_PROTECTION 1
#define GENKEY_FLAG_PRESET 2
void clear_ephemeral_keys (ctrl_t ctrl);
int check_passphrase_constraints (ctrl_t ctrl, const char *pw,
unsigned int flags,
char **failed_constraint);
gpg_error_t agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
char **r_passphrase);
int agent_genkey (ctrl_t ctrl, const char *cache_nonce, time_t timestamp,
int agent_genkey (ctrl_t ctrl, unsigned int flags,
const char *cache_nonce, time_t timestamp,
const char *keyparam, size_t keyparmlen,
int no_protection, const char *override_passphrase,
int preset, membuf_t *outbuf);
const char *override_passphrase,
membuf_t *outbuf);
gpg_error_t agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey,
char **passphrase_addr);
@ -588,7 +613,7 @@ gpg_error_t s2k_hash_passphrase (const char *passphrase, int hashalgo,
const unsigned char *s2ksalt,
unsigned int s2kcount,
unsigned char *key, size_t keylen);
gpg_error_t agent_write_shadow_key (const unsigned char *grip,
gpg_error_t agent_write_shadow_key (ctrl_t ctrl, const unsigned char *grip,
const char *serialno, const char *keyid,
const unsigned char *pkbuf, int force,
const char *dispserialno);

View File

@ -2430,14 +2430,14 @@ card_key_available (ctrl_t ctrl, const struct card_key_info_s *keyinfo,
}
hex2bin (keyinfo->keygrip, grip, sizeof (grip));
if ( agent_key_available (grip) )
if (!ctrl->ephemeral_mode && agent_key_available (ctrl, grip) )
{
char *dispserialno;
/* (Shadow)-key is not available in our key storage. */
agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno,
keyinfo->keygrip);
err = agent_write_shadow_key (grip, keyinfo->serialno,
err = agent_write_shadow_key (ctrl, grip, keyinfo->serialno,
keyinfo->idstr, pkbuf, 0, dispserialno);
xfree (dispserialno);
if (err)
@ -3222,7 +3222,7 @@ ssh_identity_register (ctrl_t ctrl, ssh_key_type_spec_t *spec,
/* Check whether the key is already in our key storage. Don't do
anything then besides (re-)adding it to sshcontrol. */
if ( !agent_key_available (key_grip_raw) )
if ( !agent_key_available (ctrl, key_grip_raw) )
goto key_exists; /* Yes, key is available. */
err = ssh_key_extract_comment (key, &comment);
@ -3286,7 +3286,7 @@ ssh_identity_register (ctrl_t ctrl, ssh_key_type_spec_t *spec,
/* Store this key to our key storage. We do not store a creation
* timestamp because we simply do not know. */
err = agent_write_private_key (key_grip_raw, buffer, buffer_n, 0,
err = agent_write_private_key (ctrl, key_grip_raw, buffer, buffer_n, 0,
NULL, NULL, NULL, 0);
if (err)
goto out;

View File

@ -251,6 +251,9 @@ reset_notify (assuan_context_t ctx, char *line)
clear_nonce_cache (ctrl);
/* Note that a RESET does not clear the ephemeral store becuase
* clients are used to issue a RESET on a connection. */
return 0;
}
@ -634,34 +637,65 @@ cmd_marktrusted (assuan_context_t ctx, char *line)
static const char hlp_havekey[] =
"HAVEKEY <hexstrings_with_keygrips>\n"
"HAVEKEY --list[=<limit>]\n"
"HAVEKEY --info <hexkeygrip>\n"
"\n"
"Return success if at least one of the secret keys with the given\n"
"keygrips is available. With --list return all available keygrips\n"
"as binary data; with <limit> bail out at this number of keygrips";
"as binary data; with <limit> bail out at this number of keygrips.\n"
"In --info mode check just one keygrip.";
static gpg_error_t
cmd_havekey (assuan_context_t ctx, char *line)
{
ctrl_t ctrl;
ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err;
unsigned char grip[20];
char *p;
int list_mode; /* Less than 0 for no limit. */
int list_mode = 0; /* Less than 0 for no limit. */
int info_mode = 0;
int counter;
char *dirname;
gnupg_dir_t dir;
char *dirname = NULL;
gnupg_dir_t dir = NULL;
gnupg_dirent_t dir_entry;
char hexgrip[41];
struct card_key_info_s *keyinfo_on_cards, *l;
if (has_option_name (line, "--list"))
if (has_option (line, "--info"))
info_mode = 1;
else if (has_option_name (line, "--list"))
{
if ((p = option_value (line, "--list")))
list_mode = atoi (p);
else
list_mode = -1;
}
else
list_mode = 0;
line = skip_options (line);
if (info_mode)
{
int keytype;
const char *infostring;
err = parse_keygrip (ctx, line, grip);
if (err)
goto leave;
err = agent_key_info_from_file (ctrl, grip, &keytype, NULL, NULL);
if (err)
goto leave;
switch (keytype)
{
case PRIVATE_KEY_CLEAR:
case PRIVATE_KEY_OPENPGP_NONE: infostring = "clear"; break;
case PRIVATE_KEY_PROTECTED: infostring = "protected"; break;
case PRIVATE_KEY_SHADOWED: infostring = "shadowed"; break;
default: infostring = "unknown"; break;
}
err = agent_write_status (ctrl, "KEYFILEINFO", infostring, NULL);
goto leave;
}
if (!list_mode)
@ -672,7 +706,7 @@ cmd_havekey (assuan_context_t ctx, char *line)
if (err)
return err;
if (!agent_key_available (grip))
if (!agent_key_available (ctrl, grip))
return 0; /* Found. */
while (*line && *line != ' ' && *line != '\t')
@ -690,7 +724,6 @@ cmd_havekey (assuan_context_t ctx, char *line)
/* List mode. */
dir = NULL;
dirname = NULL;
ctrl = assuan_get_pointer (ctx);
if (ctrl->restricted)
{
@ -1083,26 +1116,27 @@ cmd_genkey (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
int rc;
int no_protection;
unsigned char *value = NULL;
size_t valuelen;
unsigned char *newpasswd = NULL;
membuf_t outbuf;
char *cache_nonce = NULL;
char *passwd_nonce = NULL;
int opt_preset;
int opt_inq_passwd;
size_t n;
char *p, *pend;
const char *s;
time_t opt_timestamp;
int c;
unsigned int flags = 0;
if (ctrl->restricted)
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
no_protection = has_option (line, "--no-protection");
opt_preset = has_option (line, "--preset");
if (has_option (line, "--no-protection"))
flags |= GENKEY_FLAG_NO_PROTECTION;
if (has_option (line, "--preset"))
flags |= GENKEY_FLAG_PRESET;
opt_inq_passwd = has_option (line, "--inq-passwd");
passwd_nonce = option_value (line, "--passwd-nonce");
if (passwd_nonce)
@ -1157,7 +1191,7 @@ cmd_genkey (assuan_context_t ctx, char *line)
/* If requested, ask for the password to be used for the key. If
this is not used the regular Pinentry mechanism is used. */
if (opt_inq_passwd && !no_protection)
if (opt_inq_passwd && !(flags & GENKEY_FLAG_NO_PROTECTION))
{
/* (N is used as a dummy) */
assuan_begin_confidential (ctx);
@ -1170,16 +1204,17 @@ cmd_genkey (assuan_context_t ctx, char *line)
/* Empty password given - switch to no-protection mode. */
xfree (newpasswd);
newpasswd = NULL;
no_protection = 1;
flags |= GENKEY_FLAG_NO_PROTECTION;
}
}
else if (passwd_nonce)
newpasswd = agent_get_cache (ctrl, passwd_nonce, CACHE_MODE_NONCE);
rc = agent_genkey (ctrl, cache_nonce, opt_timestamp,
(char*)value, valuelen, no_protection,
newpasswd, opt_preset, &outbuf);
rc = agent_genkey (ctrl, flags, cache_nonce, opt_timestamp,
(char*)value, valuelen,
newpasswd, &outbuf);
leave:
if (newpasswd)
@ -1283,7 +1318,7 @@ cmd_keyattr (assuan_context_t ctx, char *line)
if (!err)
err = nvc_set_private_key (keymeta, s_key);
if (!err)
err = agent_update_private_key (grip, keymeta);
err = agent_update_private_key (ctrl, grip, keymeta);
}
nvc_release (keymeta);
@ -1293,6 +1328,8 @@ cmd_keyattr (assuan_context_t ctx, char *line)
leave:
return leave_cmd (ctx, err);
}
static const char hlp_readkey[] =
"READKEY [--no-data] [--format=ssh] <hexstring_with_keygrip>\n"
@ -1356,7 +1393,7 @@ cmd_readkey (assuan_context_t ctx, char *line)
goto leave;
}
if (agent_key_available (grip))
if (!ctrl->ephemeral_mode && agent_key_available (ctrl, grip))
{
/* (Shadow)-key is not available in our key storage. */
char *dispserialno;
@ -1364,7 +1401,7 @@ cmd_readkey (assuan_context_t ctx, char *line)
bin2hex (grip, 20, hexgrip);
agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno, hexgrip);
rc = agent_write_shadow_key (grip, serialno, keyid, pkbuf, 0,
rc = agent_write_shadow_key (ctrl, grip, serialno, keyid, pkbuf, 0,
dispserialno);
xfree (dispserialno);
if (rc)
@ -2900,7 +2937,7 @@ cmd_import_key (assuan_context_t ctx, char *line)
}
else
{
if (!force && !agent_key_available (grip))
if (!force && !agent_key_available (ctrl, grip))
err = gpg_error (GPG_ERR_EEXIST);
else
{
@ -2922,11 +2959,11 @@ cmd_import_key (assuan_context_t ctx, char *line)
err = agent_protect (key, passphrase, &finalkey, &finalkeylen,
ctrl->s2k_count);
if (!err)
err = agent_write_private_key (grip, finalkey, finalkeylen, force,
err = agent_write_private_key (ctrl, grip, finalkey, finalkeylen, force,
NULL, NULL, NULL, opt_timestamp);
}
else
err = agent_write_private_key (grip, key, realkeylen, force,
err = agent_write_private_key (ctrl, grip, key, realkeylen, force,
NULL, NULL, NULL, opt_timestamp);
leave:
@ -2945,7 +2982,8 @@ cmd_import_key (assuan_context_t ctx, char *line)
static const char hlp_export_key[] =
"EXPORT_KEY [--cache-nonce=<nonce>] [--openpgp|--mode1003] <hexkeygrip>\n"
"EXPORT_KEY [--cache-nonce=<nonce>] \\\n"
" [--openpgp|--mode1003] <hexkeygrip>\n"
"\n"
"Export a secret key from the key store. The key will be encrypted\n"
"using the current session's key wrapping key (cf. command KEYWRAP_KEY)\n"
@ -2953,8 +2991,8 @@ static const char hlp_export_key[] =
"prior to using this command. The function takes the keygrip as argument.\n"
"\n"
"If --openpgp is used, the secret key material will be exported in RFC 4880\n"
"compatible passphrase-protected form. If --mode1003 is use the secret key\n"
"is exported as s-expression as storred locally. Without those options,\n"
"compatible passphrase-protected form. In --mode1003 the secret key\n"
"is exported as s-expression as stored locally. Without those options,\n"
"the secret key material will be exported in the clear (after prompting\n"
"the user to unlock it, if needed).\n";
static gpg_error_t
@ -3011,7 +3049,7 @@ cmd_export_key (assuan_context_t ctx, char *line)
if (err)
goto leave;
if (agent_key_available (grip))
if (agent_key_available (ctrl, grip))
{
err = gpg_error (GPG_ERR_NO_SECKEY);
goto leave;
@ -3223,9 +3261,9 @@ cmd_keytocard (assuan_context_t ctx, char *line)
if (err)
goto leave;
if (agent_key_available (grip))
if (agent_key_available (ctrl, grip))
{
err =gpg_error (GPG_ERR_NO_SECKEY);
err = gpg_error (GPG_ERR_NO_SECKEY);
goto leave;
}
@ -3543,7 +3581,7 @@ cmd_keytotpm (assuan_context_t ctx, char *line)
if (err)
goto leave;
if (agent_key_available (grip))
if (agent_key_available (ctrl, grip))
{
err =gpg_error (GPG_ERR_NO_SECKEY);
goto leave;
@ -3835,6 +3873,7 @@ static const char hlp_getinfo[] =
" getenv NAME - Return value of envvar NAME.\n"
" connections - Return number of active connections.\n"
" jent_active - Returns OK if Libgcrypt's JENT is active.\n"
" ephemeral - Returns OK if the connection is in ephemeral mode.\n"
" restricted - Returns OK if the connection is in restricted mode.\n"
" cmd_has_option CMD OPT\n"
" - Returns OK if command CMD has option OPT.\n";
@ -3888,6 +3927,10 @@ cmd_getinfo (assuan_context_t ctx, char *line)
snprintf (numbuf, sizeof numbuf, "%lu", get_standard_s2k_count ());
rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
}
else if (!strcmp (line, "ephemeral"))
{
rc = ctrl->ephemeral_mode? 0 : gpg_error (GPG_ERR_FALSE);
}
else if (!strcmp (line, "restricted"))
{
rc = ctrl->restricted? 0 : gpg_error (GPG_ERR_FALSE);
@ -4044,6 +4087,10 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
ctrl->server_local->allow_fully_canceled =
gnupg_compare_version (value, "2.1.0");
}
else if (!strcmp (key, "ephemeral"))
{
ctrl->ephemeral_mode = *value? atoi (value) : 0;
}
else if (ctrl->restricted)
{
err = gpg_error (GPG_ERR_FORBIDDEN);

View File

@ -969,7 +969,7 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp, int dontcare_exist,
if (err)
goto leave;
if (!dontcare_exist && !from_native && !agent_key_available (grip))
if (!dontcare_exist && !from_native && !agent_key_available (ctrl, grip))
{
err = gpg_error (GPG_ERR_EEXIST);
goto leave;
@ -1147,14 +1147,16 @@ convert_from_openpgp_native (ctrl_t ctrl,
if (!agent_protect (*r_key, passphrase,
&protectedkey, &protectedkeylen,
ctrl->s2k_count))
agent_write_private_key (grip, protectedkey, protectedkeylen, 1,
NULL, NULL, NULL, 0);
agent_write_private_key (ctrl, grip,
protectedkey,
protectedkeylen,
1, NULL, NULL, NULL, 0);
xfree (protectedkey);
}
else
{
/* Empty passphrase: write key without protection. */
agent_write_private_key (grip,
agent_write_private_key (ctrl, grip,
*r_key,
gcry_sexp_canon_len (*r_key, 0, NULL,NULL),
1, NULL, NULL, NULL, 0);

View File

@ -57,7 +57,7 @@ agent_write_tpm2_shadow_key (ctrl_t ctrl, const unsigned char *grip,
}
len = gcry_sexp_canon_len (shdkey, 0, NULL, NULL);
err = agent_write_private_key (grip, shdkey, len, 1 /*force*/,
err = agent_write_private_key (ctrl, grip, shdkey, len, 1 /*force*/,
NULL, NULL, NULL, 0);
xfree (shdkey);
if (err)
@ -70,7 +70,7 @@ agent_write_tpm2_shadow_key (ctrl_t ctrl, const unsigned char *grip,
return GPG_ERR_ENOMEM;
gcry_sexp_sprint(s_key, GCRYSEXP_FMT_CANON, pkbuf, len);
err1 = agent_write_private_key (grip, pkbuf, len, 1 /*force*/,
err1 = agent_write_private_key (ctrl, grip, pkbuf, len, 1 /*force*/,
NULL, NULL, NULL, 0);
xfree(pkbuf);
if (err1)

View File

@ -40,7 +40,7 @@
#endif
static gpg_error_t read_key_file (const unsigned char *grip,
static gpg_error_t read_key_file (ctrl_t ctrl, const unsigned char *grip,
gcry_sexp_t *result, nvc_t *r_keymeta,
char **r_orig_key_value);
static gpg_error_t is_shadowed_key (gcry_sexp_t s_skey);
@ -73,6 +73,30 @@ fname_from_keygrip (const unsigned char *grip, int for_new)
}
/* Helper until we have a "wipe" mode flag in es_fopen. */
static void
wipe_and_fclose (estream_t fp)
{
void *blob;
size_t blob_size;
if (!fp)
;
else if (es_fclose_snatch (fp, &blob, &blob_size))
{
log_error ("error wiping buffer during fclose\n");
es_fclose (fp);
}
else if (blob)
{
wipememory (blob, blob_size);
gpgrt_free (blob);
}
}
/* Replace all linefeeds in STRING by "%0A" and return a new malloced
* string. May return NULL on memory error. */
static char *
@ -110,7 +134,8 @@ linefeed_to_percent0A (const char *string)
* TIMESTAMP is not zero and the key does not yet exists it will be
* recorded as creation date. */
gpg_error_t
agent_write_private_key (const unsigned char *grip,
agent_write_private_key (ctrl_t ctrl,
const unsigned char *grip,
const void *buffer, size_t length, int force,
const char *serialno, const char *keyref,
const char *dispserialno,
@ -120,7 +145,7 @@ agent_write_private_key (const unsigned char *grip,
char *fname = NULL;
char *tmpfname = NULL;
estream_t fp = NULL;
int newkey;
int newkey = 0;
nvc_t pk = NULL;
gcry_sexp_t key = NULL;
int removetmp = 0;
@ -134,11 +159,13 @@ agent_write_private_key (const unsigned char *grip,
const char *s;
int force_modify = 0;
fname = fname_from_keygrip (grip, 0);
fname = (ctrl->ephemeral_mode
? xtrystrdup ("[ephemeral key store]")
: fname_from_keygrip (grip, 0));
if (!fname)
return gpg_error_from_syserror ();
err = read_key_file (grip, &key, &pk, &orig_key_value);
err = read_key_file (ctrl, grip, &key, &pk, &orig_key_value);
if (err)
{
if (gpg_err_code (err) == GPG_ERR_ENOENT)
@ -289,6 +316,61 @@ agent_write_private_key (const unsigned char *grip,
goto leave;
}
if (ctrl->ephemeral_mode)
{
ephemeral_private_key_t ek;
void *blob;
size_t blobsize;
for (ek = ctrl->ephemeral_keys; ek; ek = ek->next)
if (!memcmp (ek->grip, grip, KEYGRIP_LEN))
break;
if (!ek)
{
ek = xtrycalloc (1, sizeof *ek);
if (!ek)
{
err = gpg_error_from_syserror ();
goto leave;
}
memcpy (ek->grip, grip, KEYGRIP_LEN);
ek->next = ctrl->ephemeral_keys;
ctrl->ephemeral_keys = ek;
}
fp = es_fopenmem (0, "wb,wipe");
if (!fp)
{
err = gpg_error_from_syserror ();
log_error ("can't open memory stream: %s\n", gpg_strerror (err));
goto leave;
}
err = nvc_write (pk, fp);
if (err)
{
log_error ("error writing to memory stream: %s\n",gpg_strerror (err));
goto leave;
}
if (es_fclose_snatch (fp, &blob, &blobsize) || !blob)
{
err = gpg_error_from_syserror ();
log_error ("error getting memory stream buffer: %s\n",
gpg_strerror (err));
/* Closing right away so that we don't try another snatch in
* the cleanup. */
es_fclose (fp);
fp = NULL;
goto leave;
}
fp = NULL;
xfree (ek->keybuf);
ek->keybuf = blob;
ek->keybuflen = blobsize;
}
else
{
/* Create a temporary file for writing. */
tmpfname = fname_from_keygrip (grip, 1);
fp = tmpfname ? es_fopen (tmpfname, "wbx,mode=-rw") : NULL;
@ -327,12 +409,16 @@ agent_write_private_key (const unsigned char *grip,
removetmp = 1;
goto leave;
}
}
bump_key_eventcounter ();
leave:
if (blocksigs)
gnupg_unblock_all_signals ();
if (ctrl->ephemeral_mode)
wipe_and_fclose (fp);
else
es_fclose (fp);
if (removetmp && tmpfname)
gnupg_remove (tmpfname);
@ -350,7 +436,7 @@ agent_write_private_key (const unsigned char *grip,
gpg_error_t
agent_update_private_key (const unsigned char *grip, nvc_t pk)
agent_update_private_key (ctrl_t ctrl, const unsigned char *grip, nvc_t pk)
{
gpg_error_t err;
char *fname0 = NULL; /* The existing file name. */
@ -359,6 +445,57 @@ agent_update_private_key (const unsigned char *grip, nvc_t pk)
int removetmp = 0;
int blocksigs = 0;
if (ctrl->ephemeral_mode)
{
ephemeral_private_key_t ek;
void *blob;
size_t blobsize;
for (ek = ctrl->ephemeral_keys; ek; ek = ek->next)
if (!memcmp (ek->grip, grip, KEYGRIP_LEN))
break;
if (!ek)
{
err = gpg_error (GPG_ERR_ENOENT);
goto leave;
}
fp = es_fopenmem (0, "wbx,wipe");
if (!fp)
{
err = gpg_error_from_syserror ();
log_error ("can't open memory stream: %s\n", gpg_strerror (err));
goto leave;
}
err = nvc_write (pk, fp);
if (err)
{
log_error ("error writing to memory stream: %s\n",gpg_strerror (err));
goto leave;
}
if (es_fclose_snatch (fp, &blob, &blobsize) || !blob)
{
err = gpg_error_from_syserror ();
log_error ("error getting memory stream buffer: %s\n",
gpg_strerror (err));
/* Closing right away so that we don't try another snatch in
* the cleanup. */
es_fclose (fp);
fp = NULL;
goto leave;
}
fp = NULL;
/* No need to revisit the linked list because the found EK is
* not expected to change due to the other syscalls above. */
xfree (ek->keybuf);
ek->keybuf = blob;
ek->keybuflen = blobsize;
goto leave;
}
fname0 = fname_from_keygrip (grip, 0);
if (!fname0)
{
@ -404,6 +541,9 @@ agent_update_private_key (const unsigned char *grip, nvc_t pk)
leave:
if (blocksigs)
gnupg_unblock_all_signals ();
if (ctrl->ephemeral_mode)
wipe_and_fclose (fp);
else
es_fclose (fp);
if (removetmp && fname)
gnupg_remove (fname);
@ -888,17 +1028,17 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text,
* caller must free 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, nvc_t *r_keymeta,
char **r_orig_key_value)
read_key_file (ctrl_t ctrl, const unsigned char *grip,
gcry_sexp_t *result, nvc_t *r_keymeta, char **r_orig_key_value)
{
gpg_error_t err;
char *fname;
estream_t fp;
struct stat st;
unsigned char *buf;
estream_t fp = NULL;
unsigned char *buf = NULL;
size_t buflen, erroff;
gcry_sexp_t s_skey;
nvc_t pk = NULL;
char first;
size_t keybuflen;
*result = NULL;
if (r_keymeta)
@ -906,19 +1046,42 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result, nvc_t *r_keymeta,
if (r_orig_key_value)
*r_orig_key_value = NULL;
fname = fname_from_keygrip (grip, 0);
fname = (ctrl->ephemeral_mode
? xtrystrdup ("[ephemeral key store]")
: fname_from_keygrip (grip, 0));
if (!fname)
{
return gpg_error_from_syserror ();
err = gpg_error_from_syserror ();
goto leave;
}
if (ctrl->ephemeral_mode)
{
ephemeral_private_key_t ek;
for (ek = ctrl->ephemeral_keys; ek; ek = ek->next)
if (!memcmp (ek->grip, grip, KEYGRIP_LEN)
&& ek->keybuf && ek->keybuflen)
break;
if (!ek || !ek->keybuf || !ek->keybuflen)
{
err = gpg_error (GPG_ERR_ENOENT);
goto leave;
}
keybuflen = ek->keybuflen;
fp = es_fopenmem_init (0, "rb", ek->keybuf, ek->keybuflen);
}
else
{
keybuflen = 0; /* Indicates that this is not ephemeral mode. */
fp = es_fopen (fname, "rb");
}
if (!fp)
{
err = gpg_error_from_syserror ();
if (gpg_err_code (err) != GPG_ERR_ENOENT)
log_error ("can't open '%s': %s\n", fname, gpg_strerror (err));
xfree (fname);
return err;
goto leave;
}
if (es_fread (&first, 1, 1, fp) != 1)
@ -926,28 +1089,22 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result, nvc_t *r_keymeta,
err = gpg_error_from_syserror ();
log_error ("error reading first byte from '%s': %s\n",
fname, gpg_strerror (err));
xfree (fname);
es_fclose (fp);
return err;
goto leave;
}
if (es_fseek (fp, 0, SEEK_SET))
{
err = gpg_error_from_syserror ();
log_error ("error seeking in '%s': %s\n", fname, gpg_strerror (err));
xfree (fname);
es_fclose (fp);
return err;
goto leave;
}
if (first != '(')
{
/* Key is in extended format. */
nvc_t pk = NULL;
int line;
err = nvc_parse_private_key (&pk, &line, fp);
es_fclose (fp);
if (err)
log_error ("error parsing '%s' line %d: %s\n",
@ -969,9 +1126,7 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result, nvc_t *r_keymeta,
if (!*r_orig_key_value)
{
err = gpg_error_from_syserror ();
nvc_release (pk);
xfree (fname);
return err;
goto leave;
}
}
}
@ -979,35 +1134,31 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result, nvc_t *r_keymeta,
}
}
if (!err && r_keymeta)
*r_keymeta = pk;
else
nvc_release (pk);
xfree (fname);
return err;
goto leave; /* Ready. */
}
if (keybuflen)
buflen = keybuflen;
else
{
struct stat st;
if (fstat (es_fileno (fp), &st))
{
err = gpg_error_from_syserror ();
log_error ("can't stat '%s': %s\n", fname, gpg_strerror (err));
xfree (fname);
es_fclose (fp);
return err;
goto leave;
}
buflen = st.st_size;
}
buflen = st.st_size;
buf = xtrymalloc (buflen+1);
if (!buf)
{
err = gpg_error_from_syserror ();
log_error ("error allocating %zu bytes for '%s': %s\n",
buflen, fname, gpg_strerror (err));
xfree (fname);
es_fclose (fp);
xfree (buf);
return err;
goto leave;
}
if (es_fread (buf, buflen, 1, fp) != 1)
@ -1015,25 +1166,32 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result, nvc_t *r_keymeta,
err = gpg_error_from_syserror ();
log_error ("error reading %zu bytes from '%s': %s\n",
buflen, fname, gpg_strerror (err));
xfree (fname);
es_fclose (fp);
xfree (buf);
return err;
goto leave;
}
/* Convert the file into a gcrypt S-expression object. */
err = gcry_sexp_sscan (&s_skey, &erroff, (char*)buf, buflen);
xfree (fname);
es_fclose (fp);
xfree (buf);
if (err)
{
gcry_sexp_t s_skey;
err = gcry_sexp_sscan (&s_skey, &erroff, (char*)buf, buflen);
if (err)
log_error ("failed to build S-Exp (off=%u): %s\n",
(unsigned int)erroff, gpg_strerror (err));
return err;
}
else
*result = s_skey;
return 0;
}
leave:
if (!err && r_keymeta)
*r_keymeta = pk;
else
nvc_release (pk);
if (ctrl->ephemeral_mode)
wipe_and_fclose (fp);
else
es_fclose (fp);
xfree (fname);
return err;
}
@ -1226,7 +1384,8 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce,
if (!grip && !ctrl->have_keygrip)
return gpg_error (GPG_ERR_NO_SECKEY);
err = read_key_file (grip? grip : ctrl->keygrip, &s_skey, &keymeta, NULL);
err = read_key_file (ctrl, grip? grip : ctrl->keygrip,
&s_skey, &keymeta, NULL);
if (err)
{
if (gpg_err_code (err) == GPG_ERR_ENOENT)
@ -1485,7 +1644,7 @@ agent_raw_key_from_file (ctrl_t ctrl, const unsigned char *grip,
*result = NULL;
err = read_key_file (grip, &s_skey, r_keymeta, NULL);
err = read_key_file (ctrl, grip, &s_skey, r_keymeta, NULL);
if (!err)
*result = s_skey;
return err;
@ -1528,7 +1687,7 @@ public_key_from_file (ctrl_t ctrl, const unsigned char *grip,
if (r_sshorder)
*r_sshorder = 0;
err = read_key_file (grip, &s_skey, for_ssh? &keymeta : NULL, NULL);
err = read_key_file (ctrl, grip, &s_skey, for_ssh? &keymeta : NULL, NULL);
if (err)
return err;
@ -1658,11 +1817,21 @@ agent_ssh_key_from_file (ctrl_t ctrl,
/* Check whether the secret key identified by GRIP is available.
Returns 0 is the key is available. */
int
agent_key_available (const unsigned char *grip)
agent_key_available (ctrl_t ctrl, const unsigned char *grip)
{
int result;
char *fname;
char hexgrip[40+4+1];
ephemeral_private_key_t ek;
if (ctrl && ctrl->ephemeral_mode)
{
for (ek = ctrl->ephemeral_keys; ek; ek = ek->next)
if (!memcmp (ek->grip, grip, KEYGRIP_LEN)
&& ek->keybuf && ek->keybuflen)
return 0;
return -1;
}
bin2hex (grip, 20, hexgrip);
strcpy (hexgrip+40, ".key");
@ -1675,7 +1844,6 @@ agent_key_available (const unsigned char *grip)
}
/* Return the information about the secret key specified by the binary
keygrip GRIP. If the key is a shadowed one the shadow information
will be stored at the address R_SHADOW_INFO as an allocated
@ -1700,7 +1868,7 @@ agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
{
gcry_sexp_t sexp;
err = read_key_file (grip, &sexp, NULL, NULL);
err = read_key_file (ctrl, grip, &sexp, NULL, NULL);
if (err)
{
if (gpg_err_code (err) == GPG_ERR_ENOENT)
@ -1784,7 +1952,13 @@ agent_delete_key (ctrl_t ctrl, const char *desc_text,
char *default_desc = NULL;
int key_type;
err = read_key_file (grip, &s_skey, NULL, NULL);
if (ctrl->ephemeral_mode)
{
err = gpg_error (GPG_ERR_NO_SECKEY);
goto leave;
}
err = read_key_file (ctrl, grip, &s_skey, NULL, NULL);
if (gpg_err_code (err) == GPG_ERR_ENOENT)
err = gpg_error (GPG_ERR_NO_SECKEY);
if (err)
@ -1885,7 +2059,7 @@ agent_delete_key (ctrl_t ctrl, const char *desc_text,
card's SERIALNO and the IDSTRING. With FORCE passed as true an
existing key with the given GRIP will get overwritten. */
gpg_error_t
agent_write_shadow_key (const unsigned char *grip,
agent_write_shadow_key (ctrl_t ctrl, const unsigned char *grip,
const char *serialno, const char *keyid,
const unsigned char *pkbuf, int force,
const char *dispserialno)
@ -1915,7 +2089,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 (ctrl, grip, shdkey, len, force,
serialno, keyid, dispserialno, 0);
xfree (shdkey);
if (err)

View File

@ -30,14 +30,36 @@
#include "../common/exechelp.h"
#include "../common/sysutils.h"
static int
store_key (gcry_sexp_t private, const char *passphrase, int force,
void
clear_ephemeral_keys (ctrl_t ctrl)
{
while (ctrl->ephemeral_keys)
{
ephemeral_private_key_t next = ctrl->ephemeral_keys->next;
if (ctrl->ephemeral_keys->keybuf)
{
wipememory (ctrl->ephemeral_keys->keybuf,
ctrl->ephemeral_keys->keybuflen);
xfree (ctrl->ephemeral_keys->keybuf);
}
xfree (ctrl->ephemeral_keys);
ctrl->ephemeral_keys = next;
}
}
/* Store the key either to a file, or in ctrl->ephemeral_mode in the
* session data. */
static gpg_error_t
store_key (ctrl_t ctrl, gcry_sexp_t private,
const char *passphrase, int force,
unsigned long s2k_count, time_t timestamp)
{
int rc;
gpg_error_t err;
unsigned char *buf;
size_t len;
unsigned char grip[20];
unsigned char grip[KEYGRIP_LEN];
if ( !gcry_pk_get_keygrip (private, grip) )
{
@ -49,7 +71,10 @@ store_key (gcry_sexp_t private, const char *passphrase, int force,
log_assert (len);
buf = gcry_malloc_secure (len);
if (!buf)
return out_of_core ();
{
err = gpg_error_from_syserror ();
goto leave;
}
len = gcry_sexp_sprint (private, GCRYSEXP_FMT_CANON, buf, len);
log_assert (len);
@ -57,20 +82,56 @@ store_key (gcry_sexp_t private, const char *passphrase, int force,
{
unsigned char *p;
rc = agent_protect (buf, passphrase, &p, &len, s2k_count);
if (rc)
{
xfree (buf);
return rc;
}
err = agent_protect (buf, passphrase, &p, &len, s2k_count);
if (err)
goto leave;
xfree (buf);
buf = p;
}
rc = agent_write_private_key (grip, buf, len, force,
if (ctrl->ephemeral_mode)
{
ephemeral_private_key_t ek;
for (ek = ctrl->ephemeral_keys; ek; ek = ek->next)
if (!memcmp (ek->grip, grip, KEYGRIP_LEN))
break;
if (!ek)
{
ek = xtrycalloc (1, sizeof *ek);
if (!ek)
{
err = gpg_error_from_syserror ();
goto leave;
}
memcpy (ek->grip, grip, KEYGRIP_LEN);
ek->next = ctrl->ephemeral_keys;
ctrl->ephemeral_keys = ek;
}
if (ek->keybuf)
{
wipememory (ek->keybuf, ek->keybuflen);
xfree (ek->keybuf);
}
ek->keybuf = buf;
buf = NULL;
ek->keybuflen = len;
}
else
err = agent_write_private_key (ctrl, grip, buf, len, force,
NULL, NULL, NULL, timestamp);
if (!err)
{
char hexgrip[2*KEYGRIP_LEN+1];
bin2hex (grip, KEYGRIP_LEN, hexgrip);
agent_write_status (ctrl, "KEYGRIP", hexgrip, NULL);
}
leave:
xfree (buf);
return rc;
return err;
}
@ -458,16 +519,19 @@ agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
/* Generate a new keypair according to the parameters given in
KEYPARAM. If CACHE_NONCE is given first try to lookup a passphrase
using the cache nonce. If NO_PROTECTION is true the key will not
be protected by a passphrase. If OVERRIDE_PASSPHRASE is true that
passphrase will be used for the new key. If TIMESTAMP is not zero
it will be recorded as creation date of the key (unless extended
format is disabled) . */
* KEYPARAM. If CACHE_NONCE is given first try to lookup a passphrase
* using the cache nonce. If NO_PROTECTION is true the key will not
* be protected by a passphrase. If OVERRIDE_PASSPHRASE is true that
* passphrase will be used for the new key. If TIMESTAMP is not zero
* it will be recorded as creation date of the key (unless extended
* format is disabled). In ctrl_ephemeral_mode the key is stored in
* the session data and an identifier is returned using a status
* line. */
int
agent_genkey (ctrl_t ctrl, const char *cache_nonce, time_t timestamp,
const char *keyparam, size_t keyparamlen, int no_protection,
const char *override_passphrase, int preset, membuf_t *outbuf)
agent_genkey (ctrl_t ctrl, unsigned int flags,
const char *cache_nonce, time_t timestamp,
const char *keyparam, size_t keyparamlen,
const char *override_passphrase, membuf_t *outbuf)
{
gcry_sexp_t s_keyparam, s_key, s_private, s_public;
char *passphrase_buffer = NULL;
@ -486,7 +550,7 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce, time_t timestamp,
/* Get the passphrase now, cause key generation may take a while. */
if (override_passphrase)
passphrase = override_passphrase;
else if (no_protection || !cache_nonce)
else if ((flags & GENKEY_FLAG_NO_PROTECTION) || !cache_nonce)
passphrase = NULL;
else
{
@ -494,8 +558,8 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce, time_t timestamp,
passphrase = passphrase_buffer;
}
if (passphrase || no_protection)
;
if (passphrase || (flags & GENKEY_FLAG_NO_PROTECTION))
; /* No need to ask for a passphrase. */
else
{
rc = agent_ask_new_passphrase (ctrl,
@ -540,11 +604,14 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce, time_t timestamp,
gcry_sexp_release (s_key); s_key = NULL;
/* store the secret key */
if (DBG_CRYPTO)
log_debug ("storing private key\n");
rc = store_key (s_private, passphrase, 0, ctrl->s2k_count, timestamp);
if (!rc)
if (opt.verbose)
log_info ("storing %sprivate key\n",
ctrl->ephemeral_mode?"ephemeral ":"");
rc = store_key (ctrl, s_private, passphrase, 0, ctrl->s2k_count, timestamp);
if (!rc && !ctrl->ephemeral_mode)
{
/* FIXME: or does it make sense to also cache passphrases in
* ephemeral mode using a dedicated cache? */
if (!cache_nonce)
{
char tmpbuf[12];
@ -552,18 +619,20 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce, time_t timestamp,
cache_nonce = bin2hex (tmpbuf, 12, NULL);
}
if (cache_nonce
&& !no_protection
&& !(flags & GENKEY_FLAG_NO_PROTECTION)
&& !agent_put_cache (ctrl, cache_nonce, CACHE_MODE_NONCE,
passphrase, ctrl->cache_ttl_opt_preset))
agent_write_status (ctrl, "CACHE_NONCE", cache_nonce, NULL);
if (preset && !no_protection)
if ((flags & GENKEY_FLAG_PRESET)
&& !(flags & GENKEY_FLAG_NO_PROTECTION))
{
unsigned char grip[20];
char hexgrip[40+1];
if (gcry_pk_get_keygrip (s_private, grip))
{
bin2hex(grip, 20, hexgrip);
rc = agent_put_cache (ctrl, hexgrip, CACHE_MODE_ANY, passphrase,
rc = agent_put_cache (ctrl, hexgrip,
CACHE_MODE_ANY, passphrase,
ctrl->cache_ttl_opt_preset);
}
}
@ -615,7 +684,8 @@ agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey,
if (passphrase_addr && *passphrase_addr)
{
/* Take an empty string as request not to protect the key. */
err = store_key (s_skey, **passphrase_addr? *passphrase_addr:NULL, 1,
err = store_key (ctrl, s_skey,
**passphrase_addr? *passphrase_addr:NULL, 1,
ctrl->s2k_count, 0);
}
else
@ -631,7 +701,7 @@ agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey,
L_("Please enter the new passphrase"),
&pass);
if (!err)
err = store_key (s_skey, pass, 1, ctrl->s2k_count, 0);
err = store_key (ctrl, s_skey, pass, 1, ctrl->s2k_count, 0);
if (!err && passphrase_addr)
*passphrase_addr = pass;
else

View File

@ -364,7 +364,7 @@ static int putty_support;
/* Path to the pipe, which handles requests from Win32-OpenSSH. */
static const char *win32_openssh_support;
#define W32_DEFAILT_AGENT_PIPE_NAME "\\\\.\\pipe\\openssh-ssh-agent"
#define W32_DEFAULT_AGENT_PIPE_NAME "\\\\.\\pipe\\openssh-ssh-agent"
#endif /*HAVE_W32_SYSTEM*/
/* The list of open file descriptors at startup. Note that this list
@ -1307,7 +1307,7 @@ main (int argc, char **argv)
if (pargs.r_type)
win32_openssh_support = pargs.r.ret_str;
else
win32_openssh_support = W32_DEFAILT_AGENT_PIPE_NAME;
win32_openssh_support = W32_DEFAULT_AGENT_PIPE_NAME;
# endif
break;
@ -2002,6 +2002,7 @@ agent_deinit_default_ctrl (ctrl_t ctrl)
{
unregister_progress_cb ();
session_env_release (ctrl->session_env);
clear_ephemeral_keys (ctrl);
xfree (ctrl->digest.data);
ctrl->digest.data = NULL;

View File

@ -155,6 +155,16 @@ This field is for card key. If given and the value is "yes"
dialog window when card is not available. When the value is "no", a
card operation is refused with GPG_ERR_UNUSABLE_SECKEY error.
*** Backup-info
This gives information for a backup of the key. The follwoing fields
are space delimited:
- Hexified keygrip (uppercase) to make it easy to identify the
filename. When restoring software should make sure that the keygrip
matches the one derived from the "Key" field.
- Backup time in as ISO string.
- Name of the backup software.
- Arbitrary information.
* Private Key Format
** Unprotected Private Key Format

View File

@ -397,7 +397,7 @@ agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force)
for (p=item->hexgrip, i=0; i < 20; p += 2, i++)
grip[i] = xtoi_2 (p);
if (!force && !agent_key_available (grip))
if (!force && !agent_key_available (ctrl, grip))
continue; /* The key is already available. */
/* Unknown key - store it. */
@ -408,12 +408,14 @@ agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force)
goto leave;
}
if (!ctrl->ephemeral_mode)
{
char *dispserialno;
agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno,
item->hexgrip);
rc = agent_write_shadow_key (grip, serialno, item->id, pubkey, force,
rc = agent_write_shadow_key (ctrl,
grip, serialno, item->id, pubkey, force,
dispserialno);
xfree (dispserialno);
}

View File

@ -371,13 +371,14 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
goto leave;
}
if (keyref)
if (keyref && !ctrl->ephemeral_mode)
{
char *dispserialno;
agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno,
hexgrip);
agent_write_shadow_key (ctrl->keygrip, serialno, keyref, pkbuf,
agent_write_shadow_key (ctrl,
ctrl->keygrip, serialno, keyref, pkbuf,
0, dispserialno);
xfree (dispserialno);
}

View File

@ -755,8 +755,9 @@ release_passphrase (char *pw)
/* Stub function. */
int
agent_key_available (const unsigned char *grip)
agent_key_available (ctrl_t ctrl, const unsigned char *grip)
{
(void)ctrl;
(void)grip;
return -1; /* Not available. */
}
@ -814,7 +815,7 @@ agent_askpin (ctrl_t ctrl,
/* Replacement for the function in findkey.c. Here we write the key
* to stdout. */
gpg_error_t
agent_write_private_key (const unsigned char *grip,
agent_write_private_key (ctrl_t ctrl, const unsigned char *grip,
const void *buffer, size_t length, int force,
const char *serialno, const char *keyref,
const char *dispserialno, time_t timestamp)
@ -822,6 +823,7 @@ agent_write_private_key (const unsigned char *grip,
char hexgrip[40+4+1];
char *p;
(void)ctrl;
(void)force;
(void)serialno;
(void)keyref;

View File

@ -94,16 +94,15 @@
# We need to know our own name.
SPEEDO_MK := $(realpath $(lastword $(MAKEFILE_LIST)))
.PHONY : help native native-gui w32-installer w32-source w32-wixlib
.PHONY : git-native git-native-gui git-w32-installer git-w32-source
.PHONY : this-native this-native-gui this-w32-installer this-w32-source
.PHONY : help native w32-installer w32-source w32-wixlib
.PHONY : git-native git-w32-installer git-w32-source
.PHONY : this-native this-w32-installer this-w32-source
help:
@echo 'usage: make -f speedo.mk TARGET'
@echo ' with TARGET being one of:'
@echo ' help This help'
@echo ' native Native build of the GnuPG core'
@echo ' native-gui Ditto but with pinentry and GPA'
@echo ' w32-installer Build a Windows installer'
@echo ' w32-source Pack a source archive'
@echo ' w32-release Build a Windows release'
@ -114,7 +113,7 @@ help:
@echo 'Prepend TARGET with "git-" to build from GIT repos.'
@echo 'Prepend TARGET with "this-" to build from the source tarball.'
@echo 'Use STATIC=1 to build with statically linked libraries.'
@echo 'Use SELFCHECK=0 for a non-released version.'
@echo 'Use SELFCHECK=1 for additional check of the gnupg version.'
@echo 'Use CUSTOM_SWDB=1 for an already downloaded swdb.lst.'
@echo 'Use WIXPREFIX to provide the WIX binaries for the MSI package.'
@echo ' Using WIX also requires wine with installed wine mono.'
@ -148,66 +147,52 @@ help-wixlib:
SPEEDOMAKE := $(MAKE) -f $(SPEEDO_MK) UPD_SWDB=1
native: check-tools
$(SPEEDOMAKE) TARGETOS=native WHAT=release WITH_GUI=0 all
$(SPEEDOMAKE) TARGETOS=native WHAT=release all
git-native: check-tools
$(SPEEDOMAKE) TARGETOS=native WHAT=git WITH_GUI=0 all
$(SPEEDOMAKE) TARGETOS=native WHAT=git all
this-native: check-tools
$(SPEEDOMAKE) TARGETOS=native WHAT=this WITH_GUI=0 all
native-gui: check-tools
$(SPEEDOMAKE) TARGETOS=native WHAT=release WITH_GUI=1 all
git-native-gui: check-tools
$(SPEEDOMAKE) TARGETOS=native WHAT=git WITH_GUI=1 all
this-native-gui: check-tools
$(SPEEDOMAKE) TARGETOS=native WHAT=this WITH_GUI=1 all
$(SPEEDOMAKE) TARGETOS=native WHAT=this all
w32-installer: check-tools
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release WITH_GUI=0 installer
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release installer
git-w32-installer: check-tools
$(SPEEDOMAKE) TARGETOS=w32 WHAT=git WITH_GUI=0 installer
$(SPEEDOMAKE) TARGETOS=w32 WHAT=git installer
this-w32-installer: check-tools
$(SPEEDOMAKE) TARGETOS=w32 WHAT=this WITH_GUI=0 \
CUSTOM_SWDB=1 installer
$(SPEEDOMAKE) TARGETOS=w32 WHAT=this CUSTOM_SWDB=1 installer
w32-wixlib: check-tools
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release WITH_GUI=0 wixlib
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release wixlib
git-w32-wixlib: check-tools
$(SPEEDOMAKE) TARGETOS=w32 WHAT=git WITH_GUI=0 wixlib
$(SPEEDOMAKE) TARGETOS=w32 WHAT=git wixlib
this-w32-wixlib: check-tools
$(SPEEDOMAKE) TARGETOS=w32 WHAT=this WITH_GUI=0 \
CUSTOM_SWDB=1 wixlib
$(SPEEDOMAKE) TARGETOS=w32 WHAT=this CUSTOM_SWDB=1 wixlib
w32-source: check-tools
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release WITH_GUI=0 dist-source
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release dist-source
git-w32-source: check-tools
$(SPEEDOMAKE) TARGETOS=w32 WHAT=git WITH_GUI=0 dist-source
$(SPEEDOMAKE) TARGETOS=w32 WHAT=git dist-source
this-w32-source: check-tools
$(SPEEDOMAKE) TARGETOS=w32 WHAT=this WITH_GUI=0 \
CUSTOM_SWDB=1 dist-source
$(SPEEDOMAKE) TARGETOS=w32 WHAT=this CUSTOM_SWDB=1 dist-source
w32-release: check-tools
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release WITH_GUI=0 SELFCHECK=0 \
installer-from-source
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release installer-from-source
w32-msi-release: check-tools
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release WITH_GUI=0 SELFCHECK=0 \
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release \
WITH_WIXLIB=1 installer-from-source
w32-sign-installer: check-tools
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release WITH_GUI=0 SELFCHECK=0 \
sign-installer
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release sign-installer
w32-release-offline: check-tools
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release WITH_GUI=0 SELFCHECK=0 \
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release \
CUSTOM_SWDB=1 pkgrep=${HOME}/b pkg10rep=${HOME}/b \
installer-from-source
@ -220,17 +205,14 @@ WHAT=git
# Set target to "native" or "w32"
TARGETOS=
# Set to 1 to build the GUI tools
WITH_GUI=0
# Set to 1 to use a pre-installed swdb.lst instead of the online version.
CUSTOM_SWDB=0
# Set to 1 to really download the swdb.
UPD_SWDB=0
# Set to 0 to skip the GnuPG version self-check
SELFCHECK=1
# Set to 1 to run an additional GnuPG version check
SELFCHECK=0
# Set to 1 to build with statically linked libraries.
STATIC=0
@ -240,7 +222,7 @@ STATIC=0
TARBALLS=$(shell pwd)/../tarballs
# Number of parallel make jobs for each package
MAKE_J=3
MAKE_J=6
# Name to use for the w32 installer and sources
INST_NAME=gnupg-w32
@ -251,6 +233,9 @@ INSTALL_PREFIX=none
# Set this to the location of wixtools
WIXPREFIX=$(shell readlink -f ~/w32root/wixtools)
# If patchelf(1) is not availale disable the command.
PATCHELF := $(shell patchelf --version 2>/dev/null >/dev/null || echo "echo please run: ")patchelf
# Read signing information from ~/.gnupg-autogen.rc
define READ_AUTOGEN_template
$(1) = $$(shell grep '^$(1)=' $$$$HOME/.gnupg-autogen.rc|cut -d= -f2)
@ -319,60 +304,16 @@ w32src := $(topsrc)/build-aux/speedo/w32
# Fixme: Do we need to build pkg-config for cross-building?
speedo_spkgs = \
libgpg-error npth libgcrypt
ifeq ($(TARGETOS),w32)
speedo_spkgs += \
zlib bzip2 sqlite
ifeq ($(WITH_GUI),1)
speedo_spkgs += gettext libiconv
endif
endif
speedo_spkgs += \
libassuan libksba
ifeq ($(TARGETOS),w32)
speedo_spkgs += \
ntbtls
endif
speedo_spkgs += \
gnupg
ifeq ($(TARGETOS),w32)
ifeq ($(WITH_GUI),1)
speedo_spkgs += \
libffi glib pkg-config
endif
endif
libgpg-error npth libgcrypt \
zlib bzip2 sqlite \
libassuan libksba ntbtls gnupg
ifeq ($(STATIC),0)
speedo_spkgs += \
gpgme
speedo_spkgs += gpgme
endif
ifeq ($(TARGETOS),w32)
ifeq ($(WITH_GUI),1)
speedo_spkgs += \
libpng \
gdk-pixbuf atk pixman cairo pango gtk+
endif
endif
ifeq ($(TARGETOS),w32)
speedo_spkgs += pinentry
ifeq ($(WITH_GUI),1)
speedo_spkgs += gpa gpgex
endif
else
ifeq ($(WITH_GUI),1)
speedo_spkgs += pinentry gpa
endif
endif
@ -383,15 +324,12 @@ endif
# only used for gpgex and thus we need to build them only if we want
# a full installer.
speedo_w64_spkgs =
ifeq ($(WITH_GUI),1)
speedo_w64_spkgs += libgpg-error libiconv gettext libassuan gpgex
endif
# Packages which use the gnupg autogen.sh build style
speedo_gnupg_style = \
libgpg-error npth libgcrypt \
libassuan libksba ntbtls gnupg gpgme \
pinentry gpa gpgex
pinentry
# Packages which use only make and no build directory
speedo_make_only_style = \
@ -451,14 +389,6 @@ pinentry_ver := $(shell awk '$$1=="pinentry_ver" {print $$2}' swdb.lst)
pinentry_sha1 := $(shell awk '$$1=="pinentry_sha1" {print $$2}' swdb.lst)
pinentry_sha2 := $(shell awk '$$1=="pinentry_sha2" {print $$2}' swdb.lst)
gpa_ver := $(shell awk '$$1=="gpa_ver" {print $$2}' swdb.lst)
gpa_sha1 := $(shell awk '$$1=="gpa_sha1" {print $$2}' swdb.lst)
gpa_sha2 := $(shell awk '$$1=="gpa_sha2" {print $$2}' swdb.lst)
gpgex_ver := $(shell awk '$$1=="gpgex_ver" {print $$2}' swdb.lst)
gpgex_sha1 := $(shell awk '$$1=="gpgex_sha1" {print $$2}' swdb.lst)
gpgex_sha2 := $(shell awk '$$1=="gpgex_sha2" {print $$2}' swdb.lst)
zlib_ver := $(shell awk '$$1=="zlib_ver" {print $$2}' swdb.lst)
zlib_sha1 := $(shell awk '$$1=="zlib_sha1_gz" {print $$2}' swdb.lst)
zlib_sha2 := $(shell awk '$$1=="zlib_sha2_gz" {print $$2}' swdb.lst)
@ -474,7 +404,7 @@ sqlite_sha2 := $(shell awk '$$1=="sqlite_sha2_gz" {print $$2}' swdb.lst)
$(info Information from the version database)
$(info GnuPG ..........: $(gnupg_ver) (building $(gnupg_ver_this)))
$(info Libgpg-error ...: $(libgpg_error_ver))
$(info GpgRT ..........: $(libgpg_error_ver))
$(info Npth ...........: $(npth_ver))
$(info Libgcrypt ......: $(libgcrypt_ver))
$(info Libassuan ......: $(libassuan_ver))
@ -485,23 +415,13 @@ $(info SQLite .........: $(sqlite_ver))
$(info NtbTLS .. ......: $(ntbtls_ver))
$(info GPGME ..........: $(gpgme_ver))
$(info Pinentry .......: $(pinentry_ver))
$(info GPA ............: $(gpa_ver))
$(info GpgEX.... ......: $(gpgex_ver))
endif
# Version number for external packages
pkg_config_ver = 0.23
libiconv_ver = 1.14
gettext_ver = 0.18.2.1
libffi_ver = 3.0.13
glib_ver = 2.34.3
libpng_ver = 1.4.12
gdk_pixbuf_ver = 2.26.5
atk_ver = 1.32.0
pango_ver = 1.29.4
pixman_ver = 0.32.4
cairo_ver = 1.12.16
gtk__ver = 2.24.17
# The GIT repository. Using a local repo is much faster.
#gitrep = git://git.gnupg.org
@ -552,10 +472,6 @@ else ifeq ($(WHAT),git)
speedo_pkg_gpgme_gitref = master
speedo_pkg_pinentry_git = $(gitrep)/pinentry
speedo_pkg_pinentry_gitref = master
speedo_pkg_gpa_git = $(gitrep)/gpa
speedo_pkg_gpa_gitref = master
speedo_pkg_gpgex_git = $(gitrep)/gpgex
speedo_pkg_gpgex_gitref = master
else ifeq ($(WHAT),release)
speedo_pkg_libgpg_error_tar = \
$(pkgrep)/libgpg-error/libgpg-error-$(libgpg_error_ver).tar.bz2
@ -573,10 +489,6 @@ else ifeq ($(WHAT),release)
$(pkgrep)/gpgme/gpgme-$(gpgme_ver).tar.bz2
speedo_pkg_pinentry_tar = \
$(pkgrep)/pinentry/pinentry-$(pinentry_ver).tar.bz2
speedo_pkg_gpa_tar = \
$(pkgrep)/gpa/gpa-$(gpa_ver).tar.bz2
speedo_pkg_gpgex_tar = \
$(pkg10rep)/gpgex/gpgex-$(gpgex_ver).tar.bz2
else
$(error invalid value for WHAT (use on of: git release this))
endif
@ -587,15 +499,6 @@ speedo_pkg_bzip2_tar = $(pkgrep)/bzip2/bzip2-$(bzip2_ver).tar.gz
speedo_pkg_sqlite_tar = $(pkgrep)/sqlite/sqlite-autoconf-$(sqlite_ver).tar.gz
speedo_pkg_libiconv_tar = $(pkg2rep)/libiconv-$(libiconv_ver).tar.gz
speedo_pkg_gettext_tar = $(pkg2rep)/gettext-$(gettext_ver).tar.gz
speedo_pkg_libffi_tar = $(pkg2rep)/libffi-$(libffi_ver).tar.gz
speedo_pkg_glib_tar = $(pkg2rep)/glib-$(glib_ver).tar.xz
speedo_pkg_libpng_tar = $(pkg2rep)/libpng-$(libpng_ver).tar.bz2
speedo_pkg_gdk_pixbuf_tar = $(pkg2rep)/gdk-pixbuf-$(gdk_pixbuf_ver).tar.xz
speedo_pkg_atk_tar = $(pkg2rep)/atk-$(atk_ver).tar.bz2
speedo_pkg_pango_tar = $(pkg2rep)/pango-$(pango_ver).tar.bz2
speedo_pkg_pixman_tar = $(pkg2rep)/pixman-$(pixman_ver).tar.gz
speedo_pkg_cairo_tar = $(pkg2rep)/cairo-$(cairo_ver).tar.xz
speedo_pkg_gtk__tar = $(pkg2rep)/gtk+-$(gtk__ver).tar.xz
#
@ -638,7 +541,7 @@ speedo_pkg_gnupg_configure = \
else
speedo_pkg_gnupg_configure = --disable-g13 --enable-wks-tools
endif
speedo_pkg_gnupg_extracflags = -g
speedo_pkg_gnupg_extracflags =
# Create the version info files only for W32 so that they won't get
# installed if for example INSTALL_PREFIX=/usr/local is used.
@ -651,25 +554,13 @@ define speedo_pkg_gnupg_post_install
endef
endif
# The LDFLAGS is needed for -lintl for glib.
ifeq ($(WITH_GUI),1)
speedo_pkg_gpgme_configure = \
--enable-static --enable-w32-glib \
--with-gpg-error-prefix=$(idir) \
LDFLAGS=-L$(idir)/lib
else
# The LDFLAGS was needed for -lintl for glib.
speedo_pkg_gpgme_configure = \
--disable-static --disable-w32-glib \
--with-gpg-error-prefix=$(idir) \
LDFLAGS=-L$(idir)/lib
endif
ifeq ($(TARGETOS),w32)
speedo_pkg_pinentry_configure = --disable-pinentry-gtk2
else
speedo_pkg_pinentry_configure = --enable-pinentry-gtk2
endif
speedo_pkg_pinentry_configure += \
--disable-pinentry-qt5 \
--disable-pinentry-qt \
@ -680,22 +571,6 @@ speedo_pkg_pinentry_configure += \
CXXFLAGS=-static-libstdc++
speedo_pkg_gpa_configure = \
--with-libiconv-prefix=$(idir) --with-libintl-prefix=$(idir) \
--with-gpgme-prefix=$(idir) --with-zlib=$(idir) \
--with-libassuan-prefix=$(idir) --with-gpg-error-prefix=$(idir)
speedo_pkg_gpgex_configure = \
--with-gpg-error-prefix=$(idir) \
--with-libassuan-prefix=$(idir) \
--enable-gpa-only
speedo_pkg_w64_gpgex_configure = \
--with-gpg-error-prefix=$(idir6) \
--with-libassuan-prefix=$(idir6) \
--enable-gpa-only
#
# External packages
#
@ -759,64 +634,12 @@ speedo_pkg_gettext_extracflags = -O2
speedo_pkg_gettext_make_dir = gettext-runtime
speedo_pkg_glib_configure = \
--disable-modular-tests \
--with-libiconv=gnu \
CPPFLAGS=-I$(idir)/include \
LDFLAGS=-L$(idir)/lib \
CCC=$(host)-g++ \
LIBFFI_CFLAGS=-I$(idir)/lib/libffi-$(libffi_ver)/include \
LIBFFI_LIBS=\"-L$(idir)/lib -lffi\"
ifeq ($(TARGETOS),w32)
speedo_pkg_glib_extracflags = -march=i486
endif
ifeq ($(TARGETOS),w32)
speedo_pkg_libpng_configure = \
CPPFLAGS=\"-I$(idir)/include -DPNG_BUILD_DLL\" \
LDFLAGS=\"-L$(idir)/lib\" LIBPNG_DEFINES=\"-DPNG_BUILD_DLL\"
else
speedo_pkg_libpng_configure = \
CPPFLAGS=\"-I$(idir)/include\" \
LDFLAGS=\"-L$(idir)/lib\"
endif
ifneq ($(TARGETOS),w32)
speedo_pkg_gdk_pixbuf_configure = --without-libtiff --without-libjpeg
endif
speedo_pkg_pixman_configure = \
CPPFLAGS=-I$(idir)/include \
LDFLAGS=-L$(idir)/lib
ifeq ($(TARGETOS),w32)
speedo_pkg_cairo_configure = \
--disable-qt --disable-ft --disable-fc \
--enable-win32 --enable-win32-font \
CPPFLAGS=-I$(idir)/include \
LDFLAGS=-L$(idir)/lib
else
speedo_pkg_cairo_configure = \
--disable-qt \
CPPFLAGS=-I$(idir)/include \
LDFLAGS=-L$(idir)/lib
endif
speedo_pkg_pango_configure = \
--disable-gtk-doc \
CPPFLAGS=-I$(idir)/include \
LDFLAGS=-L$(idir)/lib
speedo_pkg_gtk__configure = \
--disable-cups \
CPPFLAGS=-I$(idir)/include \
LDFLAGS=-L$(idir)/lib
# ---------
all: all-speedo
install: install-speedo
report: report-speedo
clean: clean-speedo
@ -1286,6 +1109,71 @@ clean-pkg-versions:
@: >$(bdir)/pkg-versions.txt
all-speedo: $(stampdir)/stamp-final
ifneq ($(TARGETOS),w32)
@(set -e;\
cd "$(idir)"; \
echo "speedo: Making RPATH relative";\
for d in bin sbin libexec lib; do \
for f in $$(find $$d -type f); do \
if file $$f | grep ELF >/dev/null; then \
$(PATCHELF) --set-rpath '$$ORIGIN/../lib' $$f; \
fi; \
done; \
done; \
echo "sysconfdir = /etc/gnupg" >bin/gpgconf.ctl ;\
echo "rootdir = $(idir)" >>bin/gpgconf.ctl ;\
echo "speedo: /*" ;\
echo "speedo: * Now copy $(idir)/ to the final location and" ;\
echo "speedo: * adjust $(idir)/bin/gpgconf.ctl accordingly" ;\
echo "speedo: * Or run:" ;\
echo "speedo: * make -f $(topsrc)/build-aux/speedo.mk install SYSROOT=/usr/local/gnupg24" ;\
echo "speedo: * ldconfig -n /usr/local/gnupg24/lib";\
echo "speedo: */")
endif
# No dependencies for the install target; instead we test whether
# some of the to be installed files are available. This avoids
# accidental rebuilds under a wrong account.
install-speedo:
ifneq ($(TARGETOS),w32)
@(set -e; \
cd "$(idir)"; \
if [ x"$$SYSROOT" = x ]; then \
echo "speedo: ERROR: SYSROOT has not been given";\
echo "speedo: Set SYSROOT to the desired install directory";\
echo "speedo: Example:";\
echo "speedo: make -f $(topsrc)/build-aux/speedo.mk install SYSROOT=/usr/local/gnupg24";\
echo "speedo: ldconfig -n /usr/local/gnupg24/lib";\
exit 1;\
fi;\
if [ ! -d "$$SYSROOT"/bin ]; then if ! mkdir "$$SYSROOT"/bin; then \
echo "speedo: error creating target directory";\
exit 1;\
fi; fi;\
if ! touch "$$SYSROOT"/bin/gpgconf.ctl; then \
echo "speedo: Error writing $$SYSROOT/bin/gpgconf.ctl";\
echo "speedo: Please check the permissions";\
exit 1;\
fi;\
if [ ! -f bin/gpgconf.ctl ]; then \
echo "speedo: ERROR: Nothing to install";\
echo "speedo: Please run a build first";\
echo "speedo: Example:";\
echo "speedo: make -f build-aux/speedo.mk native";\
exit 1;\
fi;\
echo "speedo: Installing files to $$SYSROOT";\
find . -type f -executable \
-exec install -Dm 755 "{}" "$$SYSROOT/{}" \; ;\
find . -type f \! -executable \
-exec install -Dm 644 "{}" "$$SYSROOT/{}" \; ;\
echo "sysconfdir = /etc/gnupg" > "$$SYSROOT"/bin/gpgconf.ctl ;\
echo "rootdir = $$SYSROOT" >> "$$SYSROOT"/bin/gpgconf.ctl ;\
echo '/*' ;\
echo " * Installation to $$SYSROOT done" ;\
echo ' */' )
endif
report-speedo: $(addprefix report-,$(speedo_build_list))
@ -1357,9 +1245,6 @@ $(bdir)/inst-options.ini: $(w32src)/inst-options.ini
cat $(w32src)/inst-options.ini >$(bdir)/inst-options.ini
extra_installer_options =
ifeq ($(WITH_GUI),1)
extra_installer_options += -DWITH_GUI=1
endif
# Note that we sign only when doing the final installer.
installer: all w32_insthelpers $(w32src)/inst-options.ini $(bdir)/README.txt
@ -1565,4 +1450,4 @@ check-tools: $(stampdir)/stamp-directories
# Mark phony targets
#
.PHONY: all all-speedo report-speedo clean-stamps clean-speedo installer \
w32_insthelpers check-tools clean-pkg-versions
w32_insthelpers check-tools clean-pkg-versions install-speedo install

View File

@ -222,6 +222,10 @@ copy_dir_with_fixup (const char *newdir)
{
char *result = NULL;
char *p;
#ifdef HAVE_W32_SYSTEM
char *p0;
const char *s;
#endif
if (!*newdir)
return NULL;
@ -253,6 +257,29 @@ copy_dir_with_fixup (const char *newdir)
*p-- = 0;
}
/* Hack to mitigate badly doubled backslashes. */
s = result? result : newdir;
if (s[0] == '\\' && s[1] == '\\' && s[2] != '\\')
{
/* UNC (\\Servername\file) or Long UNC (\\?\Servername\file)
* Does not seem to be double quoted. */
}
else if (strstr (s, "\\\\"))
{
/* Double quotes detected. Fold them into one because that is
* what what Windows does. This way we get a unique hash
* regardless of the number of doubled backslashes. */
if (!result)
result = xstrdup (newdir);
for (p0=p=result; *p; p++)
{
*p0++ = *p;
while (*p == '\\' && p[1] == '\\')
p++;
}
*p0 = 0;
}
#else /*!HAVE_W32_SYSTEM*/
if (newdir[strlen (newdir)-1] == '/')

View File

@ -84,9 +84,10 @@ static struct
modules (eg "xim"). */
{ "INSIDE_EMACS" }, /* Set by Emacs before running a
process. */
{ "PINENTRY_USER_DATA", "pinentry-user-data"}
{ "PINENTRY_USER_DATA", "pinentry-user-data"},
/* Used for communication with
non-standard Pinentries. */
{ "PINENTRY_GEOM_HINT" } /* Used to pass window information. */
};

View File

@ -152,6 +152,7 @@ enum
STATUS_TRUNCATED,
STATUS_MOUNTPOINT,
STATUS_BLOCKDEV,
STATUS_PLAINDEV, /* The decrypted virtual device. */
STATUS_PINENTRY_LAUNCHED,

View File

@ -366,7 +366,7 @@ gpg_error_t b64decode (const char *string, const char *title,
/*-- Simple replacement functions. */
/* We use the gnupg_ttyname macro to be safe not to run into conflicts
which an extisting but broken ttyname. */
with an existing but broken ttyname. */
#if !defined(HAVE_TTYNAME) || defined(HAVE_BROKEN_TTYNAME)
# define gnupg_ttyname(n) _gnupg_ttyname ((n))
/* Systems without ttyname (W32) will merely return NULL. */

View File

@ -29,4 +29,4 @@ built on @BUILD_HOSTNAME@ at @BUILD_TIMESTAMP@\0"
#define W32INFO_PRODUCTVERSION "@VERSION@\0"
#define W32INFO_LEGALCOPYRIGHT "Copyright \xa9 \
2023 g10 Code GmbH\0"
2024 g10 Code GmbH\0"

View File

@ -525,7 +525,7 @@ AH_BOTTOM([
#define GNUPG_OPENPGP_REVOC_DIR "openpgp-revocs.d"
#define GNUPG_CACHE_DIR "cache.d"
#define GNUPG_DEF_COPYRIGHT_LINE "Copyright (C) 2023 g10 Code GmbH"
#define GNUPG_DEF_COPYRIGHT_LINE "Copyright (C) 2024 g10 Code GmbH"
/* For some systems (DOS currently), we hardcode the path here. For
POSIX systems the values are constructed by the Makefiles, so that

View File

@ -623,19 +623,30 @@ are touched.
@anchor{option --enable-ssh-support}
@item --enable-ssh-support
@itemx --enable-win32-openssh-support
@itemx --enable-putty-support
@opindex enable-ssh-support
@opindex enable-win32-openssh-support
@opindex enable-putty-support
The OpenSSH Agent protocol is always enabled, but @command{gpg-agent}
will only set the @code{SSH_AUTH_SOCK} variable if this flag is given.
On Unix platforms the OpenSSH Agent protocol is always enabled, but
@command{gpg-agent} will only set the @code{SSH_AUTH_SOCK} variable if
the option @option{enable-ssh-support} is given. Some Linux
distributions use the presence of this option to decide whether the
old ssh-agent shall be started.
On Windows support for the native ssh implementation must be enabled
using the the option @option{enable-win32-openssh-support}. For using
gpg-agent as a replacement for PuTTY's Pageant, the option
@option{enable-putty-support} must be enabled.
In this mode of operation, the agent does not only implement the
gpg-agent protocol, but also the agent protocol used by OpenSSH
(through a separate socket). Consequently, it should be possible to use
the gpg-agent as a drop-in replacement for the well known ssh-agent.
(through a separate socket or via Named Pipes) or the protocol used by
PuTTY. Consequently, this allows to use the gpg-agent as a drop-in
replacement for the ssh-agent.
SSH Keys, which are to be used through the agent, need to be added to
SSH keys, which are to be used through the agent, need to be added to
the gpg-agent initially through the ssh-add utility. When a key is
added, ssh-add will ask for the password of the provided key file and
send the unprotected key material to the agent; this causes the

View File

@ -316,6 +316,40 @@ Write a private key object identified by @var{keygrip} to the card
under the id @var{keyref}. Option @option{--force} allows overwriting
an existing key.
@item CHECKKEYS [--ondisk] [--delete-clear-copy] [--delete-protected-copy]
@opindex checkkeys
Print a list of keys noticed on all inserted cards. With
@option{--ondisk} only smartcard keys with a copy on disk are listed.
With @option{--delete-clear-copy} copies of smartcard keys stored on
disk without any protection will be deleted. With
@option{--delete-protected-copy} password protected copies of
smartcard keys stored on disk will be deleted.
This command creates missing shadow keys. The delete options print
the status of the keys before they are deleted.
The format of the output is:
@table @var
@item Serial number
A hex-string with the serial number of the card.
@item Type
This gives the type of the card's application. For example "OpenPGP"
or "PIV".
@item Keygrip
A hex-string identifying a key.
@item Keyref
The application slot where the key is stored on the card. For example
"OpenPGP.1"
@item Status
The status of the key. The most common value is "shadowed" for a key
where only the public key along with the card's serial number is
stored on the disk. The value "clear" indicates that a copy of the
card's key is stored unprotected on disk. The value "protected"
indicated that a copy of the car's key is stored on disk but is
protected by a password. The value "error" may also be shown if there
was a problem reading information from the card.
@end table
@item YUBIKEY @var{cmd} @var{args}
@opindex yubikey
Various commands pertaining to Yubikey tokens with @var{cmd} being:

View File

@ -638,12 +638,11 @@ The @option{--dearmor} command can also be used to dearmor PEM armors.
@item --unwrap
@opindex unwrap
This command is similar to @option{--decrypt} with the difference that the
output is not the usual plaintext but the original message with the
encryption layer removed. Thus the output will be an OpenPGP data
structure which often means a signed OpenPGP message. Note that this
option may or may not remove a compression layer which is often found
beneath the encryption layer.
This option modifies the command @option{--decrypt} to output the
original message with the encryption layer removed. Thus the output
will be an OpenPGP data structure which often means a signed OpenPGP
message. Note that this option may or may not remove a compression
layer which is often found beneath the encryption layer.
@item --tofu-policy @{auto|good|unknown|bad|ask@} @var{keys}
@opindex tofu-policy
@ -2580,6 +2579,10 @@ opposite meaning. The options are:
import-clean it suppresses the final clean step after merging the
imported key into the existing key.
@item ignore-attributes
Ignore all attribute user IDs (photo IDs) and their signatures while
importing a key.
@item repair-keys
After import, fix various problems with the
keys. For example, this reorders signatures, and strips duplicate
@ -4637,10 +4640,11 @@ in the @option{--edit-key} menu.
@item Revoker: @var{algo}:@var{fpr} [sensitive]
Add a designated revoker to the generated key. Algo is the public key
algorithm of the designated revoker (i.e., RSA=1, DSA=17, etc.)
@var{fpr} is the fingerprint of the designated revoker. The optional
@samp{sensitive} flag marks the designated revoker as sensitive
information. Only v4 keys may be designated revokers.
algorithm of the designated revoker (i.e. RSA=1, DSA=17, etc.)
@var{fpr} is the fingerprint of the designated revoker. @var{fpr} may
not contain spaces or colons. The optional @samp{sensitive} flag
marks the designated revoker as sensitive information. Only v4 and v5
keys may be designated revokers.
@item Keyserver: @var{string}
This is an optional parameter that specifies the preferred keyserver

View File

@ -387,12 +387,23 @@ daemons. Note that as of now reload and kill have the same effect for
Create a directory for sockets below /run/user or /var/run/user. This
is command is only required if a non default home directory is used
and the /run based sockets shall be used. For the default home
directory GnUPG creates a directory on the fly.
directory GnuPG creates a directory on the fly.
@item --remove-socketdir
@opindex remove-socketdir
Remove a directory created with command @option{--create-socketdir}.
@item --unlock @var{name}
@itemx --lock @var{name}
Remove a stale lock file hold for @file{file}. The file is
expected in the current GnuPG home directory. This command is usually
not required because GnuPG is able to detect and remove stale lock
files. Before using the command make sure that the file protected by
the lock file is actually not in use. The lock command may be used to
lock an accidently removed lock file. Note that the commands have no
effect on Windows because the mere existence of a lock file does not
mean that the lock is active.
@end table

View File

@ -2227,7 +2227,14 @@ keyinfo_status_cb (void *opaque, const char *line)
/* Ask the agent whether a secret key for the given public key is
available. Returns 0 if not available. Bigger value is preferred. */
* available. Returns 0 if not available. Bigger value is preferred.
* Will never return a value less than 0. Defined return values are:
* 0 := No key or error
* 1 := Key available
* 2 := Key available on a smartcard
* 3 := Key available and passphrase cached
* 4 := Key available on current smartcard
*/
int
agent_probe_secret_key (ctrl_t ctrl, PKT_public_key *pk)
{
@ -2241,11 +2248,11 @@ agent_probe_secret_key (ctrl_t ctrl, PKT_public_key *pk)
err = start_agent (ctrl, 0);
if (err)
return err;
return 0;
err = hexkeygrip_from_pk (pk, &hexgrip);
if (err)
return err;
return 0;
snprintf (line, sizeof line, "KEYINFO %s", hexgrip);
xfree (hexgrip);
@ -3237,6 +3244,45 @@ agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc, int verify,
}
/* Enable or disable the ephemeral mode. In ephemeral mode keys are
* created,searched and used in a per-session key store and not in the
* on-disk file. Set ENABLE to 1 to enable this mode, to 0 to disable
* this mode and to -1 to only query the current mode. If R_PREVIOUS
* is given the previously used state of the ephemeral mode is stored
* at that address. */
gpg_error_t
agent_set_ephemeral_mode (ctrl_t ctrl, int enable, int *r_previous)
{
gpg_error_t err;
err = start_agent (ctrl, 0);
if (err)
goto leave;
if (r_previous)
{
err = assuan_transact (agent_ctx, "GETINFO ephemeral",
NULL, NULL, NULL, NULL, NULL, NULL);
if (!err)
*r_previous = 1;
else if (gpg_err_code (err) == GPG_ERR_FALSE)
*r_previous = 0;
else
goto leave;
}
/* Skip setting if we are only querying or if the mode is already set. */
if (enable == -1 || (r_previous && !!*r_previous == !!enable))
err = 0;
else
err = assuan_transact (agent_ctx,
enable? "OPTION ephemeral=1" : "OPTION ephemeral=0",
NULL, NULL, NULL, NULL, NULL, NULL);
leave:
return err;
}
/* Return the version reported by gpg-agent. */
gpg_error_t
agent_get_version (ctrl_t ctrl, char **r_version)

View File

@ -247,6 +247,10 @@ gpg_error_t agent_delete_key (ctrl_t ctrl, const char *hexkeygrip,
gpg_error_t agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
int verify,
char **cache_nonce_addr, char **passwd_nonce_addr);
/* Set or get the ephemeral mode. */
gpg_error_t agent_set_ephemeral_mode (ctrl_t ctrl, int enable, int *r_previous);
/* Get the version reported by gpg-agent. */
gpg_error_t agent_get_version (ctrl_t ctrl, char **r_version);

View File

@ -2009,8 +2009,9 @@ parse_def_secret_key (ctrl_t ctrl)
{
gpg_error_t err;
KEYDB_SEARCH_DESC desc;
KBNODE kb;
KBNODE node;
kbnode_t kb;
kbnode_t node;
int any_revoked, any_expired, any_disabled;
err = classify_user_id (t->d, &desc, 1);
if (err)
@ -2053,6 +2054,7 @@ parse_def_secret_key (ctrl_t ctrl)
merge_selfsigs (ctrl, kb);
any_revoked = any_expired = any_disabled = 0;
err = gpg_error (GPG_ERR_NO_SECKEY);
node = kb;
do
@ -2062,6 +2064,7 @@ parse_def_secret_key (ctrl_t ctrl)
/* Check if the key is valid. */
if (pk->flags.revoked)
{
any_revoked = 1;
if (DBG_LOOKUP)
log_debug ("not using %s as default key, %s",
keystr_from_pk (pk), "revoked");
@ -2069,6 +2072,7 @@ parse_def_secret_key (ctrl_t ctrl)
}
if (pk->has_expired)
{
any_expired = 1;
if (DBG_LOOKUP)
log_debug ("not using %s as default key, %s",
keystr_from_pk (pk), "expired");
@ -2076,6 +2080,7 @@ parse_def_secret_key (ctrl_t ctrl)
}
if (pk_is_disabled (pk))
{
any_disabled = 1;
if (DBG_LOOKUP)
log_debug ("not using %s as default key, %s",
keystr_from_pk (pk), "disabled");
@ -2096,9 +2101,22 @@ parse_def_secret_key (ctrl_t ctrl)
{
if (! warned && ! opt.quiet)
{
gpg_err_code_t ec;
/* Try to get a better error than no secret key if we
* only know that the public key is not usable. */
if (any_revoked)
ec = GPG_ERR_CERT_REVOKED;
else if (any_expired)
ec = GPG_ERR_KEY_EXPIRED;
else if (any_disabled)
ec = GPG_ERR_KEY_DISABLED;
else
ec = GPG_ERR_NO_SECKEY;
log_info (_("Warning: not using '%s' as default key: %s\n"),
t->d, gpg_strerror (GPG_ERR_NO_SECKEY));
print_reported_error (err, GPG_ERR_NO_SECKEY);
t->d, gpg_strerror (ec));
print_reported_error (err, ec);
}
}
else
@ -3772,6 +3790,13 @@ finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact,
continue;
}
if (secret_key_avail < last_secret_key_avail)
{
if (DBG_LOOKUP)
log_debug ("\tskipping secret key with lower avail\n");
continue;
}
if (secret_key_avail > last_secret_key_avail)
{
/* Use this key. */

View File

@ -209,6 +209,9 @@ parse_import_options(char *str,unsigned int *options,int noisy)
{"repair-keys", IMPORT_REPAIR_KEYS, NULL,
N_("repair keys on import")},
/* New options. Right now, without description string. */
{"ignore-attributes", IMPORT_IGNORE_ATTRIBUTES, NULL, NULL},
/* Hidden options which are enabled by default and are provided
* in case of problems with the respective implementation. */
{"collapse-uids", IMPORT_COLLAPSE_UIDS, NULL, NULL},
@ -1008,6 +1011,15 @@ read_block( IOBUF a, unsigned int options,
init_packet(pkt);
continue;
}
else if ((opt.import_options & IMPORT_IGNORE_ATTRIBUTES)
&& (pkt->pkttype == PKT_USER_ID || pkt->pkttype == PKT_ATTRIBUTE)
&& pkt->pkt.user_id->attrib_data)
{
skip_sigs = 1;
free_packet (pkt, &parsectx);
init_packet (pkt);
continue;
}
if (skip_sigs)
{

View File

@ -746,14 +746,16 @@ keydb_add_resource (const char *url, unsigned int flags)
err = gpg_error (GPG_ERR_RESOURCE_LIMIT);
else
{
KEYBOX_HANDLE kbxhd;
if ((flags & KEYDB_RESOURCE_FLAG_PRIMARY))
primary_keydb = token;
all_resources[used_resources].type = rt;
all_resources[used_resources].u.kb = NULL; /* Not used here */
all_resources[used_resources].token = token;
if (!(flags & KEYDB_RESOURCE_FLAG_READONLY))
{
KEYBOX_HANDLE kbxhd;
/* Do a compress run if needed and no other user is
* currently using the keybox. */
kbxhd = keybox_new_openpgp (token, 0);
@ -767,7 +769,7 @@ keydb_add_resource (const char *url, unsigned int flags)
keybox_release (kbxhd);
}
}
used_resources++;
}
}

View File

@ -1905,6 +1905,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
PACKET *pkt;
IOBUF a;
struct parse_packet_ctx_s parsectx;
int lastmode;
if (!*arg_string)
{
@ -1959,9 +1960,16 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
xfree (fname);
node = new_kbnode (pkt);
err = agent_set_ephemeral_mode (ctrl, 1, &lastmode);
if (err)
log_error ("error switching to ephemeral mode: %s\n",
gpg_strerror (err));
else
{
/* Transfer it to gpg-agent which handles secret keys. */
err = transfer_secret_keys (ctrl, NULL, node, 1, 1, 0);
if (!err)
{
/* Treat the pkt as a public key. */
pkt->pkttype = PKT_PUBLIC_KEY;
@ -1971,6 +1979,10 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
redisplay = 1;
sec_shadowing = 1;
}
}
if (!lastmode && agent_set_ephemeral_mode (ctrl, 0, NULL))
log_error ("error clearing the ephemeral mode\n");
}
release_kbnode (node);
}
break;
@ -3212,7 +3224,7 @@ keyedit_quick_addkey (ctrl_t ctrl, const char *fpr, const char *algostr,
/* We require a fingerprint because only this uniquely identifies a
* key and may thus be used to select a key for unattended subkey
* creation. */
if (find_by_primary_fpr (ctrl, fpr, &keyblock, &kdbhd))
if ((err=find_by_primary_fpr (ctrl, fpr, &keyblock, &kdbhd)))
goto leave;
if (fix_keyblock (ctrl, &keyblock))
@ -3224,6 +3236,7 @@ keyedit_quick_addkey (ctrl_t ctrl, const char *fpr, const char *algostr,
if (!opt.verbose)
show_key_with_all_names (ctrl, es_stdout, keyblock, 0, 0, 0, 0, 0, 1);
log_error ("%s%s", _("Key is revoked."), "\n");
err = gpg_error (GPG_ERR_CERT_REVOKED);
goto leave;
}
@ -3247,6 +3260,8 @@ keyedit_quick_addkey (ctrl_t ctrl, const char *fpr, const char *algostr,
log_info (_("Key not changed so no update needed.\n"));
leave:
if (err)
write_status_error ("keyedit.addkey", err);
release_kbnode (keyblock);
keydb_release (kdbhd);
}
@ -3274,7 +3289,7 @@ keyedit_quick_addadsk (ctrl_t ctrl, const char *fpr, const char *adskfpr)
/* We require a fingerprint because only this uniquely identifies a
* key and may thus be used to select a key for unattended adsk
* adding. */
if (find_by_primary_fpr (ctrl, fpr, &keyblock, &kdbhd))
if ((err = find_by_primary_fpr (ctrl, fpr, &keyblock, &kdbhd)))
goto leave;
if (fix_keyblock (ctrl, &keyblock))
@ -3286,6 +3301,7 @@ keyedit_quick_addadsk (ctrl_t ctrl, const char *fpr, const char *adskfpr)
if (!opt.verbose)
show_key_with_all_names (ctrl, es_stdout, keyblock, 0, 0, 0, 0, 0, 1);
log_error ("%s%s", _("Key is revoked."), "\n");
err = gpg_error (GPG_ERR_CERT_REVOKED);
goto leave;
}
@ -3310,6 +3326,8 @@ keyedit_quick_addadsk (ctrl_t ctrl, const char *fpr, const char *adskfpr)
}
leave:
if (err)
write_status_error ("keyedit.addadsk", err);
release_kbnode (keyblock);
keydb_release (kdbhd);
}
@ -3318,7 +3336,7 @@ keyedit_quick_addadsk (ctrl_t ctrl, const char *fpr, const char *adskfpr)
/* Unattended expiration setting function for the main key. If
* SUBKEYFPRS is not NULL and SUBKEYSFPRS[0] is neither NULL, it is
* expected to be an array of fingerprints for subkeys to change. It
* may also be an array which just one item "*" to indicate that all
* may also be an array with only the item "*" to indicate that all
* keys shall be set to that expiration date.
*/
void

View File

@ -131,6 +131,18 @@ struct output_control_s
};
/* An object to help communicating with the actual key generation
* code. */
struct common_gen_cb_parm_s
{
/* This variable set to the result of agent_genkey. The callback
* may take a copy of this so that the result can be used after we
* are back from the deep key generation call stack. */
gcry_sexp_t genkey_result;
};
typedef struct common_gen_cb_parm_s *common_gen_cb_parm_t;
/* FIXME: These globals vars are ugly. And using MAX_PREFS even for
* aeads is useless, given that we don't expects more than a very few
* algorithms. */
@ -159,7 +171,7 @@ static void do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
static int write_keyblock (iobuf_t out, kbnode_t node);
static gpg_error_t gen_card_key (int keyno, int algo, int is_primary,
kbnode_t pub_root, u32 *timestamp,
u32 expireval, int keygen_flags);
u32 expireval, int *keygen_flags);
static unsigned int get_keysize_range (int algo,
unsigned int *min, unsigned int *max);
@ -1266,6 +1278,39 @@ write_keybinding (ctrl_t ctrl, kbnode_t root,
}
/* Returns true if SEXP specified the curve ED448 or X448. */
static int
curve_is_448 (gcry_sexp_t sexp)
{
gcry_sexp_t list, l2;
char *curve;
int result;
list = gcry_sexp_find_token (sexp, "public-key", 0);
if (!list)
return 0; /* Not a public key. */
l2 = gcry_sexp_cadr (list);
gcry_sexp_release (list);
list = l2;
if (!list)
return 0; /* Bad public key. */
l2 = gcry_sexp_find_token (list, "curve", 0);
gcry_sexp_release (list);
if (!l2)
return 0; /* No curve parameter. */
curve = gcry_sexp_nth_string (l2, 1);
gcry_sexp_release (l2);
if (!curve)
return 0; /* Bad curve parameter. */
result = (!ascii_strcasecmp (curve, "X448")
|| !ascii_strcasecmp (curve, "Ed448")
|| !ascii_strcasecmp (curve, "cv448"));
xfree (curve);
return result;
}
static gpg_error_t
ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo)
{
@ -1404,7 +1449,7 @@ static int
do_create_from_keygrip (ctrl_t ctrl, int algo,
const char *hexkeygrip, int cardkey,
kbnode_t pub_root, u32 timestamp, u32 expireval,
int is_subkey, int keygen_flags)
int is_subkey, int *keygen_flags)
{
int err;
PACKET *pkt;
@ -1448,6 +1493,10 @@ do_create_from_keygrip (ctrl_t ctrl, int algo,
return err;
}
/* For X448 we force the use of v5 packets. */
if (curve_is_448 (s_key))
*keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY;
/* Build a public key packet. */
pk = xtrycalloc (1, sizeof *pk);
if (!pk)
@ -1458,7 +1507,7 @@ do_create_from_keygrip (ctrl_t ctrl, int algo,
}
pk->timestamp = timestamp;
pk->version = (keygen_flags & KEYGEN_FLAG_CREATE_V5_KEY)? 5 : 4;
pk->version = (*keygen_flags & KEYGEN_FLAG_CREATE_V5_KEY)? 5 : 4;
if (expireval)
pk->expiredate = pk->timestamp + expireval;
pk->pubkey_algo = algo;
@ -1494,12 +1543,17 @@ do_create_from_keygrip (ctrl_t ctrl, int algo,
}
/* Common code for the key generation function gen_xxx. */
/* Common code for the key generation function gen_xxx. The optinal
* (COMMON_GEN_CB,COMMON_GEN_CB_PARM) can be used as communication
* object.
*/
static int
common_gen (const char *keyparms, int algo, const char *algoelem,
kbnode_t pub_root, u32 timestamp, u32 expireval, int is_subkey,
int keygen_flags, const char *passphrase,
char **cache_nonce_addr, char **passwd_nonce_addr)
char **cache_nonce_addr, char **passwd_nonce_addr,
gpg_error_t (*common_gen_cb)(common_gen_cb_parm_t),
common_gen_cb_parm_t common_gen_cb_parm)
{
int err;
PACKET *pkt;
@ -1516,6 +1570,18 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
return err;
}
if (common_gen_cb && common_gen_cb_parm)
{
common_gen_cb_parm->genkey_result = s_key;
err = common_gen_cb (common_gen_cb_parm);
common_gen_cb_parm->genkey_result = NULL;
if (err)
{
gcry_sexp_release (s_key);
return err;
}
}
pk = xtrycalloc (1, sizeof *pk);
if (!pk)
{
@ -1568,7 +1634,9 @@ static int
gen_elg (int algo, unsigned int nbits, KBNODE pub_root,
u32 timestamp, u32 expireval, int is_subkey,
int keygen_flags, const char *passphrase,
char **cache_nonce_addr, char **passwd_nonce_addr)
char **cache_nonce_addr, char **passwd_nonce_addr,
gpg_error_t (*common_gen_cb)(common_gen_cb_parm_t),
common_gen_cb_parm_t common_gen_cb_parm)
{
int err;
char *keyparms;
@ -1610,7 +1678,8 @@ gen_elg (int algo, unsigned int nbits, KBNODE pub_root,
err = common_gen (keyparms, algo, "pgy",
pub_root, timestamp, expireval, is_subkey,
keygen_flags, passphrase,
cache_nonce_addr, passwd_nonce_addr);
cache_nonce_addr, passwd_nonce_addr,
common_gen_cb, common_gen_cb_parm);
xfree (keyparms);
}
@ -1625,7 +1694,9 @@ static gpg_error_t
gen_dsa (unsigned int nbits, KBNODE pub_root,
u32 timestamp, u32 expireval, int is_subkey,
int keygen_flags, const char *passphrase,
char **cache_nonce_addr, char **passwd_nonce_addr)
char **cache_nonce_addr, char **passwd_nonce_addr,
gpg_error_t (*common_gen_cb)(common_gen_cb_parm_t),
common_gen_cb_parm_t common_gen_cb_parm)
{
int err;
unsigned int qbits;
@ -1699,7 +1770,8 @@ gen_dsa (unsigned int nbits, KBNODE pub_root,
err = common_gen (keyparms, PUBKEY_ALGO_DSA, "pqgy",
pub_root, timestamp, expireval, is_subkey,
keygen_flags, passphrase,
cache_nonce_addr, passwd_nonce_addr);
cache_nonce_addr, passwd_nonce_addr,
common_gen_cb, common_gen_cb_parm);
xfree (keyparms);
}
@ -1709,13 +1781,17 @@ gen_dsa (unsigned int nbits, KBNODE pub_root,
/*
* Generate an ECC key
* Generate an ECC key.
* Note that KEYGEN_FLAGS might be updated by this function to
* indicate the forced creation of a v5 key.
*/
static gpg_error_t
gen_ecc (int algo, const char *curve, kbnode_t pub_root,
u32 timestamp, u32 expireval, int is_subkey,
int keygen_flags, const char *passphrase,
char **cache_nonce_addr, char **passwd_nonce_addr)
int *keygen_flags, const char *passphrase,
char **cache_nonce_addr, char **passwd_nonce_addr,
gpg_error_t (*common_gen_cb)(common_gen_cb_parm_t),
common_gen_cb_parm_t common_gen_cb_parm)
{
gpg_error_t err;
char *keyparms;
@ -1741,40 +1817,52 @@ gen_ecc (int algo, const char *curve, kbnode_t pub_root,
/* Note that we use the "comp" flag with EdDSA to request the use of
a 0x40 compression prefix octet. */
if (algo == PUBKEY_ALGO_EDDSA && !strcmp (curve, "Ed25519"))
{
keyparms = xtryasprintf
("(genkey(ecc(curve %zu:%s)(flags eddsa comp%s)))",
strlen (curve), curve,
(((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
&& (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
(((*keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
&& (*keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
" transient-key" : ""));
}
else if (algo == PUBKEY_ALGO_EDDSA && !strcmp (curve, "Ed448"))
{
*keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY;
keyparms = xtryasprintf
("(genkey(ecc(curve %zu:%s)(flags comp%s)))",
strlen (curve), curve,
(((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
&& (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
(((*keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
&& (*keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
" transient-key" : ""));
}
else if (algo == PUBKEY_ALGO_ECDH && !strcmp (curve, "Curve25519"))
{
keyparms = xtryasprintf
("(genkey(ecc(curve %zu:%s)(flags djb-tweak comp%s)))",
strlen (curve), curve,
(((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
&& (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
(((*keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
&& (*keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
" transient-key" : ""));
}
else if (algo == PUBKEY_ALGO_ECDH && !strcmp (curve, "X448"))
{
*keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY;
keyparms = xtryasprintf
("(genkey(ecc(curve %zu:%s)(flags comp%s)))",
strlen (curve), curve,
(((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
&& (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
(((*keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
&& (*keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
" transient-key" : ""));
}
else
{
keyparms = xtryasprintf
("(genkey(ecc(curve %zu:%s)(flags nocomp%s)))",
strlen (curve), curve,
(((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
&& (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
(((*keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
&& (*keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
" transient-key" : ""));
}
if (!keyparms)
err = gpg_error_from_syserror ();
@ -1782,8 +1870,9 @@ gen_ecc (int algo, const char *curve, kbnode_t pub_root,
{
err = common_gen (keyparms, algo, "",
pub_root, timestamp, expireval, is_subkey,
keygen_flags, passphrase,
cache_nonce_addr, passwd_nonce_addr);
*keygen_flags, passphrase,
cache_nonce_addr, passwd_nonce_addr,
common_gen_cb, common_gen_cb_parm);
xfree (keyparms);
}
@ -1798,7 +1887,9 @@ static int
gen_rsa (int algo, unsigned int nbits, KBNODE pub_root,
u32 timestamp, u32 expireval, int is_subkey,
int keygen_flags, const char *passphrase,
char **cache_nonce_addr, char **passwd_nonce_addr)
char **cache_nonce_addr, char **passwd_nonce_addr,
gpg_error_t (*common_gen_cb)(common_gen_cb_parm_t),
common_gen_cb_parm_t common_gen_cb_parm)
{
int err;
char *keyparms;
@ -1840,7 +1931,8 @@ gen_rsa (int algo, unsigned int nbits, KBNODE pub_root,
err = common_gen (keyparms, algo, "ne",
pub_root, timestamp, expireval, is_subkey,
keygen_flags, passphrase,
cache_nonce_addr, passwd_nonce_addr);
cache_nonce_addr, passwd_nonce_addr,
common_gen_cb, common_gen_cb_parm);
xfree (keyparms);
}
@ -3200,12 +3292,15 @@ ask_user_id (int mode, int full, KBNODE keyblock)
/* Basic key generation. Here we divert to the actual generation
routines based on the requested algorithm. */
* routines based on the requested algorithm. KEYGEN_FLAGS might be
* updated by this function. */
static int
do_create (int algo, unsigned int nbits, const char *curve, kbnode_t pub_root,
u32 timestamp, u32 expiredate, int is_subkey,
int keygen_flags, const char *passphrase,
char **cache_nonce_addr, char **passwd_nonce_addr)
int *keygen_flags, const char *passphrase,
char **cache_nonce_addr, char **passwd_nonce_addr,
gpg_error_t (*common_gen_cb)(common_gen_cb_parm_t),
common_gen_cb_parm_t common_gen_cb_parm)
{
gpg_error_t err;
@ -3220,22 +3315,26 @@ do_create (int algo, unsigned int nbits, const char *curve, kbnode_t pub_root,
if (algo == PUBKEY_ALGO_ELGAMAL_E)
err = gen_elg (algo, nbits, pub_root, timestamp, expiredate, is_subkey,
keygen_flags, passphrase,
cache_nonce_addr, passwd_nonce_addr);
*keygen_flags, passphrase,
cache_nonce_addr, passwd_nonce_addr,
common_gen_cb, common_gen_cb_parm);
else if (algo == PUBKEY_ALGO_DSA)
err = gen_dsa (nbits, pub_root, timestamp, expiredate, is_subkey,
keygen_flags, passphrase,
cache_nonce_addr, passwd_nonce_addr);
*keygen_flags, passphrase,
cache_nonce_addr, passwd_nonce_addr,
common_gen_cb, common_gen_cb_parm);
else if (algo == PUBKEY_ALGO_ECDSA
|| algo == PUBKEY_ALGO_EDDSA
|| algo == PUBKEY_ALGO_ECDH)
err = gen_ecc (algo, curve, pub_root, timestamp, expiredate, is_subkey,
keygen_flags, passphrase,
cache_nonce_addr, passwd_nonce_addr);
cache_nonce_addr, passwd_nonce_addr,
common_gen_cb, common_gen_cb_parm);
else if (algo == PUBKEY_ALGO_RSA)
err = gen_rsa (algo, nbits, pub_root, timestamp, expiredate, is_subkey,
keygen_flags, passphrase,
cache_nonce_addr, passwd_nonce_addr);
*keygen_flags, passphrase,
cache_nonce_addr, passwd_nonce_addr,
common_gen_cb, common_gen_cb_parm);
else
BUG();
@ -4106,7 +4205,7 @@ parse_revocation_key (const char *fname,
pn++;
for(i=0;i<MAX_FINGERPRINT_LEN && *pn;i++,pn+=2)
for(i=0;i<MAX_FINGERPRINT_LEN && *pn && !spacep (pn);i++,pn+=2)
{
int c=hextobyte(pn);
if(c==-1)
@ -4247,12 +4346,13 @@ proc_parameter_file (ctrl_t ctrl, struct para_data_s *para, const char *fname,
if (!err)
{
/* Default to algo capabilities if subkey-usage is not
provided */
provided. Take care not to include RENC. */
r = xmalloc_clear (sizeof(*r));
r->key = pSUBKEYUSAGE;
r->u.usage = (is_default
? PUBKEY_USAGE_ENC
: openpgp_pk_algo_usage (algo));
: (openpgp_pk_algo_usage (algo)
& ~PUBKEY_USAGE_RENC) );
append_to_parameter (para, r);
}
else if (err == -1)
@ -5100,7 +5200,7 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
strcpy (r->u.value, curve);
r->next = para;
para = r;
if (!strcmp (curve, "Ed448"))
if (!strcmp (curve, "X448") || !strcmp (curve, "Ed448"))
{
r = xmalloc_clear (sizeof *r + 20);
r->key = pVERSION;
@ -5182,7 +5282,7 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
strcpy (r->u.value, curve);
r->next = para;
para = r;
if (!strcmp (curve, "Ed448"))
if (!strcmp (curve, "X448") || !strcmp (curve, "Ed448"))
{
r = xmalloc_clear (sizeof *r + 20);
r->key = pVERSION;
@ -5613,7 +5713,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
err = do_create_from_keygrip (ctrl, algo, key_from_hexgrip, cardkey,
pub_root,
keytimestamp,
expire, 0, keygen_flags);
expire, 0, &keygen_flags);
else if (!card)
err = do_create (algo,
get_parameter_uint( para, pKEYLENGTH ),
@ -5621,13 +5721,14 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
pub_root,
keytimestamp,
expire, 0,
keygen_flags,
&keygen_flags,
get_parameter_passphrase (para),
&cache_nonce, NULL);
&cache_nonce, NULL,
NULL, NULL);
else
err = gen_card_key (1, algo,
1, pub_root, &keytimestamp,
expire, keygen_flags);
expire, &keygen_flags);
/* Get the pointer to the generated public key packet. */
if (!err)
@ -5671,7 +5772,8 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
{
err = gen_card_key (3, get_parameter_algo (ctrl, para,
pAUTHKEYTYPE, NULL ),
0, pub_root, &authkeytimestamp, expire, keygen_flags);
0, pub_root, &authkeytimestamp, expire,
&keygen_flags);
if (!err)
err = write_keybinding (ctrl, pub_root, pri_psk, NULL,
PUBKEY_USAGE_AUTH, signtimestamp, cache_nonce);
@ -5681,7 +5783,6 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
{
int subkey_algo = get_parameter_algo (ctrl, para, pSUBKEYTYPE, NULL);
s = NULL;
key_from_hexgrip = get_parameter_value (para, pSUBKEYGRIP);
keygen_flags = outctrl->keygen_flags;
@ -5693,8 +5794,17 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
key_from_hexgrip, cardkey,
pub_root, subkeytimestamp,
get_parameter_u32 (para, pSUBKEYEXPIRE),
1, keygen_flags);
else if (!card || (s = get_parameter_value (para, pCARDBACKUPKEY)))
1, &keygen_flags);
else if (get_parameter_value (para, pCARDBACKUPKEY))
{
int lastmode;
unsigned int mykeygenflags = KEYGEN_FLAG_NO_PROTECTION;
err = agent_set_ephemeral_mode (ctrl, 1, &lastmode);
if (err)
log_error ("error switching to ephemeral mode: %s\n",
gpg_strerror (err));
else
{
err = do_create (subkey_algo,
get_parameter_uint (para, pSUBKEYLENGTH),
@ -5702,9 +5812,10 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
pub_root,
subkeytimestamp,
get_parameter_u32 (para, pSUBKEYEXPIRE), 1,
s? KEYGEN_FLAG_NO_PROTECTION : keygen_flags,
&mykeygenflags,
get_parameter_passphrase (para),
&cache_nonce, NULL);
&cache_nonce, NULL,
NULL, NULL);
/* Get the pointer to the generated public subkey packet. */
if (!err)
{
@ -5714,16 +5825,41 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
sub_psk = node->pkt->pkt.public_key;
log_assert (sub_psk);
if (s)
err = card_store_key_with_backup (ctrl,
sub_psk, gnupg_homedir ());
}
/* Reset the ephemeral mode as needed. */
if (!lastmode && agent_set_ephemeral_mode (ctrl, 0, NULL))
log_error ("error clearing the ephemeral mode\n");
}
}
else if (!card)
{
err = do_create (subkey_algo,
get_parameter_uint (para, pSUBKEYLENGTH),
get_parameter_value (para, pSUBKEYCURVE),
pub_root,
subkeytimestamp,
get_parameter_u32 (para, pSUBKEYEXPIRE), 1,
&keygen_flags,
get_parameter_passphrase (para),
&cache_nonce, NULL,
NULL, NULL);
if (!err)
{
kbnode_t node;
for (node = pub_root; node; node = node->next)
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
sub_psk = node->pkt->pkt.public_key;
log_assert (sub_psk);
}
}
else
{
err = gen_card_key (2, subkey_algo, 0, pub_root,
&subkeytimestamp, expire, keygen_flags);
&subkeytimestamp, expire, &keygen_flags);
}
if (!err)
@ -6097,7 +6233,7 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr,
keyblock,
keytime? keytime : cur_time,
expire, 1,
keygen_flags);
&keygen_flags);
}
else
{
@ -6113,8 +6249,8 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr,
passwd = NULL;
err = do_create (algo, nbits, curve,
keyblock, cur_time, expire, 1, keygen_flags,
passwd, &cache_nonce, &passwd_nonce);
keyblock, cur_time, expire, 1, &keygen_flags,
passwd, &cache_nonce, &passwd_nonce, NULL, NULL);
}
if (err)
goto leave;
@ -6237,7 +6373,7 @@ generate_card_subkeypair (ctrl_t ctrl, kbnode_t pub_keyblock,
/* Note, that depending on the backend, the card key generation may
update CUR_TIME. */
err = gen_card_key (keyno, algo, 0, pub_keyblock, &cur_time, expire,
keygen_flags);
&keygen_flags);
/* Get the pointer to the generated public subkey packet. */
if (!err)
{
@ -6283,11 +6419,10 @@ write_keyblock( IOBUF out, KBNODE node )
}
/* Note that timestamp is an in/out arg.
* FIXME: Does not yet support v5 keys. */
/* Note that timestamp is an in/out arg. */
static gpg_error_t
gen_card_key (int keyno, int algo, int is_primary, kbnode_t pub_root,
u32 *timestamp, u32 expireval, int keygen_flags)
u32 *timestamp, u32 expireval, int *keygen_flags)
{
#ifdef ENABLE_CARD_SUPPORT
gpg_error_t err;
@ -6351,6 +6486,10 @@ gen_card_key (int keyno, int algo, int is_primary, kbnode_t pub_root,
return err;
}
/* Force creation of v5 keys for X448. */
if (curve_is_448 (s_key))
*keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY;
if (algo == PUBKEY_ALGO_RSA)
err = key_from_sexp (pk->pkey, s_key, "public-key", "ne");
else if (algo == PUBKEY_ALGO_ECDSA
@ -6369,7 +6508,7 @@ gen_card_key (int keyno, int algo, int is_primary, kbnode_t pub_root,
}
pk->timestamp = *timestamp;
pk->version = (keygen_flags & KEYGEN_FLAG_CREATE_V5_KEY)? 5 : 4;
pk->version = (*keygen_flags & KEYGEN_FLAG_CREATE_V5_KEY)? 5 : 4;
if (expireval)
pk->expiredate = pk->timestamp + expireval;
pk->pubkey_algo = algo;

View File

@ -408,6 +408,7 @@ EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode;
#define IMPORT_COLLAPSE_UIDS (1<<15)
#define IMPORT_COLLAPSE_SUBKEYS (1<<16)
#define IMPORT_BULK (1<<17)
#define IMPORT_IGNORE_ATTRIBUTES (1<<18)
#define EXPORT_LOCAL_SIGS (1<<0)
#define EXPORT_ATTRIBUTES (1<<1)

View File

@ -2765,7 +2765,16 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
{
ski->is_protected = 1;
ski->s2k.count = 0;
if (ski->algo == 254 || ski->algo == 255)
if (ski->algo == 253)
{
if (list_mode)
es_fprintf (listfp,
"\tS2K pseudo algo %d is not yet supported\n",
ski->algo);
err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
goto leave;
}
else if (ski->algo == 254 || ski->algo == 255)
{
if (pktlen < 3)
{

View File

@ -444,8 +444,9 @@ do_sign (ctrl_t ctrl, PKT_public_key *pksk, PKT_signature *sig,
goto leave;
}
/* Check compliance. */
if (! gnupg_digest_is_allowed (opt.compliance, 1, mdalgo))
/* Check compliance but always allow for key revocations. */
if (!IS_KEY_REV (sig)
&& ! gnupg_digest_is_allowed (opt.compliance, 1, mdalgo))
{
log_error (_("digest algorithm '%s' may not be used in %s mode\n"),
gcry_md_algo_name (mdalgo),
@ -454,7 +455,8 @@ do_sign (ctrl_t ctrl, PKT_public_key *pksk, PKT_signature *sig,
goto leave;
}
if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_SIGNING,
if (!IS_KEY_REV (sig)
&& ! gnupg_pk_is_allowed (opt.compliance, PK_USE_SIGNING,
pksk->pubkey_algo, 0,
pksk->pkey, nbits_from_pk (pksk), NULL))
{

View File

@ -433,10 +433,15 @@ static gpg_error_t
mount_status_cb (void *opaque, const char *line)
{
struct mount_parm_s *parm = opaque;
const char *s;
/* Nothing right now. */
(void)parm;
(void)line;
if ((s=has_leading_keyword (line, "PLAINDEV")))
{
if (opt.verbose || opt.no_mount)
log_info ("Device: %s\n", s);
}
return 0;
}
@ -497,7 +502,10 @@ call_syshelp_run_mount (ctrl_t ctrl, int conttype, const char *mountpoint,
{
ref_tupledesc (tuples);
parm.keyblob = get_tupledesc_data (tuples, &parm.keybloblen);
err = assuan_transact (ctx, "MOUNT dm-crypt",
err = assuan_transact (ctx,
(opt.no_mount
? "MOUNT --no-mount dm-crypt"
: "MOUNT dm-crypt"),
NULL, NULL,
mount_inq_cb, &parm,
mount_status_cb, &parm);

View File

@ -81,6 +81,8 @@ struct
/* Name of the output file - FIXME: what is this? */
const char *outfile;
int no_mount; /* Stop right before mounting a device. */
} opt;

View File

@ -583,7 +583,7 @@ g13_syshelp_i_know_what_i_am_doing (void)
if (gnupg_access (fname, F_OK))
{
log_info ("*******************************************************\n");
log_info ("* The G13 support for DM-Crypt is new and not matured.\n");
log_info ("* The G13 support for DM-Crypt is not yet widely used.\n");
log_info ("* Bugs or improper use may delete all your disks!\n");
log_info ("* To confirm that you are ware of this risk, create\n");
log_info ("* the file '%s'.\n", fname);

View File

@ -85,7 +85,7 @@ gpg_error_t sh_is_empty_partition (const char *name);
gpg_error_t sh_dmcrypt_create_container (ctrl_t ctrl, const char *devname,
estream_t devfp);
gpg_error_t sh_dmcrypt_mount_container (ctrl_t ctrl, const char *devname,
tupledesc_t keyblob);
tupledesc_t keyblob, int nomount);
gpg_error_t sh_dmcrypt_umount_container (ctrl_t ctrl, const char *devname);
gpg_error_t sh_dmcrypt_suspend_container (ctrl_t ctrl, const char *devname);
gpg_error_t sh_dmcrypt_resume_container (ctrl_t ctrl, const char *devname,

View File

@ -104,6 +104,7 @@ enum cmd_and_opt_values {
oWithColons,
oDryRun,
oNoDetach,
oNoMount,
oNoRandomSeedFile,
oFakedSystemTime
@ -138,6 +139,7 @@ static gpgrt_opt_t opts[] = {
ARGPARSE_s_s (oLogFile, "log-file", N_("|FILE|write log output to FILE")),
ARGPARSE_s_n (oNoLogFile, "no-log-file", "@"),
ARGPARSE_s_i (oLoggerFD, "logger-fd", "@"),
ARGPARSE_s_n (oNoMount, "no-mount", N_("stop right before running mount")),
ARGPARSE_s_n (oDryRun, "dry-run", N_("do not make any changes")),
@ -516,6 +518,8 @@ main (int argc, char **argv)
case oNoDetach: /*nodetach = 1; */break;
case oNoMount: opt.no_mount = 1; break;
case oDebug:
if (parse_debug_flag (pargs.r.ret_str, &opt.debug, debug_flags))
{

View File

@ -83,17 +83,17 @@ skip_options (const char *line)
/* Check whether the option NAME appears in LINE. */
/* static int */
/* has_option (const char *line, const char *name) */
/* { */
/* const char *s; */
/* int n = strlen (name); */
static int
has_option (const char *line, const char *name)
{
const char *s;
int n = strlen (name);
/* s = strstr (line, name); */
/* if (s && s >= skip_options (line)) */
/* return 0; */
/* return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n))); */
/* } */
s = strstr (line, name);
if (s && s >= skip_options (line))
return 0;
return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
}
/* Helper to print a message while leaving a command. */
@ -431,10 +431,11 @@ cmd_getkeyblob (assuan_context_t ctx, char *line)
static const char hlp_mount[] =
"MOUNT <type>\n"
"MOUNT [--no-mount] <type>\n"
"\n"
"Mount an encrypted partition on the current device.\n"
"<type> must be \"dm-crypt\" for now.";
"<type> must be \"dm-crypt\" for now. Option --no-mount\n"
"stops right before calling the mount command.\n";
static gpg_error_t
cmd_mount (assuan_context_t ctx, char *line)
{
@ -443,6 +444,9 @@ cmd_mount (assuan_context_t ctx, char *line)
unsigned char *keyblob = NULL;
size_t keybloblen;
tupledesc_t tuples = NULL;
int nomount;
nomount = has_option (line, "--no-mount");
line = skip_options (line);
@ -493,7 +497,7 @@ cmd_mount (assuan_context_t ctx, char *line)
err = sh_dmcrypt_mount_container (ctrl,
ctrl->server_local->devicename,
tuples);
tuples, nomount);
leave:
destroy_tupledesc (tuples);

View File

@ -220,7 +220,7 @@ mk_setup_area_prefix (size_t *r_length)
}
/* Create a new g13 styloe DM-Crypt container on devoce DEVNAME. */
/* Create a new g13 style DM-Crypt container on device DEVNAME. */
gpg_error_t
sh_dmcrypt_create_container (ctrl_t ctrl, const char *devname, estream_t devfp)
{
@ -538,10 +538,11 @@ sh_dmcrypt_create_container (ctrl_t ctrl, const char *devname, estream_t devfp)
/* Mount a DM-Crypt container on device DEVNAME taking keys and other
* meta data from KEYBLOB. */
* meta data from KEYBLOB. If NOMOUNT is set the actual mount command
* is not run. */
gpg_error_t
sh_dmcrypt_mount_container (ctrl_t ctrl, const char *devname,
tupledesc_t keyblob)
tupledesc_t keyblob, int nomount)
{
gpg_error_t err;
char *targetname_abs = NULL;
@ -696,8 +697,10 @@ sh_dmcrypt_mount_container (ctrl_t ctrl, const char *devname,
xfree (result);
result = NULL;
g13_status (ctrl, STATUS_PLAINDEV, targetname_abs, NULL);
/* Mount if a mountpoint has been given. */
if (ctrl->devti->mountpoint)
if (!nomount && ctrl->devti->mountpoint)
{
const char *argv[3];
@ -766,23 +769,32 @@ sh_dmcrypt_umount_container (ctrl_t ctrl, const char *devname)
goto leave;
}
/* Run the regular umount command. */
/* Run the regular umount command but first test with findmnt. */
{
const char *argv[2];
const char *argv[3];
argv[0] = targetname_abs;
argv[1] = NULL;
log_debug ("now running \"findmnt %s\"\n", targetname_abs);
err = gnupg_exec_tool ("/bin/findmnt", argv, NULL, &result, NULL);
if (err)
log_info ("Note: device was not mounted\n");
else
{
xfree (result);
result = NULL;
argv[0] = targetname_abs;
argv[1] = NULL;
log_debug ("now running \"umount %s\"\n", targetname_abs);
err = gnupg_exec_tool ("/bin/umount", argv, NULL, &result, NULL);
}
if (err)
{
log_error ("error running umount: %s\n", gpg_strerror (err));
if (1)
{
/* Try to show some info about processes using the partition. */
const char *argv[3];
argv[0] = "-mv";
argv[1] = targetname_abs;
argv[2] = NULL;
@ -792,6 +804,8 @@ sh_dmcrypt_umount_container (ctrl_t ctrl, const char *devname)
}
if (result && *result) /* (We should not see output to stdout). */
log_info ("WARNING: umount returned data on stdout! (%s)\n", result);
}
}
xfree (result);
result = NULL;

View File

@ -810,8 +810,8 @@ msgstr ""
#, fuzzy, c-format
msgid ""
"Do you really want to delete the key identified by keygrip%%0A %s%%0A %%C"
"%%0A?"
"Do you really want to delete the key identified by keygrip%%0A %s%%0A "
"%%C%%0A?"
msgstr "Realment voleu eliminar les claus seleccionades? "
#, fuzzy
@ -1953,16 +1953,16 @@ msgstr "no es pot usar un paquet asimètric ESK al estar en mode S2K\n"
msgid "using cipher %s.%s\n"
msgstr "Ha fallat el procés de signatura: %s\n"
#, fuzzy, c-format
#| msgid "`%s' already compressed\n"
msgid "'%s' already compressed\n"
msgstr "«%s» ja està comprimida\n"
#, fuzzy, c-format
#| msgid "WARNING: `%s' is an empty file\n"
msgid "WARNING: '%s' is an empty file\n"
msgstr "AVÍS: «%s» és un fitxer buit\n"
#, fuzzy, c-format
#| msgid "`%s' already compressed\n"
msgid "'%s' already compressed\n"
msgstr "«%s» ja està comprimida\n"
#, fuzzy, c-format
msgid "digest algorithm '%s' may not be used in %s mode\n"
msgstr "no podeu usar l'algorisme de resum %s mentre esteu en mode %s\n"
@ -9496,6 +9496,9 @@ msgstr "S'ha creat el certificat de revocació.\n"
msgid "store a private key to a data object"
msgstr ""
msgid "run various checks on the keys"
msgstr ""
msgid "Yubikey management commands"
msgstr ""
@ -10682,8 +10685,8 @@ msgstr ""
#~ "\n"
#~ "Note that the examples given above for levels 2 and 3 are *only* "
#~ "examples.\n"
#~ "In the end, it is up to you to decide just what \"casual\" and \"extensive"
#~ "\"\n"
#~ "In the end, it is up to you to decide just what \"casual\" and "
#~ "\"extensive\"\n"
#~ "mean to you when you sign other keys.\n"
#~ "\n"
#~ "If you don't know what the right answer is, answer \"0\"."

View File

@ -786,8 +786,8 @@ msgstr "Vyžádáno použití klíče%%0A %s%%0A %s%%0APřejete si to povolit?
#, c-format
msgid ""
"Do you really want to delete the key identified by keygrip%%0A %s%%0A %%C"
"%%0A?"
"Do you really want to delete the key identified by keygrip%%0A %s%%0A "
"%%C%%0A?"
msgstr ""
"Opravdu chcete smazat klíč určený pomocí keygripu%%0A %s%%0A %%C%%0A?"
@ -1831,14 +1831,14 @@ msgstr "v režimu S2K nelze použít SKESK paket\n"
msgid "using cipher %s.%s\n"
msgstr "použití šifry %s.%s\n"
#, c-format
msgid "'%s' already compressed\n"
msgstr "„%s“ je již zkomprimován\n"
#, c-format
msgid "WARNING: '%s' is an empty file\n"
msgstr "POZOR: soubor „%s“ je prázdný\n"
#, c-format
msgid "'%s' already compressed\n"
msgstr "„%s“ je již zkomprimován\n"
#, c-format
msgid "digest algorithm '%s' may not be used in %s mode\n"
msgstr "hashovací algoritmus „%s“ se nesmí používat v režimu %s\n"
@ -8974,6 +8974,9 @@ msgstr "uloží certifikát do datového objektu"
msgid "store a private key to a data object"
msgstr "uloží soukromý klíč do datového objektu"
msgid "run various checks on the keys"
msgstr ""
msgid "Yubikey management commands"
msgstr "Příkazy pro správu Yubikey"
@ -10568,8 +10571,8 @@ msgstr "spravuje historii příkazů"
#~ "\n"
#~ "Note that the examples given above for levels 2 and 3 are *only* "
#~ "examples.\n"
#~ "In the end, it is up to you to decide just what \"casual\" and \"extensive"
#~ "\"\n"
#~ "In the end, it is up to you to decide just what \"casual\" and "
#~ "\"extensive\"\n"
#~ "mean to you when you sign other keys.\n"
#~ "\n"
#~ "If you don't know what the right answer is, answer \"0\"."
@ -10616,8 +10619,8 @@ msgstr "spravuje historii příkazů"
#~ "Answer \"yes\" if you really want to delete this user ID.\n"
#~ "All certificates are then also lost!"
#~ msgstr ""
#~ "Pokud opravdu chcete smazat tento identifikátor uživatele, odpovězte \"ano"
#~ "\".\n"
#~ "Pokud opravdu chcete smazat tento identifikátor uživatele, odpovězte "
#~ "\"ano\".\n"
#~ "Všechny certifikáty budou také ztraceny!"
#~ msgid "Answer \"yes\" if it is okay to delete the subkey"

View File

@ -259,8 +259,8 @@ msgid ""
"Please enter a passphrase to protect the received secret key%%0A %s%%0A "
"%s%%0Awithin gpg-agent's key storage"
msgstr ""
"Indtast venligst en adgangsfrase for at beskytte den modtaget hemmelige nøgle"
"%%0A %s%%0A %s%%0Ainden i gpg-agentens nøglelager"
"Indtast venligst en adgangsfrase for at beskytte den modtaget hemmelige "
"nøgle%%0A %s%%0A %s%%0Ainden i gpg-agentens nøglelager"
#, c-format
msgid "failed to create stream from socket: %s\n"
@ -868,8 +868,8 @@ msgstr ""
#, fuzzy, c-format
#| msgid "Do you really want to delete the selected keys? (y/N) "
msgid ""
"Do you really want to delete the key identified by keygrip%%0A %s%%0A %%C"
"%%0A?"
"Do you really want to delete the key identified by keygrip%%0A %s%%0A "
"%%C%%0A?"
msgstr "Vil du virkelig slette de valgte nøgler? (j/N) "
#, fuzzy
@ -1995,16 +1995,16 @@ msgstr "kan ikke bruge en symmetrisk ESK-pakke på grund af S2K-tilstanden\n"
msgid "using cipher %s.%s\n"
msgstr "bruger chiffer %s\n"
#, fuzzy, c-format
#| msgid "`%s' already compressed\n"
msgid "'%s' already compressed\n"
msgstr "»%s« allerede komprimeret\n"
#, fuzzy, c-format
#| msgid "WARNING: `%s' is an empty file\n"
msgid "WARNING: '%s' is an empty file\n"
msgstr "ADVARSEL: »%s« er en tom fil\n"
#, fuzzy, c-format
#| msgid "`%s' already compressed\n"
msgid "'%s' already compressed\n"
msgstr "»%s« allerede komprimeret\n"
#, fuzzy, c-format
#| msgid "you may not use digest algorithm `%s' while in %s mode\n"
msgid "digest algorithm '%s' may not be used in %s mode\n"
@ -2527,8 +2527,8 @@ msgstr "ADVARSEL: Usikre indelukkede mapperettigheder på hjemmemappe »%s«\n"
#, fuzzy, c-format
#| msgid ""
#| "WARNING: unsafe enclosing directory permissions on configuration file `"
#| "%s'\n"
#| "WARNING: unsafe enclosing directory permissions on configuration file "
#| "`%s'\n"
msgid ""
"WARNING: unsafe enclosing directory permissions on configuration file '%s'\n"
msgstr ""
@ -9711,6 +9711,9 @@ msgstr " (certifkat oprettet den "
msgid "store a private key to a data object"
msgstr ""
msgid "run various checks on the keys"
msgstr ""
msgid "Yubikey management commands"
msgstr ""

View File

@ -9,7 +9,7 @@ msgid ""
msgstr ""
"Project-Id-Version: gnupg-2.4.1\n"
"Report-Msgid-Bugs-To: translations@gnupg.org\n"
"PO-Revision-Date: 2023-05-30 13:46+0200\n"
"PO-Revision-Date: 2024-01-24 14:05+0100\n"
"Last-Translator: Werner Koch <wk@gnupg.org>\n"
"Language-Team: German\n"
"Language: de\n"
@ -230,8 +230,9 @@ msgid ""
"Please enter a passphrase to protect the received secret key%%0A %s%%0A "
"%s%%0Awithin gpg-agent's key storage"
msgstr ""
"Bitte geben Sie ein Passwort ein, um den empfangenen geheimen Schlüssel"
"%%0A %s%%0A %s%%0Aim Schlüsselspeicher des Gpg-Agenten zu schützen."
"Bitte geben Sie ein Passwort ein, um den empfangenen geheimen "
"Schlüssel%%0A %s%%0A %s%%0Aim Schlüsselspeicher des Gpg-Agenten zu "
"schützen."
#, c-format
msgid "failed to create stream from socket: %s\n"
@ -710,9 +711,9 @@ msgid ""
"Do you ultimately trust%%0A \"%s\"%%0Ato correctly certify user "
"certificates?"
msgstr ""
"Wenn Sie vollständiges Vertrauen haben, daß%%0A \"%s"
"\"%%0ABenutzerzertifikate verläßlich zertifiziert, so antworten Sie mit \"Ja"
"\"."
"Wenn Sie vollständiges Vertrauen haben, daß%%0A "
"\"%s\"%%0ABenutzerzertifikate verläßlich zertifiziert, so antworten Sie mit "
"\"Ja\"."
msgid "Yes"
msgstr "Ja"
@ -776,8 +777,8 @@ msgstr ""
#, c-format
msgid ""
"Do you really want to delete the key identified by keygrip%%0A %s%%0A %%C"
"%%0A?"
"Do you really want to delete the key identified by keygrip%%0A %s%%0A "
"%%C%%0A?"
msgstr ""
"Möchten Sie den Schlüssel mit dem \"Keygrip\"%%0A %s%%0A %%C%%0Awirklich "
"entfernen?"
@ -1837,14 +1838,14 @@ msgstr "Aufgrund des S2K-Modus kann ein SKESK Paket nicht benutzt werden\n"
msgid "using cipher %s.%s\n"
msgstr "benutze Cipher %s.%s\n"
#, c-format
msgid "'%s' already compressed\n"
msgstr "`%s' ist bereits komprimiert\n"
#, c-format
msgid "WARNING: '%s' is an empty file\n"
msgstr "WARNUNG: '%s' ist eine leere Datei.\n"
#, c-format
msgid "'%s' already compressed\n"
msgstr "`%s' ist bereits komprimiert\n"
#, c-format
msgid "digest algorithm '%s' may not be used in %s mode\n"
msgstr "Die Benutzung der Hashmethode %s ist im %s Modus nicht erlaubt.\n"
@ -9106,6 +9107,9 @@ msgstr "Ein Zertifikat in einem Datenobjekt speichern"
msgid "store a private key to a data object"
msgstr "Privaten Schlüssel in einem Datenobjekt speichern"
msgid "run various checks on the keys"
msgstr "Die Schlüssel verschiedener Prüfungen unterziehen"
msgid "Yubikey management commands"
msgstr "Verwaltungskommandos für Yubikeys"
@ -10484,8 +10488,8 @@ msgstr "Verwaltung der Kommandohistorie"
#~ msgid "the trustdb is corrupted; please run \"gpg --fix-trustdb\".\n"
#~ msgstr ""
#~ "Die \"Trust\"-Datenbank ist beschädigt; verwenden Sie \"gpg --fix-trustdb"
#~ "\".\n"
#~ "Die \"Trust\"-Datenbank ist beschädigt; verwenden Sie \"gpg --fix-"
#~ "trustdb\".\n"
#~ msgid "Please report bugs to <"
#~ msgstr "Fehlerberichte bitte an <"
@ -10710,8 +10714,8 @@ msgstr "Verwaltung der Kommandohistorie"
#~ "\n"
#~ "Note that the examples given above for levels 2 and 3 are *only* "
#~ "examples.\n"
#~ "In the end, it is up to you to decide just what \"casual\" and \"extensive"
#~ "\"\n"
#~ "In the end, it is up to you to decide just what \"casual\" and "
#~ "\"extensive\"\n"
#~ "mean to you when you sign other keys.\n"
#~ "\n"
#~ "If you don't know what the right answer is, answer \"0\"."

View File

@ -777,8 +777,8 @@ msgstr ""
#, fuzzy, c-format
msgid ""
"Do you really want to delete the key identified by keygrip%%0A %s%%0A %%C"
"%%0A?"
"Do you really want to delete the key identified by keygrip%%0A %s%%0A "
"%%C%%0A?"
msgstr "Σίγουρα θέλετε να διαγραφούν τα επιλεγμένα κλειδιά; "
#, fuzzy
@ -1885,16 +1885,16 @@ msgstr "αδυναμία χρήσης ενός συμμετρικού πακέτ
msgid "using cipher %s.%s\n"
msgstr "χρήση του κρυπταλγόριθμου: %s\n"
#, fuzzy, c-format
#| msgid "`%s' already compressed\n"
msgid "'%s' already compressed\n"
msgstr "`%s' ήδη συμπιέστηκε\n"
#, fuzzy, c-format
#| msgid "WARNING: `%s' is an empty file\n"
msgid "WARNING: '%s' is an empty file\n"
msgstr "ΠΡΟΕΙΔΟΠΟΙΗΣΗ: `%s' είναι ένα άδειο αρχείο\n"
#, fuzzy, c-format
#| msgid "`%s' already compressed\n"
msgid "'%s' already compressed\n"
msgstr "`%s' ήδη συμπιέστηκε\n"
#, fuzzy, c-format
msgid "digest algorithm '%s' may not be used in %s mode\n"
msgstr ""
@ -9320,6 +9320,9 @@ msgstr "Πιστοποιητικό ανάκλησης δημιουργήθηκε
msgid "store a private key to a data object"
msgstr ""
msgid "run various checks on the keys"
msgstr ""
msgid "Yubikey management commands"
msgstr ""
@ -10489,8 +10492,8 @@ msgstr ""
#~ "\n"
#~ "Note that the examples given above for levels 2 and 3 are *only* "
#~ "examples.\n"
#~ "In the end, it is up to you to decide just what \"casual\" and \"extensive"
#~ "\"\n"
#~ "In the end, it is up to you to decide just what \"casual\" and "
#~ "\"extensive\"\n"
#~ "mean to you when you sign other keys.\n"
#~ "\n"
#~ "If you don't know what the right answer is, answer \"0\"."

View File

@ -776,8 +776,8 @@ msgstr ""
#, fuzzy, c-format
msgid ""
"Do you really want to delete the key identified by keygrip%%0A %s%%0A %%C"
"%%0A?"
"Do you really want to delete the key identified by keygrip%%0A %s%%0A "
"%%C%%0A?"
msgstr "Ĉu vi vere volas forviŝi la elektitajn ŝlosilojn? "
#, fuzzy
@ -1878,16 +1878,16 @@ msgstr ""
msgid "using cipher %s.%s\n"
msgstr "subskribado malsukcesis: %s\n"
#, fuzzy, c-format
#| msgid "`%s' already compressed\n"
msgid "'%s' already compressed\n"
msgstr "'%s' jam densigita\n"
#, fuzzy, c-format
#| msgid "WARNING: `%s' is an empty file\n"
msgid "WARNING: '%s' is an empty file\n"
msgstr "AVERTO: '%s' estas malplena dosiero\n"
#, fuzzy, c-format
#| msgid "`%s' already compressed\n"
msgid "'%s' already compressed\n"
msgstr "'%s' jam densigita\n"
#, fuzzy, c-format
msgid "digest algorithm '%s' may not be used in %s mode\n"
msgstr "Tiu komando ne eblas en la reĝimo %s.\n"
@ -9231,6 +9231,9 @@ msgstr "ŝlosilo %08lX: revokatestilo aldonita\n"
msgid "store a private key to a data object"
msgstr ""
msgid "run various checks on the keys"
msgstr ""
msgid "Yubikey management commands"
msgstr ""
@ -10312,8 +10315,8 @@ msgstr ""
#~ "\n"
#~ "Note that the examples given above for levels 2 and 3 are *only* "
#~ "examples.\n"
#~ "In the end, it is up to you to decide just what \"casual\" and \"extensive"
#~ "\"\n"
#~ "In the end, it is up to you to decide just what \"casual\" and "
#~ "\"extensive\"\n"
#~ "mean to you when you sign other keys.\n"
#~ "\n"
#~ "If you don't know what the right answer is, answer \"0\"."

View File

@ -776,8 +776,8 @@ msgid ""
"Please verify that the certificate identified as:%%0A \"%s\"%%0Ahas the "
"fingerprint:%%0A %s"
msgstr ""
"Por favor verifique que el certificado identificado como:%%0A \"%s"
"\"%%0Atiene la huella digital:%%0A %s"
"Por favor verifique que el certificado identificado como:%%0A "
"\"%s\"%%0Atiene la huella digital:%%0A %s"
#. TRANSLATORS: "Correct" is the label of a button and intended
#. to be hit if the fingerprint matches the one of the CA. The
@ -821,8 +821,8 @@ msgstr ""
#, c-format
msgid ""
"Do you really want to delete the key identified by keygrip%%0A %s%%0A %%C"
"%%0A?"
"Do you really want to delete the key identified by keygrip%%0A %s%%0A "
"%%C%%0A?"
msgstr ""
"¿De verdad quiere borrar la clave identificada con el keygrip%%0A %s%%0A "
"%%C%%0A?"
@ -1889,14 +1889,14 @@ msgstr "no puede usar un paquete simétrico ESK debido al modo S2K\n"
msgid "using cipher %s.%s\n"
msgstr "usando cifrado %s\n"
#, c-format
msgid "'%s' already compressed\n"
msgstr "'%s' ya está comprimido\n"
#, c-format
msgid "WARNING: '%s' is an empty file\n"
msgstr "ATENCIÓN '%s' es un fichero vacío\n"
#, c-format
msgid "'%s' already compressed\n"
msgstr "'%s' ya está comprimido\n"
#, c-format
msgid "digest algorithm '%s' may not be used in %s mode\n"
msgstr "no puede usar el resumen '%s' en modo %s\n"
@ -5704,8 +5704,8 @@ msgstr ""
"la clave secreta. De cualquier modo, si la clave secreta está disponible,\n"
"es mejor generar un nuevo certificado de revocación y dar una razón para la "
"misma\n"
"Para más detalles, lee la descripción de la orden gpg \"--generate-revocation"
"\"\n"
"Para más detalles, lee la descripción de la orden gpg \"--generate-"
"revocation\"\n"
"en el manual GnuPG."
msgid ""
@ -9157,6 +9157,9 @@ msgstr "añadir un certificado a la cache"
msgid "store a private key to a data object"
msgstr ""
msgid "run various checks on the keys"
msgstr ""
msgid "Yubikey management commands"
msgstr ""
@ -10532,8 +10535,8 @@ msgstr ""
#~ "\n"
#~ "Note that the examples given above for levels 2 and 3 are *only* "
#~ "examples.\n"
#~ "In the end, it is up to you to decide just what \"casual\" and \"extensive"
#~ "\"\n"
#~ "In the end, it is up to you to decide just what \"casual\" and "
#~ "\"extensive\"\n"
#~ "mean to you when you sign other keys.\n"
#~ "\n"
#~ "If you don't know what the right answer is, answer \"0\"."
@ -10572,8 +10575,8 @@ msgstr ""
#~ " al poseedor de la clave.\n"
#~ "\n"
#~ "Observe que los ejemplos dados en los niveles 2 y 3 son *solo* ejemplos.\n"
#~ "En definitiva, usted decide lo que significa \"informal\" y \"exhaustivo"
#~ "\"\n"
#~ "En definitiva, usted decide lo que significa \"informal\" y "
#~ "\"exhaustivo\"\n"
#~ "para usted cuando firma las claves de otros.\n"
#~ "\n"
#~ "Si no sabe qué contestar, conteste \"0\"."

View File

@ -774,8 +774,8 @@ msgstr ""
#, fuzzy, c-format
msgid ""
"Do you really want to delete the key identified by keygrip%%0A %s%%0A %%C"
"%%0A?"
"Do you really want to delete the key identified by keygrip%%0A %s%%0A "
"%%C%%0A?"
msgstr "Kas te tõesti soovite valitud võtmeid kustutada? "
#, fuzzy
@ -1879,16 +1879,16 @@ msgstr "S2K moodi tõttu ei saa sümmeetrilist ESK paketti kasutada\n"
msgid "using cipher %s.%s\n"
msgstr "kasutan šiffrit %s\n"
#, fuzzy, c-format
#| msgid "`%s' already compressed\n"
msgid "'%s' already compressed\n"
msgstr "`%s' on juba pakitud\n"
#, fuzzy, c-format
#| msgid "WARNING: `%s' is an empty file\n"
msgid "WARNING: '%s' is an empty file\n"
msgstr "HOIATUS: `%s' on tühi fail\n"
#, fuzzy, c-format
#| msgid "`%s' already compressed\n"
msgid "'%s' already compressed\n"
msgstr "`%s' on juba pakitud\n"
#, fuzzy, c-format
msgid "digest algorithm '%s' may not be used in %s mode\n"
msgstr "sõnumilühendi algoritm \"%s\" ei ole moodis %s lubatud\n"
@ -9235,6 +9235,9 @@ msgstr "Tühistamise sertifikaat on loodud.\n"
msgid "store a private key to a data object"
msgstr ""
msgid "run various checks on the keys"
msgstr ""
msgid "Yubikey management commands"
msgstr ""
@ -10276,8 +10279,8 @@ msgstr ""
#~ msgid "If you want to use this untrusted key anyway, answer \"yes\"."
#~ msgstr ""
#~ "Kui te ikkagi soovite kasutada seda mitteusaldatavat võtit, vastake \"jah"
#~ "\"."
#~ "Kui te ikkagi soovite kasutada seda mitteusaldatavat võtit, vastake "
#~ "\"jah\"."
#~ msgid ""
#~ "Enter the user ID of the addressee to whom you want to send the message."
@ -10373,8 +10376,8 @@ msgstr ""
#~ "\n"
#~ "Note that the examples given above for levels 2 and 3 are *only* "
#~ "examples.\n"
#~ "In the end, it is up to you to decide just what \"casual\" and \"extensive"
#~ "\"\n"
#~ "In the end, it is up to you to decide just what \"casual\" and "
#~ "\"extensive\"\n"
#~ "mean to you when you sign other keys.\n"
#~ "\n"
#~ "If you don't know what the right answer is, answer \"0\"."

View File

@ -791,8 +791,8 @@ msgstr ""
#, fuzzy, c-format
msgid ""
"Do you really want to delete the key identified by keygrip%%0A %s%%0A %%C"
"%%0A?"
"Do you really want to delete the key identified by keygrip%%0A %s%%0A "
"%%C%%0A?"
msgstr "Haluatko varmasti poistaa valitut avaimet? "
#, fuzzy
@ -1897,16 +1897,16 @@ msgstr "symmetristä ESK-pakettia ei voi käyttää S2K-tilan vuoksi\n"
msgid "using cipher %s.%s\n"
msgstr "käytetään salakirjoitusalgoritmia %s\n"
#, fuzzy, c-format
#| msgid "`%s' already compressed\n"
msgid "'%s' already compressed\n"
msgstr "\"%s\" on jo pakattu\n"
#, fuzzy, c-format
#| msgid "WARNING: `%s' is an empty file\n"
msgid "WARNING: '%s' is an empty file\n"
msgstr "VAROITUS: \"%s\" on tyhjä tiedosto\n"
#, fuzzy, c-format
#| msgid "`%s' already compressed\n"
msgid "'%s' already compressed\n"
msgstr "\"%s\" on jo pakattu\n"
#, fuzzy, c-format
msgid "digest algorithm '%s' may not be used in %s mode\n"
msgstr "tiivistealgoritmia \"%s\" ei voi käyttää %s-tilassa\n"
@ -9303,6 +9303,9 @@ msgstr "Mitätöintivarmenne luotu.\n"
msgid "store a private key to a data object"
msgstr ""
msgid "run various checks on the keys"
msgstr ""
msgid "Yubikey management commands"
msgstr ""
@ -10465,8 +10468,8 @@ msgstr ""
#~ "\n"
#~ "Note that the examples given above for levels 2 and 3 are *only* "
#~ "examples.\n"
#~ "In the end, it is up to you to decide just what \"casual\" and \"extensive"
#~ "\"\n"
#~ "In the end, it is up to you to decide just what \"casual\" and "
#~ "\"extensive\"\n"
#~ "mean to you when you sign other keys.\n"
#~ "\n"
#~ "If you don't know what the right answer is, answer \"0\"."

View File

@ -246,8 +246,8 @@ msgid ""
"Please enter a passphrase to protect the received secret key%%0A %s%%0A "
"%s%%0Awithin gpg-agent's key storage"
msgstr ""
"Veuillez entrer une phrase secrète pour protéger la clef secrète%%0A %s"
"%%0A %s%%0Areçue dans l'espace de stockage de clefs de gpg-agent"
"Veuillez entrer une phrase secrète pour protéger la clef secrète%%0A "
"%s%%0A %s%%0Areçue dans l'espace de stockage de clefs de gpg-agent"
#, c-format
msgid "failed to create stream from socket: %s\n"
@ -824,8 +824,8 @@ msgstr ""
#, fuzzy, c-format
#| msgid "Do you really want to delete the selected keys? (y/N) "
msgid ""
"Do you really want to delete the key identified by keygrip%%0A %s%%0A %%C"
"%%0A?"
"Do you really want to delete the key identified by keygrip%%0A %s%%0A "
"%%C%%0A?"
msgstr "Voulez-vous vraiment supprimer les clefs sélectionnées ? (o/N) "
msgid "Delete key"
@ -1931,14 +1931,14 @@ msgstr "impossible d'utiliser un paquet ESK symétrique en mode S2K\n"
msgid "using cipher %s.%s\n"
msgstr "utilisation de l'algorithme de chiffrement %s\n"
#, c-format
msgid "'%s' already compressed\n"
msgstr "« %s » est déjà compressé\n"
#, c-format
msgid "WARNING: '%s' is an empty file\n"
msgstr "Attention : « %s » est un fichier vide\n"
#, c-format
msgid "'%s' already compressed\n"
msgstr "« %s » est déjà compressé\n"
#, fuzzy, c-format
#| msgid "you may not use digest algorithm '%s' while in %s mode\n"
msgid "digest algorithm '%s' may not be used in %s mode\n"
@ -9514,6 +9514,9 @@ msgstr "ajouter un certificat au cache"
msgid "store a private key to a data object"
msgstr ""
msgid "run various checks on the keys"
msgstr ""
msgid "Yubikey management commands"
msgstr ""
@ -10997,8 +11000,8 @@ msgstr ""
#~ "\n"
#~ "Note that the examples given above for levels 2 and 3 are *only* "
#~ "examples.\n"
#~ "In the end, it is up to you to decide just what \"casual\" and \"extensive"
#~ "\"\n"
#~ "In the end, it is up to you to decide just what \"casual\" and "
#~ "\"extensive\"\n"
#~ "mean to you when you sign other keys.\n"
#~ "\n"
#~ "If you don't know what the right answer is, answer \"0\"."

View File

@ -779,8 +779,8 @@ msgstr ""
#, fuzzy, c-format
msgid ""
"Do you really want to delete the key identified by keygrip%%0A %s%%0A %%C"
"%%0A?"
"Do you really want to delete the key identified by keygrip%%0A %s%%0A "
"%%C%%0A?"
msgstr "¿Seguro de que quere borra-las chaves seleccionadas? "
#, fuzzy
@ -1889,16 +1889,16 @@ msgstr "non se pode empregar un paquete simétrico ESK debido ao modo S2K\n"
msgid "using cipher %s.%s\n"
msgstr "fallou a sinatura: %s\n"
#, fuzzy, c-format
#| msgid "`%s' already compressed\n"
msgid "'%s' already compressed\n"
msgstr "`%s' xa está comprimido\n"
#, fuzzy, c-format
#| msgid "WARNING: `%s' is an empty file\n"
msgid "WARNING: '%s' is an empty file\n"
msgstr "AVISO: `%s' é un ficheiro baleiro\n"
#, fuzzy, c-format
#| msgid "`%s' already compressed\n"
msgid "'%s' already compressed\n"
msgstr "`%s' xa está comprimido\n"
#, fuzzy, c-format
msgid "digest algorithm '%s' may not be used in %s mode\n"
msgstr "non se pode empregar o algoritmo de resumo \"%s\" no modo %s\n"
@ -3173,8 +3173,8 @@ msgstr "chave %08lX: non hai ID de usuario para a sinatura\n"
#, fuzzy, c-format
msgid "key %s: unsupported public key algorithm on user ID \"%s\"\n"
msgstr ""
"chave %08lX: algoritmo de chave pública non soportado no ID de usuario \"%s"
"\"\n"
"chave %08lX: algoritmo de chave pública non soportado no ID de usuario "
"\"%s\"\n"
#, fuzzy, c-format
msgid "key %s: invalid self-signature on user ID \"%s\"\n"
@ -9315,6 +9315,9 @@ msgstr "Creouse o certificado de revocación.\n"
msgid "store a private key to a data object"
msgstr ""
msgid "run various checks on the keys"
msgstr ""
msgid "Yubikey management commands"
msgstr ""
@ -10302,8 +10305,8 @@ msgstr ""
#~ msgid "the trustdb is corrupted; please run \"gpg --fix-trustdb\".\n"
#~ msgstr ""
#~ "a base de datos de confianza está corrompida; execute \"gpg --fix-trustdb"
#~ "\".\n"
#~ "a base de datos de confianza está corrompida; execute \"gpg --fix-"
#~ "trustdb\".\n"
#~ msgid "Please report bugs to <gnupg-bugs@gnu.org>.\n"
#~ msgstr ""
@ -10483,8 +10486,8 @@ msgstr ""
#~ "\n"
#~ "Note that the examples given above for levels 2 and 3 are *only* "
#~ "examples.\n"
#~ "In the end, it is up to you to decide just what \"casual\" and \"extensive"
#~ "\"\n"
#~ "In the end, it is up to you to decide just what \"casual\" and "
#~ "\"extensive\"\n"
#~ "mean to you when you sign other keys.\n"
#~ "\n"
#~ "If you don't know what the right answer is, answer \"0\"."

View File

@ -774,8 +774,8 @@ msgstr ""
#, fuzzy, c-format
msgid ""
"Do you really want to delete the key identified by keygrip%%0A %s%%0A %%C"
"%%0A?"
"Do you really want to delete the key identified by keygrip%%0A %s%%0A "
"%%C%%0A?"
msgstr "Valóban törli a kiválasztott kulcsokat? "
#, fuzzy
@ -1880,16 +1880,16 @@ msgstr "Nem tudok szimmetrikus ESK csomagot használni a S2K mód miatt!\n"
msgid "using cipher %s.%s\n"
msgstr "%s rejtjelezést használok.\n"
#, fuzzy, c-format
#| msgid "`%s' already compressed\n"
msgid "'%s' already compressed\n"
msgstr "\"%s\" már tömörített.\n"
#, fuzzy, c-format
#| msgid "WARNING: `%s' is an empty file\n"
msgid "WARNING: '%s' is an empty file\n"
msgstr "FIGYELEM: A(z) \"%s\" állomány üres.\n"
#, fuzzy, c-format
#| msgid "`%s' already compressed\n"
msgid "'%s' already compressed\n"
msgstr "\"%s\" már tömörített.\n"
#, fuzzy, c-format
msgid "digest algorithm '%s' may not be used in %s mode\n"
msgstr ""
@ -9262,6 +9262,9 @@ msgstr "Visszavonó igazolás létrehozva.\n"
msgid "store a private key to a data object"
msgstr ""
msgid "run various checks on the keys"
msgstr ""
msgid "Yubikey management commands"
msgstr ""
@ -10418,8 +10421,8 @@ msgstr ""
#~ "\n"
#~ "Note that the examples given above for levels 2 and 3 are *only* "
#~ "examples.\n"
#~ "In the end, it is up to you to decide just what \"casual\" and \"extensive"
#~ "\"\n"
#~ "In the end, it is up to you to decide just what \"casual\" and "
#~ "\"extensive\"\n"
#~ "mean to you when you sign other keys.\n"
#~ "\n"
#~ "If you don't know what the right answer is, answer \"0\"."

View File

@ -779,8 +779,8 @@ msgstr ""
#, fuzzy, c-format
msgid ""
"Do you really want to delete the key identified by keygrip%%0A %s%%0A %%C"
"%%0A?"
"Do you really want to delete the key identified by keygrip%%0A %s%%0A "
"%%C%%0A?"
msgstr "Anda ingin menghapus kunci terpilih ini? "
#, fuzzy
@ -1886,16 +1886,16 @@ msgstr "tidak dapat menggunakan paket simetri ESK karena mode S2K\n"
msgid "using cipher %s.%s\n"
msgstr "menggunakan cipher %s\n"
#, fuzzy, c-format
#| msgid "`%s' already compressed\n"
msgid "'%s' already compressed\n"
msgstr "`%s' sudah dikompresi\n"
#, fuzzy, c-format
#| msgid "WARNING: `%s' is an empty file\n"
msgid "WARNING: '%s' is an empty file\n"
msgstr "PERINGATAN: `%s' adalah file kosong\n"
#, fuzzy, c-format
#| msgid "`%s' already compressed\n"
msgid "'%s' already compressed\n"
msgstr "`%s' sudah dikompresi\n"
#, fuzzy, c-format
msgid "digest algorithm '%s' may not be used in %s mode\n"
msgstr ""
@ -9261,6 +9261,9 @@ msgstr "Sertifikat pembatalan tercipta.\n"
msgid "store a private key to a data object"
msgstr ""
msgid "run various checks on the keys"
msgstr ""
msgid "Yubikey management commands"
msgstr ""
@ -10418,8 +10421,8 @@ msgstr ""
#~ "\n"
#~ "Note that the examples given above for levels 2 and 3 are *only* "
#~ "examples.\n"
#~ "In the end, it is up to you to decide just what \"casual\" and \"extensive"
#~ "\"\n"
#~ "In the end, it is up to you to decide just what \"casual\" and "
#~ "\"extensive\"\n"
#~ "mean to you when you sign other keys.\n"
#~ "\n"
#~ "If you don't know what the right answer is, answer \"0\"."

View File

@ -225,8 +225,8 @@ msgid ""
"Please enter a passphrase to protect the received secret key%%0A %s%%0A "
"%s%%0Awithin gpg-agent's key storage"
msgstr ""
"Immettere una passphrase per proteggere la chiave segreta ricevuta%%0A %s"
"%%0A %s%%0A all'interno dell'archivio chiavi dell'agente gpg"
"Immettere una passphrase per proteggere la chiave segreta ricevuta%%0A "
"%s%%0A %s%%0A all'interno dell'archivio chiavi dell'agente gpg"
#, c-format
msgid "failed to create stream from socket: %s\n"
@ -771,8 +771,8 @@ msgstr ""
#, c-format
msgid ""
"Do you really want to delete the key identified by keygrip%%0A %s%%0A %%C"
"%%0A?"
"Do you really want to delete the key identified by keygrip%%0A %s%%0A "
"%%C%%0A?"
msgstr ""
"Si desidera eliminare la chiave identificata da keygrip%%0A %s%%0A %%C%%0A?"
@ -1828,14 +1828,14 @@ msgstr ""
msgid "using cipher %s.%s\n"
msgstr "utilizzando il cifrario %s.%s\n"
#, c-format
msgid "'%s' already compressed\n"
msgstr "'%s' già compresso\n"
#, c-format
msgid "WARNING: '%s' is an empty file\n"
msgstr "AVVISO: '%s' è un file vuoto\n"
#, c-format
msgid "'%s' already compressed\n"
msgstr "'%s' già compresso\n"
#, c-format
msgid "digest algorithm '%s' may not be used in %s mode\n"
msgstr "l'algoritmo digest '%s' non può essere utilizzato in modalità %s\n"
@ -9069,6 +9069,9 @@ msgstr "archiviare un certificato in un oggetto dati"
msgid "store a private key to a data object"
msgstr "archiviare una chiave privata in un oggetto dati"
msgid "run various checks on the keys"
msgstr ""
msgid "Yubikey management commands"
msgstr "Comandi di gestione Yubikey"

View File

@ -5,13 +5,13 @@
# Yoshihiro Kajiki <kajiki@ylug.org>, 1999.
# Takashi P.KATOH, 2002.
# NIIBE Yutaka <gniibe@fsij.org>, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
# 2020, 2021, 2022, 2023.
# 2020, 2021, 2022, 2023, 2024.
#
msgid ""
msgstr ""
"Project-Id-Version: gnupg 2.4.3\n"
"Report-Msgid-Bugs-To: translations@gnupg.org\n"
"PO-Revision-Date: 2023-11-20 10:50+0900\n"
"PO-Revision-Date: 2024-01-25 09:06+0900\n"
"Last-Translator: NIIBE Yutaka <gniibe@fsij.org>\n"
"Language-Team: none\n"
"Language: ja\n"
@ -8729,6 +8729,9 @@ msgstr "証明書をデータオブジェクトに保管します"
msgid "store a private key to a data object"
msgstr "プライベート鍵をデータオブジェクトに保管する"
msgid "run various checks on the keys"
msgstr "鍵に対して様々なチェックを実行する"
msgid "Yubikey management commands"
msgstr "Yubikey管理コマンド"

View File

@ -237,8 +237,8 @@ msgid ""
"Please enter a passphrase to protect the received secret key%%0A %s%%0A "
"%s%%0Awithin gpg-agent's key storage"
msgstr ""
"Skriv inn passordfrase som skal brukes til å beskytte mottatt hemmelig nøkkel"
"%%0A %s%%0A %s%%0Ai nøkkellageret for gpg-agent"
"Skriv inn passordfrase som skal brukes til å beskytte mottatt hemmelig "
"nøkkel%%0A %s%%0A %s%%0Ai nøkkellageret for gpg-agent"
#, c-format
msgid "failed to create stream from socket: %s\n"
@ -782,8 +782,8 @@ msgstr ""
#, c-format
msgid ""
"Do you really want to delete the key identified by keygrip%%0A %s%%0A %%C"
"%%0A?"
"Do you really want to delete the key identified by keygrip%%0A %s%%0A "
"%%C%%0A?"
msgstr ""
"Er du sikker på at du vil slette nøkkel med nøkkelgrep%%0A %s%%0A %%C%%0A?"
@ -1858,14 +1858,14 @@ msgstr "klarte ikke å bruke symmetrisk ESK-pakke på grunn av S2K-modus\n"
msgid "using cipher %s.%s\n"
msgstr "bruker krypteringsmetode %s\n"
#, c-format
msgid "'%s' already compressed\n"
msgstr "«%s» er allerede komprimert\n"
#, c-format
msgid "WARNING: '%s' is an empty file\n"
msgstr "ADVARSEL: «%s» er en tom fil\n"
#, c-format
msgid "'%s' already compressed\n"
msgstr "«%s» er allerede komprimert\n"
#, c-format
msgid "digest algorithm '%s' may not be used in %s mode\n"
msgstr "du kan ikke bruke algoritme «%s» i %s-modus\n"
@ -9046,6 +9046,9 @@ msgstr "legg til sertifikat i hurtiglager"
msgid "store a private key to a data object"
msgstr ""
msgid "run various checks on the keys"
msgstr ""
msgid "Yubikey management commands"
msgstr ""

449
po/pl.po

File diff suppressed because it is too large Load Diff

View File

@ -881,8 +881,28 @@ msgid "waiting for process %d to terminate failed: %s\n"
msgstr "falha ao aguardar pelo encerramento do processo %d: %s\n"
#, c-format
msgid "waiting for process to terminate failed: ec=%d\n"
msgstr "falha ao esperar que o processo terminasse: ec=%d\n"
msgid "error running '%s': probably not installed\n"
msgstr ""
#, fuzzy, c-format
#| msgid "error accessing '%s': http status %u\n"
msgid "error running '%s': exit status %d\n"
msgstr "erro ao aceder '%s': status http %u\n"
#, fuzzy, c-format
#| msgid "error opening '%s': %s\n"
msgid "error running '%s': terminated\n"
msgstr "erro ao abrir '%s': %s\n"
#, fuzzy, c-format
#| msgid "waiting for process %d to terminate failed: %s\n"
msgid "waiting for processes to terminate failed: %s\n"
msgstr "falha ao aguardar pelo encerramento do processo %d: %s\n"
#, fuzzy, c-format
#| msgid "error getting list of cards: %s\n"
msgid "error getting exit code of process %d: %s\n"
msgstr "erro ao obter a lista de cartões: %s\n"
#, c-format
msgid "can't connect to '%s': %s\n"
@ -8968,8 +8988,15 @@ msgstr "armazenar um certificado em um objeto de dados"
msgid "store a private key to a data object"
msgstr "armazenar uma chave privada em um objeto de dados"
msgid "run various checks on the keys"
msgstr ""
msgid "Yubikey management commands"
msgstr "comandos de gerir uma Yubikey"
msgid "manage the command history"
msgstr "gerir o histórico de comandos"
#, c-format
#~ msgid "waiting for process to terminate failed: ec=%d\n"
#~ msgstr "falha ao esperar que o processo terminasse: ec=%d\n"

View File

@ -792,8 +792,8 @@ msgstr ""
#, fuzzy, c-format
#| msgid "Do you really want to delete the selected keys? (y/N) "
msgid ""
"Do you really want to delete the key identified by keygrip%%0A %s%%0A %%C"
"%%0A?"
"Do you really want to delete the key identified by keygrip%%0A %s%%0A "
"%%C%%0A?"
msgstr "Doriţi într-adevăr să ştergeţi cheile selectate? (d/N) "
#, fuzzy
@ -1908,16 +1908,16 @@ msgstr "nu pot crea un pachet ESK simetric datorită modului S2K\n"
msgid "using cipher %s.%s\n"
msgstr "folosesc cifrul %s\n"
#, fuzzy, c-format
#| msgid "`%s' already compressed\n"
msgid "'%s' already compressed\n"
msgstr "`%s' deja compresat\n"
#, fuzzy, c-format
#| msgid "WARNING: `%s' is an empty file\n"
msgid "WARNING: '%s' is an empty file\n"
msgstr "AVERTISMENT: `%s' este un fişier gol\n"
#, fuzzy, c-format
#| msgid "`%s' already compressed\n"
msgid "'%s' already compressed\n"
msgstr "`%s' deja compresat\n"
#, fuzzy, c-format
#| msgid "you may not use digest algorithm `%s' while in %s mode\n"
msgid "digest algorithm '%s' may not be used in %s mode\n"
@ -2449,8 +2449,8 @@ msgstr ""
#, fuzzy, c-format
#| msgid ""
#| "WARNING: unsafe enclosing directory permissions on configuration file `"
#| "%s'\n"
#| "WARNING: unsafe enclosing directory permissions on configuration file "
#| "`%s'\n"
msgid ""
"WARNING: unsafe enclosing directory permissions on configuration file '%s'\n"
msgstr ""
@ -3236,8 +3236,8 @@ msgstr "cheia %s: nici un ID utilizator pentru semnătură\n"
#, c-format
msgid "key %s: unsupported public key algorithm on user ID \"%s\"\n"
msgstr ""
"cheia %s: algoritm cu cheie publică nesuportat pentru ID-ul utilizator \"%s"
"\"\n"
"cheia %s: algoritm cu cheie publică nesuportat pentru ID-ul utilizator "
"\"%s\"\n"
#, c-format
msgid "key %s: invalid self-signature on user ID \"%s\"\n"
@ -9406,6 +9406,9 @@ msgstr "Certificat de revocare creat.\n"
msgid "store a private key to a data object"
msgstr ""
msgid "run various checks on the keys"
msgstr ""
msgid "Yubikey management commands"
msgstr ""
@ -10620,8 +10623,8 @@ msgstr ""
#~ "\n"
#~ "Note that the examples given above for levels 2 and 3 are *only* "
#~ "examples.\n"
#~ "In the end, it is up to you to decide just what \"casual\" and \"extensive"
#~ "\"\n"
#~ "In the end, it is up to you to decide just what \"casual\" and "
#~ "\"extensive\"\n"
#~ "mean to you when you sign other keys.\n"
#~ "\n"
#~ "If you don't know what the right answer is, answer \"0\"."
@ -11539,8 +11542,8 @@ msgstr ""
#~ "crea\n"
#~ "o cheie sigură pentru semnături: acest program face acest lucru, dar "
#~ "alte\n"
#~ "implementări OpenPGP ar putea să nu înţeleagă varianta de semnare"
#~ "+cifrare.\n"
#~ "implementări OpenPGP ar putea să nu înţeleagă varianta de "
#~ "semnare+cifrare.\n"
#~ "\n"
#~ "Prima cheie (primară) trebuie să fie întotdeauna capabilă de semnare;\n"
#~ "acesta este motivul pentru care cheia ElGamal nu este disponibilă în\n"

View File

@ -18,8 +18,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11) ? 0 : ((n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20)) ? 1 : 2);\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11) ? 0 : ((n%10>=2 && "
"n%10<=4 && (n%100<10 || n%100>=20)) ? 1 : 2);\n"
#, c-format
msgid "failed to acquire the pinentry lock: %s\n"
@ -328,8 +328,8 @@ msgstr[2] ""
#, c-format
msgid "A passphrase may not be a known term or match%%0Acertain pattern."
msgstr ""
"Фраза-пароль не должна быть известным выражением и не должна быть составлена"
"%%0Aпо определенному образцу."
"Фраза-пароль не должна быть известным выражением и не должна быть "
"составлена%%0Aпо определенному образцу."
msgid "Warning: You have entered an insecure passphrase."
msgstr "Внимание: Вы ввели небезопасную фразу-пароль."
@ -786,8 +786,8 @@ msgstr ""
#, c-format
msgid ""
"Do you really want to delete the key identified by keygrip%%0A %s%%0A %%C"
"%%0A?"
"Do you really want to delete the key identified by keygrip%%0A %s%%0A "
"%%C%%0A?"
msgstr "Вы действительно хотите удалить ключ с кодом%%0A %s%%0A %%C%%0A?"
msgid "Delete key"
@ -1843,14 +1843,14 @@ msgstr "не могу использовать симметричный паке
msgid "using cipher %s.%s\n"
msgstr "используется симметричный шифр %s\n"
#, c-format
msgid "'%s' already compressed\n"
msgstr "'%s' уже сжат\n"
#, c-format
msgid "WARNING: '%s' is an empty file\n"
msgstr "Внимание: файл '%s' пуст\n"
#, c-format
msgid "'%s' already compressed\n"
msgstr "'%s' уже сжат\n"
#, c-format
msgid "digest algorithm '%s' may not be used in %s mode\n"
msgstr "хеш-функцию '%s' нельзя использовать в режиме %s\n"
@ -9147,6 +9147,9 @@ msgstr "добавить сертификат в буфер"
msgid "store a private key to a data object"
msgstr ""
msgid "run various checks on the keys"
msgstr ""
msgid "Yubikey management commands"
msgstr ""
@ -9617,8 +9620,8 @@ msgstr ""
#~ msgid "error setting policy for key %s, user id \"%s\": %s"
#~ msgstr ""
#~ "ошибка установки правил для ключа %s с идентификатором пользователя \"%s"
#~ "\": %s"
#~ "ошибка установки правил для ключа %s с идентификатором пользователя "
#~ "\"%s\": %s"
#~ msgid "only SHA-1 is supported for OCSP responses\n"
#~ msgstr "для ответов OCSP поддерживается только SHA-1\n"

View File

@ -779,8 +779,8 @@ msgstr ""
#, fuzzy, c-format
msgid ""
"Do you really want to delete the key identified by keygrip%%0A %s%%0A %%C"
"%%0A?"
"Do you really want to delete the key identified by keygrip%%0A %s%%0A "
"%%C%%0A?"
msgstr "Skutočne chcete zmazať vybrané kľúče? "
#, fuzzy
@ -1886,16 +1886,16 @@ msgstr "v móde S2K nemožno použiť symetrický ESK paket\n"
msgid "using cipher %s.%s\n"
msgstr "použitá šifra %s\n"
#, fuzzy, c-format
#| msgid "`%s' already compressed\n"
msgid "'%s' already compressed\n"
msgstr "`%s' je už skomprimovaný\n"
#, fuzzy, c-format
#| msgid "WARNING: `%s' is an empty file\n"
msgid "WARNING: '%s' is an empty file\n"
msgstr "VAROVANIE: súbor `%s' je prázdny\n"
#, fuzzy, c-format
#| msgid "`%s' already compressed\n"
msgid "'%s' already compressed\n"
msgstr "`%s' je už skomprimovaný\n"
#, fuzzy, c-format
msgid "digest algorithm '%s' may not be used in %s mode\n"
msgstr "nemôžete použiť hashovací algoritmus \"%s\" v móde %s\n"
@ -3180,8 +3180,8 @@ msgstr "kľúč %08lX: neexistuje id užívateľa pre podpis\n"
#, fuzzy, c-format
msgid "key %s: unsupported public key algorithm on user ID \"%s\"\n"
msgstr ""
"kľúč %08lX: nepodporovaný algoritmus verejného kľúča u užívateľského id \"%s"
"\"\n"
"kľúč %08lX: nepodporovaný algoritmus verejného kľúča u užívateľského id "
"\"%s\"\n"
#, fuzzy, c-format
msgid "key %s: invalid self-signature on user ID \"%s\"\n"
@ -9295,6 +9295,9 @@ msgstr "Revokačný certifikát bol vytvorený.\n"
msgid "store a private key to a data object"
msgstr ""
msgid "run various checks on the keys"
msgstr ""
msgid "Yubikey management commands"
msgstr ""
@ -10452,8 +10455,8 @@ msgstr ""
#~ "\n"
#~ "Note that the examples given above for levels 2 and 3 are *only* "
#~ "examples.\n"
#~ "In the end, it is up to you to decide just what \"casual\" and \"extensive"
#~ "\"\n"
#~ "In the end, it is up to you to decide just what \"casual\" and "
#~ "\"extensive\"\n"
#~ "mean to you when you sign other keys.\n"
#~ "\n"
#~ "If you don't know what the right answer is, answer \"0\"."
@ -10496,8 +10499,8 @@ msgstr ""
#, fuzzy
#~ msgid "Answer \"yes\" if you want to sign ALL the user IDs"
#~ msgstr ""
#~ "Pokiaľ chcete podpísať VŠETKY identifikátory užívateľov, odpovedzte \"ano"
#~ "\""
#~ "Pokiaľ chcete podpísať VŠETKY identifikátory užívateľov, odpovedzte "
#~ "\"ano\""
#~ msgid ""
#~ "Answer \"yes\" if you really want to delete this user ID.\n"

View File

@ -881,8 +881,8 @@ msgstr ""
#, fuzzy, c-format
#| msgid "Do you really want to delete the selected keys? (y/N) "
msgid ""
"Do you really want to delete the key identified by keygrip%%0A %s%%0A %%C"
"%%0A?"
"Do you really want to delete the key identified by keygrip%%0A %s%%0A "
"%%C%%0A?"
msgstr "Vill du verkligen ta bort de valda nycklarna? (j/N) "
#, fuzzy
@ -2026,16 +2026,16 @@ msgstr "kan inte använda symmetriska ESK-paket pga S2K-läge\n"
msgid "using cipher %s.%s\n"
msgstr "använder %s-chiffer\n"
#, fuzzy, c-format
#| msgid "`%s' already compressed\n"
msgid "'%s' already compressed\n"
msgstr "\"%s\" är redan komprimerad\n"
#, fuzzy, c-format
#| msgid "WARNING: `%s' is an empty file\n"
msgid "WARNING: '%s' is an empty file\n"
msgstr "VARNING: \"%s\" är en tom fil\n"
#, fuzzy, c-format
#| msgid "`%s' already compressed\n"
msgid "'%s' already compressed\n"
msgstr "\"%s\" är redan komprimerad\n"
#, fuzzy, c-format
#| msgid "you may not use digest algorithm `%s' while in %s mode\n"
msgid "digest algorithm '%s' may not be used in %s mode\n"
@ -2570,8 +2570,8 @@ msgstr ""
#, fuzzy, c-format
#| msgid ""
#| "WARNING: unsafe enclosing directory permissions on configuration file `"
#| "%s'\n"
#| "WARNING: unsafe enclosing directory permissions on configuration file "
#| "`%s'\n"
msgid ""
"WARNING: unsafe enclosing directory permissions on configuration file '%s'\n"
msgstr ""
@ -9851,6 +9851,9 @@ msgstr " (certifikat skapat "
msgid "store a private key to a data object"
msgstr ""
msgid "run various checks on the keys"
msgstr ""
msgid "Yubikey management commands"
msgstr ""
@ -11212,8 +11215,8 @@ msgstr ""
#~ "\n"
#~ "Note that the examples given above for levels 2 and 3 are *only* "
#~ "examples.\n"
#~ "In the end, it is up to you to decide just what \"casual\" and \"extensive"
#~ "\"\n"
#~ "In the end, it is up to you to decide just what \"casual\" and "
#~ "\"extensive\"\n"
#~ "mean to you when you sign other keys.\n"
#~ "\n"
#~ "If you don't know what the right answer is, answer \"0\"."

View File

@ -762,8 +762,8 @@ msgstr ""
#, c-format
msgid ""
"Do you really want to delete the key identified by keygrip%%0A %s%%0A %%C"
"%%0A?"
"Do you really want to delete the key identified by keygrip%%0A %s%%0A "
"%%C%%0A?"
msgstr ""
"%%0A %s%%0A %%C%%0A anahtar maşası tarafından tanımlanan anahtarı silmek "
"istediğnizden emin misiniz?"
@ -1799,14 +1799,14 @@ msgstr "S2K kipi nedeniyle bir SKESK paketi kullanılamıyor\n"
msgid "using cipher %s.%s\n"
msgstr "%s.%s şifrelemesi kullanılıyor\n"
#, c-format
msgid "'%s' already compressed\n"
msgstr "'%s' halihazırda sıkıştırılmış\n"
#, c-format
msgid "WARNING: '%s' is an empty file\n"
msgstr "UYARI: '%s', boş bir dosya\n"
#, c-format
msgid "'%s' already compressed\n"
msgstr "'%s' halihazırda sıkıştırılmış\n"
#, c-format
msgid "digest algorithm '%s' may not be used in %s mode\n"
msgstr "özet algoritması '%s', %s kipinde kullanılamayabilir\n"
@ -8910,6 +8910,9 @@ msgstr "bir veri nesnesine bir sertifika depola"
msgid "store a private key to a data object"
msgstr "bir veri nesnesine bir özel anahtar depola"
msgid "run various checks on the keys"
msgstr ""
msgid "Yubikey management commands"
msgstr "Yubikey yönetim konsolu"

View File

@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11) ? 0 : ((n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20)) ? 1 : 2);\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11) ? 0 : ((n%10>=2 && "
"n%10<=4 && (n%100<10 || n%100>=20)) ? 1 : 2);\n"
"X-Generator: Lokalize 20.11.70\n"
#, c-format
@ -235,8 +235,8 @@ msgid ""
"Please enter a passphrase to protect the received secret key%%0A %s%%0A "
"%s%%0Awithin gpg-agent's key storage"
msgstr ""
"Будь ласка, вкажіть пароль для захисту отриманого закритого ключа%%0A %s"
"%%0A %s%%0Aу сховищі ключів gpg-agent"
"Будь ласка, вкажіть пароль для захисту отриманого закритого ключа%%0A "
"%s%%0A %s%%0Aу сховищі ключів gpg-agent"
#, c-format
msgid "failed to create stream from socket: %s\n"
@ -787,8 +787,8 @@ msgstr ""
#, c-format
msgid ""
"Do you really want to delete the key identified by keygrip%%0A %s%%0A %%C"
"%%0A?"
"Do you really want to delete the key identified by keygrip%%0A %s%%0A "
"%%C%%0A?"
msgstr ""
"Справді хочете вилучити ключ, що визначається keygrip%%0A %s%%0A %%C%%0A?"
@ -1860,14 +1860,14 @@ msgstr "не можна використовувати симетричний п
msgid "using cipher %s.%s\n"
msgstr "використано шифр %s\n"
#, c-format
msgid "'%s' already compressed\n"
msgstr "«%s» вже стиснено\n"
#, c-format
msgid "WARNING: '%s' is an empty file\n"
msgstr "УВАГА: файл «%s» є порожнім\n"
#, c-format
msgid "'%s' already compressed\n"
msgstr "«%s» вже стиснено\n"
#, c-format
msgid "digest algorithm '%s' may not be used in %s mode\n"
msgstr ""
@ -9240,6 +9240,9 @@ msgstr "додати сертифікат до кешу"
msgid "store a private key to a data object"
msgstr ""
msgid "run various checks on the keys"
msgstr ""
msgid "Yubikey management commands"
msgstr ""

View File

@ -221,8 +221,8 @@ msgid ""
"Please enter a passphrase to protect the received secret key%%0A %s%%0A "
"%s%%0Awithin gpg-agent's key storage"
msgstr ""
"请输入一个密码,以便于在 gpg-agent 的密钥存储中保护接收到的私钥 %%0A %s"
"%%0A %s%%0A"
"请输入一个密码,以便于在 gpg-agent 的密钥存储中保护接收到的私钥 %%0A "
"%s%%0A %s%%0A"
#, c-format
msgid "failed to create stream from socket: %s\n"
@ -742,8 +742,8 @@ msgstr "请求使用密钥%%0A %s%%0A %s%%0A您想要允许这一请求吗"
#, c-format
msgid ""
"Do you really want to delete the key identified by keygrip%%0A %s%%0A %%C"
"%%0A?"
"Do you really want to delete the key identified by keygrip%%0A %s%%0A "
"%%C%%0A?"
msgstr ""
"您真的想要删除这个被以下的 keygrip 所标识的密钥吗 %%0A %s%%0A %%C%%0A"
@ -1774,14 +1774,14 @@ msgstr "由于在 S2K 模式,不能使用一个对称的 ESK 封包\n"
msgid "using cipher %s.%s\n"
msgstr "使用加密 %s.%s\n"
#, c-format
msgid "'%s' already compressed\n"
msgstr "%s已被压缩\n"
#, c-format
msgid "WARNING: '%s' is an empty file\n"
msgstr "警告:‘%s是一个空文件\n"
#, c-format
msgid "'%s' already compressed\n"
msgstr "%s已被压缩\n"
#, c-format
msgid "digest algorithm '%s' may not be used in %s mode\n"
msgstr "摘要算法‘%s不能在 %s 模式下使用\n"
@ -8666,6 +8666,9 @@ msgstr "储存一个证书到数据对象"
msgid "store a private key to a data object"
msgstr "储存私钥到数据对象"
msgid "run various checks on the keys"
msgstr ""
msgid "Yubikey management commands"
msgstr "Yubikey 管理命令"

View File

@ -783,8 +783,8 @@ msgstr ""
#, fuzzy, c-format
#| msgid "Do you really want to delete the selected keys? (y/N) "
msgid ""
"Do you really want to delete the key identified by keygrip%%0A %s%%0A %%C"
"%%0A?"
"Do you really want to delete the key identified by keygrip%%0A %s%%0A "
"%%C%%0A?"
msgstr "你真的想要刪除所選的金鑰嗎? (y/N) "
msgid "Delete key"
@ -1868,14 +1868,14 @@ msgstr "因處於 S2K 模式下而無法使用對稱式 ESK 封包\n"
msgid "using cipher %s.%s\n"
msgstr "正在使用 %s 編密法\n"
#, c-format
msgid "'%s' already compressed\n"
msgstr "'%s' 已經被壓縮了\n"
#, c-format
msgid "WARNING: '%s' is an empty file\n"
msgstr "警告: '%s' 是個空檔案\n"
#, c-format
msgid "'%s' already compressed\n"
msgstr "'%s' 已經被壓縮了\n"
#, fuzzy, c-format
#| msgid "you may not use digest algorithm '%s' while in %s mode\n"
msgid "digest algorithm '%s' may not be used in %s mode\n"
@ -9048,6 +9048,9 @@ msgstr "加入憑證至快取"
msgid "store a private key to a data object"
msgstr ""
msgid "run various checks on the keys"
msgstr ""
msgid "Yubikey management commands"
msgstr ""

View File

@ -56,8 +56,8 @@ typedef enum
CARDTYPE_GENERIC = 0,
CARDTYPE_GNUK,
CARDTYPE_YUBIKEY,
CARDTYPE_ZEITCONTROL
CARDTYPE_ZEITCONTROL,
CARDTYPE_SCE7 /* G+D SmartCafe Expert 7.0 */
} cardtype_t;
/* List of supported card applications. The source code for each

View File

@ -91,7 +91,8 @@ typedef enum
CARD_PRODUCT_DTRUST3, /* D-Trust GmbH (bundesdruckerei.de) */
CARD_PRODUCT_DTRUST4,
CARD_PRODUCT_GENUA, /* GeNUA mbH */
CARD_PRODUCT_NEXUS /* Technology Nexus */
CARD_PRODUCT_NEXUS, /* Technology Nexus */
CARD_PRODUCT_CVISION /* Cryptovision GmbH */
}
card_product_t;
@ -143,6 +144,8 @@ static struct
#define IS_CARDOS_5(a) ((a)->app_local->card_type == CARD_TYPE_CARDOS_50 \
|| (a)->app_local->card_type == CARD_TYPE_CARDOS_53 \
|| (a)->app_local->card_type == CARD_TYPE_CARDOS_54)
#define IS_STARCOS_3(a) ((a)->app_local->card_type == CARD_TYPE_STARCOS_32)
/* The default PKCS-15 home DF */
#define DEFAULT_HOME_DF 0x5015
@ -532,8 +535,6 @@ struct app_local_s
/*** Local prototypes. ***/
static gpg_error_t select_ef_by_path (app_t app, const unsigned short *path,
size_t pathlen);
static gpg_error_t select_df_by_path (app_t app, const unsigned short *path,
size_t pathlen);
static gpg_error_t keygrip_from_prkdf (app_t app, prkdf_object_t prkdf);
static gpg_error_t readcert_by_cdf (app_t app, cdf_object_t cdf,
unsigned char **r_cert, size_t *r_certlen);
@ -571,6 +572,7 @@ cardproduct2str (card_product_t cardproduct)
case CARD_PRODUCT_DTRUST4: return "D-Trust 4.1/4.4";
case CARD_PRODUCT_GENUA: return "GeNUA";
case CARD_PRODUCT_NEXUS: return "Nexus";
case CARD_PRODUCT_CVISION: return "Cryptovison";
}
return "";
}
@ -803,7 +805,7 @@ select_by_path (app_t app, const unsigned short *path, size_t pathlen,
log_debug ("%s: path=", __func__);
for (j=0; j < pathlen; j++)
log_printf ("%s%04hX", j? "/":"", path[j]);
log_printf ("%s\n",expect_df?" (DF requested)":"");
log_printf ("%s", expect_df?" (DF requested)":"");
log_printf ("%s\n",app->app_local->direct_path_selection?" (direct)":"");
}
@ -867,11 +869,13 @@ select_ef_by_path (app_t app, const unsigned short *path, size_t pathlen)
}
#if 0 /* Currently not used. */
static gpg_error_t
select_df_by_path (app_t app, const unsigned short *path, size_t pathlen)
{
return select_by_path (app, path, pathlen, 1);
}
#endif
/* Parse a cert Id string (or a key Id string) and return the binary
@ -3611,6 +3615,7 @@ read_p15_info (app_t app)
gpg_error_t err;
prkdf_object_t prkdf;
unsigned int flag;
const char *manu;
err = read_ef_tokeninfo (app);
if (err)
@ -3631,18 +3636,22 @@ read_p15_info (app_t app)
release_lists (app);
/* Set a product type from the manufacturer_id. */
if (IS_CARDOS_5 (app) && app->app_local->manufacturer_id)
{
const char *manu = app->app_local->manufacturer_id;
if (app->app_local->card_product)
if (!(manu = app->app_local->manufacturer_id) || !*manu)
; /* No manufacturer_id. */
else if (app->app_local->card_product)
; /* Already set. */
else if (!ascii_strcasecmp (manu, "GeNUA mbH"))
else if (IS_CARDOS_5 (app))
{
if (!ascii_strcasecmp (manu, "GeNUA mbH"))
app->app_local->card_product = CARD_PRODUCT_GENUA;
else if (!ascii_strcasecmp (manu, "Technology Nexus"))
app->app_local->card_product = CARD_PRODUCT_NEXUS;
}
else if (app->app_local->card_type == CARD_TYPE_STARCOS_32)
{
if (strstr (manu, "cryptovision"))
app->app_local->card_product = CARD_PRODUCT_CVISION;
}
/* Read the ODF so that we know the location of all directory
files. */
@ -5053,11 +5062,18 @@ prepare_verify_pin (app_t app, const char *keyref,
log_error ("p15: error selecting D-TRUST's AID for key %s: %s\n",
keyref, gpg_strerror (err));
}
else if (prkdf && app->app_local->card_type == CARD_TYPE_STARCOS_32)
else if (app->app_local->card_product == CARD_PRODUCT_CVISION)
{
err = select_df_by_path (app, prkdf->path, prkdf->pathlen);
/* According to our protocol analysis we need to select the
* PKCS#15 AID here. The traces actually show that this is done
* two times but that looks more like a bug. Before that the
* master file needs to be selected. */
err = iso7816_select_mf (app_get_slot (app));
if (!err)
err = iso7816_select_application (app_get_slot (app),
pkcs15_aid, sizeof pkcs15_aid, 0);
if (err)
log_error ("p15: error selecting file for key %s: %s\n",
log_error ("p15: error selecting PKCS#15 AID for key %s: %s\n",
keyref, gpg_strerror (err));
}
else if (prkdf)
@ -5497,6 +5513,7 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
unsigned char oidbuf[64];
size_t oidbuflen;
size_t n;
int i;
unsigned char *indata_buffer = NULL; /* Malloced helper. */
(void)ctrl;
@ -5594,7 +5611,6 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
{
unsigned int framelen;
unsigned char *frame;
int i;
framelen = (prkdf->keynbits+7) / 8;
if (!framelen)
@ -5669,6 +5685,23 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
memcpy (frame, indata, indatalen);
framelen = indatalen;
}
else if (hashalgo && IS_STARCOS_3 (app)
&& app->app_local->card_product != CARD_PRODUCT_CVISION)
{
/* For Starcos we need the plain hash w/o the prefix. */
/* Note: This has never been tested because the cvision
* sample cards seem not to work this way. */
if (indatalen != oidbuflen + digestlen
|| memcmp (indata, oidbuf, oidbuflen))
{
log_error ("p15: non-matching input data for Starcos:"
" hash=%d len=%zu\n", hashalgo, indatalen);
err = gpg_error (GPG_ERR_INV_VALUE);
goto leave;
}
framelen = indatalen - oidbuflen;
memcpy (frame, (const char*)indata + oidbuflen, framelen);
}
else
{
n = 0;
@ -5758,7 +5791,7 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
else
{
/* The D-TRUST Card 4.x doesn't support setting a security
* environment, at least as specified in the specs. Insted a
* environment, at least as specified in the specs. Instead a
* predefined security environment has to be loaded depending on the
* cipher and message digest used. The spec states SE-ID 0x25 for
* SHA256, 0x26 for SHA384 and 0x27 for SHA512, when using PKCS#1
@ -5772,6 +5805,61 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
0xf3, 0x25, NULL, 0);
}
}
else if (app->app_local->card_product == CARD_PRODUCT_CVISION)
{
/* I can't make the Starcos 3.2 work the correct way, so let's
* make them work in the same way the cryptovision product seems
* to do it: Use the plain RSA decryption instead. */
unsigned char mse[9];
i = 0;
mse[i++] = 0x84; /* Key reference. */
mse[i++] = 1;
mse[i++] = prkdf->key_reference;
mse[i++] = 0x89; /* Algorithm reference (BCD encoded). */
mse[i++] = 2;
mse[i++] = 0x11; /* RSA no padding (1 1 3 0). */
mse[i++] = 0x30;
log_assert (i <= DIM(mse));
err = iso7816_manage_security_env (app_get_slot (app), 0x41, 0xB8,
mse, i);
}
else if (prkdf->key_reference_valid && IS_STARCOS_3 (app))
{
unsigned char mse[9];
i = 0;
if (prkdf->is_ecc)
{
log_info ("Note: ECC is not yet implemented for Starcos 3 cards\n");
err = gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
}
else
{
err = 0;
mse[i++] = 0x84; /* Key reference. */
mse[i++] = 1;
mse[i++] = prkdf->key_reference;
mse[i++] = 0x89; /* Algorithm reference (BCD encoded). */
mse[i++] = 3;
mse[i++] = 0x13; /* RSA PKCS#1 (standard) (1 3 2 3). */
mse[i++] = 0x23;
switch (hashalgo)
{
case GCRY_MD_SHA1: mse[i++] = 0x10; break;
case GCRY_MD_RMD160: mse[i++] = 0x20; break;
case GCRY_MD_SHA256: mse[i++] = 0x30; break;
case GCRY_MD_SHA384: mse[i++] = 0x40; break;
case GCRY_MD_SHA512: mse[i++] = 0x50; break;
case GCRY_MD_SHA224: mse[i++] = 0x60; break;
default: err = gpg_error (GPG_ERR_DIGEST_ALGO); break;
}
log_assert (i <= DIM(mse));
if (!err)
err = iso7816_manage_security_env (app_get_slot (app), 0x41, 0xB6,
mse, i);
}
}
else if (prkdf->key_reference_valid)
{
unsigned char mse[3];
@ -5801,6 +5889,11 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
le_value = 0;
}
if (app->app_local->card_product == CARD_PRODUCT_CVISION)
err = iso7816_decipher (app_get_slot (app),
exmode, indata, indatalen,
le_value, 0, outdata, outdatalen);
else
err = iso7816_compute_ds (app_get_slot (app),
exmode, indata, indatalen,
le_value, outdata, outdatalen);
@ -5862,6 +5955,7 @@ do_decipher (app_t app, ctrl_t ctrl, const char *keyidstr,
prkdf_object_t prkdf; /* The private key object. */
aodf_object_t aodf; /* The associated authentication object. */
int exmode, le_value, padind;
int i;
(void)ctrl;
(void)r_info;
@ -5960,10 +6054,33 @@ do_decipher (app_t app, ctrl_t ctrl, const char *keyidstr,
0xF3, 0x31, NULL, 0);
}
}
else if (prkdf->key_reference_valid && IS_STARCOS_3 (app))
{
unsigned char mse[9];
i = 0;
if (prkdf->is_ecc)
{
log_info ("Note: ECC is not yet implemented for Starcos 3 cards\n");
err = gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
}
else
{
mse[i++] = 0x84; /* Key reference. */
mse[i++] = 1;
mse[i++] = prkdf->key_reference;
mse[i++] = 0x89; /* Algorithm reference (BCD encoded). */
mse[i++] = 2;
mse[i++] = 0x11; /* RSA no padding (1 1 3 0). */
mse[i++] = 0x30;
log_assert (i <= DIM(mse));
err = iso7816_manage_security_env (app_get_slot (app), 0x41, 0xB8,
mse, i);
}
}
else if (prkdf->key_reference_valid)
{
unsigned char mse[9];
int i;
/* Note: This works with CardOS but the D-Trust card has the
* problem that the next created signature would be broken. */

View File

@ -1,5 +1,5 @@
/* app-piv.c - The OpenPGP card application.
* Copyright (C) 2019, 2020 g10 Code GmbH
* Copyright (C) 2019, 2020, 2024 g10 Code GmbH
*
* This file is part of GnuPG.
*
@ -3642,6 +3642,7 @@ app_select_piv (app_t app)
size_t aptlen;
const unsigned char *s;
size_t n;
void *relptr1 = NULL;
/* Note that we select using the AID without the 2 octet version
* number. This allows for better reporting of future specs. We
@ -3667,7 +3668,21 @@ app_select_piv (app_t app)
s = find_tlv (apt, aptlen, 0x4F, &n);
/* Some cards (new Yubikey) return only the PIX, while others
* (old Yubikey, PivApplet) return the RID+PIX. */
* (old Yubikey, PivApplet) return the RID+PIX.
* Sample APTs:
* Yubikey 5.4.3: 6111 4f06 000010000100 7907 4f05 a000000308
* SCE7.0-G-F-P : 610f 4f06 001000010000 7905 a000000308
*/
if (app->card->cardtype == CARDTYPE_SCE7
&& s && apt && aptlen == 17
&& !memcmp (apt, ("\x61\x0f\x4f\x06\x00\x10\x00\x01"
"\x00\x00\x79\x05\xa0\x00\x00\x03\x08"), aptlen))
{
if (opt.verbose)
log_info ("piv: assuming G&D SCE7.0-G-F-P\n");
app->appversion = 0x0100; /* Let's assume this. */
goto apt_checked;
}
if (!s || !((n == 6 && !memcmp (s, piv_aid+5, 4))
|| (n == 11 && !memcmp (s, piv_aid, 9))))
{
@ -3702,6 +3717,7 @@ app_select_piv (app_t app)
goto leave;
}
apt_checked:
app->app_local = xtrycalloc (1, sizeof *app->app_local);
if (!app->app_local)
{
@ -3712,6 +3728,41 @@ app_select_piv (app_t app)
if (app->card->cardtype == CARDTYPE_YUBIKEY)
app->app_local->flags.yubikey = 1;
/* If we don't have a s/n construct it from the CHUID. */
if (!APP_CARD(app)->serialno)
{
unsigned char *chuid;
size_t chuidlen;
relptr1 = get_one_do (app, 0x5FC102, &chuid, &chuidlen, NULL);
if (!relptr1)
log_error ("piv: CHUID not found\n");
else
{
s = find_tlv (chuid, chuidlen, 0x34, &n);
if (!s || n != 16)
{
log_error ("piv: Card UUID %s in CHUID\n",
s? "invalid":"missing");
if (opt.debug && s)
log_printhex (s, n, "got");
}
else
{
APP_CARD(app)->serialno = xtrymalloc (n);
if (!APP_CARD(app)->serialno)
{
err = gpg_error_from_syserror ();
goto leave;
}
memcpy (APP_CARD(app)->serialno, s, n);
APP_CARD(app)->serialnolen = n;
err = app_munge_serialno (APP_CARD(app));
if (err)
goto leave;
}
}
}
/* FIXME: Parse the optional and conditional DOs in the APT. */
@ -3739,6 +3790,7 @@ app_select_piv (app_t app)
leave:
xfree (relptr1);
xfree (apt);
if (err)
do_deinit (app);

View File

@ -112,6 +112,7 @@ strcardtype (cardtype_t t)
case CARDTYPE_GNUK: return "gnuk";
case CARDTYPE_YUBIKEY: return "yubikey";
case CARDTYPE_ZEITCONTROL: return "zeitcontrol";
case CARDTYPE_SCE7: return "smartcafe";
}
return "?";
}
@ -549,6 +550,51 @@ card_reset (card_t card)
return err;
}
/* Return the card type from (ATR,ATRLEN) or CARDTYPE_GENERIC in case
* of error or if the ATR was not found. If ATR is NULL, SLOT is used
* to retrieve the ATR from the reader. */
static cardtype_t
atr_to_cardtype (int slot, const unsigned char *atr, size_t atrlen)
{
#define X(a) ((unsigned char const *)(a))
static struct
{
size_t atrlen;
unsigned char const *atr;
cardtype_t type;
} atrlist[] = {
{ 19, X("\x3b\xf9\x96\x00\x00\x80\x31\xfe"
"\x45\x53\x43\x45\x37\x20\x0f\x00\x20\x46\x4e"),
CARDTYPE_SCE7 },
{ 0 }
};
#undef X
unsigned char *atrbuf = NULL;
cardtype_t cardtype = 0;
int i;
if (atr)
{
atrbuf = apdu_get_atr (slot, &atrlen);
if (!atrbuf)
return 0;
atr = atrbuf;
}
for (i=0; atrlist[i].atrlen; i++)
if (atrlist[i].atrlen == atrlen
&& !memcmp (atrlist[i].atr, atr, atrlen))
{
cardtype = atrlist[i].type;
break;
}
xfree (atrbuf);
return cardtype;
}
static gpg_error_t
app_new_register (int slot, ctrl_t ctrl, const char *name,
int periodical_check_needed)
@ -666,13 +712,16 @@ app_new_register (int slot, ctrl_t ctrl, const char *name,
}
xfree (buf);
}
}
else
card->cardtype = atr_to_cardtype (slot, NULL, 0);
}
else /* Got 3F00 */
{
unsigned char *atr;
size_t atrlen;
/* This is heuristics to identify different implementations. */
/* FIXME: The first two checks are pretty OpenPGP card specific. */
atr = apdu_get_atr (slot, &atrlen);
if (atr)
{
@ -680,6 +729,8 @@ app_new_register (int slot, ctrl_t ctrl, const char *name,
card->cardtype = CARDTYPE_GNUK;
else if (atrlen == 21 && atr[7] == 0x75)
card->cardtype = CARDTYPE_ZEITCONTROL;
else
card->cardtype = atr_to_cardtype (slot, atr, atrlen);
xfree (atr);
}
}

View File

@ -260,7 +260,7 @@ ecdh_encrypt (DEK dek, gcry_sexp_t s_pkey, gcry_sexp_t *r_encval)
encr_algo_str = "1.3.132.1.11.2";
wrap_algo_str = "2.16.840.1.101.3.4.1.25";
hash_algo = GCRY_MD_SHA384;
cipher_algo = GCRY_CIPHER_AES256;
cipher_algo = GCRY_CIPHER_AES192;
keylen = 24;
}
else

View File

@ -681,6 +681,85 @@ store_cert_cb (void *opaque,
}
/* Helper for parse_p12. */
static gpg_error_t
p12_to_skey (gcry_mpi_t *kparms, const char *curve, gcry_sexp_t *r_skey)
{
gpg_error_t err = 0;
struct rsa_secret_key_s sk;
gcry_ctx_t ecctx = NULL;
if (curve)
{
/* log_debug ("curve: %s\n", curve); */
/* gcry_log_debugmpi ("MPI[0]", kparms[0]); */
/* We need to get the public key. */
err = gcry_mpi_ec_new (&ecctx, NULL, curve);
if (err)
{
log_error ("error creating context for curve '%s': %s\n",
curve, gpg_strerror (err));
goto leave;
}
err = gcry_mpi_ec_set_mpi ("d", kparms[0], ecctx);
if (err)
{
log_error ("error setting 'd' into context of curve '%s': %s\n",
curve, gpg_strerror (err));
goto leave;
}
kparms[1] = gcry_mpi_ec_get_mpi ("q", ecctx, 1);
if (!kparms[1])
{
log_error ("error computing 'q' from 'd' for curve '%s'\n", curve);
goto leave;
}
err = gcry_sexp_build (r_skey, NULL,
"(private-key(ecc(curve %s)(q%m)(d%m)))",
curve, kparms[1], kparms[0], NULL);
}
else /* RSA */
{
/* print_mpi (" n", kparms[0]); */
/* print_mpi (" e", kparms[1]); */
/* print_mpi (" d", kparms[2]); */
/* print_mpi (" p", kparms[3]); */
/* print_mpi (" q", kparms[4]); */
/* print_mpi ("dmp1", kparms[5]); */
/* print_mpi ("dmq1", kparms[6]); */
/* print_mpi (" u", kparms[7]); */
sk.n = kparms[0];
sk.e = kparms[1];
sk.d = kparms[2];
sk.q = kparms[3];
sk.p = kparms[4];
sk.u = kparms[7];
err = rsa_key_check (&sk);
if (err)
goto leave;
/* print_mpi (" n", sk.n); */
/* print_mpi (" e", sk.e); */
/* print_mpi (" d", sk.d); */
/* print_mpi (" p", sk.p); */
/* print_mpi (" q", sk.q); */
/* print_mpi (" u", sk.u); */
/* Create an S-expression from the parameters. */
err = gcry_sexp_build (r_skey, NULL,
"(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
sk.n, sk.e, sk.d, sk.p, sk.q, sk.u, NULL);
}
leave:
gcry_ctx_release (ecctx);
return err;
}
/* Assume that the reader is at a pkcs#12 message and try to import
certificates from that stupid format. We will transfer secret
keys to the agent. */
@ -695,7 +774,6 @@ parse_p12 (ctrl_t ctrl, ksba_reader_t reader, struct stats_s *stats)
size_t p12buflen;
size_t p12bufoff;
gcry_mpi_t *kparms = NULL;
struct rsa_secret_key_s sk;
char *passphrase = NULL;
unsigned char *key = NULL;
size_t keylen;
@ -781,82 +859,9 @@ parse_p12 (ctrl_t ctrl, ksba_reader_t reader, struct stats_s *stats)
goto leave;
}
if (curve)
{
gcry_ctx_t ecctx = NULL;
/* log_debug ("curve: %s\n", curve); */
/* gcry_log_debugmpi ("MPI[0]", kparms[0]); */
/* We need to get the public key. */
err = gcry_mpi_ec_new (&ecctx, NULL, curve);
if (err)
{
log_error ("error creating context for curve '%s': %s\n",
curve, gpg_strerror (err));
goto leave;
}
err = gcry_mpi_ec_set_mpi ("d", kparms[0], ecctx);
if (err)
{
log_error ("error setting 'd' into context of curve '%s': %s\n",
curve, gpg_strerror (err));
gcry_ctx_release (ecctx);
goto leave;
}
kparms[1] = gcry_mpi_ec_get_mpi ("q", ecctx, 1);
if (!kparms[1])
{
log_error ("error computing 'q' from 'd' for curve '%s'\n", curve);
gcry_ctx_release (ecctx);
goto leave;
}
gcry_ctx_release (ecctx);
err = gcry_sexp_build (&s_key, NULL,
"(private-key(ecc(curve %s)(q%m)(d%m)))",
curve, kparms[1], kparms[0], NULL);
}
else /* RSA */
{
/* print_mpi (" n", kparms[0]); */
/* print_mpi (" e", kparms[1]); */
/* print_mpi (" d", kparms[2]); */
/* print_mpi (" p", kparms[3]); */
/* print_mpi (" q", kparms[4]); */
/* print_mpi ("dmp1", kparms[5]); */
/* print_mpi ("dmq1", kparms[6]); */
/* print_mpi (" u", kparms[7]); */
sk.n = kparms[0];
sk.e = kparms[1];
sk.d = kparms[2];
sk.q = kparms[3];
sk.p = kparms[4];
sk.u = kparms[7];
err = rsa_key_check (&sk);
if (err)
goto leave;
/* print_mpi (" n", sk.n); */
/* print_mpi (" e", sk.e); */
/* print_mpi (" d", sk.d); */
/* print_mpi (" p", sk.p); */
/* print_mpi (" q", sk.q); */
/* print_mpi (" u", sk.u); */
/* Create an S-expression from the parameters. */
err = gcry_sexp_build (&s_key, NULL,
"(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
sk.n, sk.e, sk.d, sk.p, sk.q, sk.u, NULL);
}
/* The next is very ugly - we really should not rely on our
* knowledge of p12_parse internals. */
for (i=0; i < 8; i++)
gcry_mpi_release (kparms[i]);
gcry_free (kparms);
err = p12_to_skey (kparms, curve, &s_key);
p12_parse_free_kparms (kparms);
kparms = NULL;
if (err)
{

View File

@ -168,6 +168,9 @@ struct p12_parse_ctx_s
/* The private key as an MPI array. */
gcry_mpi_t *privatekey;
/* A second private key as an MPI array. */
gcry_mpi_t *privatekey2;
};
@ -1248,6 +1251,7 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, tlv_parser_t tlv)
int is_pbes2 = 0;
int is_aes256 = 0;
int digest_algo = GCRY_MD_SHA1;
gcry_mpi_t *privatekey;
where = "shrouded_key_bag";
if (opt_verbose)
@ -1565,19 +1569,26 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, tlv_parser_t tlv)
if (tlv_expect_sequence (tlv))
goto bailout;
if (ctx->privatekey)
if (ctx->privatekey2)
{
err = gpg_error (GPG_ERR_DUP_VALUE);
log_error ("a private key has already been received\n");
log_error ("two private kesy have already been received\n");
goto bailout;
}
ctx->privatekey = gcry_calloc (10, sizeof *ctx->privatekey);
if (!ctx->privatekey)
privatekey = gcry_calloc (10, sizeof *privatekey);
if (!privatekey)
{
err = gpg_error_from_syserror ();
log_error ("error allocating privatekey element array\n");
goto bailout;
}
if (ctx->privatekey)
{
log_info ("a private key has already been received - reading second\n");
ctx->privatekey2 = privatekey;
}
else
ctx->privatekey = privatekey;
where = "shrouded_key_bag.reading.key-parameters";
if (ctx->curve) /* ECC case. */
@ -1600,7 +1611,7 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, tlv_parser_t tlv)
goto bailout;
if (opt_verbose > 1)
log_printhex (data, datalen, "ecc q=");
err = gcry_mpi_scan (ctx->privatekey, GCRYMPI_FMT_USG,
err = gcry_mpi_scan (privatekey, GCRYMPI_FMT_USG,
data, datalen, NULL);
if (err)
{
@ -1623,7 +1634,7 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, tlv_parser_t tlv)
}
err = tlv_expect_mpinteger (tlv, firstparam,
ctx->privatekey+keyelem_count);
privatekey+keyelem_count);
if (firstparam && gpg_err_code (err) == GPG_ERR_FALSE)
; /* Ignore the first value iff it is zero. */
else if (err)
@ -1918,6 +1929,7 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
size_t oidlen;
int intval;
unsigned int startlevel;
int i;
*r_badpass = 0;
@ -2037,6 +2049,15 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
else
gcry_free (ctx.curve);
/* We have no way yet to return the second private key. */
if (ctx.privatekey2)
{
for (i=0; ctx.privatekey2[i]; i++)
gcry_mpi_release (ctx.privatekey2[i]);
gcry_free (ctx.privatekey2);
ctx.privatekey2 = NULL;
}
return ctx.privatekey;
bailout:
@ -2050,13 +2071,18 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
gpg_strerror (err));
if (ctx.privatekey)
{
int i;
for (i=0; ctx.privatekey[i]; i++)
gcry_mpi_release (ctx.privatekey[i]);
gcry_free (ctx.privatekey);
ctx.privatekey = NULL;
}
if (ctx.privatekey2)
{
for (i=0; ctx.privatekey2[i]; i++)
gcry_mpi_release (ctx.privatekey2[i]);
gcry_free (ctx.privatekey2);
ctx.privatekey2 = NULL;
}
tlv_parser_release (tlv);
gcry_free (ctx.curve);
if (r_curve)
@ -2065,6 +2091,22 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
}
/* Free the parameters as returned by p12_parse. */
void
p12_parse_free_kparms (gcry_mpi_t *kparms)
{
int i;
if (kparms)
{
for (i=0; i < 8; i++)
gcry_mpi_release (kparms[i]);
gcry_free (kparms);
}
}
static size_t
compute_tag_length (size_t n)

View File

@ -29,6 +29,7 @@ gcry_mpi_t *p12_parse (const unsigned char *buffer, size_t length,
const char *pw,
void (*certcb)(void*, const unsigned char*, size_t),
void *certcbarg, int *r_badpass, char **r_curve);
void p12_parse_free_kparms (gcry_mpi_t *kparms);
unsigned char *p12_build (gcry_mpi_t *kparms,
const void *cert, size_t certlen,

View File

@ -580,13 +580,7 @@ run_one_test (const char *name, const char *desc, const char *pass,
ret = 0;
}
if (result)
{
int i;
for (i=0; result[i]; i++)
gcry_mpi_release (result[i]);
gcry_free (result);
}
p12_parse_free_kparms (result);
xfree (certstr);
xfree (resulthash);
xfree (curve);

View File

@ -737,7 +737,12 @@ gpgsm_verify (ctrl_t ctrl, estream_t in_fp, estream_t data_fp,
char numbuf[50];
sprintf (numbuf, "%d", rc );
gpgsm_status2 (ctrl, STATUS_ERROR, "verify.leave",
numbuf, NULL);
numbuf,
gpg_err_code (rc) == GPG_ERR_EPIPE?
"-- (Broken pipe on input or output)":
gpg_err_code (rc) == GPG_ERR_EOF?
"-- (End of file)" : NULL,
NULL);
}
return rc;

View File

@ -99,8 +99,11 @@ EXTRA_DIST = $(XTESTS) $(KEYS) $(CERTS) $(TEST_FILES) \
samplekeys/opensc-test.p12 \
samplekeys/t5793-openssl.pfx \
samplekeys/t5793-test.pfx \
samplekeys/t6752-ov-user-ff.p12 \
samplekeys/edward.tester@demo.gnupg.com.p12 \
samplekeys/nistp256-openssl-self-signed.p12 \
samplekeys/credential_private_encrypted_AES256.p12 \
samplekeys/credential_private_encrypted_3DES.p12 \
samplemsgs/pwri-sample.cbc.p7m \
samplemsgs/pwri-sample.cbc-2.p7m \
samplemsgs/pwri-sample.gcm.p7m \

View File

@ -51,4 +51,16 @@ Pass: start
Cert: 4753a910e0c8b4caa8663ca0e4273a884eb5397d
Key: 93be89edd11214ab74280d988a665b6beef876c5
Name: credential_private_encrypted_AES256.p12
Desc: AES256 encrypted P12 file from T6940
Pass: qeFGds84/Sf0eKkJwcp6
Cert: 20f65740b4a15bac6d6a299026756088f7604937,cbb4b26f93cfd9715ac9fa43440470df9395571b
Key: 37eedaaf317edb69029eed79f69dd479fb10bf08
Name: credential_private_encrypted_3DES.p12
Desc: 3DES encrypted P12 file from T6940
Pass: qeFGds84/Sf0eKkJwcp6
Cert: 20f65740b4a15bac6d6a299026756088f7604937,cbb4b26f93cfd9715ac9fa43440470df9395571b
Key: 37eedaaf317edb69029eed79f69dd479fb10bf08
# eof #

View File

@ -1530,6 +1530,7 @@ scd_readkey (const char *keyrefstr, int create_shadow, gcry_sexp_t *r_result)
unsigned char *buf;
size_t len, buflen;
if (r_result)
*r_result = NULL;
err = start_agent (0);
if (err)
@ -1537,7 +1538,8 @@ scd_readkey (const char *keyrefstr, int create_shadow, gcry_sexp_t *r_result)
init_membuf (&data, 1024);
if (create_shadow)
snprintf (line, DIM(line), "READKEY --card -- %s", keyrefstr);
snprintf (line, DIM(line), "READKEY %s--card -- %s",
r_result? "" : "--no-data ", keyrefstr);
else
snprintf (line, DIM(line), "SCD READKEY %s", keyrefstr);
err = assuan_transact (agent_ctx, line,
@ -1553,7 +1555,7 @@ scd_readkey (const char *keyrefstr, int create_shadow, gcry_sexp_t *r_result)
if (!buf)
return gpg_error_from_syserror ();
err = gcry_sexp_new (r_result, buf, buflen, 0);
err = r_result ? gcry_sexp_new (r_result, buf, buflen, 0) : 0;
xfree (buf);
return err;
@ -1770,6 +1772,90 @@ agent_get_s2k_count (void)
}
struct havekey_status_parm_s
{
char *string;
};
static gpg_error_t
havekey_status_cb (void *opaque, const char *line)
{
struct havekey_status_parm_s *parm = opaque;
const char *s;
char *p;
if ((s = has_leading_keyword (line, "KEYFILEINFO")))
{
xfree (parm->string);
parm->string = xtrystrdup (s);
if (!parm->string)
return gpg_error_from_syserror ();
p = strchr (parm->string, ' ');
if (p)
*p = 0;
}
return 0;
}
/* Run the HAVEKEY --info command and stores the retrieved string at
* R_RESULT. Caller must free that string. If an error is returned
* R_RESULT is set to NULL. */
gpg_error_t
scd_havekey_info (const unsigned char *grip, char **r_result)
{
gpg_error_t err;
char line[ASSUAN_LINELENGTH];
struct havekey_status_parm_s parm = {NULL};
*r_result = NULL;
err = start_agent (0);
if (err)
return err;
snprintf (line, sizeof line, "HAVEKEY --info ");
log_assert (ASSUAN_LINELENGTH > strlen(line) + 2*KEYGRIP_LEN + 10);
bin2hex (grip, KEYGRIP_LEN, line+strlen(line));
err = assuan_transact (agent_ctx, line,
NULL, NULL, NULL, NULL,
havekey_status_cb, &parm);
if (err)
xfree (parm.string);
else
*r_result = parm.string;
return err;
}
/* Run the DELETE_KEY command. If FORCE is given the user will not be
* asked for confirmation. */
gpg_error_t
scd_delete_key (const unsigned char *grip, int force)
{
gpg_error_t err;
char line[ASSUAN_LINELENGTH];
struct default_inq_parm_s dfltparm = {NULL};
err = start_agent (0);
if (err)
return err;
dfltparm.ctx = agent_ctx;
snprintf (line, sizeof line, "DELETE_KEY%s ", force?" --force":"");
log_assert (ASSUAN_LINELENGTH > strlen(line) + 2*KEYGRIP_LEN + 10);
bin2hex (grip, KEYGRIP_LEN, line+strlen(line));
err = assuan_transact (agent_ctx, line,
NULL, NULL, default_inq_cb, &dfltparm, NULL, NULL);
return err;
}
/* Return a malloced string describing the statusword SW. On error
* NULL is returned. */
char *

View File

@ -582,12 +582,13 @@ print_shax_fpr (estream_t fp, const unsigned char *fpr, unsigned int fprlen)
/* Print the keygrip GRP. */
static void
print_keygrip (estream_t fp, const unsigned char *grp)
print_keygrip (estream_t fp, const unsigned char *grp, int with_lf)
{
int i;
for (i=0; i < 20 ; i++, grp++)
tty_fprintf (fp, "%02X", *grp);
if (with_lf)
tty_fprintf (fp, "\n");
}
@ -700,7 +701,7 @@ list_one_kinfo (card_info_t info, key_info_t kinfo,
goto leave;
}
print_keygrip (fp, kinfo->grip);
print_keygrip (fp, kinfo->grip, 1);
tty_fprintf (fp, " keyref .....: %s", kinfo->keyref);
if (kinfo->usage)
{
@ -1376,6 +1377,137 @@ cmd_list (card_info_t info, char *argstr)
}
/* The CHECKKEYS command. */
static gpg_error_t
cmd_checkkeys (card_info_t callerinfo, char *argstr)
{
gpg_error_t err;
estream_t fp = opt.interactive? NULL : es_stdout;
strlist_t cards = NULL;
strlist_t sl;
int opt_ondisk;
int opt_delete_clear;
int opt_delete_protected;
int delete_count = 0;
struct card_info_s info_buffer = { 0 };
card_info_t info = &info_buffer;
key_info_t kinfo;
if (!callerinfo)
return print_help
("CHECKKEYS [--ondisk] [--delete-clear-copy] [--delete-protected-copy]"
"\n\n"
"Print a list of keys on all inserted cards. With --ondisk only\n"
"keys are listed which also have a copy on disk. Missing shadow\n"
"keys are created. With --delete-clear-copy, copies of keys also\n"
"stored on disk without any protection will be deleted.\n"
, 0);
opt_ondisk = has_leading_option (argstr, "--ondisk");
opt_delete_clear = has_leading_option (argstr, "--delete-clear-copy");
opt_delete_protected = has_leading_option (argstr, "--delete-protected-copy");
argstr = skip_options (argstr);
if (*argstr)
{
/* No args expected */
err = gpg_error (GPG_ERR_INV_ARG);
goto leave;
}
if (!callerinfo->serialno)
{
/* This is probably the first call We need to send a SERIALNO
* command to scdaemon so that our session knows all cards. */
err = scd_serialno (NULL, NULL);
if (err)
goto leave;
}
/* Get the list of all cards. */
err = scd_cardlist (&cards);
if (err)
goto leave;
/* Loop over all cards. We use our own info buffer here. */
for (sl = cards; sl; sl = sl->next)
{
err = scd_switchcard (sl->d);
if (err)
{
log_error ("Error switching to card %s: %s\n",
sl->d, gpg_strerror (err));
continue;
}
release_card_info (info);
err = scd_learn (info, 0);
if (err)
{
log_error ("Error getting infos from card %s: %s\n",
sl->d, gpg_strerror (err));
continue;
}
for (kinfo = info->kinfo; kinfo; kinfo = kinfo->next)
{
char *infostr;
err = scd_havekey_info (kinfo->grip, &infostr);
if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
{
/* Create a shadow key and try again. */
scd_readkey (kinfo->keyref, 1, NULL);
err = scd_havekey_info (kinfo->grip, &infostr);
}
if (err && gpg_err_code (err) != GPG_ERR_NOT_FOUND)
log_error ("Error getting infos for a key: %s\n",
gpg_strerror (err));
if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
; /* does not make sense to show this. */
else if (opt_ondisk && infostr && !strcmp (infostr, "shadowed"))
; /* Don't print this one. */
else
{
tty_fprintf (fp, "%s %s ",
nullnone (info->serialno),
app_type_string (info->apptype));
print_keygrip (fp, kinfo->grip, 0);
tty_fprintf (fp, " %s %s\n",
kinfo->keyref, infostr? infostr: "error");
}
if (infostr
&& ((opt_delete_clear && !strcmp (infostr, "clear"))
|| (opt_delete_protected && !strcmp (infostr, "protected"))))
{
err = scd_delete_key (kinfo->grip, 0);
if (err)
log_error ("Error deleting a key copy: %s\n",
gpg_strerror (err));
else
delete_count++;
}
xfree (infostr);
}
}
es_fflush (es_stdout);
if (delete_count)
log_info ("Number of deleted key copies: %d\n", delete_count);
err = 0;
leave:
release_card_info (info);
free_strlist (cards);
/* Better reset to the original card. */
scd_learn (callerinfo, 0);
return err;
}
/* The VERIFY command. */
static gpg_error_t
@ -3728,6 +3860,7 @@ enum cmdids
cmdFORCESIG, cmdGENERATE, cmdPASSWD, cmdPRIVATEDO, cmdWRITECERT,
cmdREADCERT, cmdWRITEKEY, cmdUNBLOCK, cmdFACTRST, cmdKDFSETUP,
cmdUIF, cmdAUTH, cmdYUBIKEY, cmdAPDU, cmdGPG, cmdGPGSM, cmdHISTORY,
cmdCHECKKEYS,
cmdINVCMD
};
@ -3767,6 +3900,7 @@ static struct
{ "readcert", cmdREADCERT, N_("read a certificate from a data object")},
{ "writecert", cmdWRITECERT, N_("store a certificate to a data object")},
{ "writekey", cmdWRITEKEY, N_("store a private key to a data object")},
{ "checkkeys", cmdCHECKKEYS, N_("run various checks on the keys")},
{ "yubikey", cmdYUBIKEY, N_("Yubikey management commands")},
{ "gpg", cmdGPG, NULL},
{ "gpgsm", cmdGPGSM, NULL},
@ -3903,6 +4037,7 @@ dispatch_command (card_info_t info, const char *orig_command)
case cmdGPG: err = cmd_gpg (info, argstr, 0); break;
case cmdGPGSM: err = cmd_gpg (info, argstr, 1); break;
case cmdHISTORY: err = 0; break; /* Only used in interactive mode. */
case cmdCHECKKEYS: err = cmd_checkkeys (info, argstr); break;
case cmdINVCMD:
default:
@ -4162,6 +4297,7 @@ interactive_loop (void)
case cmdGPG: err = cmd_gpg (info, argstr, 0); break;
case cmdGPGSM: err = cmd_gpg (info, argstr, 1); break;
case cmdHISTORY: err = cmd_history (info, argstr); break;
case cmdCHECKKEYS: err = cmd_checkkeys (info, argstr); break;
case cmdINVCMD:
default:

View File

@ -246,6 +246,8 @@ gpg_error_t scd_cardlist (strlist_t *result);
gpg_error_t scd_applist (strlist_t *result, int all);
gpg_error_t scd_change_pin (const char *pinref, int reset_mode, int nullpin);
gpg_error_t scd_checkpin (const char *serialno);
gpg_error_t scd_havekey_info (const unsigned char *grip, char **r_result);
gpg_error_t scd_delete_key (const unsigned char *grip, int force);
unsigned long agent_get_s2k_count (void);

View File

@ -86,30 +86,31 @@ enum cmd_and_opt_values
/* The list of commands and options. */
static gpgrt_opt_t opts[] =
{
{ 300, NULL, 0, N_("@Commands:\n ") },
ARGPARSE_group (300, N_("@Commands:\n ")),
{ aListComponents, "list-components", 256, N_("list all components") },
{ aCheckPrograms, "check-programs", 256, N_("check all programs") },
{ aListOptions, "list-options", 256, N_("|COMPONENT|list options") },
{ aChangeOptions, "change-options", 256, N_("|COMPONENT|change options") },
{ aCheckOptions, "check-options", 256, N_("|COMPONENT|check options") },
{ aApplyDefaults, "apply-defaults", 256,
N_("apply global default values") },
{ aApplyProfile, "apply-profile", 256,
N_("|FILE|update configuration files using FILE") },
{ aListDirs, "list-dirs", 256,
N_("get the configuration directories for @GPGCONF@") },
{ aListConfig, "list-config", 256,
N_("list global configuration file") },
{ aCheckConfig, "check-config", 256,
N_("check global configuration file") },
{ aQuerySWDB, "query-swdb", 256,
N_("query the software version database") },
{ aReload, "reload", 256, N_("reload all or a given component")},
{ aLaunch, "launch", 256, N_("launch a given component")},
{ aKill, "kill", 256, N_("kill a given component")},
{ aCreateSocketDir, "create-socketdir", 256, "@"},
{ aRemoveSocketDir, "remove-socketdir", 256, "@"},
ARGPARSE_c (aListComponents, "list-components", N_("list all components")),
ARGPARSE_c (aCheckPrograms, "check-programs", N_("check all programs")),
ARGPARSE_c (aListOptions, "list-options", N_("|COMPONENT|list options")),
ARGPARSE_c (aChangeOptions, "change-options",
N_("|COMPONENT|change options")),
ARGPARSE_c (aCheckOptions, "check-options", N_("|COMPONENT|check options")),
ARGPARSE_c (aApplyDefaults, "apply-defaults",
N_("apply global default values")),
ARGPARSE_c (aApplyProfile, "apply-profile",
N_("|FILE|update configuration files using FILE")),
ARGPARSE_c (aListDirs, "list-dirs",
N_("get the configuration directories for @GPGCONF@")),
ARGPARSE_c (aListConfig, "list-config",
N_("list global configuration file")),
ARGPARSE_c (aCheckConfig, "check-config",
N_("check global configuration file")),
ARGPARSE_c (aQuerySWDB, "query-swdb",
N_("query the software version database")),
ARGPARSE_c (aReload, "reload", N_("reload all or a given component")),
ARGPARSE_c (aLaunch, "launch", N_("launch a given component")),
ARGPARSE_c (aKill, "kill", N_("kill a given component")),
ARGPARSE_c (aCreateSocketDir, "create-socketdir", "@"),
ARGPARSE_c (aRemoveSocketDir, "remove-socketdir", "@"),
ARGPARSE_c (aShowVersions, "show-versions", ""),
ARGPARSE_c (aShowConfigs, "show-configs", ""),
/* hidden commands: for debugging */
@ -117,24 +118,25 @@ static gpgrt_opt_t opts[] =
ARGPARSE_c (aDotlockLock, "lock", "@"),
ARGPARSE_c (aDotlockUnlock, "unlock", "@"),
{ 301, NULL, 0, N_("@\nOptions:\n ") },
ARGPARSE_header (NULL, N_("@\nOptions:\n ")),
{ oOutput, "output", 2, N_("use as output file") },
{ oVerbose, "verbose", 0, N_("verbose") },
{ oQuiet, "quiet", 0, N_("quiet") },
{ oDryRun, "dry-run", 0, N_("do not make any changes") },
{ oRuntime, "runtime", 0, N_("activate changes at runtime, if possible") },
ARGPARSE_s_s (oOutput, "output", N_("use as output file")),
ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
ARGPARSE_s_n (oQuiet, "quiet", N_("quiet")),
ARGPARSE_s_n (oDryRun, "dry-run", N_("do not make any changes")),
ARGPARSE_s_n (oRuntime, "runtime",
N_("activate changes at runtime, if possible")),
ARGPARSE_s_i (oStatusFD, "status-fd",
N_("|FD|write status info to this FD")),
/* hidden options */
{ oHomedir, "homedir", 2, "@" },
{ oBuilddir, "build-prefix", 2, "@" },
{ oNull, "null", 0, "@" },
{ oNoVerbose, "no-verbose", 0, "@"},
ARGPARSE_s_s (oHomedir, "homedir", "@"),
ARGPARSE_s_s (oBuilddir, "build-prefix", "@"),
ARGPARSE_s_n (oNull, "null", "@"),
ARGPARSE_s_n (oNoVerbose, "no-verbose", "@"),
ARGPARSE_s_n (oShowSocket, "show-socket", "@"),
ARGPARSE_s_s (oChUid, "chuid", "@"),
ARGPARSE_end(),
ARGPARSE_end ()
};
@ -1072,12 +1074,12 @@ main (int argc, char **argv)
#if !defined(HAVE_W32_SYSTEM)
if (!fname)
{
es_fprintf (es_stderr, "usage: %s [options] lock|unlock NAME",
GPGCONF_NAME);
es_fprintf (es_stderr, "usage: %s --%slock NAME",
GPGCONF_NAME, cmd==aDotlockUnlock?"un":"");
es_putc ('\n', es_stderr);
es_fputs (_("Need one NAME argument"), es_stderr);
es_fputs ("Need name of file protected by the lock", es_stderr);
es_putc ('\n', es_stderr);
gpgconf_failure (GPG_ERR_USER_2);
gpgconf_failure (GPG_ERR_SYNTAX);
}
else
{
@ -1151,10 +1153,12 @@ get_revision_from_blurb (const char *blurb, int *r_len)
static void
show_version_gnupg (estream_t fp, const char *prefix)
{
char *fname, *p;
char *fname, *p, *p0;
size_t n;
estream_t verfp;
char line[100];
char *line = NULL;
size_t line_len = 0;
ssize_t length;
es_fprintf (fp, "%s%sGnuPG %s (%s)\n%s%s\n", prefix, *prefix?"":"* ",
gpgrt_strusage (13), BUILD_REVISION, prefix, gpgrt_strusage (17));
@ -1173,20 +1177,46 @@ show_version_gnupg (estream_t fp, const char *prefix)
verfp = es_fopen (fname, "r");
if (!verfp)
es_fprintf (fp, "%s[VERSION file not found]\n", prefix);
else if (!es_fgets (line, sizeof line, verfp))
es_fprintf (fp, "%s[VERSION file is empty]\n", prefix);
else
{
int lnr = 0;
p0 = NULL;
while ((length = es_read_line (verfp, &line, &line_len, NULL))>0)
{
lnr++;
trim_spaces (line);
for (p=line; *p; p++)
if (lnr == 1 && *line != '[')
{
/* Old file format where we look only at the
* first line. */
p0 = line;
break;
}
else if (!strncmp (line, "version=", 8))
{
p0 = line + 8;
break;
}
}
if (length < 0 || es_ferror (verfp))
es_fprintf (fp, "%s[VERSION file read error]\n", prefix);
else if (p0)
{
for (p=p0; *p; p++)
if (*p < ' ' || *p > '~' || *p == '[')
*p = '?';
es_fprintf (fp, "%s%s\n", prefix, line);
es_fprintf (fp, "%s%s\n", prefix, p0);
}
else
es_fprintf (fp, "%s[VERSION file is empty]\n", prefix);
es_fclose (verfp);
}
}
xfree (fname);
}
xfree (line);
#ifdef HAVE_W32_SYSTEM
{