g10: factor out a function for secret key retrieval.

* g10/export.c (receive_seckey_from_agent): New.
(do_export_stream): Use it.

--

Also fixed a memory leak of WRAPPEDKEY on a successful path of
build_packet.

In the log message, key is now by a hexgrip instead of a format by
keystr_with_sub.
This commit is contained in:
NIIBE Yutaka 2015-12-17 13:03:56 +09:00
parent fc010b6c7f
commit e644aa7f59
1 changed files with 83 additions and 70 deletions

View File

@ -825,6 +825,78 @@ print_status_exported (PKT_public_key *pk)
}
/*
* Receive a secret key from agent specified by HEXGRIP.
*
* Since the key data from agant is encrypted, decrypt it by CIPHERHD.
* Then, parse the decrypted key data in transfer format, and put
* secret papameters into PK.
*
* CACHE_NONCE_ADDR is used to share nonce for multple key retrievals.
*/
gpg_error_t
receive_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd,
char **cache_nonce_addr, const char *hexgrip,
PKT_public_key *pk)
{
gpg_error_t err = 0;
unsigned char *wrappedkey = NULL;
size_t wrappedkeylen;
unsigned char *key = NULL;
size_t keylen, realkeylen;
gcry_sexp_t s_skey;
char *prompt;
if (opt.verbose)
log_info ("key %s: asking agent for the secret parts\n", hexgrip);
prompt = gpg_format_keydesc (pk, FORMAT_KEYDESC_EXPORT,1);
err = agent_export_key (ctrl, hexgrip, prompt, cache_nonce_addr,
&wrappedkey, &wrappedkeylen);
xfree (prompt);
if (err)
goto unwraperror;
if (wrappedkeylen < 24)
{
err = gpg_error (GPG_ERR_INV_LENGTH);
goto unwraperror;
}
keylen = wrappedkeylen - 8;
key = xtrymalloc_secure (keylen);
if (!key)
{
err = gpg_error_from_syserror ();
goto unwraperror;
}
err = gcry_cipher_decrypt (cipherhd, key, keylen, wrappedkey, wrappedkeylen);
if (err)
goto unwraperror;
realkeylen = gcry_sexp_canon_len (key, keylen, NULL, &err);
if (!realkeylen)
goto unwraperror; /* Invalid csexp. */
err = gcry_sexp_sscan (&s_skey, NULL, key, realkeylen);
if (!err)
{
err = transfer_format_to_openpgp (s_skey, pk);
gcry_sexp_release (s_skey);
}
unwraperror:
xfree (key);
xfree (wrappedkey);
if (err)
{
log_error ("key %s: error receiving key from agent:"
" %s%s\n", hexgrip, gpg_strerror (err),
gpg_err_code (err) == GPG_ERR_FULLY_CANCELED?
"":_(" - skipped"));
}
return err;
}
/* Export the keys identified by the list of strings in USERS to the
stream OUT. If Secret is false public keys will be exported. With
secret true secret keys will be exported; in this case 1 means the
@ -1203,83 +1275,24 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
}
else if (!err)
{
/* FIXME: Move this spaghetti code into a separate
function. */
unsigned char *wrappedkey = NULL;
size_t wrappedkeylen;
unsigned char *key = NULL;
size_t keylen, realkeylen;
gcry_sexp_t s_skey;
if (opt.verbose)
log_info ("key %s: asking agent for the secret parts\n",
keystr_with_sub (keyid, subkid));
{
char *prompt = gpg_format_keydesc (pk,
FORMAT_KEYDESC_EXPORT,1);
err = agent_export_key (ctrl, hexgrip, prompt, &cache_nonce,
&wrappedkey, &wrappedkeylen);
xfree (prompt);
}
if (err)
goto unwraperror;
if (wrappedkeylen < 24)
{
err = gpg_error (GPG_ERR_INV_LENGTH);
goto unwraperror;
}
keylen = wrappedkeylen - 8;
key = xtrymalloc_secure (keylen);
if (!key)
{
err = gpg_error_from_syserror ();
goto unwraperror;
}
err = gcry_cipher_decrypt (cipherhd, key, keylen,
wrappedkey, wrappedkeylen);
if (err)
goto unwraperror;
realkeylen = gcry_sexp_canon_len (key, keylen, NULL, &err);
if (!realkeylen)
goto unwraperror; /* Invalid csexp. */
err = gcry_sexp_sscan (&s_skey, NULL, key, realkeylen);
xfree (key);
key = NULL;
if (err)
goto unwraperror;
err = transfer_format_to_openpgp (s_skey, pk);
gcry_sexp_release (s_skey);
if (err)
goto unwraperror;
err = build_packet (out, node->pkt);
if (!err && node->pkt->pkttype == PKT_PUBLIC_KEY)
{
stats->exported++;
print_status_exported (node->pkt->pkt.public_key);
}
goto unwraperror_leave;
unwraperror:
xfree (wrappedkey);
xfree (key);
err = receive_seckey_from_agent (ctrl, cipherhd, &cache_nonce,
hexgrip, pk);
if (err)
{
log_error ("key %s: error receiving key from agent:"
" %s%s\n",
keystr_with_sub (keyid, subkid),
gpg_strerror (err),
gpg_err_code (err) == GPG_ERR_FULLY_CANCELED?
"":_(" - skipped"));
if (gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
goto leave;
skip_until_subkey = 1;
err = 0;
}
unwraperror_leave:
;
else
{
err = build_packet (out, node->pkt);
if (node->pkt->pkttype == PKT_PUBLIC_KEY)
{
stats->exported++;
print_status_exported (node->pkt->pkt.public_key);
}
}
}
else
{