diff options
Diffstat (limited to 'g10/keygen.c')
-rw-r--r-- | g10/keygen.c | 484 |
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; |