aboutsummaryrefslogtreecommitdiffstats
path: root/g10/keygen.c
diff options
context:
space:
mode:
Diffstat (limited to 'g10/keygen.c')
-rw-r--r--g10/keygen.c484
1 files changed, 429 insertions, 55 deletions
diff --git a/g10/keygen.c b/g10/keygen.c
index 48e5b3a40..4bdb9f53a 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -1,7 +1,7 @@
/* keygen.c - Generate a key pair
* Copyright (C) 1998-2007, 2009-2011 Free Software Foundation, Inc.
* Copyright (C) 2014, 2015, 2016, 2017, 2018 Werner Koch
- * Copyright (C) 2020 g10 Code GmbH
+ * Copyright (C) 2020, 2024 g10 Code GmbH
*
* This file is part of GnuPG.
*
@@ -139,10 +139,23 @@ struct common_gen_cb_parm_s
* may take a copy of this so that the result can be used after we
* are back from the deep key generation call stack. */
gcry_sexp_t genkey_result;
+ /* For a dual algorithms the result of the second algorithm
+ * (e.g. Kyber). */
+ gcry_sexp_t genkey_result2;
};
typedef struct common_gen_cb_parm_s *common_gen_cb_parm_t;
+/* A communication object to help adding certain notations to a key
+ * binding signature. */
+struct opaque_data_usage_and_pk
+{
+ unsigned int usage;
+ const char *cpl_notation;
+ PKT_public_key *pk;
+};
+
+
/* FIXME: These globals vars are ugly. And using MAX_PREFS even for
* aeads is useless, given that we don't expects more than a very few
* algorithms. */
@@ -174,6 +187,9 @@ static gpg_error_t gen_card_key (int keyno, int algo, int is_primary,
u32 expireval, int *keygen_flags);
static unsigned int get_keysize_range (int algo,
unsigned int *min, unsigned int *max);
+static void do_add_notation (PKT_signature *sig,
+ const char *name, const char *value,
+ int critical);
@@ -338,6 +354,20 @@ keygen_add_key_flags_and_expire (PKT_signature *sig, void *opaque)
}
+/* This is only used to write the key binding signature. It is not
+ * used for the primary key. */
+static int
+keygen_add_key_flags_from_oduap (PKT_signature *sig, void *opaque)
+{
+ struct opaque_data_usage_and_pk *oduap = opaque;
+
+ do_add_key_flags (sig, oduap->usage);
+ if (oduap->cpl_notation)
+ do_add_notation (sig, "[email protected]", oduap->cpl_notation, 0);
+ return keygen_add_key_expire (sig, oduap->pk);
+}
+
+
static int
set_one_pref (int val, int type, const char *item, byte *buf, int *nbuf)
{
@@ -943,6 +973,44 @@ keygen_add_keyserver_url(PKT_signature *sig, void *opaque)
return 0;
}
+
+/* This function is used to add a notations to a signature. In
+ * general the caller should have cleared exiting notations before
+ * adding new ones. For example by calling:
+ *
+ * delete_sig_subpkt(sig->hashed,SIGSUBPKT_NOTATION);
+ * delete_sig_subpkt(sig->unhashed,SIGSUBPKT_NOTATION);
+ *
+ * Only human readable notaions may be added. NAME and value are
+ * expected to be UTF-* strings.
+ */
+static void
+do_add_notation (PKT_signature *sig, const char *name, const char *value,
+ int critical)
+{
+ unsigned char *buf;
+ unsigned int n1,n2;
+
+ n1 = strlen (name);
+ n2 = strlen (value);
+
+ buf = xmalloc (8 + n1 + n2);
+
+ buf[0] = 0x80; /* human readable. */
+ buf[1] = buf[2] = buf[3] = 0;
+ buf[4] = n1 >> 8;
+ buf[5] = n1;
+ buf[6] = n2 >> 8;
+ buf[7] = n2;
+ memcpy (buf+8, name, n1);
+ memcpy (buf+8+n1, value, n2);
+ build_sig_subpkt (sig,
+ (SIGSUBPKT_NOTATION|(critical?SIGSUBPKT_FLAG_CRITICAL:0)),
+ buf, 8+n1+n2 );
+ xfree (buf);
+}
+
+
int
keygen_add_notations(PKT_signature *sig,void *opaque)
{
@@ -992,6 +1060,7 @@ keygen_add_notations(PKT_signature *sig,void *opaque)
return 0;
}
+
int
keygen_add_revkey (PKT_signature *sig, void *opaque)
{
@@ -1225,6 +1294,7 @@ write_keybinding (ctrl_t ctrl, kbnode_t root,
PKT_signature *sig;
KBNODE node;
PKT_public_key *pri_pk, *sub_pk;
+ struct opaque_data_usage_and_pk oduap;
if (opt.verbose)
log_info(_("writing key binding signature\n"));
@@ -1250,10 +1320,21 @@ write_keybinding (ctrl_t ctrl, kbnode_t root,
BUG();
/* Make the signature. */
- sub_pk->pubkey_usage = use;
+ oduap.usage = use;
+ if ((use & PUBKEY_USAGE_ENC)
+ && opt.compliance == CO_DE_VS
+ /* The required libgcrypt 1.11 won't yet claim a compliant RNG. */
+ && gnupg_rng_is_compliant (CO_DE_VS))
+ oduap.cpl_notation = "de-vs";
+ else if ((use & PUBKEY_USAGE_ENC)
+ && sub_pk->pubkey_algo == PUBKEY_ALGO_KYBER)
+ oduap.cpl_notation = "fips203.ipd.2023-08-24";
+ else
+ oduap.cpl_notation = NULL;
+ oduap.pk = sub_pk;
err = make_keysig_packet (ctrl, &sig, pri_pk, NULL, sub_pk, pri_psk, 0x18,
timestamp, 0,
- keygen_add_key_flags_and_expire, sub_pk,
+ keygen_add_key_flags_from_oduap, &oduap,
cache_nonce);
if (err)
{
@@ -1311,8 +1392,12 @@ curve_is_448 (gcry_sexp_t sexp)
}
+/* Extract the parameters in OpenPGP format from SEXP and put them
+ * into the caller provided ARRAY. SEXP2 is used to provide the
+ * parameters for dual algorithm (e.g. Kyber). */
static gpg_error_t
-ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo)
+ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp,
+ gcry_sexp_t sexp2, int algo, int pkversion)
{
gpg_error_t err;
gcry_sexp_t list, l2;
@@ -1355,6 +1440,10 @@ ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo)
err = gpg_error (GPG_ERR_INV_OBJ);
goto leave;
}
+ /* For v5 keys we prefer the modern OID for cv25519. */
+ if (pkversion > 4 && !strcmp (oidstr, "1.3.6.1.4.1.3029.1.5.1"))
+ oidstr = "1.3.101.110";
+
err = openpgp_oid_from_str (oidstr, &array[0]);
if (err)
goto leave;
@@ -1364,8 +1453,46 @@ ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo)
goto leave;
gcry_sexp_release (list);
+ list = NULL;
- if (algo == PUBKEY_ALGO_ECDH)
+ if (algo == PUBKEY_ALGO_KYBER)
+ {
+ if (!sexp2)
+ {
+ err = gpg_error (GPG_ERR_MISSING_VALUE);
+ goto leave;
+ }
+
+ list = gcry_sexp_find_token (sexp2, "public-key", 0);
+ if (!list)
+ {
+ err = gpg_error (GPG_ERR_INV_OBJ);
+ goto leave;
+ }
+ l2 = gcry_sexp_cadr (list);
+ gcry_sexp_release (list);
+ list = l2;
+ if (!list)
+ {
+ err = gpg_error (GPG_ERR_NO_OBJ);
+ goto leave;
+ }
+
+ l2 = gcry_sexp_find_token (list, "p", 1);
+ if (!l2)
+ {
+ err = gpg_error (GPG_ERR_NO_OBJ); /* required parameter not found */
+ goto leave;
+ }
+ array[2] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_OPAQUE);
+ gcry_sexp_release (l2);
+ if (!array[2])
+ {
+ err = gpg_error (GPG_ERR_INV_OBJ); /* required parameter invalid */
+ goto leave;
+ }
+ }
+ else if (algo == PUBKEY_ALGO_ECDH)
{
array[2] = pk_ecdh_default_params (nbits);
if (!array[2])
@@ -1377,6 +1504,7 @@ ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo)
leave:
xfree (curve);
+ gcry_sexp_release (list);
if (err)
{
for (i=0; i < 3; i++)
@@ -1455,10 +1583,24 @@ do_create_from_keygrip (ctrl_t ctrl, int algo,
PACKET *pkt;
PKT_public_key *pk;
gcry_sexp_t s_key;
+ gcry_sexp_t s_key2 = NULL;
const char *algoelem;
+ char *hexkeygrip_buffer = NULL;
+ char *hexkeygrip2 = NULL;
if (hexkeygrip[0] == '&')
hexkeygrip++;
+ if (strchr (hexkeygrip, ','))
+ {
+ hexkeygrip_buffer = xtrystrdup (hexkeygrip);
+ if (!hexkeygrip_buffer)
+ return gpg_error_from_syserror ();
+ hexkeygrip = hexkeygrip_buffer;
+ hexkeygrip2 = strchr (hexkeygrip_buffer, ',');
+ if (hexkeygrip2)
+ *hexkeygrip2++ = 0;
+ }
+
switch (algo)
{
@@ -1468,16 +1610,21 @@ do_create_from_keygrip (ctrl_t ctrl, int algo,
case PUBKEY_ALGO_ECDH:
case PUBKEY_ALGO_ECDSA: algoelem = ""; break;
case PUBKEY_ALGO_EDDSA: algoelem = ""; break;
- default: return gpg_error (GPG_ERR_INTERNAL);
+ case PUBKEY_ALGO_KYBER: algoelem = ""; break;
+ default:
+ xfree (hexkeygrip_buffer);
+ return gpg_error (GPG_ERR_INTERNAL);
}
-
/* Ask the agent for the public key matching HEXKEYGRIP. */
if (cardkey)
{
err = agent_scd_readkey (ctrl, hexkeygrip, &s_key, NULL);
if (err)
- return err;
+ {
+ xfree (hexkeygrip_buffer);
+ return err;
+ }
}
else
{
@@ -1485,16 +1632,41 @@ do_create_from_keygrip (ctrl_t ctrl, int algo,
err = agent_readkey (ctrl, 0, hexkeygrip, &public);
if (err)
- return err;
+ {
+ xfree (hexkeygrip_buffer);
+ return err;
+ }
err = gcry_sexp_sscan (&s_key, NULL, public,
gcry_sexp_canon_len (public, 0, NULL, NULL));
xfree (public);
if (err)
- return err;
+ {
+ xfree (hexkeygrip_buffer);
+ return err;
+ }
+ if (hexkeygrip2)
+ {
+ err = agent_readkey (ctrl, 0, hexkeygrip2, &public);
+ if (err)
+ {
+ gcry_sexp_release (s_key);
+ xfree (hexkeygrip_buffer);
+ return err;
+ }
+ err = gcry_sexp_sscan (&s_key2, NULL, public,
+ gcry_sexp_canon_len (public, 0, NULL, NULL));
+ xfree (public);
+ if (err)
+ {
+ gcry_sexp_release (s_key);
+ xfree (hexkeygrip_buffer);
+ return err;
+ }
+ }
}
- /* For X448 we force the use of v5 packets. */
- if (curve_is_448 (s_key))
+ /* For X448 and Kyber we force the use of v5 packets. */
+ if (curve_is_448 (s_key) || algo == PUBKEY_ALGO_KYBER)
*keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY;
/* Build a public key packet. */
@@ -1503,6 +1675,8 @@ do_create_from_keygrip (ctrl_t ctrl, int algo,
{
err = gpg_error_from_syserror ();
gcry_sexp_release (s_key);
+ gcry_sexp_release (s_key2);
+ xfree (hexkeygrip_buffer);
return err;
}
@@ -1512,26 +1686,32 @@ do_create_from_keygrip (ctrl_t ctrl, int algo,
pk->expiredate = pk->timestamp + expireval;
pk->pubkey_algo = algo;
- if (algo == PUBKEY_ALGO_ECDSA
+ if (algo == PUBKEY_ALGO_KYBER)
+ err = ecckey_from_sexp (pk->pkey, s_key, s_key2, algo, pk->version);
+ else if (algo == PUBKEY_ALGO_ECDSA
|| algo == PUBKEY_ALGO_EDDSA
|| algo == PUBKEY_ALGO_ECDH )
- err = ecckey_from_sexp (pk->pkey, s_key, algo);
+ err = ecckey_from_sexp (pk->pkey, s_key, NULL, algo, pk->version);
else
err = key_from_sexp (pk->pkey, s_key, "public-key", algoelem);
if (err)
{
log_error ("key_from_sexp failed: %s\n", gpg_strerror (err) );
gcry_sexp_release (s_key);
+ gcry_sexp_release (s_key2);
free_public_key (pk);
+ xfree (hexkeygrip_buffer);
return err;
}
gcry_sexp_release (s_key);
+ gcry_sexp_release (s_key2);
pkt = xtrycalloc (1, sizeof *pkt);
if (!pkt)
{
err = gpg_error_from_syserror ();
free_public_key (pk);
+ xfree (hexkeygrip_buffer);
return err;
}
@@ -1539,16 +1719,18 @@ do_create_from_keygrip (ctrl_t ctrl, int algo,
pkt->pkt.public_key = pk;
add_kbnode (pub_root, new_kbnode (pkt));
+ xfree (hexkeygrip_buffer);
return 0;
}
-/* Common code for the key generation function gen_xxx. The optinal
+/* Common code for the key generation function gen_xxx. The optional
* (COMMON_GEN_CB,COMMON_GEN_CB_PARM) can be used as communication
- * object.
+ * object. A KEYPARMS2 forces the use of a dual key (e.g. Kyber+ECC).
*/
static int
-common_gen (const char *keyparms, int algo, const char *algoelem,
+common_gen (const char *keyparms, const char *keyparms2,
+ int algo, const char *algoelem,
kbnode_t pub_root, u32 timestamp, u32 expireval, int is_subkey,
int keygen_flags, const char *passphrase,
char **cache_nonce_addr, char **passwd_nonce_addr,
@@ -1559,6 +1741,7 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
PACKET *pkt;
PKT_public_key *pk;
gcry_sexp_t s_key;
+ gcry_sexp_t s_key2 = NULL;
err = agent_genkey (NULL, cache_nonce_addr, passwd_nonce_addr, keyparms,
!!(keygen_flags & KEYGEN_FLAG_NO_PROTECTION),
@@ -1570,14 +1753,32 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
return err;
}
+ if (keyparms2)
+ {
+ err = agent_genkey (NULL, NULL, NULL, keyparms2,
+ 1 /* No protection */,
+ NULL, timestamp,
+ &s_key2);
+ if (err)
+ {
+ log_error ("agent_genkey failed for second algo: %s\n",
+ gpg_strerror (err) );
+ gcry_sexp_release (s_key);
+ return err;
+ }
+ }
+
if (common_gen_cb && common_gen_cb_parm)
{
common_gen_cb_parm->genkey_result = s_key;
+ common_gen_cb_parm->genkey_result2 = s_key2;
err = common_gen_cb (common_gen_cb_parm);
common_gen_cb_parm->genkey_result = NULL;
+ common_gen_cb_parm->genkey_result2 = NULL;
if (err)
{
gcry_sexp_release (s_key);
+ gcry_sexp_release (s_key2);
return err;
}
}
@@ -1596,10 +1797,12 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
pk->expiredate = pk->timestamp + expireval;
pk->pubkey_algo = algo;
- if (algo == PUBKEY_ALGO_ECDSA
- || algo == PUBKEY_ALGO_EDDSA
- || algo == PUBKEY_ALGO_ECDH )
- err = ecckey_from_sexp (pk->pkey, s_key, algo);
+ if (algo == PUBKEY_ALGO_KYBER)
+ err = ecckey_from_sexp (pk->pkey, s_key, s_key2, algo, pk->version);
+ else if (algo == PUBKEY_ALGO_ECDSA
+ || algo == PUBKEY_ALGO_EDDSA
+ || algo == PUBKEY_ALGO_ECDH )
+ err = ecckey_from_sexp (pk->pkey, s_key, NULL, algo, pk->version);
else
err = key_from_sexp (pk->pkey, s_key, "public-key", algoelem);
if (err)
@@ -1610,6 +1813,7 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
return err;
}
gcry_sexp_release (s_key);
+ gcry_sexp_release (s_key2);
pkt = xtrycalloc (1, sizeof *pkt);
if (!pkt)
@@ -1675,7 +1879,7 @@ gen_elg (int algo, unsigned int nbits, KBNODE pub_root,
err = gpg_error_from_syserror ();
else
{
- err = common_gen (keyparms, algo, "pgy",
+ err = common_gen (keyparms, NULL, algo, "pgy",
pub_root, timestamp, expireval, is_subkey,
keygen_flags, passphrase,
cache_nonce_addr, passwd_nonce_addr,
@@ -1767,7 +1971,7 @@ gen_dsa (unsigned int nbits, KBNODE pub_root,
err = gpg_error_from_syserror ();
else
{
- err = common_gen (keyparms, PUBKEY_ALGO_DSA, "pqgy",
+ err = common_gen (keyparms, NULL, PUBKEY_ALGO_DSA, "pqgy",
pub_root, timestamp, expireval, is_subkey,
keygen_flags, passphrase,
cache_nonce_addr, passwd_nonce_addr,
@@ -1868,7 +2072,7 @@ gen_ecc (int algo, const char *curve, kbnode_t pub_root,
err = gpg_error_from_syserror ();
else
{
- err = common_gen (keyparms, algo, "",
+ err = common_gen (keyparms, NULL, algo, "",
pub_root, timestamp, expireval, is_subkey,
*keygen_flags, passphrase,
cache_nonce_addr, passwd_nonce_addr,
@@ -1880,6 +2084,79 @@ gen_ecc (int algo, const char *curve, kbnode_t pub_root,
}
+/* Generate a dual ECC+Kyber key. Note that KEYGEN_FLAGS will be
+ * updated by this function to indicate the forced creation of a v5
+ * key. */
+static gpg_error_t
+gen_kyber (int algo, unsigned int nbits, const char *curve, kbnode_t pub_root,
+ u32 timestamp, u32 expireval, int is_subkey,
+ int *keygen_flags, const char *passphrase,
+ char **cache_nonce_addr, char **passwd_nonce_addr,
+ gpg_error_t (*common_gen_cb)(common_gen_cb_parm_t),
+ common_gen_cb_parm_t common_gen_cb_parm)
+{
+ gpg_error_t err;
+ char *keyparms1;
+ const char *keyparms2;
+
+ log_assert (algo == PUBKEY_ALGO_KYBER);
+
+ if (nbits == 768)
+ keyparms2 = "(genkey(kyber768))";
+ else if (nbits == 1024)
+ keyparms2 = "(genkey(kyber1024))";
+ else
+ return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
+
+ if (!curve || !*curve)
+ return gpg_error (GPG_ERR_UNKNOWN_CURVE);
+
+ *keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY;
+
+ if (!strcmp (curve, "Curve25519"))
+ {
+ keyparms1 = xtryasprintf
+ ("(genkey(ecc(curve %zu:%s)(flags djb-tweak comp%s)))",
+ strlen (curve), curve,
+ (((*keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
+ && (*keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
+ " transient-key" : ""));
+ }
+ else if (!strcmp (curve, "X448"))
+ {
+ keyparms1 = xtryasprintf
+ ("(genkey(ecc(curve %zu:%s)(flags comp%s)))",
+ strlen (curve), curve,
+ (((*keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
+ && (*keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
+ " transient-key" : ""));
+ }
+ else /* Should we use the compressed format? Check smartcard support. */
+ {
+ keyparms1 = xtryasprintf
+ ("(genkey(ecc(curve %zu:%s)(flags nocomp%s)))",
+ strlen (curve), curve,
+ (((*keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
+ && (*keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
+ " transient-key" : ""));
+ }
+
+ if (!keyparms1)
+ err = gpg_error_from_syserror ();
+ else
+ {
+ err = common_gen (keyparms1, keyparms2, algo, "",
+ pub_root, timestamp, expireval, is_subkey,
+ *keygen_flags, passphrase,
+ cache_nonce_addr, passwd_nonce_addr,
+ common_gen_cb, common_gen_cb_parm);
+ xfree (keyparms1);
+ }
+
+ return err;
+}
+
+
/*
* Generate an RSA key.
*/
@@ -1928,7 +2205,7 @@ gen_rsa (int algo, unsigned int nbits, KBNODE pub_root,
err = gpg_error_from_syserror ();
else
{
- err = common_gen (keyparms, algo, "ne",
+ err = common_gen (keyparms, NULL, algo, "ne",
pub_root, timestamp, expireval, is_subkey,
keygen_flags, passphrase,
cache_nonce_addr, passwd_nonce_addr,
@@ -2350,7 +2627,26 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
continue;
}
- if (strlen (answer) != 40 &&
+ if (strlen (answer) == 40+1+40 && answer[40]==',')
+ {
+ int algo1, algo2;
+
+ answer[40] = 0;
+ algo1 = check_keygrip (ctrl, answer);
+ algo2 = check_keygrip (ctrl, answer+41);
+ answer[40] = ',';
+ if (algo1 == PUBKEY_ALGO_ECDH && algo2 == PUBKEY_ALGO_KYBER)
+ {
+ algo = PUBKEY_ALGO_KYBER;
+ break;
+ }
+ else if (!algo1 || !algo2)
+ tty_printf (_("No key with this keygrip\n"));
+ else
+ tty_printf ("Invalid combination for dual algo (%d,%d)\n",
+ algo1, algo2);
+ }
+ else if (strlen (answer) != 40 &&
!(answer[0] == '&' && strlen (answer+1) == 40))
tty_printf
(_("Not a valid keygrip (expecting 40 hex digits)\n"));
@@ -2560,6 +2856,12 @@ get_keysize_range (int algo, unsigned int *min, unsigned int *max)
def=255;
break;
+ case PUBKEY_ALGO_KYBER:
+ *min = 768;
+ *max = 1024;
+ def = 768;
+ break;
+
default:
*min = opt.compliance == CO_DE_VS ? 2048: 1024;
*max = 4096;
@@ -2575,45 +2877,44 @@ get_keysize_range (int algo, unsigned int *min, unsigned int *max)
static unsigned int
fixup_keysize (unsigned int nbits, int algo, int silent)
{
+ unsigned int orig_nbits = nbits;
+
if (algo == PUBKEY_ALGO_DSA && (nbits % 64))
{
nbits = ((nbits + 63) / 64) * 64;
- if (!silent)
- tty_printf (_("rounded up to %u bits\n"), nbits);
}
else if (algo == PUBKEY_ALGO_EDDSA)
{
- if (nbits != 255 && nbits != 441)
- {
- if (nbits < 256)
- nbits = 255;
- else
- nbits = 441;
- if (!silent)
- tty_printf (_("rounded to %u bits\n"), nbits);
- }
+ if (nbits < 256)
+ nbits = 255;
+ else
+ nbits = 441;
}
else if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA)
{
- if (nbits != 256 && nbits != 384 && nbits != 521)
- {
- if (nbits < 256)
- nbits = 256;
- else if (nbits < 384)
- nbits = 384;
- else
- nbits = 521;
- if (!silent)
- tty_printf (_("rounded to %u bits\n"), nbits);
- }
+ if (nbits < 256)
+ nbits = 256;
+ else if (nbits < 384)
+ nbits = 384;
+ else
+ nbits = 521;
+ }
+ else if (algo == PUBKEY_ALGO_KYBER)
+ {
+ /* (in reality the numbers are not bits) */
+ if (nbits < 768)
+ nbits = 768;
+ else if (nbits > 1024)
+ nbits = 1024;
}
else if ((nbits % 32))
{
nbits = ((nbits + 31) / 32) * 32;
- if (!silent)
- tty_printf (_("rounded up to %u bits\n"), nbits );
}
+ if (!silent && orig_nbits != nbits)
+ tty_printf (_("rounded to %u bits\n"), nbits);
+
return nbits;
}
@@ -3343,6 +3644,12 @@ do_create (int algo, unsigned int nbits, const char *curve, kbnode_t pub_root,
keygen_flags, passphrase,
cache_nonce_addr, passwd_nonce_addr,
common_gen_cb, common_gen_cb_parm);
+ else if (algo == PUBKEY_ALGO_KYBER)
+ err = gen_kyber (algo, nbits, curve,
+ pub_root, timestamp, expiredate, is_subkey,
+ keygen_flags, passphrase,
+ cache_nonce_addr, passwd_nonce_addr,
+ common_gen_cb, common_gen_cb_parm);
else if (algo == PUBKEY_ALGO_RSA)
err = gen_rsa (algo, nbits, pub_root, timestamp, expiredate, is_subkey,
*keygen_flags, passphrase,
@@ -3421,6 +3728,7 @@ parse_key_parameter_part (ctrl_t ctrl,
char *keygrip = NULL;
u32 keytime = 0;
int is_448 = 0;
+ int is_pqc = 0;
if (!string || !*string)
return 0; /* Success. */
@@ -3446,6 +3754,7 @@ parse_key_parameter_part (ctrl_t ctrl,
; /* We need the flags before we can figure out the key to use. */
else if (algo)
{
+ /* This is one of the algos parsed above (rsa, dsa, or elg). */
if (!string[3])
size = get_keysize_range (algo, NULL, NULL);
else
@@ -3455,6 +3764,63 @@ parse_key_parameter_part (ctrl_t ctrl,
return gpg_error (GPG_ERR_INV_VALUE);
}
}
+ else if (!ascii_strcasecmp (string, "kyber")
+ || !ascii_strcasecmp (string, "kyber768"))
+ {
+ /* Get the curve and check that it can technically be used
+ * (i.e. everything except the EdXXXX curves. */
+ curve = openpgp_is_curve_supported ("brainpoolP256r1", &algo, NULL);
+ if (!curve || algo == PUBKEY_ALGO_EDDSA)
+ return gpg_error (GPG_ERR_UNKNOWN_CURVE);
+ algo = PUBKEY_ALGO_KYBER;
+ size = 768;
+ is_pqc = 1;
+ }
+ else if (!ascii_strcasecmp (string, "kyber1024"))
+ {
+ /* Get the curve and check that it can technically be used
+ * (i.e. everything except the EdXXXX curves. */
+ curve = openpgp_is_curve_supported ("brainpoolP384r1", &algo, NULL);
+ if (!curve || algo == PUBKEY_ALGO_EDDSA)
+ return gpg_error (GPG_ERR_UNKNOWN_CURVE);
+ algo = PUBKEY_ALGO_KYBER;
+ size = 1024;
+ is_pqc = 1;
+ }
+ else if (!ascii_strncasecmp (string, "ky768_", 6)
+ || !ascii_strncasecmp (string, "ky1024_", 7)
+ || !ascii_strncasecmp (string, "kyber768_", 9)
+ || !ascii_strncasecmp (string, "kyber1024_", 10)
+ )
+ {
+ /* Get the curve and check that it can technically be used
+ * (i.e. everything except the EdXXXX curves. */
+ s = strchr (string, '_');
+ log_assert (s);
+ s++;
+ curve = openpgp_is_curve_supported (s, &algo, NULL);
+ if (!curve || algo == PUBKEY_ALGO_EDDSA)
+ return gpg_error (GPG_ERR_UNKNOWN_CURVE);
+ algo = PUBKEY_ALGO_KYBER;
+ size = strstr (string, "768_")? 768 : 1024;
+ is_pqc = 1;
+ }
+ else if (!ascii_strcasecmp (string, "dil3"))
+ {
+ algo = PUBKEY_ALGO_DIL3_25519;
+ is_pqc = 1;
+ }
+ else if (!ascii_strcasecmp (string, "dil5"))
+ {
+ algo = PUBKEY_ALGO_DIL5_448;
+ is_pqc = 1;
+ }
+ else if (!ascii_strcasecmp (string, "sphinx")
+ || !ascii_strcasecmp (string, "sphinx_sha2"))
+ {
+ algo = PUBKEY_ALGO_SPHINX_SHA2;
+ is_pqc = 1;
+ }
else if ((curve = openpgp_is_curve_supported (string, &algo, &size)))
{
if (!algo)
@@ -3703,8 +4069,8 @@ parse_key_parameter_part (ctrl_t ctrl,
return gpg_error (GPG_ERR_WRONG_KEY_USAGE);
}
- /* Ed448 and X448 must only be used as v5 keys. */
- if (is_448)
+ /* Ed448, X448 and the PQC algos must only be used as v5 keys. */
+ if (is_448 || is_pqc)
{
if (keyversion == 4)
log_info (_("WARNING: v4 is specified, but overridden by v5.\n"));
@@ -3768,6 +4134,8 @@ parse_key_parameter_part (ctrl_t ctrl,
* cv25519 := ECDH using curve Curve25519.
* cv448 := ECDH using curve X448.
* nistp256:= ECDSA or ECDH using curve NIST P-256
+ * kyber := Kyber with the default parameters
+ * ky768_bp384 := Kyber-768 with BrainpoolP256r1 as second algo
*
* All strings with an unknown prefix are considered an elliptic
* curve. Curves which have no implicit algorithm require that FLAGS
@@ -5924,9 +6292,12 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
list_keyblock_direct (ctrl, pub_root, 0, 1,
opt.fingerprint || opt.with_fingerprint,
1);
+ /* Note that we ignore errors from the list function
+ * because that would only be an additional info. It
+ * has already been remarked that the key has been
+ * created. */
}
-
if (!opt.batch
&& (get_parameter_algo (ctrl, para,
pKEYTYPE, NULL) == PUBKEY_ALGO_DSA
@@ -6137,6 +6508,8 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr,
err = hexkeygrip_from_pk (pri_psk, &hexgrip);
if (err)
goto leave;
+ /* FIXME: Right now the primary key won't be a dual key. But this
+ * will change */
if (agent_get_keyinfo (NULL, hexgrip, &serialno, NULL))
{
if (interactive)
@@ -6476,12 +6849,14 @@ gen_card_key (int keyno, int algo, int is_primary, kbnode_t pub_root,
if (curve_is_448 (s_key))
*keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY;
+ pk->version = (*keygen_flags & KEYGEN_FLAG_CREATE_V5_KEY)? 5 : 4;
+
if (algo == PUBKEY_ALGO_RSA)
err = key_from_sexp (pk->pkey, s_key, "public-key", "ne");
else if (algo == PUBKEY_ALGO_ECDSA
|| algo == PUBKEY_ALGO_EDDSA
|| algo == PUBKEY_ALGO_ECDH )
- err = ecckey_from_sexp (pk->pkey, s_key, algo);
+ err = ecckey_from_sexp (pk->pkey, s_key, NULL, algo, pk->version);
else
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
gcry_sexp_release (s_key);
@@ -6494,7 +6869,6 @@ gen_card_key (int keyno, int algo, int is_primary, kbnode_t pub_root,
}
pk->timestamp = *timestamp;
- pk->version = (*keygen_flags & KEYGEN_FLAG_CREATE_V5_KEY)? 5 : 4;
if (expireval)
pk->expiredate = pk->timestamp + expireval;
pk->pubkey_algo = algo;