aboutsummaryrefslogtreecommitdiffstats
path: root/g10/keygen.c
diff options
context:
space:
mode:
Diffstat (limited to 'g10/keygen.c')
-rw-r--r--g10/keygen.c249
1 files changed, 203 insertions, 46 deletions
diff --git a/g10/keygen.c b/g10/keygen.c
index c98deb635..8df8294d6 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -139,6 +139,9 @@ 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;
@@ -1311,8 +1314,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)
{
gpg_error_t err;
gcry_sexp_t list, l2;
@@ -1364,8 +1371,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 +1422,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++)
@@ -1515,7 +1561,7 @@ do_create_from_keygrip (ctrl_t ctrl, int algo,
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);
else
err = key_from_sexp (pk->pkey, s_key, "public-key", algoelem);
if (err)
@@ -1543,12 +1589,13 @@ do_create_from_keygrip (ctrl_t ctrl, int algo,
}
-/* 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 +1606,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 +1618,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 +1662,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);
+ else if (algo == PUBKEY_ALGO_ECDSA
+ || algo == PUBKEY_ALGO_EDDSA
+ || algo == PUBKEY_ALGO_ECDH )
+ err = ecckey_from_sexp (pk->pkey, s_key, NULL, algo);
else
err = key_from_sexp (pk->pkey, s_key, "public-key", algoelem);
if (err)
@@ -1610,6 +1678,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 +1744,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 +1836,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 +1937,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 +1949,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 +2070,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,
@@ -2547,6 +2689,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;
@@ -2562,45 +2710,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;
}
@@ -3330,6 +3477,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,
@@ -3434,6 +3587,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
@@ -3443,14 +3597,15 @@ parse_key_parameter_part (ctrl_t ctrl,
return gpg_error (GPG_ERR_INV_VALUE);
}
}
- else if (!ascii_strcasecmp (string, "ky768"))
- {
- algo = PUBKEY_ALGO_KY768_25519;
- is_pqc = 1;
- }
- else if (!ascii_strcasecmp (string, "ky1024"))
+ else if (!ascii_strcasecmp (string, "kyber"))
{
- algo = PUBKEY_ALGO_KY1024_448;
+ /* 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 = 768;
is_pqc = 1;
}
else if (!ascii_strcasecmp (string, "dil3"))
@@ -3782,6 +3937,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
@@ -6495,7 +6652,7 @@ gen_card_key (int keyno, int algo, int is_primary, kbnode_t pub_root,
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);
else
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
gcry_sexp_release (s_key);