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

gpg: New export option "mode1003".

* agent/command.c (cmd_export_key): Add option --mode1003.
(command_has_option): Ditto.
* g10/build-packet.c (do_key): Implement mode 1003.
* g10/parse-packet.c (parse_key): Ditto.
* g10/options.h (EXPORT_MODE1003): New.o
* g10/call-agent.c (agent_export_key): Add arg mode1003.
* g10/export.c (parse_export_options): Add "mode1003"
(secret_key_to_mode1003): New.
(receive_seckey_from_agent): Add arg mode1003.
(do_export_one_keyblock): Pass option down.
--

This option allows to export a secret key in GnuPG's native format.
Thus no re-encryption is required and further the public key parameters
are also authenticated if a protection passphrase has been used.

Note that --import is not yet able to handle this new mode.  Although
old version of GnuPG will bail out with "invalid packet" if a mode1003
exported secret key is seen.
This commit is contained in:
Werner Koch 2022-12-02 10:03:36 +01:00
parent 1d88e14de7
commit 1a85ee9a43
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
11 changed files with 320 additions and 35 deletions

View File

@ -2935,7 +2935,7 @@ cmd_import_key (assuan_context_t ctx, char *line)
static const char hlp_export_key[] = static const char hlp_export_key[] =
"EXPORT_KEY [--cache-nonce=<nonce>] [--openpgp] <hexstring_with_keygrip>\n" "EXPORT_KEY [--cache-nonce=<nonce>] [--openpgp|--mode1003] <hexkeygrip>\n"
"\n" "\n"
"Export a secret key from the key store. The key will be encrypted\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" "using the current session's key wrapping key (cf. command KEYWRAP_KEY)\n"
@ -2943,9 +2943,10 @@ static const char hlp_export_key[] =
"prior to using this command. The function takes the keygrip as argument.\n" "prior to using this command. The function takes the keygrip as argument.\n"
"\n" "\n"
"If --openpgp is used, the secret key material will be exported in RFC 4880\n" "If --openpgp is used, the secret key material will be exported in RFC 4880\n"
"compatible passphrase-protected form. Without --openpgp, the secret key\n" "compatible passphrase-protected form. If --mode1003 is use the secret key\n"
"material will be exported in the clear (after prompting the user to unlock\n" "is exported as s-expression as storred locally. Without those options,\n"
"it, if needed).\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 static gpg_error_t
cmd_export_key (assuan_context_t ctx, char *line) cmd_export_key (assuan_context_t ctx, char *line)
{ {
@ -2958,7 +2959,7 @@ cmd_export_key (assuan_context_t ctx, char *line)
gcry_cipher_hd_t cipherhd = NULL; gcry_cipher_hd_t cipherhd = NULL;
unsigned char *wrappedkey = NULL; unsigned char *wrappedkey = NULL;
size_t wrappedkeylen; size_t wrappedkeylen;
int openpgp; int openpgp, mode1003;
char *cache_nonce; char *cache_nonce;
char *passphrase = NULL; char *passphrase = NULL;
unsigned char *shadow_info = NULL; unsigned char *shadow_info = NULL;
@ -2969,6 +2970,10 @@ cmd_export_key (assuan_context_t ctx, char *line)
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN)); return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
openpgp = has_option (line, "--openpgp"); openpgp = has_option (line, "--openpgp");
mode1003 = has_option (line, "--mode1003");
if (mode1003)
openpgp = 0;
cache_nonce = option_value (line, "--cache-nonce"); cache_nonce = option_value (line, "--cache-nonce");
if (cache_nonce) if (cache_nonce)
{ {
@ -3003,7 +3008,13 @@ cmd_export_key (assuan_context_t ctx, char *line)
} }
/* Get the key from the file. With the openpgp flag we also ask for /* Get the key from the file. With the openpgp flag we also ask for
the passphrase so that we can use it to re-encrypt it. */ * the passphrase so that we can use it to re-encrypt it. In
* mode1003 we return the key as-is. FIXME: if the key is still in
* OpenPGP-native mode we should first convert it to our internal
* protection. */
if (mode1003)
err = agent_raw_key_from_file (ctrl, grip, &s_skey, NULL);
else
err = agent_key_from_file (ctrl, cache_nonce, err = agent_key_from_file (ctrl, cache_nonce,
ctrl->server_local->keydesc, grip, ctrl->server_local->keydesc, grip,
&shadow_info, CACHE_MODE_IGNORE, NULL, &s_skey, &shadow_info, CACHE_MODE_IGNORE, NULL, &s_skey,
@ -4150,6 +4161,11 @@ command_has_option (const char *cmd, const char *cmdopt)
if (!strcmp (cmdopt, "newsymkey")) if (!strcmp (cmdopt, "newsymkey"))
return 1; return 1;
} }
else if (!strcmp (cmd, "EXPORT_KEY"))
{
if (!strcmp (cmdopt, "mode1003"))
return 1;
}
return 0; return 0;
} }

View File

@ -1504,6 +1504,14 @@ CREATE TABLE signatures (
- One octet with the length of the following serial number. - One octet with the length of the following serial number.
- The serial number. Regardless of what the length octet - The serial number. Regardless of what the length octet
indicates no more than 16 octets are stored. indicates no more than 16 octets are stored.
- 3 :: The internal representation of a private key: For v4 keys we
first write 4 octets big endian length of the following
s-expression with the protected or unprotected private key;
for v5 keys this is not necessarily because that length
header is always there. The actual data are N octets of
s-expression. Any protection (including the real S2K) is
part of that data. Note that the public key aparemters are
repeated in th s-expression.
Note that gpg stores the GNU S2K Extension Number internally as an Note that gpg stores the GNU S2K Extension Number internally as an
S2K Specifier with an offset of 1000. S2K Specifier with an offset of 1000.

View File

@ -2721,6 +2721,16 @@ opposite meaning. The options are:
each record to allow diverting the records to the corresponding zone each record to allow diverting the records to the corresponding zone
file. file.
@item mode1003
Enable the use of a new secret key export format. This format
avoids the re-encryption as required with the current OpenPGP format
and also improves the security of the secret key if it has been
protected with a passphrase. Note that an unprotected key is
exported as-is and thus not secure; the general rule to convey
secret keys in an OpenPGP encrypted file still applies with this
mode. Versions of GnuPG before 2.4.0 are not able to import such a
secret file.
@end table @end table
@item --with-colons @item --with-colons

View File

@ -674,7 +674,8 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
count += 8; /* Salt. */ count += 8; /* Salt. */
if (ski->s2k.mode == 3) if (ski->s2k.mode == 3)
count++; /* S2K.COUNT */ count++; /* S2K.COUNT */
if (ski->s2k.mode != 1001 && ski->s2k.mode != 1002) if (ski->s2k.mode != 1001 && ski->s2k.mode != 1002
&& ski->s2k.mode != 1003)
count += ski->ivlen; count += ski->ivlen;
iobuf_put (a, count); iobuf_put (a, count);
@ -704,8 +705,9 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
if (ski->s2k.mode == 3) if (ski->s2k.mode == 3)
iobuf_put (a, ski->s2k.count); iobuf_put (a, ski->s2k.count);
/* For our special modes 1001, 1002 we do not need an IV. */ /* For our special modes 1001..1003 we do not need an IV. */
if (ski->s2k.mode != 1001 && ski->s2k.mode != 1002) if (ski->s2k.mode != 1001 && ski->s2k.mode != 1002
&& ski->s2k.mode != 1003)
iobuf_write (a, ski->iv, ski->ivlen); iobuf_write (a, ski->iv, ski->ivlen);
} }
@ -733,6 +735,22 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
/* The serial number gets stored in the IV field. */ /* The serial number gets stored in the IV field. */
iobuf_write (a, ski->iv, ski->ivlen); iobuf_write (a, ski->iv, ski->ivlen);
} }
else if (ski->s2k.mode == 1003)
{
/* GnuPG extension - Store raw s-expression. */
byte *p;
unsigned int ndatabits;
log_assert (gcry_mpi_get_flag (pk->pkey[npkey], GCRYMPI_FLAG_OPAQUE));
p = gcry_mpi_get_opaque (pk->pkey[npkey], &ndatabits);
/* For v5 keys we first write the number of octets of the
* following key material. */
if (is_v5)
write_32 (a, p? (ndatabits+7)/8 : 0);
if (p)
iobuf_write (a, p, (ndatabits+7)/8 );
}
else if (ski->is_protected) else if (ski->is_protected)
{ {
/* The secret key is protected - write it out as it is. */ /* The secret key is protected - write it out as it is. */

View File

@ -2997,13 +2997,15 @@ agent_import_key (ctrl_t ctrl, const char *desc, char **cache_nonce_addr,
keygrip, DESC a prompt to be displayed with the agent's passphrase keygrip, DESC a prompt to be displayed with the agent's passphrase
question (needs to be plus+percent escaped). if OPENPGP_PROTECTED question (needs to be plus+percent escaped). if OPENPGP_PROTECTED
is not zero, ensure that the key material is returned in RFC is not zero, ensure that the key material is returned in RFC
4880-compatible passphrased-protected form. If CACHE_NONCE_ADDR is 4880-compatible passphrased-protected form; if instead MODE1003 is
not NULL the agent is advised to first try a passphrase associated not zero the raw gpg-agent private key format is requested (either
with that nonce. On success the key is stored as a canonical protected or unprotected). If CACHE_NONCE_ADDR is not NULL the
S-expression at R_RESULT and R_RESULTLEN. */ agent is advised to first try a passphrase associated with that
nonce. On success the key is stored as a canonical S-expression at
R_RESULT and R_RESULTLEN. */
gpg_error_t gpg_error_t
agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc, agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
int openpgp_protected, char **cache_nonce_addr, int openpgp_protected, int mode1003, char **cache_nonce_addr,
unsigned char **r_result, size_t *r_resultlen, unsigned char **r_result, size_t *r_resultlen,
u32 *keyid, u32 *mainkeyid, int pubkey_algo) u32 *keyid, u32 *mainkeyid, int pubkey_algo)
{ {
@ -3028,6 +3030,12 @@ agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
return err; return err;
dfltparm.ctx = agent_ctx; dfltparm.ctx = agent_ctx;
/* Check that the gpg-agent supports the --mode1003 option. */
if (mode1003 && assuan_transact (agent_ctx,
"GETINFO cmd_has_option EXPORT_KEY mode1003",
NULL, NULL, NULL, NULL, NULL, NULL))
return gpg_error (GPG_ERR_NOT_SUPPORTED);
if (desc) if (desc)
{ {
snprintf (line, DIM(line), "SETKEYDESC %s", desc); snprintf (line, DIM(line), "SETKEYDESC %s", desc);
@ -3038,7 +3046,7 @@ agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
} }
snprintf (line, DIM(line), "EXPORT_KEY %s%s%s %s", snprintf (line, DIM(line), "EXPORT_KEY %s%s%s %s",
openpgp_protected ? "--openpgp ":"", mode1003? "--mode1003" : openpgp_protected ? "--openpgp ":"",
cache_nonce_addr && *cache_nonce_addr? "--cache-nonce=":"", cache_nonce_addr && *cache_nonce_addr? "--cache-nonce=":"",
cache_nonce_addr && *cache_nonce_addr? *cache_nonce_addr:"", cache_nonce_addr && *cache_nonce_addr? *cache_nonce_addr:"",
hexkeygrip); hexkeygrip);

View File

@ -231,7 +231,7 @@ gpg_error_t agent_import_key (ctrl_t ctrl, const char *desc,
/* Receive a key from the agent. */ /* Receive a key from the agent. */
gpg_error_t agent_export_key (ctrl_t ctrl, const char *keygrip, gpg_error_t agent_export_key (ctrl_t ctrl, const char *keygrip,
const char *desc, int openpgp_protected, const char *desc, int openpgp_protected,
char **cache_nonce_addr, int mode1003, char **cache_nonce_addr,
unsigned char **r_result, size_t *r_resultlen, unsigned char **r_result, size_t *r_resultlen,
u32 *keyid, u32 *mainkeyid, int pubkey_algo); u32 *keyid, u32 *mainkeyid, int pubkey_algo);

View File

@ -2,6 +2,7 @@
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
* 2005, 2010 Free Software Foundation, Inc. * 2005, 2010 Free Software Foundation, Inc.
* Copyright (C) 1998-2016 Werner Koch * Copyright (C) 1998-2016 Werner Koch
* Copyright (C) 2022 g10 Code GmbH
* *
* This file is part of GnuPG. * This file is part of GnuPG.
* *
@ -140,6 +141,9 @@ parse_export_options(char *str,unsigned int *options,int noisy)
N_("use the GnuPG key backup format")}, N_("use the GnuPG key backup format")},
{"export-backup", EXPORT_BACKUP, NULL, NULL }, {"export-backup", EXPORT_BACKUP, NULL, NULL },
{"mode1003", EXPORT_MODE1003, NULL,
N_("export secret keys using the GnuPG format") },
/* Aliases for backward compatibility */ /* Aliases for backward compatibility */
{"include-local-sigs",EXPORT_LOCAL_SIGS,NULL,NULL}, {"include-local-sigs",EXPORT_LOCAL_SIGS,NULL,NULL},
{"include-attributes",EXPORT_ATTRIBUTES,NULL,NULL}, {"include-attributes",EXPORT_ATTRIBUTES,NULL,NULL},
@ -639,6 +643,183 @@ canon_pk_algo (enum gcry_pk_algos algo)
} }
/* Take an s-expression wit the public and private key and change the
* parameter array in PK to include the secret parameters. */
static gpg_error_t
secret_key_to_mode1003 (gcry_sexp_t s_key, PKT_public_key *pk)
{
gpg_error_t err;
gcry_sexp_t list = NULL;
gcry_sexp_t l2;
enum gcry_pk_algos pk_algo;
struct seckey_info *ski;
int idx;
char *string;
size_t npkey, nskey;
gcry_mpi_t pub_params[10] = { NULL };
/* We look for a private-key, then the first element in it tells us
the type */
list = gcry_sexp_find_token (s_key, "protected-private-key", 0);
if (!list)
list = gcry_sexp_find_token (s_key, "private-key", 0);
if (!list)
{
err = gpg_error (GPG_ERR_BAD_SECKEY);
goto leave;
}
log_assert (!pk->seckey_info);
/* Parse the gcrypt PK algo and check that it is okay. */
l2 = gcry_sexp_cadr (list);
if (!l2)
{
err = gpg_error (GPG_ERR_BAD_SECKEY);
goto leave;
}
gcry_sexp_release (list);
list = l2;
string = gcry_sexp_nth_string (list, 0);
if (!string)
{
err = gpg_error (GPG_ERR_BAD_SECKEY);
goto leave;
}
pk_algo = gcry_pk_map_name (string);
xfree (string); string = NULL;
if (gcry_pk_algo_info (pk_algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &npkey)
|| gcry_pk_algo_info (pk_algo, GCRYCTL_GET_ALGO_NSKEY, NULL, &nskey)
|| !npkey || npkey >= nskey)
{
err = gpg_error (GPG_ERR_BAD_SECKEY);
goto leave;
}
/* Check that the pubkey algo and the received parameters matches
* those from the public key. */
switch (canon_pk_algo (pk_algo))
{
case GCRY_PK_RSA:
if (!is_RSA (pk->pubkey_algo) || npkey != 2)
err = gpg_error (GPG_ERR_PUBKEY_ALGO); /* Does not match. */
else
err = gcry_sexp_extract_param (list, NULL, "ne",
&pub_params[0],
&pub_params[1],
NULL);
break;
case GCRY_PK_DSA:
if (!is_DSA (pk->pubkey_algo) || npkey != 4)
err = gpg_error (GPG_ERR_PUBKEY_ALGO); /* Does not match. */
else
err = gcry_sexp_extract_param (list, NULL, "pqgy",
&pub_params[0],
&pub_params[1],
&pub_params[2],
&pub_params[3],
NULL);
break;
case GCRY_PK_ELG:
if (!is_ELGAMAL (pk->pubkey_algo) || npkey != 3)
err = gpg_error (GPG_ERR_PUBKEY_ALGO); /* Does not match. */
else
err = gcry_sexp_extract_param (list, NULL, "pgy",
&pub_params[0],
&pub_params[1],
&pub_params[2],
NULL);
break;
case GCRY_PK_ECC:
err = 0;
if (!(pk->pubkey_algo == PUBKEY_ALGO_ECDSA
|| pk->pubkey_algo == PUBKEY_ALGO_ECDH
|| pk->pubkey_algo == PUBKEY_ALGO_EDDSA))
{
err = gpg_error (GPG_ERR_PUBKEY_ALGO); /* Does not match. */
goto leave;
}
npkey = 2;
if (pk->pubkey_algo == PUBKEY_ALGO_ECDH)
npkey++;
/* Dedicated check of the curve. */
pub_params[0] = NULL;
err = match_curve_skey_pk (list, pk);
if (err)
goto leave;
/* ... and of the Q parameter. */
err = sexp_extract_param_sos (list, "q", &pub_params[1]);
if (!err && (gcry_mpi_cmp (pk->pkey[1], pub_params[1])))
err = gpg_error (GPG_ERR_BAD_PUBKEY);
break;
default:
err = gpg_error (GPG_ERR_PUBKEY_ALGO); /* Unknown. */
break;
}
if (err)
goto leave;
nskey = npkey + 1; /* We only have one skey param. */
if (nskey > PUBKEY_MAX_NSKEY)
{
err = gpg_error (GPG_ERR_BAD_SECKEY);
goto leave;
}
/* Check that the public key parameters match. For ECC we already
* did this in the switch above. */
if (canon_pk_algo (pk_algo) != GCRY_PK_ECC)
{
for (idx=0; idx < npkey; idx++)
if (gcry_mpi_cmp (pk->pkey[idx], pub_params[idx]))
{
err = gpg_error (GPG_ERR_BAD_PUBKEY);
goto leave;
}
}
/* Store the maybe protected secret key as an s-expression. */
pk->seckey_info = ski = xtrycalloc (1, sizeof *ski);
if (!ski)
{
err = gpg_error_from_syserror ();
goto leave;
}
pk->seckey_info = ski = xtrycalloc (1, sizeof *ski);
if (!ski)
{
err = gpg_error_from_syserror ();
goto leave;
}
ski->is_protected = 1;
ski->s2k.mode = 1003;
{
unsigned char *buf;
size_t buflen;
err = make_canon_sexp (s_key, &buf, &buflen);
if (err)
goto leave;
pk->pkey[npkey] = gcry_mpi_set_opaque (NULL, buf, buflen*8);
for (idx=npkey+1; idx < PUBKEY_MAX_NSKEY; idx++)
pk->pkey[idx] = NULL;
}
leave:
gcry_sexp_release (list);
for (idx=0; idx < DIM(pub_params); idx++)
gcry_mpi_release (pub_params[idx]);
return err;
}
/* Take a cleartext dump of a secret key in PK and change the /* Take a cleartext dump of a secret key in PK and change the
* parameter array in PK to include the secret parameters. */ * parameter array in PK to include the secret parameters. */
static gpg_error_t static gpg_error_t
@ -1248,6 +1429,11 @@ print_status_exported (PKT_public_key *pk)
* passphrase-protected. Otherwise, store secret key material in the * passphrase-protected. Otherwise, store secret key material in the
* clear. * clear.
* *
* If MODE1003 is set, the key is requested in raw GnuPG format from
* the agent. This usually does not require a passphrase unless the
* gpg-agent has not yet used the key and needs to convert it to its
* internal format first.
*
* CACHE_NONCE_ADDR is used to share nonce for multiple key retrievals. * CACHE_NONCE_ADDR is used to share nonce for multiple key retrievals.
* *
* If PK is NULL, the raw key is returned (e.g. for ssh export) at * If PK is NULL, the raw key is returned (e.g. for ssh export) at
@ -1255,7 +1441,7 @@ print_status_exported (PKT_public_key *pk)
*/ */
gpg_error_t gpg_error_t
receive_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd, receive_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd,
int cleartext, int cleartext, int mode1003,
char **cache_nonce_addr, const char *hexgrip, char **cache_nonce_addr, const char *hexgrip,
PKT_public_key *pk, gcry_sexp_t *r_key) PKT_public_key *pk, gcry_sexp_t *r_key)
{ {
@ -1275,7 +1461,7 @@ receive_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd,
if (pk) if (pk)
{ {
prompt = gpg_format_keydesc (ctrl, pk, FORMAT_KEYDESC_EXPORT, 1); prompt = gpg_format_keydesc (ctrl, pk, FORMAT_KEYDESC_EXPORT, 1);
err = agent_export_key (ctrl, hexgrip, prompt, !cleartext, err = agent_export_key (ctrl, hexgrip, prompt, !cleartext, mode1003,
cache_nonce_addr, cache_nonce_addr,
&wrappedkey, &wrappedkeylen, &wrappedkey, &wrappedkeylen,
pk->keyid, pk->main_keyid, pk->pubkey_algo); pk->keyid, pk->main_keyid, pk->pubkey_algo);
@ -1283,7 +1469,7 @@ receive_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd,
else else
{ {
prompt = gpg_format_keydesc (ctrl, NULL, FORMAT_KEYDESC_KEYGRIP, 1); prompt = gpg_format_keydesc (ctrl, NULL, FORMAT_KEYDESC_KEYGRIP, 1);
err = agent_export_key (ctrl, hexgrip, prompt, 0, err = agent_export_key (ctrl, hexgrip, prompt, 0, 0,
NULL, NULL,
&wrappedkey, &wrappedkeylen, &wrappedkey, &wrappedkeylen,
NULL, NULL, 0); NULL, NULL, 0);
@ -1314,7 +1500,9 @@ receive_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd,
err = gcry_sexp_sscan (&s_skey, NULL, key, realkeylen); err = gcry_sexp_sscan (&s_skey, NULL, key, realkeylen);
if (!err) if (!err)
{ {
if (pk && cleartext) if (pk && mode1003)
err = secret_key_to_mode1003 (s_skey, pk);
else if (pk && cleartext)
err = cleartext_secret_key_to_openpgp (s_skey, pk); err = cleartext_secret_key_to_openpgp (s_skey, pk);
else if (pk) else if (pk)
err = transfer_format_to_openpgp (s_skey, pk); err = transfer_format_to_openpgp (s_skey, pk);
@ -1832,7 +2020,9 @@ do_export_one_keyblock (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid,
else if (!err) else if (!err)
{ {
err = receive_seckey_from_agent (ctrl, cipherhd, err = receive_seckey_from_agent (ctrl, cipherhd,
cleartext, &cache_nonce, cleartext,
!!(options & EXPORT_MODE1003),
&cache_nonce,
hexgrip, pk, NULL); hexgrip, pk, NULL);
if (err) if (err)
{ {
@ -2781,7 +2971,7 @@ export_secret_ssh_key (ctrl_t ctrl, const char *userid)
if ((err = get_keywrap_key (ctrl, &cipherhd))) if ((err = get_keywrap_key (ctrl, &cipherhd)))
goto leave; goto leave;
err = receive_seckey_from_agent (ctrl, cipherhd, 0, NULL, hexgrip, NULL, err = receive_seckey_from_agent (ctrl, cipherhd, 0, 0, NULL, hexgrip, NULL,
&skey); &skey);
if (err) if (err)
goto leave; goto leave;

View File

@ -5286,7 +5286,7 @@ card_store_key_with_backup (ctrl_t ctrl, PKT_public_key *sub_psk,
goto leave; goto leave;
} }
err = receive_seckey_from_agent (ctrl, cipherhd, 0, err = receive_seckey_from_agent (ctrl, cipherhd, 0, 0,
&cache_nonce, hexgrip, sk, NULL); &cache_nonce, hexgrip, sk, NULL);
if (err) if (err)
{ {

View File

@ -431,7 +431,7 @@ gpg_error_t export_pubkey_buffer (ctrl_t ctrl, const char *keyspec,
void **r_data, size_t *r_datalen); void **r_data, size_t *r_datalen);
gpg_error_t receive_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd, gpg_error_t receive_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd,
int cleartext, int cleartext, int mode1003,
char **cache_nonce_addr, char **cache_nonce_addr,
const char *hexgrip, const char *hexgrip,
PKT_public_key *pk, gcry_sexp_t *r_key); PKT_public_key *pk, gcry_sexp_t *r_key);

View File

@ -407,6 +407,7 @@ EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode;
#define EXPORT_DANE_FORMAT (1<<7) #define EXPORT_DANE_FORMAT (1<<7)
#define EXPORT_BACKUP (1<<10) #define EXPORT_BACKUP (1<<10)
#define EXPORT_REVOCS (1<<11) #define EXPORT_REVOCS (1<<11)
#define EXPORT_MODE1003 (1<<12)
#define LIST_SHOW_PHOTOS (1<<0) #define LIST_SHOW_PHOTOS (1<<0)
#define LIST_SHOW_POLICY_URLS (1<<1) #define LIST_SHOW_POLICY_URLS (1<<1)

View File

@ -2752,11 +2752,15 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
break; break;
case 1001: case 1001:
if (list_mode) if (list_mode)
es_fprintf (listfp, "\tgnu-dummy S2K"); es_fprintf (listfp, "\tgnu-dummy");
break; break;
case 1002: case 1002:
if (list_mode) if (list_mode)
es_fprintf (listfp, "\tgnu-divert-to-card S2K"); es_fprintf (listfp, "\tgnu-divert-to-card");
break;
case 1003:
if (list_mode)
es_fprintf (listfp, "\tgnu-mode1003");
break; break;
default: default:
if (list_mode) if (list_mode)
@ -2768,7 +2772,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
} }
/* Print some info. */ /* Print some info. */
if (list_mode) if (list_mode && ski->s2k.mode != 1003)
{ {
es_fprintf (listfp, ", algo: %d,%s hash: %d", es_fprintf (listfp, ", algo: %d,%s hash: %d",
ski->algo, ski->algo,
@ -2779,8 +2783,9 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
es_fprintf (listfp, ", salt: "); es_fprintf (listfp, ", salt: ");
es_write_hexstring (listfp, ski->s2k.salt, 8, 0, NULL); es_write_hexstring (listfp, ski->s2k.salt, 8, 0, NULL);
} }
es_putc ('\n', listfp);
} }
if (list_mode)
es_putc ('\n', listfp);
/* Read remaining protection parameters. */ /* Read remaining protection parameters. */
if (ski->s2k.mode == 3) if (ski->s2k.mode == 3)
@ -2838,7 +2843,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
ski->ivlen = openpgp_cipher_blocklen (ski->algo); ski->ivlen = openpgp_cipher_blocklen (ski->algo);
log_assert (ski->ivlen <= sizeof (temp)); log_assert (ski->ivlen <= sizeof (temp));
if (ski->s2k.mode == 1001) if (ski->s2k.mode == 1001 || ski->s2k.mode == 1003)
ski->ivlen = 0; ski->ivlen = 0;
else if (ski->s2k.mode == 1002) else if (ski->s2k.mode == 1002)
ski->ivlen = snlen < 16 ? snlen : 16; ski->ivlen = snlen < 16 ? snlen : 16;
@ -2850,7 +2855,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
} }
for (i = 0; i < ski->ivlen; i++, pktlen--) for (i = 0; i < ski->ivlen; i++, pktlen--)
temp[i] = iobuf_get_noeof (inp); temp[i] = iobuf_get_noeof (inp);
if (list_mode) if (list_mode && ski->s2k.mode != 1003)
{ {
es_fprintf (listfp, es_fprintf (listfp,
ski->s2k.mode == 1002 ? "\tserial-number: " ski->s2k.mode == 1002 ? "\tserial-number: "
@ -2888,6 +2893,35 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
10 * 8); 10 * 8);
pktlen = 0; pktlen = 0;
} }
else if (ski->s2k.mode == 1003)
{
void *tmpp;
if (pktlen < 2) /* At least two bytes for parenthesis. */
{
err = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
tmpp = read_rest (inp, pktlen);
if (list_mode)
{
if (mpi_print_mode)
{
char *tmpsxp = canon_sexp_to_string (tmpp, pktlen);
es_fprintf (listfp, "\tskey[%d]: %s\n", npkey,
tmpsxp? trim_trailing_spaces (tmpsxp)
/* */: "[invalid S-expression]");
xfree (tmpsxp);
}
else
es_fprintf (listfp, "\tskey[%d]: [s-expression %lu octets]\n",
npkey, pktlen);
}
pk->pkey[npkey] = gcry_mpi_set_opaque (NULL,
tmpp, tmpp? pktlen * 8 : 0);
pktlen = 0;
}
else if (ski->is_protected) else if (ski->is_protected)
{ {
void *tmpp; void *tmpp;