summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/openpgp-oid.c28
-rw-r--r--common/util.h1
-rw-r--r--g10/pkglue.c88
3 files changed, 93 insertions, 24 deletions
diff --git a/common/openpgp-oid.c b/common/openpgp-oid.c
index 4b59c1aeb..74541a03f 100644
--- a/common/openpgp-oid.c
+++ b/common/openpgp-oid.c
@@ -45,14 +45,15 @@ static struct {
const char *alias; /* NULL or alternative name of the curve. */
const char *abbr; /* NULL or abbreviated name of the curve. */
int pubkey_algo; /* Required OpenPGP algo or 0 for ECDSA/ECDH. */
+ enum gcry_kem_algos kem_algo; /* 0 or the KEM algorithm for PQC. */
} oidtable[] = {
{ "Curve25519", "1.3.6.1.4.1.3029.1.5.1", 255, "cv25519", NULL,
- PUBKEY_ALGO_ECDH },
+ PUBKEY_ALGO_ECDH, GCRY_KEM_RAW_X25519 /* only during development */},
{ "Ed25519", "1.3.6.1.4.1.11591.15.1", 255, "ed25519", NULL,
PUBKEY_ALGO_EDDSA },
{ "Curve25519", "1.3.101.110", 255, "cv25519", NULL,
- PUBKEY_ALGO_ECDH },
+ PUBKEY_ALGO_ECDH, GCRY_KEM_RAW_X25519 },
{ "Ed25519", "1.3.101.112", 255, "ed25519", NULL,
PUBKEY_ALGO_EDDSA },
{ "X448", "1.3.101.111", 448, "cv448", NULL,
@@ -542,6 +543,29 @@ openpgp_oid_or_name_to_curve (const char *oidname, int canon)
}
+/* Return the KEM algorithm id for the curve with OIDNAME. */
+enum gcry_kem_algos
+openpgp_oid_to_kem_algo (const char *oidname)
+{
+ int i;
+
+ if (!oidname)
+ return 0;
+
+ for (i=0; oidtable[i].name; i++)
+ if (!strcmp (oidtable[i].oidstr, oidname))
+ return oidtable[i].kem_algo;
+
+ for (i=0; oidtable[i].name; i++)
+ if (!ascii_strcasecmp (oidtable[i].name, oidname)
+ || (oidtable[i].alias
+ && !ascii_strcasecmp (oidtable[i].alias, oidname)))
+ return oidtable[i].kem_algo;
+
+ return 0;
+}
+
+
/* Return true if the curve with NAME is supported. */
static int
curve_supported_p (const char *name)
diff --git a/common/util.h b/common/util.h
index 5c953a8a1..238b8f1bc 100644
--- a/common/util.h
+++ b/common/util.h
@@ -227,6 +227,7 @@ int openpgp_oidbuf_is_cv25519 (const void *buf, size_t len);
int openpgp_oid_is_cv25519 (gcry_mpi_t a);
int openpgp_oid_is_cv448 (gcry_mpi_t a);
int openpgp_oid_is_ed448 (gcry_mpi_t a);
+enum gcry_kem_algos openpgp_oid_to_kem_algo (const char *oidname);
const char *openpgp_curve_to_oid (const char *name,
unsigned int *r_nbits, int *r_algo);
const char *openpgp_oid_to_curve (const char *oid, int mode);
diff --git a/g10/pkglue.c b/g10/pkglue.c
index 0167e80e3..2de0e80ab 100644
--- a/g10/pkglue.c
+++ b/g10/pkglue.c
@@ -417,6 +417,11 @@ pk_verify (pubkey_algo_t pkalgo, gcry_mpi_t hash,
}
+#if GCRY_KEM_MLKEM1024_ENCAPS_LEN < GCRY_KEM_MLKEM768_ENCAPS_LEN \
+ || GCRY_KEM_MLKEM1024_SHARED_LEN < GCRY_KEM_MLKEM768_SHARED_LEN
+# error Bad Kyber constants in Libgcrypt
+#endif
+
/* Core of the encryption for KEM algorithms. See pk_decrypt for a
* description of the arguments. */
static gpg_error_t
@@ -428,6 +433,8 @@ do_encrypt_kem (PKT_public_key *pk, gcry_mpi_t data, int seskey_algo,
unsigned int nbits, n;
gcry_sexp_t s_data = NULL;
gcry_cipher_hd_t hd = NULL;
+ char *ecc_oid = NULL;
+ enum gcry_kem_algos kyber_algo, ecc_algo;
const unsigned char *ecc_pubkey;
size_t ecc_pubkey_len;
@@ -445,10 +452,9 @@ do_encrypt_kem (PKT_public_key *pk, gcry_mpi_t data, int seskey_algo,
unsigned char ecc_ss[GCRY_KEM_RAW_X25519_SHARED_LEN];
size_t ecc_ss_len = GCRY_KEM_RAW_X25519_SHARED_LEN;
- unsigned char kyber_ct[GCRY_KEM_MLKEM768_ENCAPS_LEN];
- size_t kyber_ct_len = GCRY_KEM_MLKEM768_ENCAPS_LEN;
- unsigned char kyber_ss[GCRY_KEM_MLKEM768_SHARED_LEN];
- size_t kyber_ss_len = GCRY_KEM_MLKEM768_SHARED_LEN;
+ unsigned char kyber_ct[GCRY_KEM_MLKEM1024_ENCAPS_LEN];
+ unsigned char kyber_ss[GCRY_KEM_MLKEM1024_SHARED_LEN];
+ size_t kyber_ct_len, kyber_ss_len;
char fixedinfo[1+MAX_FINGERPRINT_LEN];
int fixedlen;
@@ -463,23 +469,48 @@ do_encrypt_kem (PKT_public_key *pk, gcry_mpi_t data, int seskey_algo,
* second public key is expected. Right now we take the keys
* directly from the PK->data elements. */
- /* FIXME: This is only for cv25519 */
- ecc_pubkey = gcry_mpi_get_opaque (pk->pkey[1], &nbits);
- ecc_pubkey_len = (nbits+7)/8;
- if (ecc_pubkey_len != 33)
+ ecc_oid = openpgp_oid_to_str (pk->pkey[0]);
+ if (!ecc_oid)
+ {
+ err = gpg_error_from_syserror ();
+ log_error ("%s: error getting OID for ECC key\n", __func__);
+ goto leave;
+ }
+ ecc_algo = openpgp_oid_to_kem_algo (ecc_oid);
+ if (ecc_algo == GCRY_KEM_RAW_X25519)
+ {
+ if (!strcmp (ecc_oid, "1.3.6.1.4.1.3029.1.5.1"))
+ log_info ("Warning: "
+ "legacy OID for cv25519 accepted during develpment\n");
+ ecc_pubkey = gcry_mpi_get_opaque (pk->pkey[1], &nbits);
+ ecc_pubkey_len = (nbits+7)/8;
+ if (ecc_pubkey_len != 33)
+ {
+ if (opt.verbose)
+ log_info ("%s: ECC public key length invalid (%zu)\n",
+ __func__, ecc_pubkey_len);
+ err = gpg_error (GPG_ERR_INV_DATA);
+ goto leave;
+ }
+ ecc_pubkey++; /* Remove the 0x40 prefix. */
+ ecc_pubkey_len--;
+ }
+ else
{
if (opt.verbose)
- log_info ("%s: ECC public key length invalid (%zu)\n",
- __func__, ecc_pubkey_len);
+ log_info ("%s: ECC curve %s not supported\n", __func__, ecc_oid);
err = gpg_error (GPG_ERR_INV_DATA);
goto leave;
}
- ecc_pubkey++; /* Remove the 0x40 prefix. */
- ecc_pubkey_len--;
+
+
if (DBG_CRYPTO)
- log_printhex (ecc_pubkey, ecc_pubkey_len, "ECC pubkey:");
+ {
+ log_debug ("ECC curve: %s\n", ecc_oid);
+ log_printhex (ecc_pubkey, ecc_pubkey_len, "ECC pubkey:");
+ }
- err = gcry_kem_encap (GCRY_KEM_RAW_X25519,
+ err = gcry_kem_encap (ecc_algo,
ecc_pubkey, ecc_pubkey_len,
ecc_ct, ecc_ct_len,
ecc_ecdh, ecc_ecdh_len,
@@ -487,7 +518,8 @@ do_encrypt_kem (PKT_public_key *pk, gcry_mpi_t data, int seskey_algo,
if (err)
{
if (opt.verbose)
- log_info ("%s: gcry_kem_encap for ECC failed\n", __func__);
+ log_info ("%s: gcry_kem_encap for ECC (%s) failed\n",
+ __func__, ecc_oid);
goto leave;
}
if (DBG_CRYPTO)
@@ -509,21 +541,32 @@ do_encrypt_kem (PKT_public_key *pk, gcry_mpi_t data, int seskey_algo,
if (DBG_CRYPTO)
log_printhex (ecc_ss, ecc_ss_len, "ECC shared:");
- /* FIXME: This is only for kyber768 */
kyber_pubkey = gcry_mpi_get_opaque (pk->pkey[2], &nbits);
kyber_pubkey_len = (nbits+7)/8;
- if (kyber_pubkey_len != GCRY_KEM_MLKEM768_PUBKEY_LEN)
+ if (kyber_pubkey_len == GCRY_KEM_MLKEM768_PUBKEY_LEN)
+ {
+ kyber_algo = GCRY_KEM_MLKEM768;
+ kyber_ct_len = GCRY_KEM_MLKEM768_ENCAPS_LEN;
+ kyber_ss_len = GCRY_KEM_MLKEM768_SHARED_LEN;
+ }
+ else if (kyber_pubkey_len == GCRY_KEM_MLKEM1024_PUBKEY_LEN)
+ {
+ kyber_algo = GCRY_KEM_MLKEM1024;
+ kyber_ct_len = GCRY_KEM_MLKEM1024_ENCAPS_LEN;
+ kyber_ss_len = GCRY_KEM_MLKEM1024_SHARED_LEN;
+ }
+ else
{
if (opt.verbose)
- log_info ("%s: Kyber public key length invalid (%zu)\n",
- __func__, kyber_pubkey_len);
+ log_info ("%s: Kyber public key length invalid (%zu)\n",
+ __func__, kyber_pubkey_len);
err = gpg_error (GPG_ERR_INV_DATA);
goto leave;
}
if (DBG_CRYPTO)
log_printhex (kyber_pubkey, kyber_pubkey_len, "|!trunc|Kyber pubkey:");
- err = gcry_kem_encap (GCRY_KEM_MLKEM768,
+ err = gcry_kem_encap (kyber_algo,
kyber_pubkey, kyber_pubkey_len,
kyber_ct, kyber_ct_len,
kyber_ss, kyber_ss_len,
@@ -625,11 +668,12 @@ do_encrypt_kem (PKT_public_key *pk, gcry_mpi_t data, int seskey_algo,
wipememory (ecc_ct, ecc_ct_len);
wipememory (ecc_ecdh, ecc_ecdh_len);
wipememory (ecc_ss, ecc_ss_len);
- wipememory (kyber_ct, kyber_ct_len);
- wipememory (kyber_ss, kyber_ss_len);
+ wipememory (kyber_ct, sizeof kyber_ct);
+ wipememory (kyber_ss, sizeof kyber_ss);
wipememory (kek, kek_len);
xfree (enc_seskey);
gcry_cipher_close (hd);
+ xfree (ecc_oid);
return err;
}