Import OpenPGP keys into the agent.

This commit is contained in:
Werner Koch 2010-08-31 15:58:39 +00:00
parent 71bc88fbae
commit 87fac99112
23 changed files with 1669 additions and 282 deletions

4
NEWS
View File

@ -37,6 +37,10 @@ Noteworthy changes in version 2.1.x (under development)
* Fixed output of "gpgconf --check-options".
* GPG does not anymore use secring.gpg but delegates all secret key
operations to gpg-agent. The import command moves secret keys to
the agent.
Noteworthy changes in version 2.0.13 (2009-09-04)
-------------------------------------------------

View File

@ -1,3 +1,18 @@
2010-08-31 Werner Koch <wk@g10code.com>
* pksign.c (do_encode_dsa): Fix sign problem.
* findkey.c (agent_is_dsa_key): Adjust to actual usage.
2010-08-30 Werner Koch <wk@g10code.com>
* protect.c (s2k_hash_passphrase): New public function.
2010-08-27 Werner Koch <wk@g10code.com>
* command.c (cmd_import_key): Support OpenPGP keys.
* cvt-openpgp.h, cvt-openpgp.c: New. Some of the code is based on
code taken from g10/seckey-cert.c.
2010-08-26 Werner Koch <wk@g10code.com>
* command-ssh.c (open_control_file): Use estream to create the file.

View File

@ -46,6 +46,7 @@ gpg_agent_SOURCES = \
protect.c \
trustlist.c \
divert-scd.c \
cvt-openpgp.c cvt-openpgp.h \
call-scd.c \
learncard.c

View File

@ -171,8 +171,8 @@ struct pin_entry_info_s
int with_qualitybar; /* Set if the quality bar should be displayed. */
int (*check_cb)(struct pin_entry_info_s *); /* CB used to check the PIN */
void *check_cb_arg; /* optional argument which might be of use in the CB */
const char *cb_errtext; /* used by the cb to displaye a specific error */
size_t max_length; /* allocated length of the buffer */
const char *cb_errtext; /* used by the cb to display a specific error */
size_t max_length; /* allocated length of the buffer */
char pin[1];
};
@ -306,6 +306,11 @@ int agent_get_shadow_info (const unsigned char *shadowkey,
unsigned char const **shadow_info);
gpg_error_t parse_shadow_info (const unsigned char *shadow_info,
char **r_hexsn, char **r_idstr);
gpg_error_t s2k_hash_passphrase (const char *passphrase, int hashalgo,
int s2kmode,
const unsigned char *s2ksalt,
unsigned int s2kcount,
unsigned char *key, size_t keylen);
/*-- trustlist.c --*/

View File

@ -37,7 +37,7 @@
#include "agent.h"
#include <assuan.h>
#include "i18n.h"
#include "cvt-openpgp.h"
/* Maximum allowed size of the inquired ciphertext. */
@ -357,6 +357,12 @@ leave_cmd (assuan_context_t ctx, gpg_error_t err)
const char *name = assuan_get_command_name (ctx);
if (!name)
name = "?";
/* Most code from common/ does not know the error source, thus
we fix this here. */
if (gpg_err_source (err) == GPG_ERR_SOURCE_UNKNOWN)
err = gpg_err_make (GPG_ERR_SOURCE_DEFAULT, gpg_err_code (err));
if (gpg_err_source (err) == GPG_ERR_SOURCE_DEFAULT)
log_error ("command '%s' failed: %s\n", name,
gpg_strerror (err));
@ -566,8 +572,8 @@ cmd_sigkey (assuan_context_t ctx, char *line)
static const char hlp_setkeydesc[] =
"SETKEYDESC plus_percent_escaped_string\n"
"\n"
"Set a description to be used for the next PKSIGN, PKDECRYPT or EXPORT_KEY\n"
"operation if this operation requires the entry of a passphrase. If\n"
"Set a description to be used for the next PKSIGN, PKDECRYPT, IMPORT_KEY\n"
"or EXPORT_KEY operation if this operation requires a passphrase. If\n"
"this command is not used a default text will be used. Note, that\n"
"this description implictly selects the label used for the entry\n"
"box; if the string contains the string PIN (which in general will\n"
@ -575,8 +581,8 @@ static const char hlp_setkeydesc[] =
"\"passphrase\" is used. The description string should not contain\n"
"blanks unless they are percent or '+' escaped.\n"
"\n"
"The description is only valid for the next PKSIGN, PKDECRYPT or\n"
"EXPORT_KEY operation.";
"The description is only valid for the next PKSIGN, PKDECRYPT,\n"
"IMPORT_KEY or EXPORT_KEY operation.";
static gpg_error_t
cmd_setkeydesc (assuan_context_t ctx, char *line)
{
@ -1478,6 +1484,7 @@ cmd_import_key (assuan_context_t ctx, char *line)
unsigned char *finalkey = NULL;
size_t finalkeylen;
unsigned char grip[20];
gcry_sexp_t openpgp_sexp = NULL;
(void)line;
@ -1528,20 +1535,58 @@ cmd_import_key (assuan_context_t ctx, char *line)
err = keygrip_from_canon_sexp (key, realkeylen, grip);
if (err)
goto leave;
if (!agent_key_available (grip))
{
err = gpg_error (GPG_ERR_EEXIST);
goto leave;
/* This might be due to an unsupported S-expression format.
Check whether this is openpgp-private-key and trigger that
import code. */
if (!gcry_sexp_sscan (&openpgp_sexp, NULL, key, realkeylen))
{
const char *tag;
size_t taglen;
tag = gcry_sexp_nth_data (openpgp_sexp, 0, &taglen);
if (tag && taglen == 19 && !memcmp (tag, "openpgp-private-key", 19))
;
else
{
gcry_sexp_release (openpgp_sexp);
openpgp_sexp = NULL;
}
}
if (!openpgp_sexp)
goto leave; /* Note that ERR is still set. */
}
err = agent_ask_new_passphrase
(ctrl, _("Please enter the passphrase to protect the "
"imported object within the GnuPG system."),
&passphrase);
if (err)
goto leave;
if (openpgp_sexp)
{
/* In most cases the key is encrypted and thus the conversion
function from the OpenPGP format to our internal format will
ask for a passphrase. That passphrase will be returned and
used to protect the key using the same code as for regular
key import. */
err = convert_openpgp (ctrl, openpgp_sexp, grip,
ctrl->server_local->keydesc,
&key, &passphrase);
if (err)
goto leave;
realkeylen = gcry_sexp_canon_len (key, keylen, NULL, &err);
if (!realkeylen)
goto leave; /* Invalid canonical encoded S-expression. */
}
else
{
if (!agent_key_available (grip))
err = gpg_error (GPG_ERR_EEXIST);
else
err = agent_ask_new_passphrase
(ctrl, _("Please enter the passphrase to protect the "
"imported object within the GnuPG system."),
&passphrase);
if (err)
goto leave;
}
if (passphrase)
{
@ -1553,11 +1598,14 @@ cmd_import_key (assuan_context_t ctx, char *line)
err = agent_write_private_key (grip, key, realkeylen, 0);
leave:
gcry_sexp_release (openpgp_sexp);
xfree (finalkey);
xfree (passphrase);
xfree (key);
gcry_cipher_close (cipherhd);
xfree (wrappedkey);
xfree (ctrl->server_local->keydesc);
ctrl->server_local->keydesc = NULL;
return leave_cmd (ctx, err);
}

807
agent/cvt-openpgp.c Normal file
View File

@ -0,0 +1,807 @@
/* cvt-openpgp.c - Convert an OpenPGP key to our internal format.
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2006, 2009,
* 2010 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "agent.h"
#include "i18n.h"
#include "cvt-openpgp.h"
/* Helper to pass data via the callback to do_unprotect. */
struct try_do_unprotect_arg_s
{
int is_v4;
int is_protected;
int pubkey_algo;
int protect_algo;
char *iv;
int ivlen;
int s2k_mode;
int s2k_algo;
byte *s2k_salt;
u32 s2k_count;
u16 desired_csum;
gcry_mpi_t *skey;
size_t skeysize;
int skeyidx;
gcry_sexp_t *r_key;
};
/* Compute the keygrip from the public key and store it at GRIP. */
static gpg_error_t
get_keygrip (int pubkey_algo, gcry_mpi_t *pkey, unsigned char *grip)
{
gpg_error_t err;
gcry_sexp_t s_pkey = NULL;
switch (pubkey_algo)
{
case GCRY_PK_DSA:
err = gcry_sexp_build (&s_pkey, NULL,
"(public-key(dsa(p%m)(q%m)(g%m)(y%m)))",
pkey[0], pkey[1], pkey[2], pkey[3]);
break;
case GCRY_PK_ELG:
case GCRY_PK_ELG_E:
err = gcry_sexp_build (&s_pkey, NULL,
"(public-key(elg(p%m)(g%m)(y%m)))",
pkey[0], pkey[1], pkey[2]);
break;
case GCRY_PK_RSA:
case GCRY_PK_RSA_E:
case GCRY_PK_RSA_S:
err = gcry_sexp_build (&s_pkey, NULL,
"(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]);
break;
default:
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
break;
}
if (!err && !gcry_pk_get_keygrip (s_pkey, grip))
err = gpg_error (GPG_ERR_INTERNAL);
gcry_sexp_release (s_pkey);
return err;
}
/* Convert a secret key given as algorithm id and an array of key
parameters into our s-expression based format. */
static gpg_error_t
convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey)
{
gpg_error_t err;
gcry_sexp_t s_skey = NULL;
*r_key = NULL;
switch (pubkey_algo)
{
case GCRY_PK_DSA:
err = gcry_sexp_build (&s_skey, NULL,
"(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
skey[0], skey[1], skey[2], skey[3], skey[4]);
break;
case GCRY_PK_ELG:
case GCRY_PK_ELG_E:
err = gcry_sexp_build (&s_skey, NULL,
"(private-key(elg(p%m)(g%m)(y%m)(x%m)))",
skey[0], skey[1], skey[2], skey[3]);
break;
case GCRY_PK_RSA:
case GCRY_PK_RSA_E:
case GCRY_PK_RSA_S:
err = gcry_sexp_build (&s_skey, NULL,
"(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
skey[0], skey[1], skey[2], skey[3], skey[4],
skey[5]);
default:
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
break;
}
if (!err)
*r_key = s_skey;
return err;
}
/* Hash the passphrase and set the key. */
static gpg_error_t
hash_passphrase_and_set_key (const char *passphrase,
gcry_cipher_hd_t hd, int protect_algo,
int s2k_mode, int s2k_algo,
byte *s2k_salt, u32 s2k_count)
{
gpg_error_t err;
unsigned char *key;
size_t keylen;
keylen = gcry_cipher_get_algo_keylen (protect_algo);
if (!keylen)
return gpg_error (GPG_ERR_INTERNAL);
key = xtrymalloc_secure (keylen);
if (!key)
return gpg_error_from_syserror ();
err = s2k_hash_passphrase (passphrase,
s2k_algo, s2k_mode, s2k_salt, s2k_count,
key, keylen);
if (!err)
err = gcry_cipher_setkey (hd, key, keylen);
xfree (key);
return err;
}
static u16
checksum (const unsigned char *p, unsigned int n)
{
u16 a;
for (a=0; n; n-- )
a += *p++;
return a;
}
/* Note that this function modified SKEY. SKEYSIZE is the allocated
size of the array including the NULL item; this is used for a
bounds check. On success a converted key is stored at R_KEY. */
static int
do_unprotect (const char *passphrase,
int pkt_version, int pubkey_algo, int is_protected,
gcry_mpi_t *skey, size_t skeysize,
int protect_algo, void *protect_iv, size_t protect_ivlen,
int s2k_mode, int s2k_algo, byte *s2k_salt, u32 s2k_count,
u16 desired_csum, gcry_sexp_t *r_key)
{
gpg_error_t err;
size_t npkey, nskey, skeylen;
gcry_cipher_hd_t cipher_hd = NULL;
u16 actual_csum;
size_t nbytes;
int i;
gcry_mpi_t tmpmpi;
*r_key = NULL;
/* Count the actual number of MPIs is in the array and set the
remainder to NULL for easier processing later on. */
for (skeylen = 0; skey[skeylen]; skeylen++)
;
for (i=skeylen; i < skeysize; i++)
skey[i] = NULL;
/* Check some args. */
if (s2k_mode == 1001)
{
/* Stub key. */
log_info (_("secret key parts are not available\n"));
return gpg_error (GPG_ERR_UNUSABLE_SECKEY);
}
if (gcry_pk_test_algo (pubkey_algo))
{
/* The algorithm numbers are Libgcrypt numbers but fortunately
the OpenPGP algorithm numbers map one-to-one to the Libgcrypt
numbers. */
log_info (_("public key algorithm %d (%s) is not supported\n"),
pubkey_algo, gcry_pk_algo_name (pubkey_algo));
return gpg_error (GPG_ERR_PUBKEY_ALGO);
}
/* Get properties of the public key algorithm and do some
consistency checks. Note that we need at least NPKEY+1 elements
in the SKEY array. */
if ( (err = gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NPKEY,
NULL, &npkey))
|| (err = gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NSKEY,
NULL, &nskey)))
return err;
if (!npkey || npkey >= nskey)
return gpg_error (GPG_ERR_INTERNAL);
if (skeylen <= npkey)
return gpg_error (GPG_ERR_MISSING_VALUE);
if (nskey+1 >= skeysize)
return gpg_error (GPG_ERR_BUFFER_TOO_SHORT);
/* Check whether SKEY is at all protected. If it is not protected
merely verify the checksum. */
if (!is_protected)
{
unsigned char *buffer;
actual_csum = 0;
for (i=npkey; i < nskey; i++)
{
if (!skey[i] || gcry_mpi_get_flag (skey[i], GCRYMPI_FLAG_OPAQUE))
return gpg_error (GPG_ERR_BAD_SECKEY);
err = gcry_mpi_print (GCRYMPI_FMT_PGP, NULL, 0, &nbytes, skey[i]);
if (!err)
{
buffer = (gcry_is_secure (skey[i])?
xtrymalloc_secure (nbytes) : xtrymalloc (nbytes));
if (!buffer)
return gpg_error_from_syserror ();
err = gcry_mpi_print (GCRYMPI_FMT_PGP, buffer, nbytes,
NULL, skey[i]);
if (!err)
actual_csum += checksum (buffer, nbytes);
xfree (buffer);
}
if (err)
return err;
}
if (actual_csum != desired_csum)
return gpg_error (GPG_ERR_CHECKSUM);
return 0;
}
if (gcry_cipher_test_algo (protect_algo))
{
/* The algorithm numbers are Libgcrypt numbers but fortunately
the OpenPGP algorithm numbers map one-to-one to the Libgcrypt
numbers. */
log_info (_("protection algorithm %d (%s) is not supported\n"),
protect_algo, gcry_cipher_algo_name (protect_algo));
return gpg_error (GPG_ERR_CIPHER_ALGO);
}
if (gcry_md_test_algo (s2k_algo))
{
log_info (_("protection hash algorithm %d (%s) is not supported\n"),
s2k_algo, gcry_md_algo_name (s2k_algo));
return gpg_error (GPG_ERR_DIGEST_ALGO);
}
err = gcry_cipher_open (&cipher_hd, protect_algo,
GCRY_CIPHER_MODE_CFB,
(GCRY_CIPHER_SECURE
| (protect_algo >= 100 ?
0 : GCRY_CIPHER_ENABLE_SYNC)));
if (err)
{
log_error ("failed to open cipher_algo %d: %s\n",
protect_algo, gpg_strerror (err));
return err;
}
err = hash_passphrase_and_set_key (passphrase, cipher_hd, protect_algo,
s2k_mode, s2k_algo, s2k_salt, s2k_count);
if (err)
{
gcry_cipher_close (cipher_hd);
return err;
}
gcry_cipher_setiv (cipher_hd, protect_iv, protect_ivlen);
actual_csum = 0;
if (pkt_version >= 4)
{
int ndata;
unsigned int ndatabits;
unsigned char *p, *data;
u16 csum_pgp7 = 0;
if (!gcry_mpi_get_flag (skey[npkey], GCRYMPI_FLAG_OPAQUE ))
{
gcry_cipher_close (cipher_hd);
return gpg_error (GPG_ERR_BAD_SECKEY);
}
p = gcry_mpi_get_opaque (skey[npkey], &ndatabits);
ndata = (ndatabits+7)/8;
if (ndata > 1)
csum_pgp7 = p[ndata-2] << 8 | p[ndata-1];
data = xtrymalloc_secure (ndata);
if (!data)
{
err = gpg_error_from_syserror ();
gcry_cipher_close (cipher_hd);
return err;
}
gcry_cipher_decrypt (cipher_hd, data, ndata, p, ndata);
p = data;
if (is_protected == 2)
{
/* This is the new SHA1 checksum method to detect tampering
with the key as used by the Klima/Rosa attack. */
desired_csum = 0;
actual_csum = 1; /* Default to bad checksum. */
if (ndata < 20)
log_error ("not enough bytes for SHA-1 checksum\n");
else
{
gcry_md_hd_t h;
if (gcry_md_open (&h, GCRY_MD_SHA1, 1))
BUG(); /* Algo not available. */
gcry_md_write (h, data, ndata - 20);
gcry_md_final (h);
if (!memcmp (gcry_md_read (h, GCRY_MD_SHA1), data+ndata-20, 20))
actual_csum = 0; /* Digest does match. */
gcry_md_close (h);
}
}
else
{
/* Old 16 bit checksum method. */
if (ndata < 2)
{
log_error ("not enough bytes for checksum\n");
desired_csum = 0;
actual_csum = 1; /* Mark checksum bad. */
}
else
{
desired_csum = (data[ndata-2] << 8 | data[ndata-1]);
actual_csum = checksum (data, ndata-2);
if (desired_csum != actual_csum)
{
/* This is a PGP 7.0.0 workaround */
desired_csum = csum_pgp7; /* Take the encrypted one. */
}
}
}
/* Better check it here. Otherwise the gcry_mpi_scan would fail
because the length may have an arbitrary value. */
if (desired_csum == actual_csum)
{
for (i=npkey; i < nskey; i++ )
{
if (gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_PGP, p, ndata, &nbytes))
{
/* Checksum was okay, but not correctly decrypted. */
desired_csum = 0;
actual_csum = 1; /* Mark checksum bad. */
break;
}
gcry_mpi_release (skey[i]);
skey[i] = tmpmpi;
ndata -= nbytes;
p += nbytes;
}
skey[i] = NULL;
skeylen = i;
assert (skeylen <= skeysize);
/* Note: at this point NDATA should be 2 for a simple
checksum or 20 for the sha1 digest. */
}
xfree(data);
}
else /* Packet version <= 3. */
{
unsigned char *buffer;
for (i = npkey; i < nskey; i++)
{
unsigned char *p;
size_t ndata;
unsigned int ndatabits;
if (!skey[i] || !gcry_mpi_get_flag (skey[i], GCRYMPI_FLAG_OPAQUE))
{
gcry_cipher_close (cipher_hd);
return gpg_error (GPG_ERR_BAD_SECKEY);
}
p = gcry_mpi_get_opaque (skey[i], &ndatabits);
ndata = (ndatabits+7)/8;
if (!(ndata >= 2) || !(ndata == ((p[0] << 8 | p[1]) + 7)/8 + 2))
{
gcry_cipher_close (cipher_hd);
return gpg_error (GPG_ERR_BAD_SECKEY);
}
buffer = xtrymalloc_secure (ndata);
if (!buffer)
{
err = gpg_error_from_syserror ();
gcry_cipher_close (cipher_hd);
return err;
}
gcry_cipher_sync (cipher_hd);
buffer[0] = p[0];
buffer[1] = p[1];
gcry_cipher_decrypt (cipher_hd, buffer+2, ndata-2, p+2, ndata-2);
actual_csum += checksum (buffer, ndata);
err = gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_PGP, buffer, ndata, &ndata);
xfree (buffer);
if (err)
{
/* Checksum was okay, but not correctly decrypted. */
desired_csum = 0;
actual_csum = 1; /* Mark checksum bad. */
break;
}
gcry_mpi_release (skey[i]);
skey[i] = tmpmpi;
}
}
gcry_cipher_close (cipher_hd);
/* Now let's see whether we have used the correct passphrase. */
if (actual_csum != desired_csum)
return gpg_error (GPG_ERR_BAD_PASSPHRASE);
if (nskey != skeylen)
err = gpg_error (GPG_ERR_BAD_SECKEY);
else
err = convert_secret_key (r_key, pubkey_algo, skey);
if (err)
return err;
/* The checksum may fail, thus we also check the key itself. */
err = gcry_pk_testkey (*r_key);
if (err)
{
gcry_sexp_release (*r_key);
*r_key = NULL;
return gpg_error (GPG_ERR_BAD_PASSPHRASE);
}
return 0;
}
/* Callback function to try the unprotection from the passpharse query
code. */
static int
try_do_unprotect_cb (struct pin_entry_info_s *pi)
{
gpg_error_t err;
struct try_do_unprotect_arg_s *arg = pi->check_cb_arg;
err = do_unprotect (pi->pin, arg->is_v4? 4:3,
arg->pubkey_algo, arg->is_protected,
arg->skey, arg->skeysize,
arg->protect_algo, arg->iv, arg->ivlen,
arg->s2k_mode, arg->s2k_algo,
arg->s2k_salt, arg->s2k_count,
arg->desired_csum, arg->r_key);
/* SKEY may be modified now, thus we need to re-compute SKEYIDX. */
for (arg->skeyidx = 0; (arg->skeyidx < arg->skeysize
&& arg->skey[arg->skeyidx]); arg->skeyidx++)
;
return err;
}
/* Convert an OpenPGP transfer key into our internal format. Before
asking for a passphrase we check whether the key already exists in
our key storage. S_PGP is the OpenPGP key in transfer format. On
success R_KEY will receive a canonical encoded S-expression with
the unprotected key in our internal format; the caller needs to
release that memory. The passphrase used to decrypt the OpenPGP
key will be returned at R_PASSPHRASE; the caller must release this
passphrase. The keygrip will be stored at the 20 byte buffer
pointed to by GRIP. On error NULL is stored at all return
arguments. */
gpg_error_t
convert_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp,
unsigned char *grip, const char *prompt,
unsigned char **r_key, char **r_passphrase)
{
gpg_error_t err;
gcry_sexp_t top_list;
gcry_sexp_t list = NULL;
const char *value;
size_t valuelen;
char *string;
int idx;
int is_v4, is_protected;
int pubkey_algo;
int protect_algo = 0;
char iv[16];
int ivlen = 0;
int s2k_mode = 0;
int s2k_algo = 0;
byte s2k_salt[8];
u32 s2k_count = 0;
size_t npkey, nskey;
gcry_mpi_t skey[10]; /* We support up to 9 parameters. */
u16 desired_csum;
int skeyidx = 0;
gcry_sexp_t s_skey;
struct pin_entry_info_s *pi;
struct try_do_unprotect_arg_s pi_arg;
*r_key = NULL;
*r_passphrase = NULL;
top_list = gcry_sexp_find_token (s_pgp, "openpgp-private-key", 0);
if (!top_list)
goto bad_seckey;
list = gcry_sexp_find_token (top_list, "version", 0);
if (!list)
goto bad_seckey;
value = gcry_sexp_nth_data (list, 1, &valuelen);
if (!value || valuelen != 1 || !(value[0] == '3' || value[0] == '4'))
goto bad_seckey;
is_v4 = (value[0] == '4');
gcry_sexp_release (list);
list = gcry_sexp_find_token (top_list, "protection", 0);
if (!list)
goto bad_seckey;
value = gcry_sexp_nth_data (list, 1, &valuelen);
if (!value)
goto bad_seckey;
if (valuelen == 4 && !memcmp (value, "sha1", 4))
is_protected = 2;
else if (valuelen == 3 && !memcmp (value, "sum", 3))
is_protected = 1;
else if (valuelen == 4 && !memcmp (value, "none", 4))
is_protected = 0;
else
goto bad_seckey;
if (is_protected)
{
string = gcry_sexp_nth_string (list, 2);
if (!string)
goto bad_seckey;
protect_algo = gcry_cipher_map_name (string);
if (!protect_algo && !!strcmp (string, "IDEA"))
protect_algo = GCRY_CIPHER_IDEA;
xfree (string);
value = gcry_sexp_nth_data (list, 3, &valuelen);
if (!value || !valuelen || valuelen > sizeof iv)
goto bad_seckey;
memcpy (iv, value, valuelen);
ivlen = valuelen;
string = gcry_sexp_nth_string (list, 4);
if (!string)
goto bad_seckey;
s2k_mode = strtol (string, NULL, 10);
xfree (string);
string = gcry_sexp_nth_string (list, 5);
if (!string)
goto bad_seckey;
s2k_algo = gcry_md_map_name (string);
xfree (string);
value = gcry_sexp_nth_data (list, 6, &valuelen);
if (!value || !valuelen || valuelen > sizeof s2k_salt)
goto bad_seckey;
memcpy (s2k_salt, value, valuelen);
string = gcry_sexp_nth_string (list, 7);
if (!string)
goto bad_seckey;
s2k_count = strtoul (string, NULL, 10);
xfree (string);
}
gcry_sexp_release (list);
list = gcry_sexp_find_token (top_list, "algo", 0);
if (!list)
goto bad_seckey;
string = gcry_sexp_nth_string (list, 1);
if (!string)
goto bad_seckey;
pubkey_algo = gcry_pk_map_name (string);
xfree (string);
if (gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &npkey)
|| gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NSKEY, NULL, &nskey)
|| !npkey || npkey >= nskey)
goto bad_seckey;
gcry_sexp_release (list);
list = gcry_sexp_find_token (top_list, "skey", 0);
if (!list)
goto bad_seckey;
for (idx=0;;)
{
int is_enc;
value = gcry_sexp_nth_data (list, ++idx, &valuelen);
if (!value && skeyidx >= npkey)
break; /* Ready. */
/* Check for too many parameters. Note that depending on the
protection mode and version number we may see less than NSKEY
(but at least NPKEY+1) parameters. */
if (idx >= 2*nskey)
goto bad_seckey;
if (skeyidx >= DIM (skey)-1)
goto bad_seckey;
if (!value || valuelen != 1 || !(value[0] == '_' || value[0] == 'e'))
goto bad_seckey;
is_enc = (value[0] == 'e');
value = gcry_sexp_nth_data (list, ++idx, &valuelen);
if (!value || !valuelen)
goto bad_seckey;
if (is_enc)
{
void *p = xtrymalloc (valuelen);
if (!p)
goto outofmem;
memcpy (p, value, valuelen);
skey[skeyidx] = gcry_mpi_set_opaque (NULL, p, valuelen*8);
if (!skey[skeyidx])
goto outofmem;
}
else
{
if (gcry_mpi_scan (skey + skeyidx, GCRYMPI_FMT_STD,
value, valuelen, NULL))
goto bad_seckey;
}
skeyidx++;
}
skey[skeyidx++] = NULL;
gcry_sexp_release (list);
list = gcry_sexp_find_token (top_list, "csum", 0);
if (list)
{
string = gcry_sexp_nth_string (list, 1);
if (!string)
goto bad_seckey;
desired_csum = strtoul (string, NULL, 10);
xfree (string);
}
else
desired_csum = 0;
gcry_sexp_release (list); list = NULL;
gcry_sexp_release (top_list); top_list = NULL;
/* log_debug ("XXX is_v4=%d\n", is_v4); */
/* log_debug ("XXX pubkey_algo=%d\n", pubkey_algo); */
/* log_debug ("XXX is_protected=%d\n", is_protected); */
/* log_debug ("XXX protect_algo=%d\n", protect_algo); */
/* log_printhex ("XXX iv", iv, ivlen); */
/* log_debug ("XXX ivlen=%d\n", ivlen); */
/* log_debug ("XXX s2k_mode=%d\n", s2k_mode); */
/* log_debug ("XXX s2k_algo=%d\n", s2k_algo); */
/* log_printhex ("XXX s2k_salt", s2k_salt, sizeof s2k_salt); */
/* log_debug ("XXX s2k_count=%lu\n", (unsigned long)s2k_count); */
/* for (idx=0; skey[idx]; idx++) */
/* { */
/* int is_enc = gcry_mpi_get_flag (skey[idx], GCRYMPI_FLAG_OPAQUE); */
/* log_info ("XXX skey[%d]%s:", idx, is_enc? " (enc)":""); */
/* if (is_enc) */
/* { */
/* void *p; */
/* unsigned int nbits; */
/* p = gcry_mpi_get_opaque (skey[idx], &nbits); */
/* log_printhex (NULL, p, (nbits+7)/8); */
/* } */
/* else */
/* gcry_mpi_dump (skey[idx]); */
/* log_printf ("\n"); */
/* } */
err = get_keygrip (pubkey_algo, skey, grip);
if (err)
goto leave;
if (!agent_key_available (grip))
{
err = gpg_error (GPG_ERR_EEXIST);
goto leave;
}
pi = xtrycalloc_secure (1, sizeof (*pi) + 100);
if (!pi)
return gpg_error_from_syserror ();
pi->max_length = 100;
pi->min_digits = 0; /* We want a real passphrase. */
pi->max_digits = 16;
pi->max_tries = 3;
pi->check_cb = try_do_unprotect_cb;
pi->check_cb_arg = &pi_arg;
pi_arg.is_v4 = is_v4;
pi_arg.is_protected = is_protected;
pi_arg.pubkey_algo = pubkey_algo;
pi_arg.protect_algo = protect_algo;
pi_arg.iv = iv;
pi_arg.ivlen = ivlen;
pi_arg.s2k_mode = s2k_mode;
pi_arg.s2k_algo = s2k_algo;
pi_arg.s2k_salt = s2k_salt;
pi_arg.s2k_count = s2k_count;
pi_arg.desired_csum = desired_csum;
pi_arg.skey = skey;
pi_arg.skeysize = DIM (skey);
pi_arg.skeyidx = skeyidx;
pi_arg.r_key = &s_skey;
err = agent_askpin (ctrl, prompt, NULL, NULL, pi);
skeyidx = pi_arg.skeyidx;
if (!err)
{
*r_passphrase = xtrystrdup (pi->pin);
if (!*r_passphrase)
err = gpg_error_from_syserror ();
}
xfree (pi);
if (err)
goto leave;
/* Save some memory and get rid of the SKEY array now. */
for (idx=0; idx < skeyidx; idx++)
gcry_mpi_release (skey[idx]);
skeyidx = 0;
/* Note that the padding is not required - we use it only because
that function allows us to created the result in secure memory. */
err = make_canon_sexp_pad (s_skey, 1, r_key, NULL);
gcry_sexp_release (s_skey);
leave:
gcry_sexp_release (list);
gcry_sexp_release (top_list);
for (idx=0; idx < skeyidx; idx++)
gcry_mpi_release (skey[idx]);
if (err)
{
xfree (*r_passphrase);
*r_passphrase = NULL;
}
return err;
bad_seckey:
err = gpg_error (GPG_ERR_BAD_SECKEY);
goto leave;
outofmem:
err = gpg_error (GPG_ERR_ENOMEM);
goto leave;
}

27
agent/cvt-openpgp.h Normal file
View File

@ -0,0 +1,27 @@
/* cvt-openpgp.h - Convert an OpenPGP key to our internal format.
* Copyright (C) 2010 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GNUPG_AGENT_CVT_OPENPGP_H
#define GNUPG_AGENT_CVT_OPENPGP_H
gpg_error_t convert_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp,
unsigned char *grip, const char *prompt,
unsigned char **r_key, char **r_passphrase);
#endif /*GNUPG_AGENT_CVT_OPENPGP_H*/

View File

@ -702,7 +702,8 @@ key_parms_from_sexp (gcry_sexp_t s_key, gcry_sexp_t *r_list,
}
/* Return true if S_KEY is a DSA style key. */
/* Return the public key algorithm number if S_KEY is a DSA style key.
If it is not a DSA style key, return 0. */
int
agent_is_dsa_key (gcry_sexp_t s_key)
{
@ -714,7 +715,12 @@ agent_is_dsa_key (gcry_sexp_t s_key)
if (key_parms_from_sexp (s_key, NULL, algoname, sizeof algoname, NULL, 0))
return 0; /* Error - assume it is not an DSA key. */
return (!strcmp (algoname, "dsa") || !strcmp (algoname, "ecdsa"));
if (!strcmp (algoname, "dsa"))
return GCRY_PK_DSA;
else if (!strcmp (algoname, "ecdsa"))
return GCRY_PK_ECDSA;
else
return 0;
}

View File

@ -159,7 +159,34 @@ second list with the information has this layout:
More items may be added to the list.
OpenPGP Private Key Transfer Format
===================================
This format is used to transfer keys between gpg and gpg-agent.
(openpgp-private-key
(version V)
(protection PROTTYPE PROTALGO IV S2KMODE S2KHASH S2KSALT S2KCOUNT)
(algo PUBKEYALGO)
(skey CSUM c P1 c P2 c P3 ... e PN))
* V is the packet version number (3 or 4).
* PUBKEYALGO is a Libgcrypt algo name
* CSUM is the 16 bit checksum as defined by OpenPGP.
* P1 .. PN are the parameters; the public parameters are never encrypted
the secrect key parameters are encrypted if the "protection" list is
given. To make this more explicit each parameter is preceded by a
flag "_" for cleartext or "e" for encrypted text.
* If PROTTYPE is "sha1" the new style SHA1 checksum is used if it is "sum"
the old 16 bit checksum is used and if it is "none" no protection at
all is used.
* PROTALGO is a Libgcrypt style cipher algorithm name
* IV is the initialization verctor.
* S2KMODE is the value from RFC-4880.
* S2KHASH is a a libgcrypt style hash algorithm identifier.
* S2KSALT is the 8 byte salt
* S2KCOUNT is the count value from RFC-4880.

View File

@ -164,10 +164,22 @@ do_encode_dsa (const byte * md, size_t mdlen, int dsaalgo, gcry_sexp_t pkey,
if (mdlen > qbits/8)
mdlen = qbits/8;
/* Create the S-expression. */
err = gcry_sexp_build (&hash, NULL,
"(data (flags raw) (value %b))",
(int)mdlen, md);
/* Create the S-expression. We need to convert to an MPI first
because we want an unsigned integer. Using %b directly is not
possible because libgcrypt assumes an mpi and uses
GCRYMPI_FMT_STD for parsing and thus possible yielding a negative
value. */
{
gcry_mpi_t mpi;
err = gcry_mpi_scan (&mpi, GCRYMPI_FMT_USG, md, mdlen, NULL);
if (!err)
{
err = gcry_sexp_build (&hash, NULL,
"(data (flags raw) (value %m))", mpi);
gcry_mpi_release (mpi);
}
}
if (!err)
*r_hash = hash;
return err;
@ -304,8 +316,10 @@ agent_pksign_do (ctrl_t ctrl, const char *desc_text,
if (DBG_CRYPTO)
{
log_debug ("skey: ");
log_debug ("skey:\n");
gcry_sexp_dump (s_skey);
log_debug ("hash:\n");
gcry_sexp_dump (s_hash);
}
/* sign */
@ -319,7 +333,7 @@ agent_pksign_do (ctrl_t ctrl, const char *desc_text,
if (DBG_CRYPTO)
{
log_debug ("result: ");
log_debug ("result:\n");
gcry_sexp_dump (s_sig);
}
}

View File

@ -73,6 +73,8 @@ hash_passphrase (const char *passphrase, int hashalgo,
const unsigned char *s2ksalt, unsigned long s2kcount,
unsigned char *key, size_t keylen);
/* Get the process time and store it in DATA. */
static void
calibrate_get_time (struct calibrate_time_s *data)
@ -1076,6 +1078,19 @@ hash_passphrase (const char *passphrase, int hashalgo,
}
gpg_error_t
s2k_hash_passphrase (const char *passphrase, int hashalgo,
int s2kmode,
const unsigned char *s2ksalt,
unsigned int s2kcount,
unsigned char *key, size_t keylen)
{
return hash_passphrase (passphrase, hashalgo, s2kmode, s2ksalt,
(16ul + (s2kcount & 15)) << ((s2kcount >> 4) + 6),
key, keylen);
}
/* Create an canonical encoded S-expression with the shadow info from

View File

@ -1,3 +1,32 @@
2010-08-30 Werner Koch <wk@g10code.com>
* keyid.c (KEYID_STR_SIZE): New
(keystr): Use snprintf and new macro.
(keystr_with_sub): New.
(keystr_from_sk_with_sub): New.
(keystr_from_pk_with_sub): New.
2010-08-27 Werner Koch <wk@g10code.com>
* gpg.c (main): Change scope of CTRL to the entire function.
* import.c (import_secret_one, import, import_keys_internal)
(import_keys, import_keys_stream): Add arg CTRL.
* call-agent.c (agent_keywrap_key): New.
(agent_import_key, inq_import_key_parms): New.
2010-08-26 Werner Koch <wk@g10code.com>
* misc.c (openpgp_pk_algo_name): New.
(openpgp_md_algo_name): New.
2010-08-24 Werner Koch <wk@g10code.com>
* options.h (IMPORT_SK2PK): Remove.
* import.c (parse_import_options): Turn convert-sk-to-pk into a
dummy option.
(sec_to_pub_keyblock): Use modern functions.
2010-08-16 Werner Koch <wk@g10code.com>
* gpg.c (list_config, gpgconf_list): Use es_printf.

View File

@ -77,6 +77,13 @@ struct genkey_parm_s
const char *keyparms;
};
struct import_key_parm_s
{
ctrl_t ctrl;
assuan_context_t ctx;
const void *key;
size_t keylen;
};
static gpg_error_t learn_status_cb (void *opaque, const char *line);
@ -1706,3 +1713,97 @@ agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
*r_buf = buf;
return 0;
}
/* Retrieve a key encryption key from the agent. With FOREXPORT true
the key shall be used for export, with false for import. On success
the new key is stored at R_KEY and its length at R_KEKLEN. */
gpg_error_t
agent_keywrap_key (ctrl_t ctrl, int forexport, void **r_kek, size_t *r_keklen)
{
gpg_error_t err;
membuf_t data;
size_t len;
unsigned char *buf;
char line[ASSUAN_LINELENGTH];
*r_kek = NULL;
err = start_agent (ctrl, 0);
if (err)
return err;
snprintf (line, DIM(line)-1, "KEYWRAP_KEY %s",
forexport? "--export":"--import");
init_membuf_secure (&data, 64);
err = assuan_transact (agent_ctx, line,
membuf_data_cb, &data,
default_inq_cb, ctrl, NULL, NULL);
if (err)
{
xfree (get_membuf (&data, &len));
return err;
}
buf = get_membuf (&data, &len);
if (!buf)
return gpg_error_from_syserror ();
*r_kek = buf;
*r_keklen = len;
return 0;
}
/* Handle the inquiry for an IMPORT_KEY command. */
static gpg_error_t
inq_import_key_parms (void *opaque, const char *line)
{
struct import_key_parm_s *parm = opaque;
gpg_error_t err;
if (!strncmp (line, "KEYDATA", 7) && (line[7]==' '||!line[7]))
{
err = assuan_send_data (parm->ctx, parm->key, parm->keylen);
}
else
err = default_inq_cb (parm->ctrl, line);
return err;
}
/* Call the agent to import a key into the agent. */
gpg_error_t
agent_import_key (ctrl_t ctrl, const char *desc, const void *key, size_t keylen)
{
gpg_error_t err;
struct import_key_parm_s parm;
err = start_agent (ctrl, 0);
if (err)
return err;
if (desc)
{
char line[ASSUAN_LINELENGTH];
snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
line[DIM(line)-1] = 0;
err = assuan_transact (agent_ctx, line,
NULL, NULL, NULL, NULL, NULL, NULL);
if (err)
return err;
}
parm.ctrl = ctrl;
parm.ctx = agent_ctx;
parm.key = key;
parm.keylen = keylen;
err = assuan_transact (agent_ctx, "IMPORT_KEY",
NULL, NULL, inq_import_key_parms, &parm, NULL, NULL);
return err;
}

View File

@ -163,6 +163,14 @@ gpg_error_t agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
gcry_sexp_t s_ciphertext,
unsigned char **r_buf, size_t *r_buflen);
/* Retrieve a key encryption key. */
gpg_error_t agent_keywrap_key (ctrl_t ctrl, int forexport,
void **r_kek, size_t *r_keklen);
/* Send a key to the agent. */
gpg_error_t agent_import_key (ctrl_t ctrl, const char *desc,
const void *key, size_t keylen);
#endif /*GNUPG_G10_CALL_AGENT_H*/

View File

@ -1925,6 +1925,7 @@ main (int argc, char **argv)
int any_explicit_recipient = 0;
int require_secmem=0,got_secmem=0;
struct assuan_malloc_hooks malloc_hooks;
ctrl_t ctrl;
#ifdef __riscos__
opt.lock_once = 1;
@ -1984,23 +1985,24 @@ main (int argc, char **argv)
opt.pgp2_workarounds = 1;
opt.escape_from = 1;
opt.flags.require_cross_cert = 1;
opt.import_options=IMPORT_SK2PK;
opt.export_options=EXPORT_ATTRIBUTES;
opt.keyserver_options.import_options=IMPORT_REPAIR_PKS_SUBKEY_BUG;
opt.keyserver_options.export_options=EXPORT_ATTRIBUTES;
opt.keyserver_options.options=
KEYSERVER_HONOR_KEYSERVER_URL|KEYSERVER_HONOR_PKA_RECORD;
opt.verify_options=
VERIFY_SHOW_POLICY_URLS|VERIFY_SHOW_STD_NOTATIONS|VERIFY_SHOW_KEYSERVER_URLS;
opt.trust_model=TM_AUTO;
opt.mangle_dos_filenames=0;
opt.min_cert_level=2;
set_screen_dimensions();
opt.keyid_format=KF_SHORT;
opt.def_sig_expire="0";
opt.def_cert_expire="0";
set_homedir ( default_homedir () );
opt.passphrase_repeat=1;
opt.import_options = 0;
opt.export_options = EXPORT_ATTRIBUTES;
opt.keyserver_options.import_options = IMPORT_REPAIR_PKS_SUBKEY_BUG;
opt.keyserver_options.export_options = EXPORT_ATTRIBUTES;
opt.keyserver_options.options = (KEYSERVER_HONOR_KEYSERVER_URL
| KEYSERVER_HONOR_PKA_RECORD );
opt.verify_options = (VERIFY_SHOW_POLICY_URLS
| VERIFY_SHOW_STD_NOTATIONS
| VERIFY_SHOW_KEYSERVER_URLS);
opt.trust_model = TM_AUTO;
opt.mangle_dos_filenames = 0;
opt.min_cert_level = 2;
set_screen_dimensions ();
opt.keyid_format = KF_SHORT;
opt.def_sig_expire = "0";
opt.def_cert_expire = "0";
set_homedir (default_homedir ());
opt.passphrase_repeat = 1;
/* Check whether we have a config file on the command line. */
orig_argc = argc;
@ -3403,6 +3405,9 @@ main (int argc, char **argv)
if(fname && utf8_strings)
opt.flags.utf8_filename=1;
ctrl = xtrycalloc (1, sizeof *ctrl);
gpg_init_default_ctrl (ctrl);
switch( cmd ) {
case aPrimegen:
case aPrintMD:
@ -3438,13 +3443,7 @@ main (int argc, char **argv)
switch( cmd )
{
case aServer:
{
ctrl_t ctrl = xtrycalloc (1, sizeof *ctrl);
gpg_init_default_ctrl (ctrl);
gpg_server (ctrl);
gpg_deinit_default_ctrl (ctrl);
xfree (ctrl);
}
gpg_server (ctrl);
break;
case aStore: /* only store the file */
@ -3704,7 +3703,7 @@ main (int argc, char **argv)
case aFastImport:
opt.import_options |= IMPORT_FAST;
case aImport:
import_keys( argc? argv:NULL, argc, NULL, opt.import_options );
import_keys (ctrl, argc? argv:NULL, argc, NULL, opt.import_options);
break;
/* TODO: There are a number of command that use this same
@ -4055,6 +4054,8 @@ main (int argc, char **argv)
}
/* cleanup */
gpg_deinit_default_ctrl (ctrl);
xfree (ctrl);
release_armor_context (afx);
FREE_STRLIST(remusr);
FREE_STRLIST(locusr);

View File

@ -1,6 +1,6 @@
/* import.c - import a key into our key storage.
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
* 2007 Free Software Foundation, Inc.
* 2007, 2010 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -37,6 +37,8 @@
#include "ttyio.h"
#include "status.h"
#include "keyserver-internal.h"
#include "call-agent.h"
#include "../common/membuf.h"
struct stats_s {
ulong count;
@ -58,14 +60,15 @@ struct stats_s {
};
static int import( IOBUF inp, const char* fname,struct stats_s *stats,
unsigned char **fpr,size_t *fpr_len,unsigned int options );
static int import (ctrl_t ctrl,
IOBUF inp, const char* fname, struct stats_s *stats,
unsigned char **fpr, size_t *fpr_len, unsigned int options);
static int read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root );
static void revocation_present(KBNODE keyblock);
static int import_one(const char *fname, KBNODE keyblock,struct stats_s *stats,
unsigned char **fpr,size_t *fpr_len,
unsigned int options,int from_sk);
static int import_secret_one( const char *fname, KBNODE keyblock,
static int import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock,
struct stats_s *stats, unsigned int options);
static int import_revoke_cert( const char *fname, KBNODE node,
struct stats_s *stats);
@ -96,8 +99,6 @@ parse_import_options(char *str,unsigned int *options,int noisy)
N_("repair damage from the pks keyserver during import")},
{"fast-import",IMPORT_FAST,NULL,
N_("do not update the trustdb after import")},
{"convert-sk-to-pk",IMPORT_SK2PK,NULL,
N_("create a public key when importing a secret key")},
{"merge-only",IMPORT_MERGE_ONLY,NULL,
N_("only accept updates to existing keys")},
{"import-clean",IMPORT_CLEAN,NULL,
@ -111,6 +112,7 @@ parse_import_options(char *str,unsigned int *options,int noisy)
{"import-unusable-sigs",0,NULL,NULL},
{"import-clean-sigs",0,NULL,NULL},
{"import-clean-uids",0,NULL,NULL},
{"convert-sk-to-pk",0, NULL,NULL},
{NULL,0,NULL,NULL}
};
@ -161,7 +163,7 @@ import_release_stats_handle (void *p)
*
*/
static int
import_keys_internal( IOBUF inp, char **fnames, int nnames,
import_keys_internal (ctrl_t ctrl, iobuf_t inp, char **fnames, int nnames,
void *stats_handle, unsigned char **fpr, size_t *fpr_len,
unsigned int options )
{
@ -172,7 +174,7 @@ import_keys_internal( IOBUF inp, char **fnames, int nnames,
stats = import_new_stats_handle ();
if (inp) {
rc = import( inp, "[stream]", stats, fpr, fpr_len, options);
rc = import (ctrl, inp, "[stream]", stats, fpr, fpr_len, options);
}
else {
if( !fnames && !nnames )
@ -193,7 +195,7 @@ import_keys_internal( IOBUF inp, char **fnames, int nnames,
log_error(_("can't open `%s': %s\n"), fname, strerror(errno) );
else
{
rc = import( inp2, fname, stats, fpr, fpr_len, options );
rc = import (ctrl, inp2, fname, stats, fpr, fpr_len, options);
iobuf_close(inp2);
/* Must invalidate that ugly cache to actually close it. */
iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE,
@ -224,21 +226,23 @@ import_keys_internal( IOBUF inp, char **fnames, int nnames,
}
void
import_keys( char **fnames, int nnames,
import_keys (ctrl_t ctrl, char **fnames, int nnames,
void *stats_handle, unsigned int options )
{
import_keys_internal(NULL,fnames,nnames,stats_handle,NULL,NULL,options);
import_keys_internal (ctrl, NULL, fnames, nnames, stats_handle,
NULL, NULL, options);
}
int
import_keys_stream( IOBUF inp, void *stats_handle,
unsigned char **fpr, size_t *fpr_len,unsigned int options )
import_keys_stream (ctrl_t ctrl, IOBUF inp, void *stats_handle,
unsigned char **fpr, size_t *fpr_len,unsigned int options)
{
return import_keys_internal(inp,NULL,0,stats_handle,fpr,fpr_len,options);
return import_keys_internal (ctrl, inp, NULL, 0, stats_handle,
fpr, fpr_len, options);
}
static int
import( IOBUF inp, const char* fname,struct stats_s *stats,
import (ctrl_t ctrl, IOBUF inp, const char* fname,struct stats_s *stats,
unsigned char **fpr,size_t *fpr_len,unsigned int options )
{
PACKET *pending_pkt = NULL;
@ -262,7 +266,7 @@ import( IOBUF inp, const char* fname,struct stats_s *stats,
if( keyblock->pkt->pkttype == PKT_PUBLIC_KEY )
rc = import_one( fname, keyblock, stats, fpr, fpr_len, options, 0);
else if( keyblock->pkt->pkttype == PKT_SECRET_KEY )
rc = import_secret_one( fname, keyblock, stats, options );
rc = import_secret_one (ctrl, fname, keyblock, stats, options);
else if( keyblock->pkt->pkttype == PKT_SIGNATURE
&& keyblock->pkt->pkt.signature->sig_class == 0x20 )
rc = import_revoke_cert( fname, keyblock, stats );
@ -528,7 +532,7 @@ fix_pks_corruption(KBNODE keyblock)
equal. Although direct key signatures are now checked during
import, there might still be bogus signatures sitting in a keyring.
We need to detect and delete them before doing a merge. This
fucntion returns the number of removed sigs. */
function returns the number of removed sigs. */
static int
fix_bad_direct_key_sigs (kbnode_t keyblock, u32 *keyid)
{
@ -1076,66 +1080,298 @@ import_one( const char *fname, KBNODE keyblock, struct stats_s *stats,
return rc;
}
/* Walk a secret keyblock and produce a public keyblock out of it. */
static KBNODE
sec_to_pub_keyblock(KBNODE sec_keyblock)
/* Transfer all the secret keys in SEC_KEYBLOCK to the gpg-agent. The
function prints diagnostics and returns an error code. */
static gpg_error_t
transfer_secret_keys (ctrl_t ctrl, kbnode_t sec_keyblock)
{
KBNODE secnode,pub_keyblock=NULL,ctx=NULL;
gpg_error_t err = 0;
void *kek = NULL;
size_t keklen;
kbnode_t ctx = NULL;
kbnode_t node;
PKT_secret_key *main_sk, *sk;
int nskey;
membuf_t mbuf;
int i, j;
size_t n;
void *format_args_buf_ptr[PUBKEY_MAX_NSKEY];
int format_args_buf_int[PUBKEY_MAX_NSKEY];
void *format_args[2*PUBKEY_MAX_NSKEY];
gcry_sexp_t skey, prot, tmpsexp;
unsigned char *transferkey = NULL;
size_t transferkeylen;
gcry_cipher_hd_t cipherhd = NULL;
unsigned char *wrappedkey = NULL;
size_t wrappedkeylen;
while((secnode=walk_kbnode(sec_keyblock,&ctx,0)))
/* Get the current KEK. */
err = agent_keywrap_key (ctrl, 0, &kek, &keklen);
if (err)
{
KBNODE pubnode;
log_error ("error getting the KEK: %s\n", gpg_strerror (err));
goto leave;
}
if(secnode->pkt->pkttype==PKT_SECRET_KEY ||
secnode->pkt->pkttype==PKT_SECRET_SUBKEY)
/* Prepare a cipher context. */
err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128,
GCRY_CIPHER_MODE_AESWRAP, 0);
if (!err)
err = gcry_cipher_setkey (cipherhd, kek, keklen);
if (err)
goto leave;
xfree (kek);
kek = NULL;
main_sk = NULL;
while ((node = walk_kbnode (sec_keyblock, &ctx, 0)))
{
if (node->pkt->pkttype != PKT_SECRET_KEY
&& node->pkt->pkttype != PKT_SECRET_SUBKEY)
continue;
sk = node->pkt->pkt.secret_key;
if (!main_sk)
main_sk = sk;
/* Convert our internal secret key object into an S-expression. */
nskey = pubkey_get_nskey (sk->pubkey_algo);
if (!nskey || nskey > PUBKEY_MAX_NSKEY)
{
err = gpg_error (GPG_ERR_BAD_SECKEY);
log_error ("internal error: %s\n", gpg_strerror (err));
goto leave;
}
init_membuf (&mbuf, 50);
put_membuf_str (&mbuf, "(skey");
for (i=j=0; i < nskey; i++)
{
if (gcry_mpi_get_flag (sk->skey[i], GCRYMPI_FLAG_OPAQUE))
{
put_membuf_str (&mbuf, " e %b");
format_args_buf_ptr[i] = gcry_mpi_get_opaque (sk->skey[i], &n);
format_args_buf_int[i] = (n+7)/8;
format_args[j++] = format_args_buf_int + i;
format_args[j++] = format_args_buf_ptr + i;
}
else
{
put_membuf_str (&mbuf, " _ %m");
format_args[j++] = sk->skey + i;
}
}
put_membuf_str (&mbuf, ")\n");
put_membuf (&mbuf, "", 1);
{
char *format = get_membuf (&mbuf, NULL);
if (!format)
err = gpg_error_from_syserror ();
else
err = gcry_sexp_build_array (&skey, NULL, format, format_args);
xfree (format);
}
if (err)
{
log_error ("error building skey array: %s\n", gpg_strerror (err));
goto leave;
}
if (sk->is_protected)
{
char countbuf[35];
snprintf (countbuf, sizeof countbuf, "%lu",
(unsigned long)sk->protect.s2k.count);
err = gcry_sexp_build
(&prot, NULL,
" (protection %s %s %b %d %s %b %s)\n",
sk->protect.sha1chk? "sha1":"sum",
openpgp_cipher_algo_name (sk->protect.algo),
(int)sk->protect.ivlen, sk->protect.iv,
sk->protect.s2k.mode,
openpgp_md_algo_name (sk->protect.s2k.hash_algo),
(int)sizeof (sk->protect.s2k.salt), sk->protect.s2k.salt,
countbuf);
}
else
err = gcry_sexp_build (&prot, NULL, " (protection none)\n");
tmpsexp = NULL;
xfree (transferkey);
transferkey = NULL;
if (!err)
err = gcry_sexp_build (&tmpsexp, NULL,
"(openpgp-private-key\n"
" (version %d)\n"
" (algo %s)\n"
" %S\n"
" (csum %d)\n"
" %S)\n",
sk->version,
openpgp_pk_algo_name (sk->pubkey_algo),
skey, (int)(unsigned long)sk->csum, prot);
gcry_sexp_release (skey);
gcry_sexp_release (prot);
if (!err)
err = make_canon_sexp_pad (tmpsexp, 1, &transferkey, &transferkeylen);
gcry_sexp_release (tmpsexp);
if (err)
{
log_error ("error building transfer key: %s\n", gpg_strerror (err));
goto leave;
}
/* Wrap the key. */
wrappedkeylen = transferkeylen + 8;
xfree (wrappedkey);
wrappedkey = xtrymalloc (wrappedkeylen);
if (!wrappedkey)
err = gpg_error_from_syserror ();
else
err = gcry_cipher_encrypt (cipherhd, wrappedkey, wrappedkeylen,
transferkey, transferkeylen);
if (err)
goto leave;
xfree (transferkey);
transferkey = NULL;
/* Send the wrapped key to the agent. */
{
char *uid, *desc;
size_t uidlen;
u32 keyid[2];
char *orig_codeset;
keyid_from_sk (sk, keyid);
uid = get_user_id (keyid, &uidlen);
orig_codeset = i18n_switchto_utf8 ();
desc = xtryasprintf (_("Please enter the passphrase to import the"
" secret key for the OpenPGP certificate:\n"
"\"%.*s\"\n" \
"%u-bit %s key, ID %s,\n"
"created %s.\n"),
(int)uidlen, uid,
nbits_from_sk (sk),
openpgp_pk_algo_name (sk->pubkey_algo),
(main_sk == sk
? keystr_from_sk (sk)
: keystr_from_sk_with_sub (main_sk, sk)),
strtimestamp (sk->timestamp));
i18n_switchback (orig_codeset);
xfree (uid);
if (desc)
{
uid = percent_plus_escape (desc);
xfree (desc);
desc = uid;
}
err = agent_import_key (ctrl, desc, wrappedkey, wrappedkeylen);
xfree (desc);
}
if (!err)
{
if (opt.verbose)
log_info (_("key %s: secret key imported\n"),
keystr_from_sk_with_sub (main_sk, sk));
/* stats->count++; */
/* stats->secret_read++; */
/* stats->secret_imported++; */
}
else if ( gpg_err_code (err) == GPG_ERR_EEXIST )
{
if (opt.verbose)
log_info (_("key %s: secret key already exists\n"),
keystr_from_sk_with_sub (main_sk, sk));
err = 0;
/* stats->count++; */
/* stats->secret_read++; */
/* stats->secret_dups++; */
}
else
{
log_error (_("key %s: error sending to agent: %s\n"),
keystr_from_sk_with_sub (main_sk, sk),
gpg_strerror (err));
if (sk->protect.algo == GCRY_CIPHER_IDEA
&& gpg_err_code (err) == GPG_ERR_CIPHER_ALGO)
{
write_status (STATUS_RSA_OR_IDEA);
idea_cipher_warn (0);
}
if (gpg_err_code (err) == GPG_ERR_CANCELED)
break; /* Don't try the other subkeys. */
}
}
leave:
xfree (wrappedkey);
xfree (transferkey);
gcry_cipher_close (cipherhd);
xfree (kek);
return err;
}
/* Walk a secret keyblock and produce a public keyblock out of it.
Returns a new node or NULL on error. */
static kbnode_t
sec_to_pub_keyblock (kbnode_t sec_keyblock)
{
kbnode_t pub_keyblock = NULL;
kbnode_t ctx = NULL;
kbnode_t secnode, pubnode;
while ((secnode = walk_kbnode (sec_keyblock, &ctx, 0)))
{
if (secnode->pkt->pkttype == PKT_SECRET_KEY
|| secnode->pkt->pkttype == PKT_SECRET_SUBKEY)
{
/* Make a public key. We only need to convert enough to
write the keyblock out. */
PACKET *pkt;
PKT_secret_key *sk;
PKT_public_key *pk;
int n, i;
PKT_secret_key *sk=secnode->pkt->pkt.secret_key;
PACKET *pkt=xmalloc_clear(sizeof(PACKET));
PKT_public_key *pk=xmalloc_clear(sizeof(PKT_public_key));
int n;
pkt = xcalloc (1, sizeof *pkt);
sk = secnode->pkt->pkt.secret_key;
pk = xcalloc (1, sizeof *pk);
if(secnode->pkt->pkttype==PKT_SECRET_KEY)
pkt->pkttype=PKT_PUBLIC_KEY;
if (secnode->pkt->pkttype == PKT_SECRET_KEY)
pkt->pkttype = PKT_PUBLIC_KEY;
else
pkt->pkttype=PKT_PUBLIC_SUBKEY;
pkt->pkttype = PKT_PUBLIC_SUBKEY;
pkt->pkt.public_key=pk;
pkt->pkt.public_key = pk;
pk->version=sk->version;
pk->timestamp=sk->timestamp;
pk->expiredate=sk->expiredate;
pk->pubkey_algo=sk->pubkey_algo;
pk->version = sk->version;
pk->timestamp = sk->timestamp;
pk->expiredate = sk->expiredate;
pk->pubkey_algo = sk->pubkey_algo;
n=pubkey_get_npkey(pk->pubkey_algo);
if(n==0)
n = pubkey_get_npkey (pk->pubkey_algo);
if (!n)
{
/* we can't properly extract the pubkey without knowing
/* We can't properly extract the pubkey without knowing
the number of MPIs */
release_kbnode(pub_keyblock);
release_kbnode (pub_keyblock);
return NULL;
}
else
{
int i;
for(i=0;i<n;i++)
pk->pkey[i]=mpi_copy(sk->skey[i]);
}
pubnode=new_kbnode(pkt);
for (i=0; i < n; i++)
pk->pkey[i] = mpi_copy (sk->skey[i]);
pubnode = new_kbnode (pkt);
}
else
{
pubnode=clone_kbnode(secnode);
pubnode = clone_kbnode (secnode);
}
if(pub_keyblock==NULL)
pub_keyblock=pubnode;
if (!pub_keyblock)
pub_keyblock = pubnode;
else
add_kbnode(pub_keyblock,pubnode);
add_kbnode (pub_keyblock, pubnode);
}
return pub_keyblock;
@ -1148,132 +1384,126 @@ sec_to_pub_keyblock(KBNODE sec_keyblock)
* with the trust calculation.
*/
static int
import_secret_one( const char *fname, KBNODE keyblock,
import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock,
struct stats_s *stats, unsigned int options)
{
PKT_secret_key *sk;
KBNODE node, uidnode;
u32 keyid[2];
int rc = 0;
/* get the key and print some info about it */
node = find_kbnode( keyblock, PKT_SECRET_KEY );
if( !node )
BUG();
sk = node->pkt->pkt.secret_key;
keyid_from_sk( sk, keyid );
uidnode = find_next_kbnode( keyblock, PKT_USER_ID );
if( opt.verbose )
{
log_info( "sec %4u%c/%s %s ",
nbits_from_sk( sk ),
pubkey_letter( sk->pubkey_algo ),
keystr_from_sk(sk), datestr_from_sk(sk) );
if( uidnode )
print_utf8_buffer (es_stderr, uidnode->pkt->pkt.user_id->name,
uidnode->pkt->pkt.user_id->len );
log_printf ("\n");
}
stats->secret_read++;
if( !uidnode )
{
log_error( _("key %s: no user ID\n"), keystr_from_sk(sk));
return 0;
}
if(sk->protect.algo>110)
{
log_error(_("key %s: secret key with invalid cipher %d"
" - skipped\n"),keystr_from_sk(sk),sk->protect.algo);
return 0;
}
PKT_secret_key *sk;
KBNODE node, uidnode;
u32 keyid[2];
int have_seckey;
int rc = 0;
/* Get the key and print some info about it */
node = find_kbnode (keyblock, PKT_SECRET_KEY);
if (!node)
BUG ();
sk = node->pkt->pkt.secret_key;
keyid_from_sk (sk, keyid);
uidnode = find_next_kbnode (keyblock, PKT_USER_ID);
if (opt.verbose)
{
log_info ("sec %4u%c/%s %s ",
nbits_from_sk (sk),
pubkey_letter (sk->pubkey_algo),
keystr_from_sk (sk), datestr_from_sk (sk));
if (uidnode)
print_utf8_buffer (es_stderr, uidnode->pkt->pkt.user_id->name,
uidnode->pkt->pkt.user_id->len);
log_printf ("\n");
}
stats->secret_read++;
if (!uidnode)
{
log_error( _("key %s: no user ID\n"), keystr_from_sk(sk));
return 0;
}
/* A quick check to not import keys with an invalid protection
cipher algorithm (only checks the primary key, though). */
if (sk->protect.algo > 110)
{
log_error (_("key %s: secret key with invalid cipher %d"
" - skipped\n"),keystr_from_sk(sk),sk->protect.algo);
return 0;
}
#ifdef ENABLE_SELINUX_HACKS
if (1)
{
/* We don't allow to import secret keys because that may be used
to put a secret key into the keyring and the user might later
be tricked into signing stuff with that key. */
log_error (_("importing secret keys not allowed\n"));
return 0;
}
if (1)
{
/* We don't allow to import secret keys because that may be used
to put a secret key into the keyring and the user might later
be tricked into signing stuff with that key. */
log_error (_("importing secret keys not allowed\n"));
return 0;
}
#endif
clear_kbnode_flags( keyblock );
clear_kbnode_flags( keyblock );
have_seckey = have_secret_key_with_kid (keyid);
/* do we have this key already in one of our secrings ? */
rc = -1 /* fixme seckey_available( keyid ) is not anymore
available and has been replaced by
have_secret_key_with_kid. We need to rework the entire
secret key import code. The solution I am currently
thinking about is to move that code into a helper
program. */;
if( rc == G10ERR_NO_SECKEY && !(opt.import_options&IMPORT_MERGE_ONLY) )
{
/* simply insert this key */
KEYDB_HANDLE hd = keydb_new (); /* FIXME*/
if (!have_seckey && !(opt.import_options&IMPORT_MERGE_ONLY) )
{
/* We don't have this key, insert as a new key. */
kbnode_t pub_keyblock;
/* get default resource */
rc = keydb_locate_writable (hd, NULL);
if (rc) {
log_error (_("no default secret keyring: %s\n"), g10_errstr (rc));
keydb_release (hd);
return G10ERR_GENERAL;
}
rc = keydb_insert_keyblock (hd, keyblock );
if (rc)
log_error (_("error writing keyring `%s': %s\n"),
keydb_get_resource_name (hd), g10_errstr(rc) );
keydb_release (hd);
/* we are ready */
if( !opt.quiet )
log_info( _("key %s: secret key imported\n"), keystr_from_sk(sk));
stats->secret_imported++;
if (is_status_enabled ())
print_import_ok (NULL, sk, 1|16);
stats->secret_imported++;
if (is_status_enabled ())
print_import_ok (NULL, sk, 1|16);
if(options&IMPORT_SK2PK)
{
/* Try and make a public key out of this. */
/* Make a public key out of this. */
pub_keyblock = sec_to_pub_keyblock (keyblock);
if (!pub_keyblock)
log_error ("oops: FIXME (bad error message)\n");
else
{
import_one (fname, pub_keyblock, stats,
NULL, NULL, opt.import_options, 1);
/* Fixme: We should check for an invalid keyblock and
cancel the secret key import in this case. */
release_kbnode (pub_keyblock);
/* Read the keyblock again to get the effects of a merge. */
/* Fixme: we should do this based on the fingerprint or
even better let import_one return the merged
keyblock. */
node = get_pubkeyblock (keyid);
if (!node)
log_error ("oops: error getting public keyblock again\n");
else
{
if (!transfer_secret_keys (ctrl, keyblock))
{
if (!opt.quiet)
log_info (_("key %s: secret key imported\n"),
keystr_from_sk (sk));
check_prefs (node);
}
release_kbnode (node);
}
}
}
else if (have_seckey)
{
/* We can't yet merge secret keys. - Well, with the new system
we can => FIXME */
log_error( _("key %s: secret key part already available\n"),
keystr_from_sk(sk));
stats->secret_dups++;
if (is_status_enabled ())
print_import_ok (NULL, sk, 16);
/* TODO: if we ever do merge secret keys, make sure to handle
the sec_to_pub_keyblock feature as well. */
}
else
log_error( _("key %s: secret key not found: %s\n"),
keystr_from_sk(sk), g10_errstr(rc));
KBNODE pub_keyblock=sec_to_pub_keyblock(keyblock);
if(pub_keyblock)
{
import_one(fname,pub_keyblock,stats,
NULL,NULL,opt.import_options,1);
release_kbnode(pub_keyblock);
}
}
/* Now that the key is definitely incorporated into the keydb,
if we have the public part of this key, we need to check if
the prefs are rational. */
node=get_pubkeyblock(keyid);
if(node)
{
check_prefs(node);
release_kbnode(node);
}
}
else if( !rc )
{ /* we can't merge secret keys */
log_error( _("key %s: already in secret keyring\n"),
keystr_from_sk(sk));
stats->secret_dups++;
if (is_status_enabled ())
print_import_ok (NULL, sk, 16);
/* TODO: if we ever do merge secret keys, make sure to handle
the sec_to_pub_keyblock feature as well. */
}
else
log_error( _("key %s: secret key not found: %s\n"),
keystr_from_sk(sk), g10_errstr(rc));
return rc;
return rc;
}

View File

@ -259,8 +259,13 @@ u32 v3_keyid (gcry_mpi_t a, u32 *ki);
void hash_public_key( gcry_md_hd_t md, PKT_public_key *pk );
size_t keystrlen(void);
const char *keystr(u32 *keyid);
const char *keystr_with_sub (u32 *main_kid, u32 *sub_kid);
const char *keystr_from_pk(PKT_public_key *pk);
const char *keystr_from_pk_with_sub (PKT_public_key *main_pk,
PKT_public_key *sub_pk);
const char *keystr_from_sk(PKT_secret_key *sk);
const char *keystr_from_sk_with_sub (PKT_secret_key *main_sk,
PKT_secret_key *sub_sk);
const char *keystr_from_desc(KEYDB_SEARCH_DESC *desc);
u32 keyid_from_sk( PKT_secret_key *sk, u32 *keyid );
u32 keyid_from_pk( PKT_public_key *pk, u32 *keyid );

View File

@ -35,6 +35,9 @@
#include "i18n.h"
#include "rmd160.h"
#define KEYID_STR_SIZE 19
int
pubkey_letter( int algo )
{
@ -204,35 +207,38 @@ keystrlen(void)
}
}
const char *
keystr(u32 *keyid)
{
static char keyid_str[19];
switch(opt.keyid_format)
const char *
keystr (u32 *keyid)
{
static char keyid_str[KEYID_STR_SIZE];
switch (opt.keyid_format)
{
case KF_SHORT:
sprintf(keyid_str,"%08lX",(ulong)keyid[1]);
snprintf (keyid_str, sizeof keyid_str, "%08lX", (ulong)keyid[1]);
break;
case KF_LONG:
if(keyid[0])
sprintf(keyid_str,"%08lX%08lX",(ulong)keyid[0],(ulong)keyid[1]);
if (keyid[0])
snprintf (keyid_str, sizeof keyid_str, "%08lX%08lX",
(ulong)keyid[0], (ulong)keyid[1]);
else
sprintf(keyid_str,"%08lX",(ulong)keyid[1]);
snprintf (keyid_str, sizeof keyid_str, "%08lX", (ulong)keyid[1]);
break;
case KF_0xSHORT:
sprintf(keyid_str,"0x%08lX",(ulong)keyid[1]);
snprintf (keyid_str, sizeof keyid_str, "0x%08lX", (ulong)keyid[1]);
break;
case KF_0xLONG:
if(keyid[0])
sprintf(keyid_str,"0x%08lX%08lX",(ulong)keyid[0],(ulong)keyid[1]);
snprintf (keyid_str, sizeof keyid_str, "0x%08lX%08lX",
(ulong)keyid[0],(ulong)keyid[1]);
else
sprintf(keyid_str,"0x%08lX",(ulong)keyid[1]);
snprintf (keyid_str, sizeof keyid_str, "0x%08lX", (ulong)keyid[1]);
break;
default:
BUG();
}
@ -240,6 +246,21 @@ keystr(u32 *keyid)
return keyid_str;
}
const char *
keystr_with_sub (u32 *main_kid, u32 *sub_kid)
{
static char buffer[KEYID_STR_SIZE+1+KEYID_STR_SIZE];
char *p;
mem2str (buffer, keystr (main_kid), KEYID_STR_SIZE);
p = buffer + strlen (buffer);
*p++ = '/';
mem2str (p, keystr (sub_kid), KEYID_STR_SIZE);
return buffer;
}
const char *
keystr_from_pk(PKT_public_key *pk)
{
@ -248,14 +269,36 @@ keystr_from_pk(PKT_public_key *pk)
return keystr(pk->keyid);
}
const char *
keystr_from_pk_with_sub (PKT_public_key *main_pk, PKT_public_key *sub_pk)
{
keyid_from_pk (main_pk, NULL);
keyid_from_pk (sub_pk, NULL);
return keystr_with_sub (main_pk->keyid, sub_pk->keyid);
}
const char *
keystr_from_sk(PKT_secret_key *sk)
{
keyid_from_sk(sk,NULL);
keyid_from_sk (sk,NULL);
return keystr(sk->keyid);
}
const char *
keystr_from_sk_with_sub (PKT_secret_key *main_sk, PKT_secret_key *sub_sk)
{
keyid_from_sk (main_sk, NULL);
keyid_from_sk (sub_sk, NULL);
return keystr_with_sub (main_sk->keyid, sub_sk->keyid);
}
const char *
keystr_from_desc(KEYDB_SEARCH_DESC *desc)
{

View File

@ -1494,9 +1494,10 @@ keyserver_spawn(enum ks_action action,strlist_t list,KEYDB_SEARCH_DESC *desc,
gpg complain about "no valid OpenPGP data found". One
way to do this could be to continue parsing this
line-by-line and make a temp iobuf for each key. */
import_keys_stream(spawn->fromchild,stats_handle,fpr,fpr_len,
opt.keyserver_options.import_options);
/* FIXME: Pass CTRL. */
import_keys_stream (NULL, spawn->fromchild,stats_handle,fpr,fpr_len,
opt.keyserver_options.import_options);
import_print_stats(stats_handle);
import_release_stats_handle(stats_handle);
@ -2037,8 +2038,9 @@ keyserver_import_cert(const char *name,unsigned char **fpr,size_t *fpr_len)
/* CERTs are always in binary format */
opt.no_armor=1;
rc=import_keys_stream(key,NULL,fpr,fpr_len,
opt.keyserver_options.import_options);
/* FIXME: Pass CTRL. */
rc = import_keys_stream (NULL, key, NULL, fpr, fpr_len,
opt.keyserver_options.import_options);
opt.no_armor=armor_status;

View File

@ -96,7 +96,9 @@ const char *openpgp_cipher_algo_name (int algo);
int openpgp_pk_test_algo( int algo );
int openpgp_pk_test_algo2 ( int algo, unsigned int use );
int openpgp_pk_algo_usage ( int algo );
const char *openpgp_pk_algo_name (int algo);
int openpgp_md_test_algo( int algo );
const char *openpgp_md_algo_name (int algo);
#ifdef USE_IDEA
void idea_cipher_warn( int show );
@ -263,10 +265,11 @@ gcry_mpi_t encode_md_value (PKT_public_key *pk,
/*-- import.c --*/
int parse_import_options(char *str,unsigned int *options,int noisy);
void import_keys( char **fnames, int nnames,
void *stats_hd, unsigned int options );
int import_keys_stream( iobuf_t inp,void *stats_hd,unsigned char **fpr,
size_t *fpr_len,unsigned int options );
void import_keys (ctrl_t ctrl, char **fnames, int nnames,
void *stats_hd, unsigned int options);
int import_keys_stream (ctrl_t ctrl, iobuf_t inp, void *stats_hd,
unsigned char **fpr,
size_t *fpr_len, unsigned int options);
void *import_new_stats_handle (void);
void import_release_stats_handle (void *p);
void import_print_stats (void *hd);

View File

@ -478,6 +478,28 @@ openpgp_pk_algo_usage ( int algo )
return use;
}
/* Map the OpenPGP pubkey algorithm whose ID is contained in ALGO to a
string representation of the algorithm name. For unknown algorithm
IDs this function returns "?". */
const char *
openpgp_pk_algo_name (int algo)
{
switch (algo)
{
case PUBKEY_ALGO_RSA:
case PUBKEY_ALGO_RSA_E:
case PUBKEY_ALGO_RSA_S: return "rsa";
case PUBKEY_ALGO_ELGAMAL:
case PUBKEY_ALGO_ELGAMAL_E: return "elg";
case PUBKEY_ALGO_DSA: return "dsa";
default: return "?";
}
}
int
openpgp_md_test_algo( int algo )
{
@ -491,6 +513,19 @@ openpgp_md_test_algo( int algo )
return gcry_md_test_algo (algo);
}
/* Map the OpenPGP digest algorithm whose ID is contained in ALGO to a
string representation of the algorithm name. For unknown algorithm
IDs this function returns "?". */
const char *
openpgp_md_algo_name (int algo)
{
if (algo < 0 || algo > 110)
return "?";
return gcry_md_algo_name (algo);
}
#ifdef USE_IDEA
/* Special warning for the IDEA cipher */
void

View File

@ -320,7 +320,6 @@ EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode;
#define IMPORT_LOCAL_SIGS (1<<0)
#define IMPORT_REPAIR_PKS_SUBKEY_BUG (1<<1)
#define IMPORT_FAST (1<<2)
#define IMPORT_SK2PK (1<<3)
#define IMPORT_MERGE_ONLY (1<<4)
#define IMPORT_MINIMAL (1<<5)
#define IMPORT_CLEAN (1<<6)

View File

@ -244,41 +244,3 @@ pk_decrypt (int algo, gcry_mpi_t * result, gcry_mpi_t * data,
return 0;
}
/* Check whether SKEY is a suitable secret key. */
int
REMOVE_ME_pk_check_secret_key (int algo, gcry_mpi_t *skey)
{
gcry_sexp_t s_skey;
int rc;
if (algo == GCRY_PK_DSA)
{
rc = gcry_sexp_build (&s_skey, NULL,
"(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
skey[0], skey[1], skey[2], skey[3], skey[4]);
}
else if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
{
rc = gcry_sexp_build (&s_skey, NULL,
"(private-key(elg(p%m)(g%m)(y%m)(x%m)))",
skey[0], skey[1], skey[2], skey[3]);
}
else if (algo == GCRY_PK_RSA
|| algo == GCRY_PK_RSA_S || algo == GCRY_PK_RSA_E)
{
rc = gcry_sexp_build (&s_skey, NULL,
"(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
skey[0], skey[1], skey[2], skey[3], skey[4],
skey[5]);
}
else
return GPG_ERR_PUBKEY_ALGO;
if (!rc)
{
rc = gcry_pk_testkey (s_skey);
gcry_sexp_release (s_skey);
}
return rc;
}