aboutsummaryrefslogtreecommitdiffstats
path: root/g10
diff options
context:
space:
mode:
Diffstat (limited to 'g10')
-rw-r--r--g10/import.c140
-rw-r--r--g10/keygen.c116
-rw-r--r--g10/parse-packet.c7
3 files changed, 122 insertions, 141 deletions
diff --git a/g10/import.c b/g10/import.c
index 8223041d1..2b219a28d 100644
--- a/g10/import.c
+++ b/g10/import.c
@@ -1128,37 +1128,6 @@ import_one (ctrl_t ctrl,
}
-/* Extract one MPI value from the S-expression PKEY which is expected
- to hold a "public-key". Returns NULL on error. */
-static gcry_mpi_t
-one_mpi_from_pkey (gcry_sexp_t pkey, const char *name, size_t namelen)
-{
- gcry_sexp_t list, l2;
- gcry_mpi_t a;
-
- list = gcry_sexp_find_token (pkey, "public-key", 0);
- if (!list)
- return NULL;
- l2 = gcry_sexp_cadr (list);
- gcry_sexp_release (list);
- list = l2;
- if (!list)
- return NULL;
-
- l2 = gcry_sexp_find_token (list, name, namelen);
- if (!l2)
- {
- gcry_sexp_release (list);
- return NULL;
- }
- a = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
- gcry_sexp_release (l2);
- gcry_sexp_release (list);
-
- return a;
-}
-
-
/* 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
@@ -1174,18 +1143,15 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock)
int nskey;
membuf_t mbuf;
int i, j;
- unsigned int 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;
+ gcry_sexp_t curve = NULL;
unsigned char *transferkey = NULL;
size_t transferkeylen;
gcry_cipher_hd_t cipherhd = NULL;
unsigned char *wrappedkey = NULL;
size_t wrappedkeylen;
char *cache_nonce = NULL;
- gcry_mpi_t ecc_params[5] = {NULL, NULL, NULL, NULL, NULL};
/* Get the current KEK. */
err = agent_keywrap_key (ctrl, 0, &kek, &keklen);
@@ -1263,65 +1229,30 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock)
|| pk->pubkey_algo == PUBKEY_ALGO_EDDSA
|| pk->pubkey_algo == PUBKEY_ALGO_ECDH)
{
- /* We need special treatment for ECC algorithms. OpenPGP
- stores only the curve name but the agent expects a full
- key. This is so that we can keep all curve name
- validation code out of gpg-agent. */
-#if PUBKEY_MAX_NSKEY < 7
-#error PUBKEY_MAX_NSKEY too low for ECC
-#endif
- char *curve = openpgp_oid_to_str (pk->pkey[0]);
- if (!curve)
+ /* The ECC case. */
+ char *curvestr = openpgp_oid_to_str (pk->pkey[0]);
+ if (!curvestr)
err = gpg_error_from_syserror ();
else
{
- gcry_sexp_t cparam = gcry_pk_get_param (GCRY_PK_ECC, curve);
-
- xfree (curve);
- if (!cparam)
- err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
- else
+ err = gcry_sexp_build (&curve, NULL, "(curve %s)", curvestr);
+ xfree (curvestr);
+ if (!err)
{
- const char *s;
-
- /* Append the curve parameters P, A, B, G and N. */
- for (i=j=0; !err && *(s = "pabgn"+i); i++)
- {
- ecc_params[i] = one_mpi_from_pkey (cparam, s, 1);
- if (!ecc_params[i])
- err = gpg_error (GPG_ERR_INV_CURVE);
- else
- {
- put_membuf_str (&mbuf, " _ %m");
- format_args[j++] = ecc_params+i;
- }
- }
- gcry_sexp_release (cparam);
- if (!err)
- {
- /* Append the public key element Q. */
- put_membuf_str (&mbuf, " _ %m");
- format_args[j++] = pk->pkey + 1;
-
- /* Append the secret key element D. Note that
- for ECDH we need to skip PKEY[2] because this
- holds the KEK which is not needed. */
- i = pk->pubkey_algo == PUBKEY_ALGO_ECDH? 3 : 2;
- if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_OPAQUE))
- {
- put_membuf_str (&mbuf, " e %b");
- format_args_buf_ptr[i]
- = gcry_mpi_get_opaque (pk->pkey[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++] = pk->pkey + i;
- }
- }
+ j = 0;
+ /* Append the public key element Q. */
+ put_membuf_str (&mbuf, " _ %m");
+ format_args[j++] = pk->pkey + 1;
+
+ /* Append the secret key element D. For ECDH we
+ skip PKEY[2] because this holds the KEK which is
+ not needed by gpg-agent. */
+ i = pk->pubkey_algo == PUBKEY_ALGO_ECDH? 3 : 2;
+ if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_USER1))
+ put_membuf_str (&mbuf, " e %m");
+ else
+ put_membuf_str (&mbuf, " _ %m");
+ format_args[j++] = pk->pkey + i;
}
}
}
@@ -1331,23 +1262,16 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock)
for (i=j=0; i < nskey; i++)
{
if (!pk->pkey[i])
- ; /* Protected keys only have NPKEY+1 elements. */
- else if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_OPAQUE))
- {
- put_membuf_str (&mbuf, " e %b");
- format_args_buf_ptr[i] = gcry_mpi_get_opaque (pk->pkey[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;
- }
+ continue; /* Protected keys only have NPKEY+1 elements. */
+
+ if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_USER1))
+ put_membuf_str (&mbuf, " e %m");
else
- {
- put_membuf_str (&mbuf, " _ %m");
- format_args[j++] = pk->pkey + i;
- }
+ put_membuf_str (&mbuf, " _ %m");
+ format_args[j++] = pk->pkey + i;
}
}
- put_membuf_str (&mbuf, ")\n");
+ put_membuf_str (&mbuf, ")");
put_membuf (&mbuf, "", 1);
if (err)
xfree (get_membuf (&mbuf, NULL));
@@ -1398,12 +1322,13 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock)
"(openpgp-private-key\n"
" (version %d)\n"
" (algo %s)\n"
- " %S\n"
+ " %S%S\n"
" (csum %d)\n"
" %S)\n",
pk->version,
openpgp_pk_algo_name (pk->pubkey_algo),
- skey, (int)(unsigned long)ski->csum, prot);
+ curve, skey,
+ (int)(unsigned long)ski->csum, prot);
gcry_sexp_release (skey);
gcry_sexp_release (prot);
if (!err)
@@ -1463,8 +1388,7 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock)
}
leave:
- for (i=0; i < DIM (ecc_params); i++)
- gcry_mpi_release (ecc_params[i]);
+ gcry_sexp_release (curve);
xfree (cache_nonce);
xfree (wrappedkey);
xfree (transferkey);
diff --git a/g10/keygen.c b/g10/keygen.c
index f3052e492..314cf9bab 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -2086,29 +2086,30 @@ ask_keysize (int algo, unsigned int primary_keysize)
}
-/* Ask for the key size. ALGO is the algorithm. If PRIMARY_KEYSIZE
- is not 0, the function asks for the size of the encryption
- subkey. */
+/* Ask for the curve. ALGO is the selected algorithm which this
+ function may adjust. Returns a malloced string with the name of
+ the curve. */
static char *
-ask_curve (void)
+ask_curve (int *algo)
{
struct {
const char *name;
int available;
int expert_only;
+ int fix_curve;
const char *pretty_name;
} curves[] = {
#if GPG_USE_EDDSA
- { "Ed25519", 0, 0, "Curve 25519" },
+ { "Curve25519", 0, 0, 1, "Curve 25519" },
#endif
#if GPG_USE_ECDSA || GPG_USE_ECDH
- { "NIST P-256", 0, 1, },
- { "NIST P-384", 0, 0, },
- { "NIST P-521", 0, 1, },
- { "brainpoolP256r1", 0, 1, "Brainpool P-256" },
- { "brainpoolP384r1", 0, 1, "Brainpool P-384" },
- { "brainpoolP512r1", 0, 1, "Brainpool P-512" },
- { "secp256k1", 0, 1 },
+ { "NIST P-256", 0, 1, 0, },
+ { "NIST P-384", 0, 0, 0, },
+ { "NIST P-521", 0, 1, 0, },
+ { "brainpoolP256r1", 0, 1, 0, "Brainpool P-256" },
+ { "brainpoolP384r1", 0, 1, 0, "Brainpool P-384" },
+ { "brainpoolP512r1", 0, 1, 0, "Brainpool P-512" },
+ { "secp256k1", 0, 1, 0 },
#endif
};
int idx;
@@ -2127,9 +2128,14 @@ ask_curve (void)
if (!opt.expert && curves[idx].expert_only)
continue;
+ /* FIXME: The strcmp below is a temporary hack during
+ development. It shall be removed as soon as we have proper
+ Curve25519 support in Libgcrypt. */
gcry_sexp_release (keyparms);
rc = gcry_sexp_build (&keyparms, NULL,
- "(public-key(ecc(curve %s)))", curves[idx].name);
+ "(public-key(ecc(curve %s)))",
+ (!strcmp (curves[idx].name, "Curve25519")
+ ? "Ed25519" : curves[idx].name));
if (rc)
continue;
if (!gcry_pk_get_curve (keyparms, 0, NULL))
@@ -2171,7 +2177,22 @@ ask_curve (void)
tty_printf (_("Invalid selection.\n"));
else
{
- result = xstrdup (curves[idx].name);
+ if (curves[idx].fix_curve)
+ log_info ("WARNING: Curve25519 is an experimental algorithm and"
+ " not yet specified by OpenPGP. The current"
+ " implementation may change with the next GnuPG release"
+ " and thus rendering the key unusable!\n");
+
+ /* If the user selected a signing algorithm and Curve25519
+ we need to update the algo and and the curve name. */
+ if ((*algo == PUBKEY_ALGO_ECDSA || *algo == PUBKEY_ALGO_EDDSA)
+ && curves[idx].fix_curve)
+ {
+ *algo = PUBKEY_ALGO_EDDSA;
+ result = xstrdup ("Ed25519");
+ }
+ else
+ result = xstrdup (curves[idx].name);
break;
}
}
@@ -3459,16 +3480,16 @@ generate_keypair (ctrl_t ctrl, const char *fname, const char *card_serialno,
{
/* Create primary and subkey at once. */
both = 1;
- r = xmalloc_clear( sizeof *r + 20 );
- r->key = pKEYTYPE;
- sprintf( r->u.value, "%d", algo );
- r->next = para;
- para = r;
if (algo == PUBKEY_ALGO_ECDSA
|| algo == PUBKEY_ALGO_EDDSA
|| algo == PUBKEY_ALGO_ECDH)
{
- curve = ask_curve ();
+ curve = ask_curve (&algo);
+ r = xmalloc_clear( sizeof *r + 20 );
+ r->key = pKEYTYPE;
+ sprintf( r->u.value, "%d", algo);
+ r->next = para;
+ para = r;
nbits = 0;
r = xmalloc_clear (sizeof *r + strlen (curve));
r->key = pKEYCURVE;
@@ -3478,6 +3499,11 @@ generate_keypair (ctrl_t ctrl, const char *fname, const char *card_serialno,
}
else
{
+ r = xmalloc_clear( sizeof *r + 20 );
+ r->key = pKEYTYPE;
+ sprintf( r->u.value, "%d", algo);
+ r->next = para;
+ para = r;
nbits = ask_keysize (algo, 0);
r = xmalloc_clear( sizeof *r + 20 );
r->key = pKEYLENGTH;
@@ -3501,9 +3527,43 @@ generate_keypair (ctrl_t ctrl, const char *fname, const char *card_serialno,
strcpy( r->u.value, "encrypt" );
r->next = para;
para = r;
+
+ if (algo == PUBKEY_ALGO_ECDSA
+ || algo == PUBKEY_ALGO_EDDSA
+ || algo == PUBKEY_ALGO_ECDH)
+ {
+ if (algo == PUBKEY_ALGO_EDDSA
+ && subkey_algo == PUBKEY_ALGO_ECDH)
+ {
+ /* Need to switch to a different curve for the
+ encryption key. */
+ xfree (curve);
+ curve = xstrdup ("Curve25519");
+ }
+ r = xmalloc_clear (sizeof *r + strlen (curve));
+ r->key = pSUBKEYCURVE;
+ strcpy (r->u.value, curve);
+ r->next = para;
+ para = r;
+ }
}
- else
+ else /* Create only a single key. */
{
+ /* For ECC we need to ask for the curve before storing the
+ algo becuase ask_curve may change the algo. */
+ if (algo == PUBKEY_ALGO_ECDSA
+ || algo == PUBKEY_ALGO_EDDSA
+ || algo == PUBKEY_ALGO_ECDH)
+ {
+ curve = ask_curve (&algo);
+ nbits = 0;
+ r = xmalloc_clear (sizeof *r + strlen (curve));
+ r->key = pKEYCURVE;
+ strcpy (r->u.value, curve);
+ r->next = para;
+ para = r;
+ }
+
r = xmalloc_clear( sizeof *r + 20 );
r->key = pKEYTYPE;
sprintf( r->u.value, "%d", algo );
@@ -3528,13 +3588,7 @@ generate_keypair (ctrl_t ctrl, const char *fname, const char *card_serialno,
|| algo == PUBKEY_ALGO_EDDSA
|| algo == PUBKEY_ALGO_ECDH)
{
- if (!both)
- curve = ask_curve ();
- r = xmalloc_clear (sizeof *r + strlen (curve));
- r->key = both? pSUBKEYCURVE : pKEYCURVE;
- strcpy (r->u.value, curve);
- r->next = para;
- para = r;
+ /* The curve has already been set. */
}
else
{
@@ -4031,11 +4085,7 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
else if (algo == PUBKEY_ALGO_ECDSA
|| algo == PUBKEY_ALGO_EDDSA
|| algo == PUBKEY_ALGO_ECDH)
- {
- curve = ask_curve ();
- if (curve && !strcmp (curve, "Ed25519"))
- algo = PUBKEY_ALGO_EDDSA;
- }
+ curve = ask_curve (&algo);
else
nbits = ask_keysize (algo, 0);
diff --git a/g10/parse-packet.c b/g10/parse-packet.c
index f70878846..424b052b9 100644
--- a/g10/parse-packet.c
+++ b/g10/parse-packet.c
@@ -2240,6 +2240,11 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
pk->pkey[npkey] = gcry_mpi_set_opaque (NULL,
read_rest (inp, pktlen),
pktlen * 8);
+ /* Mark that MPI as protected - we need this information for
+ importing a key. The OPAQUE flag can't be used because
+ we also store public EdDSA values in opaque MPIs. */
+ if (pk->pkey[npkey])
+ gcry_mpi_set_flag (pk->pkey[npkey], GCRYMPI_FLAG_USER1);
pktlen = 0;
if (list_mode)
es_fprintf (listfp, "\tskey[%d]: [v4 protected]\n", npkey);
@@ -2252,6 +2257,8 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
if (ski->is_protected)
{
pk->pkey[i] = read_protected_v3_mpi (inp, &pktlen);
+ if (pk->pkey[i])
+ gcry_mpi_set_flag (pk->pkey[i], GCRYMPI_FLAG_USER1);
if (list_mode)
es_fprintf (listfp, "\tskey[%d]: [v3 protected]\n", i);
}