From: d-Dudas Date: Sun, 28 Jul 2024 21:00:40 +0000 (+0300) Subject: Add experimental support for post-quantum digital signature algorithms in X.509 certi... X-Git-Tag: 3.8.9~21^2~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e659e84e2f96d27da2ca859f4773296bf878f82d;p=thirdparty%2Fgnutls.git Add experimental support for post-quantum digital signature algorithms in X.509 certificates - Dilithium - Falcon - Sphincs family Signed-off-by: David Dudas --- diff --git a/doc/Makefile.am b/doc/Makefile.am index af7431961c..64fde86542 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -567,7 +567,6 @@ ENUMS += enums/gnutls_ocsp_verify_reason_t ENUMS += enums/gnutls_openpgp_crt_status_t ENUMS += enums/gnutls_params_type_t ENUMS += enums/gnutls_pin_flag_t -ENUMS += enums/gnutls_pk_algorithm_t ENUMS += enums/gnutls_pkcs11_obj_flags ENUMS += enums/gnutls_pkcs11_obj_info_t ENUMS += enums/gnutls_pkcs11_obj_type_t @@ -587,7 +586,6 @@ ENUMS += enums/gnutls_rnd_level_t ENUMS += enums/gnutls_sec_param_t ENUMS += enums/gnutls_server_name_type_t ENUMS += enums/gnutls_session_flags_t -ENUMS += enums/gnutls_sign_algorithm_t ENUMS += enums/gnutls_srtp_profile_t ENUMS += enums/gnutls_supplemental_data_format_type_t ENUMS += enums/gnutls_tpmkey_fmt_t diff --git a/lib/algorithms.h b/lib/algorithms.h index 2e1b694c64..383b6da609 100644 --- a/lib/algorithms.h +++ b/lib/algorithms.h @@ -55,6 +55,34 @@ #define IS_KEM(x) \ (((x) == GNUTLS_PK_MLKEM768) || ((x) == GNUTLS_PK_EXP_KYBER768)) +#ifdef HAVE_LIBOQS +#define IS_DILITHIUM(x) \ + (((x) == GNUTLS_PK_EXP_DILITHIUM2) || \ + ((x) == GNUTLS_PK_EXP_DILITHIUM3) || \ + ((x) == GNUTLS_PK_EXP_DILITHIUM5)) + +#define IS_FALCON(x) \ + (((x) == GNUTLS_PK_EXP_FALCON512) || ((x) == GNUTLS_PK_EXP_FALCON1024)) + +#define IS_SIMPLE_SPHINCS(x) \ + (((x) == GNUTLS_PK_EXP_SPHINCS_SHA2_128S) || \ + ((x) == GNUTLS_PK_EXP_SPHINCS_SHA2_192S) || \ + ((x) == GNUTLS_PK_EXP_SPHINCS_SHA2_256S) || \ + ((x) == GNUTLS_PK_EXP_SPHINCS_SHAKE_128S) || \ + ((x) == GNUTLS_PK_EXP_SPHINCS_SHAKE_192S) || \ + ((x) == GNUTLS_PK_EXP_SPHINCS_SHAKE_256S)) + +#define IS_FAST_SPHINCS(x) \ + (((x) == GNUTLS_PK_EXP_SPHINCS_SHA2_128F) || \ + ((x) == GNUTLS_PK_EXP_SPHINCS_SHA2_192F) || \ + ((x) == GNUTLS_PK_EXP_SPHINCS_SHA2_256F) || \ + ((x) == GNUTLS_PK_EXP_SPHINCS_SHAKE_128F) || \ + ((x) == GNUTLS_PK_EXP_SPHINCS_SHAKE_192F) || \ + ((x) == GNUTLS_PK_EXP_SPHINCS_SHAKE_256F)) + +#define IS_SPHINCS(x) (IS_SIMPLE_SPHINCS(x) || IS_FAST_SPHINCS(x)) +#endif + #define SIG_SEM_PRE_TLS12 (1 << 1) #define SIG_SEM_TLS13 (1 << 2) #define SIG_SEM_DEFAULT (SIG_SEM_PRE_TLS12 | SIG_SEM_TLS13) diff --git a/lib/algorithms/publickey.c b/lib/algorithms/publickey.c index 15f77f70c5..6f0f7c3513 100644 --- a/lib/algorithms/publickey.c +++ b/lib/algorithms/publickey.c @@ -213,6 +213,101 @@ static const gnutls_pk_entry pk_algorithms[] = { .oid = NULL, .id = GNUTLS_PK_EXP_KYBER768, .curve = GNUTLS_ECC_CURVE_INVALID }, + { .name = "Dilithium2", + .oid = DILITHIUM2_OID, + .id = GNUTLS_PK_EXP_DILITHIUM2, + .curve = GNUTLS_ECC_CURVE_INVALID, + .no_prehashed = 1 }, + { .name = "Dilithium3", + .oid = DILITHIUM3_OID, + .id = GNUTLS_PK_EXP_DILITHIUM3, + .curve = GNUTLS_ECC_CURVE_INVALID, + .no_prehashed = 1 }, + { .name = "Dilithium5", + .oid = DILITHIUM5_OID, + .id = GNUTLS_PK_EXP_DILITHIUM5, + .curve = GNUTLS_ECC_CURVE_INVALID, + .no_prehashed = 1 }, + { .name = "Falcon512", + .oid = FALCON512_OID, + .id = GNUTLS_PK_EXP_FALCON512, + .curve = GNUTLS_ECC_CURVE_INVALID, + .no_prehashed = 1 }, + { .name = "Falcon1024", + .oid = FALCON1024_OID, + .id = GNUTLS_PK_EXP_FALCON1024, + .curve = GNUTLS_ECC_CURVE_INVALID, + .no_prehashed = 1 }, + { .name = "Falcon512", + .oid = FALCON512_OID, + .id = GNUTLS_PK_EXP_FALCON512, + .curve = GNUTLS_ECC_CURVE_INVALID, + .no_prehashed = 1 }, + { .name = "Falcon1024", + .oid = FALCON1024_OID, + .id = GNUTLS_PK_EXP_FALCON1024, + .curve = GNUTLS_ECC_CURVE_INVALID, + .no_prehashed = 1 }, + { .name = "Sphincs SHA2 128F", + .oid = SPHINCS_SHA2_128F_OID, + .id = GNUTLS_PK_EXP_SPHINCS_SHA2_128F, + .curve = GNUTLS_ECC_CURVE_INVALID, + .no_prehashed = 1 }, + { .name = "Sphincs SHA2 128S", + .oid = SPHINCS_SHA2_128S_OID, + .id = GNUTLS_PK_EXP_SPHINCS_SHA2_128S, + .curve = GNUTLS_ECC_CURVE_INVALID, + .no_prehashed = 1 }, + { .name = "Sphincs SHA2 192F", + .oid = SPHINCS_SHA2_192F_OID, + .id = GNUTLS_PK_EXP_SPHINCS_SHA2_192F, + .curve = GNUTLS_ECC_CURVE_INVALID, + .no_prehashed = 1 }, + { .name = "Sphincs SHA2 192S", + .oid = SPHINCS_SHA2_192S_OID, + .id = GNUTLS_PK_EXP_SPHINCS_SHA2_192S, + .curve = GNUTLS_ECC_CURVE_INVALID, + .no_prehashed = 1 }, + { .name = "Sphincs SHA2 256F", + .oid = SPHINCS_SHA2_256F_OID, + .id = GNUTLS_PK_EXP_SPHINCS_SHA2_256F, + .curve = GNUTLS_ECC_CURVE_INVALID, + .no_prehashed = 1 }, + { .name = "Sphincs SHA2 256S", + .oid = SPHINCS_SHA2_256S_OID, + .id = GNUTLS_PK_EXP_SPHINCS_SHA2_256S, + .curve = GNUTLS_ECC_CURVE_INVALID, + .no_prehashed = 1 }, + { .name = "Sphincs SHAKE 128F", + .oid = SPHINCS_SHAKE_128F_OID, + .id = GNUTLS_PK_EXP_SPHINCS_SHAKE_128F, + .curve = GNUTLS_ECC_CURVE_INVALID, + .no_prehashed = 1 }, + { .name = "Sphincs SHAKE 128S", + .oid = SPHINCS_SHAKE_128S_OID, + .id = GNUTLS_PK_EXP_SPHINCS_SHAKE_128S, + .curve = GNUTLS_ECC_CURVE_INVALID, + .no_prehashed = 1 }, + { .name = "Sphincs SHAKE 192F", + .oid = SPHINCS_SHAKE_192F_OID, + .id = GNUTLS_PK_EXP_SPHINCS_SHAKE_192F, + .curve = GNUTLS_ECC_CURVE_INVALID, + .no_prehashed = 1 }, + { .name = "Sphincs SHAKE 192S", + .oid = SPHINCS_SHAKE_192S_OID, + .id = GNUTLS_PK_EXP_SPHINCS_SHAKE_192S, + .curve = GNUTLS_ECC_CURVE_INVALID, + .no_prehashed = 1 }, + { .name = "Sphincs SHAKE 256F", + .oid = SPHINCS_SHAKE_256F_OID, + .id = GNUTLS_PK_EXP_SPHINCS_SHAKE_256F, + .curve = GNUTLS_ECC_CURVE_INVALID, + .no_prehashed = 1 }, + { .name = "Sphincs SHAKE 256S", + .oid = SPHINCS_SHAKE_256S_OID, + .id = GNUTLS_PK_EXP_SPHINCS_SHAKE_256S, + .curve = GNUTLS_ECC_CURVE_INVALID, + .no_prehashed = 1 }, #endif { .name = "UNKNOWN", .oid = NULL, diff --git a/lib/algorithms/secparams.c b/lib/algorithms/secparams.c index f498b0f5a1..0bc3a891f4 100644 --- a/lib/algorithms/secparams.c +++ b/lib/algorithms/secparams.c @@ -35,28 +35,92 @@ typedef struct { */ unsigned int subgroup_bits; /* subgroup bits */ unsigned int ecc_bits; /* bits for ECC keys */ +#ifdef HAVE_LIBOQS + unsigned int dilithium_bits; + unsigned int falcon_bits; + unsigned int sphincs_bits; +#endif } gnutls_sec_params_entry; static const gnutls_sec_params_entry sec_params[] = { - { "Insecure", GNUTLS_SEC_PARAM_INSECURE, 0, 0, 0, 0, 0 }, - { "Export", GNUTLS_SEC_PARAM_EXPORT, 42, 512, 0, 84, 0 }, - { "Very weak", GNUTLS_SEC_PARAM_VERY_WEAK, 64, 767, 0, 128, 0 }, - { "Weak", GNUTLS_SEC_PARAM_WEAK, 72, 1008, 1008, 160, 160 }, + { "Insecure", GNUTLS_SEC_PARAM_INSECURE, 0, 0, 0, 0, 0, +#ifdef HAVE_LIBOQS + 0, 0, 0 +#endif + }, + { "Export", GNUTLS_SEC_PARAM_EXPORT, 42, 512, 0, 84, 0, +#ifdef HAVE_LIBOQS + 0, 0, 0 +#endif + }, + { "Very weak", GNUTLS_SEC_PARAM_VERY_WEAK, 64, 767, 0, 128, 0, +#ifdef HAVE_LIBOQS + 0, 0, 0 +#endif + }, + { "Weak", GNUTLS_SEC_PARAM_WEAK, 72, 1008, 1008, 160, 160, +#ifdef HAVE_LIBOQS + 0, 0, 0 +#endif + }, #ifdef ENABLE_FIPS140 - { "Low", GNUTLS_SEC_PARAM_LOW, 80, 1024, 1024, 160, 160 }, - { "Legacy", GNUTLS_SEC_PARAM_LEGACY, 96, 1024, 1024, 192, 192 }, - { "Medium", GNUTLS_SEC_PARAM_MEDIUM, 112, 2048, 2048, 224, 224 }, - { "High", GNUTLS_SEC_PARAM_HIGH, 128, 3072, 3072, 256, 256 }, + { "Low", GNUTLS_SEC_PARAM_LOW, 80, 1024, 1024, 160, 160, +#ifdef HAVE_LIBOQS + 0, 0, 0 +#endif + }, + { "Legacy", GNUTLS_SEC_PARAM_LEGACY, 96, 1024, 1024, 192, 192, +#ifdef HAVE_LIBOQS + 0, 897, 32 +#endif + }, + { "Medium", GNUTLS_SEC_PARAM_MEDIUM, 112, 2048, 2048, 224, 224, +#ifdef HAVE_LIBOQS + 1312, 0, 0 +#endif + }, + { "High", GNUTLS_SEC_PARAM_HIGH, 128, 3072, 3072, 256, 256, +#ifdef HAVE_LIBOQS + 0, 0, 48 +#endif + }, #else - { "Low", GNUTLS_SEC_PARAM_LOW, 80, 1024, 1024, 160, - 160 }, /* ENISA-LEGACY */ - { "Legacy", GNUTLS_SEC_PARAM_LEGACY, 96, 1776, 2048, 192, 192 }, - { "Medium", GNUTLS_SEC_PARAM_MEDIUM, 112, 2048, 2048, 256, 224 }, - { "High", GNUTLS_SEC_PARAM_HIGH, 128, 3072, 3072, 256, 256 }, -#endif - { "Ultra", GNUTLS_SEC_PARAM_ULTRA, 192, 8192, 8192, 384, 384 }, - { "Future", GNUTLS_SEC_PARAM_FUTURE, 256, 15360, 15360, 512, 512 }, - { NULL, 0, 0, 0, 0, 0 } + { "Low", GNUTLS_SEC_PARAM_LOW, 80, 1024, 1024, 160, 160, +#ifdef HAVE_LIBOQS + 0, 0, 0 +#endif + }, /* ENISA-LEGACY */ + { "Legacy", GNUTLS_SEC_PARAM_LEGACY, 96, 1776, 2048, 192, 192, +#ifdef HAVE_LIBOQS + 0, 897, 32 +#endif + }, + { "Medium", GNUTLS_SEC_PARAM_MEDIUM, 112, 2048, 2048, 256, 224, +#ifdef HAVE_LIBOQS + 1312, 0, 0 +#endif + }, + { "High", GNUTLS_SEC_PARAM_HIGH, 128, 3072, 3072, 256, 256, +#ifdef HAVE_LIBOQS + 0, 0, 48 +#endif + }, +#endif + { "Ultra", GNUTLS_SEC_PARAM_ULTRA, 192, 8192, 8192, 384, 384, +#ifdef HAVE_LIBOQS + 1952, 0, 0 +#endif + }, + { "Future", GNUTLS_SEC_PARAM_FUTURE, 256, 15360, 15360, 512, 512, +#ifdef HAVE_LIBOQS + 2592, 1793, 64 +#endif + }, + { NULL, 0, 0, 0, 0, +#ifdef HAVE_LIBOQS + 0, 0, 0 +#endif + } }; /** @@ -87,6 +151,14 @@ unsigned int gnutls_sec_param_to_pk_bits(gnutls_pk_algorithm_t algo, ret = p->dsa_bits; else if (IS_EC(algo) || IS_GOSTEC(algo)) ret = p->ecc_bits; +#ifdef HAVE_LIBOQS + else if (IS_DILITHIUM(algo)) + ret = p->dilithium_bits; + else if (IS_FALCON(algo)) + ret = p->falcon_bits; + else if (IS_SPHINCS(algo)) + ret = p->sphincs_bits; +#endif else ret = p->pk_bits; break; @@ -216,6 +288,26 @@ gnutls_sec_param_t gnutls_pk_bits_to_sec_param(gnutls_pk_algorithm_t algo, break; ret = p->sec_param; } +#ifdef HAVE_LIBOQS + } else if (IS_DILITHIUM(algo)) { + for (p = sec_params; p->name; p++) { + if (p->dilithium_bits > bits) + break; + ret = p->sec_param; + } + } else if (IS_FALCON(algo)) { + for (p = sec_params; p->name; p++) { + if (p->falcon_bits > bits) + break; + ret = p->sec_param; + } + } else if (IS_SPHINCS(algo)) { + for (p = sec_params; p->name; p++) { + if (p->sphincs_bits > bits) + break; + ret = p->sec_param; + } +#endif } else { for (p = sec_params; p->name; p++) { if (p->pk_bits > bits) diff --git a/lib/algorithms/sign.c b/lib/algorithms/sign.c index 638dfd0c94..021da73af6 100644 --- a/lib/algorithms/sign.c +++ b/lib/algorithms/sign.c @@ -402,7 +402,110 @@ static SYSTEM_CONFIG_OR_CONST gnutls_sign_entry_st sign_algorithms[] = { .pk = GNUTLS_PK_DSA, .hash = GNUTLS_DIG_SHA512, .aid = TLS_SIGN_AID_UNKNOWN }, - +#ifdef HAVE_LIBOQS + { .name = "Dilithium2", + .oid = DILITHIUM2_OID, + .id = GNUTLS_SIGN_EXP_DILITHIUM2, + .pk = GNUTLS_PK_EXP_DILITHIUM2, + .hash = GNUTLS_DIG_SHAKE_256, + .aid = TLS_SIGN_AID_UNKNOWN }, + { .name = "Dilithium3", + .oid = DILITHIUM3_OID, + .id = GNUTLS_SIGN_EXP_DILITHIUM3, + .pk = GNUTLS_PK_EXP_DILITHIUM3, + .hash = GNUTLS_DIG_SHAKE_256, + .aid = TLS_SIGN_AID_UNKNOWN }, + { .name = "Dilithium5", + .oid = DILITHIUM5_OID, + .id = GNUTLS_SIGN_EXP_DILITHIUM5, + .pk = GNUTLS_PK_EXP_DILITHIUM5, + .hash = GNUTLS_DIG_SHAKE_256, + .aid = TLS_SIGN_AID_UNKNOWN }, + { .name = "Falcon512", + .oid = FALCON512_OID, + .id = GNUTLS_SIGN_EXP_FALCON512, + .pk = GNUTLS_PK_EXP_FALCON512, + .hash = GNUTLS_DIG_SHAKE_256, + .aid = TLS_SIGN_AID_UNKNOWN }, + { .name = "Falcon1024", + .oid = FALCON1024_OID, + .id = GNUTLS_SIGN_EXP_FALCON1024, + .pk = GNUTLS_PK_EXP_FALCON1024, + .hash = GNUTLS_DIG_SHAKE_256, + .aid = TLS_SIGN_AID_UNKNOWN }, + { .name = "Sphincs-SHA2-128F", + .oid = SPHINCS_SHA2_128F_OID, + .id = GNUTLS_SIGN_EXP_SPHINCS_SHA2_128F, + .pk = GNUTLS_PK_EXP_SPHINCS_SHA2_128F, + .hash = GNUTLS_DIG_SHA256, // + .aid = TLS_SIGN_AID_UNKNOWN }, + { .name = "Sphincs-SHA2-128S", + .oid = SPHINCS_SHA2_128S_OID, + .id = GNUTLS_SIGN_EXP_SPHINCS_SHA2_128S, + .pk = GNUTLS_PK_EXP_SPHINCS_SHA2_128S, + .hash = GNUTLS_DIG_SHA256, + .aid = TLS_SIGN_AID_UNKNOWN }, + { .name = "Sphincs-SHA2-192F", + .oid = SPHINCS_SHA2_192F_OID, + .id = GNUTLS_SIGN_EXP_SPHINCS_SHA2_192F, + .pk = GNUTLS_PK_EXP_SPHINCS_SHA2_192F, + .hash = GNUTLS_DIG_SHA256, + .aid = TLS_SIGN_AID_UNKNOWN }, + { .name = "Sphincs-SHA2-192S", + .oid = SPHINCS_SHA2_192S_OID, + .id = GNUTLS_SIGN_EXP_SPHINCS_SHA2_192S, + .pk = GNUTLS_PK_EXP_SPHINCS_SHA2_192S, + .hash = GNUTLS_DIG_SHA256, + .aid = TLS_SIGN_AID_UNKNOWN }, + { .name = "Sphincs-SHA2-256F", + .oid = SPHINCS_SHA2_256F_OID, + .id = GNUTLS_SIGN_EXP_SPHINCS_SHA2_256F, + .pk = GNUTLS_PK_EXP_SPHINCS_SHA2_256F, + .hash = GNUTLS_DIG_SHA256, + .aid = TLS_SIGN_AID_UNKNOWN }, + { .name = "Sphincs-SHA2-256S", + .oid = SPHINCS_SHA2_256S_OID, + .id = GNUTLS_SIGN_EXP_SPHINCS_SHA2_256S, + .pk = GNUTLS_PK_EXP_SPHINCS_SHA2_256S, + .hash = GNUTLS_DIG_SHA256, + .aid = TLS_SIGN_AID_UNKNOWN }, + { .name = "Sphincs-SHAKE-128F", + .oid = SPHINCS_SHAKE_128F_OID, + .id = GNUTLS_SIGN_EXP_SPHINCS_SHAKE_128F, + .pk = GNUTLS_PK_EXP_SPHINCS_SHAKE_128F, + .hash = GNUTLS_DIG_SHAKE_256, + .aid = TLS_SIGN_AID_UNKNOWN }, + { .name = "Sphincs-SHAKE-128S", + .oid = SPHINCS_SHAKE_128S_OID, + .id = GNUTLS_SIGN_EXP_SPHINCS_SHAKE_128S, + .pk = GNUTLS_PK_EXP_SPHINCS_SHAKE_128S, + .hash = GNUTLS_DIG_SHAKE_256, + .aid = TLS_SIGN_AID_UNKNOWN }, + { .name = "Sphincs-SHAKE-192F", + .oid = SPHINCS_SHAKE_192F_OID, + .id = GNUTLS_SIGN_EXP_SPHINCS_SHAKE_192F, + .pk = GNUTLS_PK_EXP_SPHINCS_SHAKE_192F, + .hash = GNUTLS_DIG_SHAKE_256, + .aid = TLS_SIGN_AID_UNKNOWN }, + { .name = "Sphincs-SHAKE-192S", + .oid = SPHINCS_SHAKE_192S_OID, + .id = GNUTLS_SIGN_EXP_SPHINCS_SHAKE_192S, + .pk = GNUTLS_PK_EXP_SPHINCS_SHAKE_192S, + .hash = GNUTLS_DIG_SHAKE_256, + .aid = TLS_SIGN_AID_UNKNOWN }, + { .name = "Sphincs-SHAKE-256F", + .oid = SPHINCS_SHAKE_256F_OID, + .id = GNUTLS_SIGN_EXP_SPHINCS_SHAKE_256F, + .pk = GNUTLS_PK_EXP_SPHINCS_SHAKE_256F, + .hash = GNUTLS_DIG_SHAKE_256, + .aid = TLS_SIGN_AID_UNKNOWN }, + { .name = "Sphincs-SHAKE-256S", + .oid = SPHINCS_SHAKE_256S_OID, + .id = GNUTLS_SIGN_EXP_SPHINCS_SHAKE_256S, + .pk = GNUTLS_PK_EXP_SPHINCS_SHAKE_256S, + .hash = GNUTLS_DIG_SHAKE_256, + .aid = TLS_SIGN_AID_UNKNOWN }, +#endif { .name = 0, .oid = 0, .id = 0, diff --git a/lib/crypto-backend.h b/lib/crypto-backend.h index 5c0630adaa..28aadfcb38 100644 --- a/lib/crypto-backend.h +++ b/lib/crypto-backend.h @@ -278,6 +278,11 @@ void gnutls_pk_params_init(gnutls_pk_params_st *p); #define RSA_PRIVATE_PARAMS 8 #define ECC_PRIVATE_PARAMS 3 #define GOST_PRIVATE_PARAMS 3 +#ifdef HAVE_LIBOQS +#define DILITHIUM_PRIVATE_PARAMS 4 +#define FALCON_PRIVATE_PARAMS 4 +#define SPHINCS_PRIVATE_PARAMS 4 +#endif #if MAX_PRIV_PARAMS_SIZE - RSA_PRIVATE_PARAMS < 0 #error INCREASE MAX_PRIV_PARAMS diff --git a/lib/dlwrap/oqsfuncs.h b/lib/dlwrap/oqsfuncs.h index 54a44d173a..a6b5ffff2e 100644 --- a/lib/dlwrap/oqsfuncs.h +++ b/lib/dlwrap/oqsfuncs.h @@ -16,3 +16,9 @@ VOID_FUNC(void, OQS_KEM_free, (OQS_KEM *kem), (kem)) VOID_FUNC(void, OQS_SHA2_set_callbacks, (struct OQS_SHA2_callbacks *new_callbacks), (new_callbacks)) VOID_FUNC(void, OQS_SHA3_set_callbacks, (struct OQS_SHA3_callbacks *new_callbacks), (new_callbacks)) VOID_FUNC(void, OQS_SHA3_x4_set_callbacks, (struct OQS_SHA3_x4_callbacks *new_callbacks), (new_callbacks)) +FUNC(const char *, OQS_version, (void), ()) +FUNC(OQS_SIG *, OQS_SIG_new, (const char *method_name), (method_name)) +FUNC(OQS_STATUS, OQS_SIG_keypair, (const OQS_SIG* sig, uint8_t* public_key, uint8_t *secret_key), (sig, public_key, secret_key)) +FUNC(OQS_STATUS, OQS_SIG_sign, (const OQS_SIG* sig, uint8_t *signature, size_t *signature_len, const uint8_t *message, size_t message_len, const uint8_t* secret_key), (sig, signature, signature_len, message, message_len, secret_key)) +FUNC(OQS_STATUS, OQS_SIG_verify, (const OQS_SIG* sig, const uint8_t *message, size_t message_len, uint8_t *signature, size_t signature_len, const uint8_t* public_key), (sig, message, message_len, signature, signature_len, public_key)) +VOID_FUNC(void, OQS_SIG_free, (OQS_SIG *sig), (sig)) diff --git a/lib/gnutls.asn b/lib/gnutls.asn index a4b9e873c5..7713e3d996 100644 --- a/lib/gnutls.asn +++ b/lib/gnutls.asn @@ -189,4 +189,25 @@ TPMKey ::= SEQUENCE { privkey OCTET STRING } +DilithiumPrivateKey ::= SEQUENCE { + version INTEGER, + privateKeyAlgorithm AlgorithmIdentifier, + privateKey OCTET STRING, + publicKey [1] OCTET STRING OPTIONAL +} + +FalconPrivateKey ::= SEQUENCE { + version INTEGER, + privateKeyAlgorithm AlgorithmIdentifier, + privateKey OCTET STRING, + publicKey [1] OCTET STRING OPTIONAL +} + +SphincsPrivateKey ::= SEQUENCE { + version INTEGER, + privateKeyAlgorithm AlgorithmIdentifier, + privateKey OCTET STRING, + publicKey [1] OCTET STRING OPTIONAL +} + END diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in index 8b3bb52131..dfa86d60cf 100644 --- a/lib/includes/gnutls/gnutls.h.in +++ b/lib/includes/gnutls/gnutls.h.in @@ -912,9 +912,26 @@ typedef enum { GNUTLS_PK_MAX = GNUTLS_PK_MLKEM768, /* Experimental algorithms */ - GNUTLS_PK_EXP_KYBER768 = 256, - GNUTLS_PK_EXP_MIN = GNUTLS_PK_EXP_KYBER768, - GNUTLS_PK_EXP_MAX = GNUTLS_PK_EXP_KYBER768 + GNUTLS_PK_EXP_MIN = 256, + GNUTLS_PK_EXP_KYBER768 = GNUTLS_PK_EXP_MIN + 0, + GNUTLS_PK_EXP_DILITHIUM2 = GNUTLS_PK_EXP_MIN + 1, + GNUTLS_PK_EXP_DILITHIUM3 = GNUTLS_PK_EXP_MIN + 2, + GNUTLS_PK_EXP_DILITHIUM5 = GNUTLS_PK_EXP_MIN + 3, + GNUTLS_PK_EXP_FALCON512 = GNUTLS_PK_EXP_MIN + 4, + GNUTLS_PK_EXP_FALCON1024 = GNUTLS_PK_EXP_MIN + 5, + GNUTLS_PK_EXP_SPHINCS_SHA2_128F = GNUTLS_PK_EXP_MIN + 6, + GNUTLS_PK_EXP_SPHINCS_SHA2_128S = GNUTLS_PK_EXP_MIN + 7, + GNUTLS_PK_EXP_SPHINCS_SHA2_192F = GNUTLS_PK_EXP_MIN + 8, + GNUTLS_PK_EXP_SPHINCS_SHA2_192S = GNUTLS_PK_EXP_MIN + 9, + GNUTLS_PK_EXP_SPHINCS_SHA2_256F = GNUTLS_PK_EXP_MIN + 10, + GNUTLS_PK_EXP_SPHINCS_SHA2_256S = GNUTLS_PK_EXP_MIN + 11, + GNUTLS_PK_EXP_SPHINCS_SHAKE_128F = GNUTLS_PK_EXP_MIN + 12, + GNUTLS_PK_EXP_SPHINCS_SHAKE_128S = GNUTLS_PK_EXP_MIN + 13, + GNUTLS_PK_EXP_SPHINCS_SHAKE_192F = GNUTLS_PK_EXP_MIN + 14, + GNUTLS_PK_EXP_SPHINCS_SHAKE_192S = GNUTLS_PK_EXP_MIN + 15, + GNUTLS_PK_EXP_SPHINCS_SHAKE_256F = GNUTLS_PK_EXP_MIN + 16, + GNUTLS_PK_EXP_SPHINCS_SHAKE_256S = GNUTLS_PK_EXP_MIN + 17, + GNUTLS_PK_EXP_MAX = GNUTLS_PK_EXP_SPHINCS_SHAKE_256S } gnutls_pk_algorithm_t; const char *gnutls_pk_algorithm_get_name(gnutls_pk_algorithm_t algorithm); @@ -1035,7 +1052,27 @@ typedef enum { GNUTLS_SIGN_GOST_256 = 44, GNUTLS_SIGN_GOST_512 = 45, GNUTLS_SIGN_EDDSA_ED448 = 46, - GNUTLS_SIGN_MAX = GNUTLS_SIGN_EDDSA_ED448 + GNUTLS_SIGN_MAX = GNUTLS_SIGN_EDDSA_ED448, + + GNUTLS_SIGN_EXP_MIN = 256, + GNUTLS_SIGN_EXP_DILITHIUM2 = GNUTLS_SIGN_EXP_MIN + 0, + GNUTLS_SIGN_EXP_DILITHIUM3 = GNUTLS_SIGN_EXP_MIN + 1, + GNUTLS_SIGN_EXP_DILITHIUM5 = GNUTLS_SIGN_EXP_MIN + 2, + GNUTLS_SIGN_EXP_FALCON512 = GNUTLS_SIGN_EXP_MIN + 3, + GNUTLS_SIGN_EXP_FALCON1024 = GNUTLS_SIGN_EXP_MIN + 4, + GNUTLS_SIGN_EXP_SPHINCS_SHA2_128F = GNUTLS_SIGN_EXP_MIN + 5, + GNUTLS_SIGN_EXP_SPHINCS_SHA2_128S = GNUTLS_SIGN_EXP_MIN + 6, + GNUTLS_SIGN_EXP_SPHINCS_SHA2_192F = GNUTLS_SIGN_EXP_MIN + 7, + GNUTLS_SIGN_EXP_SPHINCS_SHA2_192S = GNUTLS_SIGN_EXP_MIN + 8, + GNUTLS_SIGN_EXP_SPHINCS_SHA2_256F = GNUTLS_SIGN_EXP_MIN + 9, + GNUTLS_SIGN_EXP_SPHINCS_SHA2_256S = GNUTLS_SIGN_EXP_MIN + 10, + GNUTLS_SIGN_EXP_SPHINCS_SHAKE_128F = GNUTLS_SIGN_EXP_MIN + 11, + GNUTLS_SIGN_EXP_SPHINCS_SHAKE_128S = GNUTLS_SIGN_EXP_MIN + 12, + GNUTLS_SIGN_EXP_SPHINCS_SHAKE_192F = GNUTLS_SIGN_EXP_MIN + 13, + GNUTLS_SIGN_EXP_SPHINCS_SHAKE_192S = GNUTLS_SIGN_EXP_MIN + 14, + GNUTLS_SIGN_EXP_SPHINCS_SHAKE_256F = GNUTLS_SIGN_EXP_MIN + 15, + GNUTLS_SIGN_EXP_SPHINCS_SHAKE_256S = GNUTLS_SIGN_EXP_MIN + 16, + GNUTLS_SIGN_EXP_MAX = GNUTLS_SIGN_EXP_SPHINCS_SHAKE_256S, } gnutls_sign_algorithm_t; /** diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c index 00fa706b8d..f2abffb25c 100644 --- a/lib/nettle/pk.c +++ b/lib/nettle/pk.c @@ -1433,6 +1433,51 @@ static inline int eddsa_sign(gnutls_pk_algorithm_t algo, const uint8_t *pub, } } +#ifdef HAVE_LIBOQS +static inline const char *convert_to_oqs_alg(gnutls_pk_algorithm_t algo) +{ + switch (algo) { + case GNUTLS_PK_EXP_DILITHIUM2: + return OQS_SIG_alg_dilithium_2; + case GNUTLS_PK_EXP_DILITHIUM3: + return OQS_SIG_alg_dilithium_3; + case GNUTLS_PK_EXP_DILITHIUM5: + return OQS_SIG_alg_dilithium_5; + case GNUTLS_PK_EXP_FALCON512: + return OQS_SIG_alg_falcon_512; + case GNUTLS_PK_EXP_FALCON1024: + return OQS_SIG_alg_falcon_1024; + case GNUTLS_PK_EXP_SPHINCS_SHA2_128F: + return OQS_SIG_alg_sphincs_sha2_128f_simple; + case GNUTLS_PK_EXP_SPHINCS_SHA2_128S: + return OQS_SIG_alg_sphincs_sha2_128s_simple; + case GNUTLS_PK_EXP_SPHINCS_SHA2_192F: + return OQS_SIG_alg_sphincs_sha2_192f_simple; + case GNUTLS_PK_EXP_SPHINCS_SHA2_192S: + return OQS_SIG_alg_sphincs_sha2_192s_simple; + case GNUTLS_PK_EXP_SPHINCS_SHA2_256F: + return OQS_SIG_alg_sphincs_sha2_256f_simple; + case GNUTLS_PK_EXP_SPHINCS_SHA2_256S: + return OQS_SIG_alg_sphincs_sha2_256s_simple; + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128F: + return OQS_SIG_alg_sphincs_shake_128f_simple; + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128S: + return OQS_SIG_alg_sphincs_shake_128s_simple; + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192F: + return OQS_SIG_alg_sphincs_shake_192f_simple; + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192S: + return OQS_SIG_alg_sphincs_shake_192s_simple; + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256F: + return OQS_SIG_alg_sphincs_shake_256f_simple; + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256S: + return OQS_SIG_alg_sphincs_shake_256s_simple; + default: + gnutls_assert_val(GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM); + return ""; + } +} +#endif + /* This is the lower-level part of privkey_sign_raw_data(). * * It accepts data in the appropriate hash form, i.e., DigestInfo @@ -1852,6 +1897,56 @@ static int _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo, break; } +#ifdef HAVE_LIBOQS + case GNUTLS_PK_EXP_DILITHIUM2: + case GNUTLS_PK_EXP_DILITHIUM3: + case GNUTLS_PK_EXP_DILITHIUM5: + case GNUTLS_PK_EXP_FALCON512: + case GNUTLS_PK_EXP_FALCON1024: + case GNUTLS_PK_EXP_SPHINCS_SHA2_128F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_128S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256S: { + OQS_SIG *sig; + OQS_STATUS rc; + size_t size; + + sig = GNUTLS_OQS_FUNC(OQS_SIG_new)(convert_to_oqs_alg(algo)); + if (sig == NULL) { + ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + goto oqs_fail; + } + + size = sig->length_signature; + signature->data = gnutls_malloc(size); + + rc = GNUTLS_OQS_FUNC(OQS_SIG_sign)(sig, signature->data, &size, + vdata->data, vdata->size, + pk_params->raw_priv.data); + if (rc != OQS_SUCCESS) { + ret = gnutls_assert_val(GNUTLS_E_PK_SIGN_FAILED); + goto oqs_fail; + } + + signature->size = size; + + ret = GNUTLS_E_SUCCESS; + + oqs_fail: + GNUTLS_OQS_FUNC(OQS_SIG_free)(sig); + if (ret < 0) + goto cleanup; + break; + } +#endif default: gnutls_assert(); ret = GNUTLS_E_INTERNAL_ERROR; @@ -2224,6 +2319,50 @@ static int _wrap_nettle_pk_verify(gnutls_pk_algorithm_t algo, break; } +#ifdef HAVE_LIBOQS + case GNUTLS_PK_EXP_DILITHIUM2: + case GNUTLS_PK_EXP_DILITHIUM3: + case GNUTLS_PK_EXP_DILITHIUM5: + case GNUTLS_PK_EXP_FALCON512: + case GNUTLS_PK_EXP_FALCON1024: + case GNUTLS_PK_EXP_SPHINCS_SHA2_128F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_128S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256S: { + OQS_SIG *sig; + OQS_STATUS rc; + + sig = GNUTLS_OQS_FUNC(OQS_SIG_new)(convert_to_oqs_alg(algo)); + if (sig == NULL) { + ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + goto oqs_fail; + } + + rc = GNUTLS_OQS_FUNC(OQS_SIG_verify)( + sig, vdata->data, vdata->size, signature->data, + signature->size, pk_params->raw_pub.data); + if (rc != OQS_SUCCESS) { + ret = gnutls_assert_val(GNUTLS_E_PK_SIG_VERIFY_FAILED); + goto oqs_fail; + } + + ret = GNUTLS_E_SUCCESS; + + oqs_fail: + GNUTLS_OQS_FUNC(OQS_SIG_free)(sig); + if (ret < 0) + goto cleanup; + break; + } +#endif default: gnutls_assert(); ret = GNUTLS_E_INTERNAL_ERROR; @@ -2611,6 +2750,23 @@ static int wrap_nettle_pk_generate_params(gnutls_pk_algorithm_t algo, case GNUTLS_PK_GOST_12_512: #endif case GNUTLS_PK_MLKEM768: + case GNUTLS_PK_EXP_DILITHIUM2: + case GNUTLS_PK_EXP_DILITHIUM3: + case GNUTLS_PK_EXP_DILITHIUM5: + case GNUTLS_PK_EXP_FALCON512: + case GNUTLS_PK_EXP_FALCON1024: + case GNUTLS_PK_EXP_SPHINCS_SHA2_128F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_128S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256S: break; default: gnutls_assert(); @@ -3146,6 +3302,27 @@ cleanup: return ret; } +#ifdef HAVE_LIBOQS +static inline int pqc_alg_prepare_key_containers(OQS_SIG *sig, + gnutls_pk_params_st *params) +{ + params->raw_priv.size = sig->length_secret_key; + params->raw_priv.data = + gnutls_malloc(params->raw_priv.size + sig->length_public_key); + + if (params->raw_priv.data == NULL) + return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + + params->raw_pub.size = sig->length_public_key; + params->raw_pub.data = gnutls_malloc(params->raw_pub.size); + + if (params->raw_pub.data == NULL) + return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + + return GNUTLS_E_SUCCESS; +} +#endif + /* To generate a DH key either q must be set in the params or * level should be set to the number of required bits. */ @@ -3838,6 +4015,71 @@ wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo, ret = 0; break; } + case GNUTLS_PK_EXP_DILITHIUM2: + case GNUTLS_PK_EXP_DILITHIUM3: + case GNUTLS_PK_EXP_DILITHIUM5: + case GNUTLS_PK_EXP_FALCON512: + case GNUTLS_PK_EXP_FALCON1024: + case GNUTLS_PK_EXP_SPHINCS_SHA2_128F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_128S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256S: + if (params->pkflags & GNUTLS_PK_FLAG_PROVABLE) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + { + OQS_SIG *sig = NULL; + OQS_STATUS rc; + + if (_gnutls_liboqs_ensure() < 0) { + ret = gnutls_assert_val( + GNUTLS_E_UNKNOWN_PK_ALGORITHM); + goto cleanup; + } + + not_approved = true; + + sig = GNUTLS_OQS_FUNC(OQS_SIG_new)( + convert_to_oqs_alg(algo)); + if (sig == NULL) { + ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + goto cleanup; + } + + ret = pqc_alg_prepare_key_containers(sig, params); + if (ret < 0) + goto oqs_fail; + + rc = GNUTLS_OQS_FUNC( + OQS_SIG_keypair)(sig, params->raw_pub.data, + params->raw_priv.data); + if (rc != OQS_SUCCESS) { + ret = gnutls_assert_val( + GNUTLS_E_INTERNAL_ERROR); + goto oqs_fail; + } + + memcpy(¶ms->raw_priv.data[sig->length_secret_key], + params->raw_pub.data, sig->length_public_key); + + ret = GNUTLS_E_SUCCESS; + + oqs_fail: + GNUTLS_OQS_FUNC(OQS_SIG_free)(sig); + + if (ret < 0) + goto cleanup; + + break; + } #endif default: gnutls_assert(); @@ -4110,6 +4352,25 @@ static int wrap_nettle_pk_verify_priv_params(gnutls_pk_algorithm_t algo, ret = 0; break; } + case GNUTLS_PK_EXP_DILITHIUM2: + case GNUTLS_PK_EXP_DILITHIUM3: + case GNUTLS_PK_EXP_DILITHIUM5: + case GNUTLS_PK_EXP_FALCON512: + case GNUTLS_PK_EXP_FALCON1024: + case GNUTLS_PK_EXP_SPHINCS_SHA2_128F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_128S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256S: + ret = 0; + break; #endif #if ENABLE_GOST case GNUTLS_PK_GOST_01: diff --git a/lib/privkey.c b/lib/privkey.c index eb234384e2..46b0519675 100644 --- a/lib/privkey.c +++ b/lib/privkey.c @@ -243,6 +243,25 @@ static int privkey_to_pubkey(gnutls_pk_algorithm_t pk, case GNUTLS_PK_EDDSA_ED448: case GNUTLS_PK_ECDH_X25519: case GNUTLS_PK_ECDH_X448: +#ifdef HAVE_LIBOQS + case GNUTLS_PK_EXP_DILITHIUM2: + case GNUTLS_PK_EXP_DILITHIUM3: + case GNUTLS_PK_EXP_DILITHIUM5: + case GNUTLS_PK_EXP_FALCON512: + case GNUTLS_PK_EXP_FALCON1024: + case GNUTLS_PK_EXP_SPHINCS_SHA2_128F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_128S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256S: +#endif ret = _gnutls_set_datum(&pub->raw_pub, priv->raw_pub.data, priv->raw_pub.size); if (ret < 0) diff --git a/lib/pubkey.c b/lib/pubkey.c index 77565f8646..0a599a8e56 100644 --- a/lib/pubkey.c +++ b/lib/pubkey.c @@ -38,6 +38,10 @@ #include "urls.h" #include "ecc.h" +#ifdef HAVE_LIBOQS +#include +#endif + static int pubkey_verify_hashed_data(const gnutls_sign_entry_st *se, const mac_entry_st *me, const gnutls_datum_t *hash, @@ -49,6 +53,69 @@ static int pubkey_verify_hashed_data(const gnutls_sign_entry_st *se, static int pubkey_supports_sig(gnutls_pubkey_t pubkey, const gnutls_sign_entry_st *se); +#ifdef HAVE_LIBOQS +struct OQS_alg_pubkey_bits { + gnutls_pk_algorithm_t algorithm; + int pubkey_bits; +}; + +struct OQS_alg_pubkey_bits pqc_pubkey_bits[] = { +#if defined(GNUTLS_PK_EXP_DILITHIUM2) && \ + defined(OQS_SIG_dilithium_2_length_public_key) + { GNUTLS_PK_EXP_DILITHIUM2, OQS_SIG_dilithium_2_length_public_key }, +#endif +#if defined(GNUTLS_PK_EXP_DILITHIUM3) && \ + defined(OQS_SIG_dilithium_3_length_public_key) + { GNUTLS_PK_EXP_DILITHIUM3, OQS_SIG_dilithium_3_length_public_key }, +#endif +#if defined(GNUTLS_PK_EXP_DILITHIUM5) && \ + defined(OQS_SIG_dilithium_5_length_public_key) + { GNUTLS_PK_EXP_DILITHIUM5, OQS_SIG_dilithium_5_length_public_key }, +#endif + { GNUTLS_PK_EXP_FALCON512, OQS_SIG_falcon_512_length_public_key }, + { GNUTLS_PK_EXP_FALCON1024, OQS_SIG_falcon_1024_length_public_key }, + { GNUTLS_PK_EXP_SPHINCS_SHA2_128F, + OQS_SIG_sphincs_sha2_128f_simple_length_public_key }, + { GNUTLS_PK_EXP_SPHINCS_SHA2_128S, + OQS_SIG_sphincs_sha2_128s_simple_length_public_key }, + { GNUTLS_PK_EXP_SPHINCS_SHA2_192F, + OQS_SIG_sphincs_sha2_192f_simple_length_public_key }, + { GNUTLS_PK_EXP_SPHINCS_SHA2_192S, + OQS_SIG_sphincs_sha2_192s_simple_length_public_key }, + { GNUTLS_PK_EXP_SPHINCS_SHA2_256F, + OQS_SIG_sphincs_sha2_256f_simple_length_public_key }, + { GNUTLS_PK_EXP_SPHINCS_SHA2_256S, + OQS_SIG_sphincs_sha2_256s_simple_length_public_key }, + { GNUTLS_PK_EXP_SPHINCS_SHAKE_128F, + OQS_SIG_sphincs_shake_128f_simple_length_public_key }, + { GNUTLS_PK_EXP_SPHINCS_SHAKE_128S, + OQS_SIG_sphincs_shake_128s_simple_length_public_key }, + { GNUTLS_PK_EXP_SPHINCS_SHAKE_192F, + OQS_SIG_sphincs_shake_192f_simple_length_public_key }, + { GNUTLS_PK_EXP_SPHINCS_SHAKE_192S, + OQS_SIG_sphincs_shake_192s_simple_length_public_key }, + { GNUTLS_PK_EXP_SPHINCS_SHAKE_256F, + OQS_SIG_sphincs_shake_256f_simple_length_public_key }, + { GNUTLS_PK_EXP_SPHINCS_SHAKE_256S, + OQS_SIG_sphincs_shake_256s_simple_length_public_key }, + + { GNUTLS_PK_UNKNOWN, 0 } +}; + +static int pqc_pubkey_to_bits(gnutls_pk_algorithm_t algo) +{ + struct OQS_alg_pubkey_bits *pubkey_to_bits = pqc_pubkey_bits; + while (pubkey_to_bits->algorithm != algo && + pubkey_to_bits->algorithm != GNUTLS_PK_UNKNOWN) + pubkey_to_bits++; + + if (pubkey_to_bits->algorithm == GNUTLS_PK_UNKNOWN) + gnutls_assert(); + + return pubkey_to_bits->pubkey_bits; +} +#endif + unsigned pubkey_to_bits(const gnutls_pk_params_st *params) { switch (params->algo) { @@ -67,6 +134,26 @@ unsigned pubkey_to_bits(const gnutls_pk_params_st *params) case GNUTLS_PK_GOST_12_256: case GNUTLS_PK_GOST_12_512: return gnutls_ecc_curve_get_size(params->curve) * 8; +#ifdef HAVE_LIBOQS + case GNUTLS_PK_EXP_DILITHIUM2: + case GNUTLS_PK_EXP_DILITHIUM3: + case GNUTLS_PK_EXP_DILITHIUM5: + case GNUTLS_PK_EXP_FALCON512: + case GNUTLS_PK_EXP_FALCON1024: + case GNUTLS_PK_EXP_SPHINCS_SHA2_128F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_128S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256S: + return pqc_pubkey_to_bits(params->algo); +#endif default: return 0; } @@ -351,7 +438,33 @@ int gnutls_pubkey_get_preferred_hash_algorithm(gnutls_pubkey_t key, pubkey_to_bits(&key->params)); ret = 0; break; - +#ifdef HAVE_LIBOQS + case GNUTLS_PK_EXP_DILITHIUM2: + case GNUTLS_PK_EXP_DILITHIUM3: + case GNUTLS_PK_EXP_DILITHIUM5: + case GNUTLS_PK_EXP_FALCON512: + case GNUTLS_PK_EXP_FALCON1024: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256S: + if (hash) + *hash = GNUTLS_DIG_SHAKE_256; + ret = 0; + break; + case GNUTLS_PK_EXP_SPHINCS_SHA2_128F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_128S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256S: + if (hash) + *hash = GNUTLS_DIG_SHA256; + ret = 0; + break; +#endif default: gnutls_assert(); ret = GNUTLS_E_INTERNAL_ERROR; @@ -2650,6 +2763,25 @@ int pubkey_verify_data(const gnutls_sign_entry_st *se, const mac_entry_st *me, case GNUTLS_PK_EDDSA_ED25519: case GNUTLS_PK_EDDSA_ED448: +#ifdef HAVE_LIBOQS + case GNUTLS_PK_EXP_DILITHIUM2: + case GNUTLS_PK_EXP_DILITHIUM3: + case GNUTLS_PK_EXP_DILITHIUM5: + case GNUTLS_PK_EXP_FALCON512: + case GNUTLS_PK_EXP_FALCON1024: + case GNUTLS_PK_EXP_SPHINCS_SHA2_128F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_128S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256S: +#endif if (_gnutls_pk_verify(se->pk, data, signature, params, sign_params) != 0) { gnutls_assert(); diff --git a/lib/x509/common.h b/lib/x509/common.h index 7a556926b5..094003b11e 100644 --- a/lib/x509/common.h +++ b/lib/x509/common.h @@ -117,6 +117,28 @@ #define GOST28147_89_CPC_OID "1.2.643.2.2.31.3" #define GOST28147_89_CPD_OID "1.2.643.2.2.31.4" +#ifdef HAVE_LIBOQS +#define DILITHIUM2_OID "1.3.6.1.4.1.2.267.7.4.4" +#define DILITHIUM3_OID "1.3.6.1.4.1.2.267.7.5.4" +#define DILITHIUM5_OID "1.3.6.1.4.1.2.267.7.6.4" + +#define FALCON512_OID "1.3.9999.3.1" +#define FALCON1024_OID "1.3.9999.3.4" + +#define SPHINCS_SHA2_128F_OID "1.3.9999.6.4.1" +#define SPHINCS_SHA2_128S_OID "1.3.9999.6.4.2" +#define SPHINCS_SHA2_192F_OID "1.3.9999.6.5.1" +#define SPHINCS_SHA2_192S_OID "1.3.9999.6.5.2" +#define SPHINCS_SHA2_256F_OID "1.3.9999.6.6.1" +#define SPHINCS_SHA2_256S_OID "1.3.9999.6.6.2" +#define SPHINCS_SHAKE_128F_OID "1.3.9999.6.7.1" +#define SPHINCS_SHAKE_128S_OID "1.3.9999.6.7.2" +#define SPHINCS_SHAKE_192F_OID "1.3.9999.6.8.1" +#define SPHINCS_SHAKE_192S_OID "1.3.9999.6.8.2" +#define SPHINCS_SHAKE_256F_OID "1.3.9999.6.9.1" +#define SPHINCS_SHAKE_256S_OID "1.3.9999.6.9.2" +#endif + #define ASN1_NULL "\x05\x00" #define ASN1_NULL_SIZE 2 diff --git a/lib/x509/key_decode.c b/lib/x509/key_decode.c index 7328878099..24b87fbc7c 100644 --- a/lib/x509/key_decode.c +++ b/lib/x509/key_decode.c @@ -735,6 +735,27 @@ int _gnutls_x509_read_pubkey(gnutls_pk_algorithm_t algo, uint8_t *der, params->params_nr = GOST_PUBLIC_PARAMS; } break; +#ifdef HAVE_LIBOQS + case GNUTLS_PK_EXP_DILITHIUM2: + case GNUTLS_PK_EXP_DILITHIUM3: + case GNUTLS_PK_EXP_DILITHIUM5: + case GNUTLS_PK_EXP_FALCON512: + case GNUTLS_PK_EXP_FALCON1024: + case GNUTLS_PK_EXP_SPHINCS_SHA2_128F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_128S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256S: + ret = _gnutls_set_datum(¶ms->raw_pub, der, dersize); + break; +#endif default: ret = gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE); break; @@ -832,6 +853,25 @@ int _gnutls_x509_check_pubkey_params(gnutls_pk_params_st *params) case GNUTLS_PK_GOST_01: case GNUTLS_PK_GOST_12_256: case GNUTLS_PK_GOST_12_512: +#ifdef HAVE_LIBOQS + case GNUTLS_PK_EXP_DILITHIUM2: + case GNUTLS_PK_EXP_DILITHIUM3: + case GNUTLS_PK_EXP_DILITHIUM5: + case GNUTLS_PK_EXP_FALCON512: + case GNUTLS_PK_EXP_FALCON1024: + case GNUTLS_PK_EXP_SPHINCS_SHA2_128F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_128S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256S: +#endif return 0; default: return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE); diff --git a/lib/x509/key_encode.c b/lib/x509/key_encode.c index 2b090fd5e4..aa035ca541 100644 --- a/lib/x509/key_encode.c +++ b/lib/x509/key_encode.c @@ -257,6 +257,27 @@ cleanup: return ret; } +#ifdef HAVE_LIBOQS +static int _gnutls_x509_write_pqc_alg_pubkey(const gnutls_pk_params_st *params, + gnutls_datum_t *raw) +{ + int ret; + + raw->data = NULL; + raw->size = 0; + + if (params->raw_pub.size == 0) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + ret = _gnutls_set_datum(raw, params->raw_pub.data, + params->raw_pub.size); + if (ret < 0) + return gnutls_assert_val(ret); + + return 0; +} +#endif + int _gnutls_x509_write_pubkey_params(const gnutls_pk_params_st *params, gnutls_datum_t *der) { @@ -281,6 +302,25 @@ int _gnutls_x509_write_pubkey_params(const gnutls_pk_params_st *params, case GNUTLS_PK_EDDSA_ED448: case GNUTLS_PK_ECDH_X25519: case GNUTLS_PK_ECDH_X448: +#ifdef HAVE_LIBOQS + case GNUTLS_PK_EXP_DILITHIUM2: + case GNUTLS_PK_EXP_DILITHIUM3: + case GNUTLS_PK_EXP_DILITHIUM5: + case GNUTLS_PK_EXP_FALCON512: + case GNUTLS_PK_EXP_FALCON1024: + case GNUTLS_PK_EXP_SPHINCS_SHA2_128F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_128S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256S: +#endif der->data = NULL; der->size = 0; @@ -316,6 +356,26 @@ int _gnutls_x509_write_pubkey(const gnutls_pk_params_st *params, case GNUTLS_PK_GOST_12_256: case GNUTLS_PK_GOST_12_512: return _gnutls_x509_write_gost_pubkey(params, der); +#ifdef HAVE_LIBOQS + case GNUTLS_PK_EXP_DILITHIUM2: + case GNUTLS_PK_EXP_DILITHIUM3: + case GNUTLS_PK_EXP_DILITHIUM5: + case GNUTLS_PK_EXP_FALCON512: + case GNUTLS_PK_EXP_FALCON1024: + case GNUTLS_PK_EXP_SPHINCS_SHA2_128F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_128S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256S: + return _gnutls_x509_write_pqc_alg_pubkey(params, der); +#endif default: return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE); } @@ -1146,6 +1206,205 @@ cleanup: return ret; } +#ifdef HAVE_LIBOQS +static int _gnutls_asn1_encode_pqc_alg(asn1_node *c2, + gnutls_pk_params_st *params, + const char *oid, uint8_t version) +{ + int ret; + + if ((ret = asn1_write_value(*c2, "version", &version, 1)) != + ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(ret); + } + + if ((ret = asn1_write_value(*c2, "privateKeyAlgorithm.algorithm", oid, + 1)) != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(ret); + } + + if ((ret = asn1_write_value(*c2, "privateKeyAlgorithm.parameters", NULL, + 0)) != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(ret); + } + + if (params->raw_pub.size == 0 || params->raw_priv.size == 0) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + ret = asn1_write_value(*c2, "privateKey", params->raw_priv.data, + params->raw_priv.size); + if (ret != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(ret); + } + + ret = asn1_write_value(*c2, "publicKey", params->raw_pub.data, + params->raw_pub.size); + if (ret != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(ret); + } + + return GNUTLS_E_SUCCESS; +} + +static uint8_t _gnutls_get_pqc_alg_version(gnutls_pk_params_st *params) +{ + switch (params->algo) { + case GNUTLS_PK_EXP_DILITHIUM2: + return '\x02'; + case GNUTLS_PK_EXP_DILITHIUM3: + return '\x03'; + case GNUTLS_PK_EXP_DILITHIUM5: + return '\x05'; + case GNUTLS_PK_EXP_FALCON512: + return '\x01'; + case GNUTLS_PK_EXP_FALCON1024: + return '\x02'; + case GNUTLS_PK_EXP_SPHINCS_SHA2_128F: + return '\x01'; + case GNUTLS_PK_EXP_SPHINCS_SHA2_128S: + return '\x02'; + case GNUTLS_PK_EXP_SPHINCS_SHA2_192F: + return '\x03'; + case GNUTLS_PK_EXP_SPHINCS_SHA2_192S: + return '\x04'; + case GNUTLS_PK_EXP_SPHINCS_SHA2_256F: + return '\x05'; + case GNUTLS_PK_EXP_SPHINCS_SHA2_256S: + return '\x06'; + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128F: + return '\x07'; + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128S: + return '\x08'; + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192F: + return '\x09'; + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192S: + return '\x0a'; + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256F: + return '\x0b'; + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256S: + return '\x0c'; + default: + return '\x00'; + } +} + +static int _gnutls_asn1_encode_dilithium(asn1_node *c2, + gnutls_pk_params_st *params) +{ + int ret; + const char *oid; + + oid = gnutls_pk_get_oid(params->algo); + if (oid == NULL) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + /* first make sure that no previously allocated data are leaked */ + if (*c2 != NULL) { + asn1_delete_structure(c2); + *c2 = NULL; + } + + if ((ret = asn1_create_element(_gnutls_get_gnutls_asn(), + "GNUTLS.DilithiumPrivateKey", c2)) != + ASN1_SUCCESS) { + gnutls_assert(); + ret = _gnutls_asn2err(ret); + goto cleanup; + } + + ret = _gnutls_asn1_encode_pqc_alg(c2, params, oid, + _gnutls_get_pqc_alg_version(params)); + if (ret < 0) + goto cleanup; + + return GNUTLS_E_SUCCESS; + +cleanup: + asn1_delete_structure2(c2, ASN1_DELETE_FLAG_ZEROIZE); + + return ret; +} + +static int _gnutls_asn1_encode_falcon(asn1_node *c2, + gnutls_pk_params_st *params) +{ + int ret; + const char *oid; + + oid = gnutls_pk_get_oid(params->algo); + if (oid == NULL) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + /* first make sure that no previously allocated data are leaked */ + if (*c2 != NULL) { + asn1_delete_structure(c2); + *c2 = NULL; + } + + if ((ret = asn1_create_element(_gnutls_get_gnutls_asn(), + "GNUTLS.FalconPrivateKey", c2)) != + ASN1_SUCCESS) { + gnutls_assert(); + ret = _gnutls_asn2err(ret); + goto cleanup; + + ret = _gnutls_asn1_encode_pqc_alg( + c2, params, oid, _gnutls_get_pqc_alg_version(params)); + if (ret < 0) + goto cleanup; + + return GNUTLS_E_SUCCESS; + } + +cleanup: + asn1_delete_structure2(c2, ASN1_DELETE_FLAG_ZEROIZE); + + return ret; +} + +static int _gnutls_asn1_encode_sphincs(asn1_node *c2, + gnutls_pk_params_st *params) +{ + int ret; + const char *oid; + + oid = gnutls_pk_get_oid(params->algo); + if (oid == NULL) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + /* first make sure that no previously allocated data are leaked */ + if (*c2 != NULL) { + asn1_delete_structure(c2); + *c2 = NULL; + } + + if ((ret = asn1_create_element(_gnutls_get_gnutls_asn(), + "GNUTLS.SphincsPrivateKey", c2)) != + ASN1_SUCCESS) { + gnutls_assert(); + ret = _gnutls_asn2err(ret); + goto cleanup; + } + + ret = _gnutls_asn1_encode_pqc_alg(c2, params, oid, + _gnutls_get_pqc_alg_version(params)); + if (ret < 0) + goto cleanup; + + return GNUTLS_E_SUCCESS; + +cleanup: + asn1_delete_structure2(c2, ASN1_DELETE_FLAG_ZEROIZE); + + return ret; +} +#endif + int _gnutls_asn1_encode_privkey(asn1_node *c2, gnutls_pk_params_st *params) { switch (params->algo) { @@ -1168,6 +1427,28 @@ int _gnutls_asn1_encode_privkey(asn1_node *c2, gnutls_pk_params_st *params) case GNUTLS_PK_DH: /* DH keys are only exportable in PKCS#8 format */ return GNUTLS_E_INVALID_REQUEST; +#ifdef HAVE_LIBOQS + case GNUTLS_PK_EXP_DILITHIUM2: + case GNUTLS_PK_EXP_DILITHIUM3: + case GNUTLS_PK_EXP_DILITHIUM5: + return _gnutls_asn1_encode_dilithium(c2, params); + case GNUTLS_PK_EXP_FALCON512: + case GNUTLS_PK_EXP_FALCON1024: + return _gnutls_asn1_encode_falcon(c2, params); + case GNUTLS_PK_EXP_SPHINCS_SHA2_128F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_128S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256S: + return _gnutls_asn1_encode_sphincs(c2, params); +#endif default: return GNUTLS_E_UNIMPLEMENTED_FEATURE; } diff --git a/lib/x509/mpi.c b/lib/x509/mpi.c index 14c75a92ab..d48f490fef 100644 --- a/lib/x509/mpi.c +++ b/lib/x509/mpi.c @@ -133,8 +133,28 @@ int _gnutls_get_asn_mpis(asn1_node asn, const char *root, pk_algorithm != GNUTLS_PK_EDDSA_ED25519 && pk_algorithm != GNUTLS_PK_ECDH_X25519 && pk_algorithm != GNUTLS_PK_EDDSA_ED448 && - pk_algorithm != GNUTLS_PK_ECDH_X448) { - /* RSA and EdDSA do not use parameters */ + pk_algorithm != GNUTLS_PK_ECDH_X448 +#ifdef HAVE_LIBOQS + && pk_algorithm != GNUTLS_PK_EXP_DILITHIUM2 && + pk_algorithm != GNUTLS_PK_EXP_DILITHIUM3 && + pk_algorithm != GNUTLS_PK_EXP_DILITHIUM5 && + pk_algorithm != GNUTLS_PK_EXP_FALCON512 && + pk_algorithm != GNUTLS_PK_EXP_FALCON1024 && + pk_algorithm != GNUTLS_PK_EXP_SPHINCS_SHA2_128F && + pk_algorithm != GNUTLS_PK_EXP_SPHINCS_SHA2_128S && + pk_algorithm != GNUTLS_PK_EXP_SPHINCS_SHA2_192F && + pk_algorithm != GNUTLS_PK_EXP_SPHINCS_SHA2_192S && + pk_algorithm != GNUTLS_PK_EXP_SPHINCS_SHA2_256F && + pk_algorithm != GNUTLS_PK_EXP_SPHINCS_SHA2_256S && + pk_algorithm != GNUTLS_PK_EXP_SPHINCS_SHAKE_128F && + pk_algorithm != GNUTLS_PK_EXP_SPHINCS_SHAKE_128S && + pk_algorithm != GNUTLS_PK_EXP_SPHINCS_SHAKE_192F && + pk_algorithm != GNUTLS_PK_EXP_SPHINCS_SHAKE_192S && + pk_algorithm != GNUTLS_PK_EXP_SPHINCS_SHAKE_256F && + pk_algorithm != GNUTLS_PK_EXP_SPHINCS_SHAKE_256S +#endif + ) { + /* RSA, EdDSA and PQC algorithms do not use parameters */ result = _gnutls_x509_read_value(asn, name, &tmp); if (pk_algorithm == GNUTLS_PK_RSA_PSS && (result == GNUTLS_E_ASN1_VALUE_NOT_FOUND || diff --git a/lib/x509/privkey.c b/lib/x509/privkey.c index 131ec69dba..7b0caaab97 100644 --- a/lib/x509/privkey.c +++ b/lib/x509/privkey.c @@ -36,6 +36,9 @@ #include "ecc.h" #include "pin.h" +#ifdef HAVE_LIBOQS +#include +#endif /** * gnutls_x509_privkey_init: * @key: A pointer to the type to be initialized @@ -324,6 +327,282 @@ error: return ret; } +#ifdef HAVE_LIBOQS +struct PQCAlgorithmVersion { + uint8_t version; + gnutls_pk_algorithm_t algorithm; + int secret_key_length; + int public_key_length; +}; + +int _gnutls_decode_pqc_keys(asn1_node *pkey_asn, const gnutls_datum_t *raw_key, + gnutls_x509_privkey_t pkey, uint8_t *version) +{ + int result; + unsigned int _version; + + result = _asn1_strict_der_decode(pkey_asn, raw_key->data, raw_key->size, + NULL); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + return result; + } + + result = _gnutls_x509_read_uint(*pkey_asn, "version", &_version); + *version = _version; + if (result < 0) { + gnutls_assert(); + return result; + } + + result = _gnutls_x509_read_value(*pkey_asn, "privateKey", + &pkey->params.raw_priv); + if (result < 0) { + gnutls_assert(); + return result; + } + + result = _gnutls_x509_read_value(*pkey_asn, "publicKey", + &pkey->params.raw_pub); + if (result < 0) { + gnutls_assert(); + return result; + } + + return GNUTLS_E_SUCCESS; +} + +struct PQCAlgorithmVersion dilithium_versions[] = { +#if defined(GNUTLS_PK_EXP_DILITHIUM2) && \ + defined(OQS_SIG_dilithium_2_length_secret_key) && \ + defined(OQS_SIG_dilithium_2_length_public_key) + { '\x02', GNUTLS_PK_EXP_DILITHIUM2, + OQS_SIG_dilithium_2_length_secret_key, + OQS_SIG_dilithium_2_length_public_key }, +#endif +#if defined(GNUTLS_PK_EXP_DILITHIUM3) && \ + defined(OQS_SIG_dilithium_3_length_secret_key) && \ + defined(OQS_SIG_dilithium_3_length_public_key) + { '\x03', GNUTLS_PK_EXP_DILITHIUM3, + OQS_SIG_dilithium_3_length_secret_key, + OQS_SIG_dilithium_3_length_public_key }, +#endif +#if defined(GNUTLS_PK_EXP_DILITHIUM5) && \ + defined(OQS_SIG_dilithium_5_length_secret_key) && \ + defined(OQS_SIG_dilithium_5_length_public_key) + { '\x05', GNUTLS_PK_EXP_DILITHIUM5, + OQS_SIG_dilithium_5_length_secret_key, + OQS_SIG_dilithium_5_length_public_key }, +#endif + + { '\x00', GNUTLS_PK_UNKNOWN, 0, 0 } +}; + +static int _gnutls_set_dilithium_params(const uint8_t *version, + gnutls_x509_privkey_t pkey) +{ + struct PQCAlgorithmVersion *v = dilithium_versions; + while (v->algorithm != GNUTLS_PK_UNKNOWN && v->version != *version) + v++; + + pkey->params.raw_priv.size = v->secret_key_length; + pkey->params.raw_pub.size = v->public_key_length; + pkey->params.params_nr = DILITHIUM_PRIVATE_PARAMS; + pkey->params.algo = v->algorithm; + + if (v->algorithm == GNUTLS_PK_UNKNOWN) + return GNUTLS_E_UNKNOWN_ALGORITHM; + + return 0; +} + +int _gnutls_privkey_decode_dilithium_key(asn1_node *pkey_asn, + const gnutls_datum_t *raw_key, + gnutls_x509_privkey_t pkey) +{ + int result; + uint8_t version; + + gnutls_pk_params_init(&pkey->params); + + if ((result = asn1_create_element(_gnutls_get_gnutls_asn(), + "GNUTLS.DilithiumPrivateKey", + pkey_asn)) != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + + result = _gnutls_decode_pqc_keys(pkey_asn, raw_key, pkey, &version); + if (result < 0) + goto error; + + result = _gnutls_set_dilithium_params(&version, pkey); + if (result < 0) + goto error; + + return 0; + +error: + asn1_delete_structure2(pkey_asn, ASN1_DELETE_FLAG_ZEROIZE); + gnutls_pk_params_clear(&pkey->params); + gnutls_pk_params_release(&pkey->params); + return result; +} + +struct PQCAlgorithmVersion falcon_versions[] = { + { '\x01', GNUTLS_PK_EXP_FALCON512, OQS_SIG_falcon_512_length_secret_key, + OQS_SIG_falcon_512_length_public_key }, + { '\x02', GNUTLS_PK_EXP_FALCON1024, + OQS_SIG_falcon_1024_length_secret_key, + OQS_SIG_falcon_1024_length_public_key }, + + { '\x00', GNUTLS_PK_UNKNOWN, 0, 0 } +}; + +static int _gnutls_set_falcon_params(const uint8_t *version, + gnutls_x509_privkey_t pkey) +{ + struct PQCAlgorithmVersion *v = falcon_versions; + while (v->algorithm != GNUTLS_PK_UNKNOWN && v->version != *version) + v++; + + pkey->params.raw_priv.size = v->secret_key_length; + pkey->params.raw_pub.size = v->public_key_length; + pkey->params.params_nr = FALCON_PRIVATE_PARAMS; + pkey->params.algo = v->algorithm; + + if (v->algorithm == GNUTLS_PK_UNKNOWN) + return GNUTLS_E_UNKNOWN_ALGORITHM; + + return 0; +} + +int _gnutls_privkey_decode_falcon_key(asn1_node *pkey_asn, + const gnutls_datum_t *raw_key, + gnutls_x509_privkey_t pkey) +{ + int result; + uint8_t version; + + gnutls_pk_params_init(&pkey->params); + + if ((result = asn1_create_element(_gnutls_get_gnutls_asn(), + "GNUTLS.FalconPrivateKey", + pkey_asn)) != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + + result = _gnutls_decode_pqc_keys(pkey_asn, raw_key, pkey, &version); + if (result < 0) + goto error; + + result = _gnutls_set_falcon_params(&version, pkey); + if (result < 0) + goto error; + + return 0; + +error: + asn1_delete_structure2(pkey_asn, ASN1_DELETE_FLAG_ZEROIZE); + gnutls_pk_params_clear(&pkey->params); + gnutls_pk_params_release(&pkey->params); + return result; +} + +struct PQCAlgorithmVersion sphincs_versions[] = { + { '\x01', GNUTLS_PK_EXP_SPHINCS_SHA2_128F, + OQS_SIG_sphincs_sha2_128f_simple_length_secret_key, + OQS_SIG_sphincs_sha2_128f_simple_length_public_key }, + { '\x02', GNUTLS_PK_EXP_SPHINCS_SHA2_128S, + OQS_SIG_sphincs_sha2_128s_simple_length_secret_key, + OQS_SIG_sphincs_sha2_128s_simple_length_public_key }, + { '\x03', GNUTLS_PK_EXP_SPHINCS_SHA2_192F, + OQS_SIG_sphincs_sha2_192f_simple_length_secret_key, + OQS_SIG_sphincs_sha2_192f_simple_length_public_key }, + { '\x04', GNUTLS_PK_EXP_SPHINCS_SHA2_192S, + OQS_SIG_sphincs_sha2_192s_simple_length_secret_key, + OQS_SIG_sphincs_sha2_192s_simple_length_public_key }, + { '\x05', GNUTLS_PK_EXP_SPHINCS_SHA2_256F, + OQS_SIG_sphincs_sha2_256f_simple_length_secret_key, + OQS_SIG_sphincs_sha2_256f_simple_length_public_key }, + { '\x06', GNUTLS_PK_EXP_SPHINCS_SHA2_256S, + OQS_SIG_sphincs_sha2_256s_simple_length_secret_key, + OQS_SIG_sphincs_sha2_256s_simple_length_public_key }, + { '\x07', GNUTLS_PK_EXP_SPHINCS_SHAKE_128F, + OQS_SIG_sphincs_shake_128f_simple_length_secret_key, + OQS_SIG_sphincs_shake_128f_simple_length_public_key }, + { '\x08', GNUTLS_PK_EXP_SPHINCS_SHAKE_128S, + OQS_SIG_sphincs_shake_128s_simple_length_secret_key, + OQS_SIG_sphincs_shake_128s_simple_length_public_key }, + { '\x09', GNUTLS_PK_EXP_SPHINCS_SHAKE_192F, + OQS_SIG_sphincs_shake_192f_simple_length_secret_key, + OQS_SIG_sphincs_shake_192f_simple_length_public_key }, + { '\x0a', GNUTLS_PK_EXP_SPHINCS_SHAKE_192S, + OQS_SIG_sphincs_shake_192s_simple_length_secret_key, + OQS_SIG_sphincs_shake_192s_simple_length_public_key }, + { '\x0b', GNUTLS_PK_EXP_SPHINCS_SHAKE_256F, + OQS_SIG_sphincs_shake_256f_simple_length_secret_key, + OQS_SIG_sphincs_shake_256f_simple_length_public_key }, + { '\x0c', GNUTLS_PK_EXP_SPHINCS_SHAKE_256S, + OQS_SIG_sphincs_shake_256s_simple_length_secret_key, + OQS_SIG_sphincs_shake_256s_simple_length_public_key }, + + { '\x00', GNUTLS_PK_UNKNOWN, 0, 0 } +}; + +static int _gnutls_set_sphincs_params(const uint8_t *version, + gnutls_x509_privkey_t pkey) +{ + struct PQCAlgorithmVersion *v = sphincs_versions; + while (v->algorithm != GNUTLS_PK_UNKNOWN && v->version != *version) + v++; + + pkey->params.raw_priv.size = v->secret_key_length; + pkey->params.raw_pub.size = v->public_key_length; + pkey->params.params_nr = SPHINCS_PRIVATE_PARAMS; + pkey->params.algo = v->algorithm; + + if (v->algorithm == GNUTLS_PK_UNKNOWN) + return GNUTLS_E_UNKNOWN_ALGORITHM; + + return 0; +} + +int _gnutls_privkey_decode_sphincs_key(asn1_node *pkey_asn, + const gnutls_datum_t *raw_key, + gnutls_x509_privkey_t pkey) +{ + int result; + uint8_t version; + + gnutls_pk_params_init(&pkey->params); + + if ((result = asn1_create_element(_gnutls_get_gnutls_asn(), + "GNUTLS.SphincsPrivateKey", + pkey_asn)) != ASN1_SUCCESS) { + gnutls_assert(); + return _gnutls_asn2err(result); + } + + result = _gnutls_decode_pqc_keys(pkey_asn, raw_key, pkey, &version); + if (result < 0) + goto error; + + result = _gnutls_set_sphincs_params(&version, pkey); + if (result < 0) + goto error; + + return 0; + +error: + asn1_delete_structure2(pkey_asn, ASN1_DELETE_FLAG_ZEROIZE); + gnutls_pk_params_clear(&pkey->params); + gnutls_pk_params_release(&pkey->params); + return result; +} +#endif + static asn1_node decode_dsa_key(const gnutls_datum_t *raw_key, gnutls_x509_privkey_t pkey) { @@ -408,6 +687,11 @@ error: #define PEM_KEY_DSA "DSA PRIVATE KEY" #define PEM_KEY_RSA "RSA PRIVATE KEY" #define PEM_KEY_ECC "EC PRIVATE KEY" +#ifdef HAVE_LIBOQS +#define PEM_KEY_DILITHIUM "DILITHIUM PRIVATE KEY" +#define PEM_KEY_FALCON "FALCON PRIVATE KEY" +#define PEM_KEY_SPHINCS "SPHINCS PRIVATE KEY" +#endif #define PEM_KEY_PKCS8 "PRIVATE KEY" #define MAX_PEM_HEADER_SIZE 25 @@ -507,6 +791,41 @@ int gnutls_x509_privkey_import(gnutls_x509_privkey_t key, if (result >= 0) key->params.algo = GNUTLS_PK_DSA; +#ifdef HAVE_LIBOQS + } else if (left > sizeof(PEM_KEY_DILITHIUM) && + memcmp(ptr, PEM_KEY_DILITHIUM, + sizeof(PEM_KEY_DILITHIUM) - + 1) == 0) { + result = _gnutls_fbase64_decode( + PEM_KEY_DILITHIUM, begin_ptr, + left, &_data); + if (result >= 0) { + key->params.algo = + GNUTLS_PK_EXP_DILITHIUM2; + } + } else if (left > sizeof(PEM_KEY_FALCON) && + memcmp(ptr, PEM_KEY_FALCON, + sizeof(PEM_KEY_FALCON) - 1) == + 0) { + result = _gnutls_fbase64_decode( + PEM_KEY_FALCON, begin_ptr, left, + &_data); + if (result >= 0) { + key->params.algo = + GNUTLS_PK_EXP_FALCON512; + } + } else if (left > sizeof(PEM_KEY_SPHINCS) && + memcmp(ptr, PEM_KEY_SPHINCS, + sizeof(PEM_KEY_SPHINCS) - + 1) == 0) { + result = _gnutls_fbase64_decode( + PEM_KEY_SPHINCS, begin_ptr, + left, &_data); + if (result >= 0) { + key->params.algo = + GNUTLS_PK_EXP_SPHINCS_SHA2_128F; + } +#endif } if (key->params.algo == GNUTLS_PK_UNKNOWN && @@ -566,6 +885,32 @@ int gnutls_x509_privkey_import(gnutls_x509_privkey_t key, gnutls_assert(); key->key = NULL; } +#ifdef HAVE_LIBOQS + } else if (key->params.algo == GNUTLS_PK_EXP_DILITHIUM2) { + result = _gnutls_privkey_decode_dilithium_key(&key->key, &_data, + key); + + if (result < 0) { + gnutls_assert(); + key->key = NULL; + } + } else if (key->params.algo == GNUTLS_PK_EXP_FALCON512) { + result = _gnutls_privkey_decode_falcon_key(&key->key, &_data, + key); + + if (result < 0) { + gnutls_assert(); + key->key = NULL; + } + } else if (key->params.algo == GNUTLS_PK_EXP_SPHINCS_SHA2_128F) { + result = _gnutls_privkey_decode_sphincs_key(&key->key, &_data, + key); + + if (result < 0) { + gnutls_assert(); + key->key = NULL; + } +#endif } else { /* Try decoding each of the keys, and accept the one that * succeeds. @@ -668,6 +1013,14 @@ fail: return ret; } +#ifdef HAVE_LIBOQS +#define MAX_ALGORITHM_NAME_SIZE_IN_PEM_HEADER 21 +#define MAX_PEM_KEY_SIZE PEM_KEY_DILITHIUM +#else +#define MAX_ALGORITHM_NAME_SIZE_IN_PEM_HEADER 15 +#define MAX_PEM_KEY_SIZE PEM_KEY_RSA +#endif + /** * gnutls_x509_privkey_import2: * @key: The data to store the parsed key @@ -711,9 +1064,10 @@ int gnutls_x509_privkey_import2(gnutls_x509_privkey_t key, left = data->size - ((ptrdiff_t)ptr - (ptrdiff_t)data->data); - if (data->size - left > 15) { - ptr -= 15; - left += 15; + if (data->size - left > + MAX_ALGORITHM_NAME_SIZE_IN_PEM_HEADER) { + ptr -= MAX_ALGORITHM_NAME_SIZE_IN_PEM_HEADER; + left += MAX_ALGORITHM_NAME_SIZE_IN_PEM_HEADER; } else { ptr = (char *)data->data; left = data->size; @@ -727,13 +1081,23 @@ int gnutls_x509_privkey_import2(gnutls_x509_privkey_t key, ((ptrdiff_t)ptr - (ptrdiff_t)data->data); } - if (ptr != NULL && left > sizeof(PEM_KEY_RSA)) { + if (ptr != NULL && left > sizeof(MAX_PEM_KEY_SIZE)) { if (memcmp(ptr, PEM_KEY_RSA, sizeof(PEM_KEY_RSA) - 1) == 0 || memcmp(ptr, PEM_KEY_ECC, sizeof(PEM_KEY_ECC) - 1) == 0 || memcmp(ptr, PEM_KEY_DSA, - sizeof(PEM_KEY_DSA) - 1) == 0) { + sizeof(PEM_KEY_DSA) - 1) == 0 +#ifdef HAVE_LIBOQS + || memcmp(ptr, PEM_KEY_DILITHIUM, + sizeof(PEM_KEY_DILITHIUM) - 1) == + 0 || + memcmp(ptr, PEM_KEY_FALCON, + sizeof(PEM_KEY_FALCON) - 1) == 0 || + memcmp(ptr, PEM_KEY_SPHINCS, + sizeof(PEM_KEY_SPHINCS) - 1) == 0 +#endif + ) { head_enc = 0; } } @@ -1477,14 +1841,39 @@ int gnutls_x509_privkey_set_spki(gnutls_x509_privkey_t key, static const char *set_msg(gnutls_x509_privkey_t key) { - if (GNUTLS_PK_IS_RSA(key->params.algo)) { + switch (key->params.algo) { + case GNUTLS_PK_RSA: + case GNUTLS_PK_RSA_PSS: return PEM_KEY_RSA; - } else if (key->params.algo == GNUTLS_PK_DSA) { + case GNUTLS_PK_DSA: return PEM_KEY_DSA; - } else if (key->params.algo == GNUTLS_PK_EC) + case GNUTLS_PK_EC: return PEM_KEY_ECC; - else +#ifdef HAVE_LIBOQS + case GNUTLS_PK_EXP_DILITHIUM2: + case GNUTLS_PK_EXP_DILITHIUM3: + case GNUTLS_PK_EXP_DILITHIUM5: + return PEM_KEY_DILITHIUM; + case GNUTLS_PK_EXP_FALCON512: + case GNUTLS_PK_EXP_FALCON1024: + return PEM_KEY_FALCON; + case GNUTLS_PK_EXP_SPHINCS_SHA2_128F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_128S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256S: + return PEM_KEY_SPHINCS; +#endif + default: return "UNKNOWN"; + } } /** diff --git a/lib/x509/privkey_pkcs8.c b/lib/x509/privkey_pkcs8.c index 5f8ba89daf..34e02a6143 100644 --- a/lib/x509/privkey_pkcs8.c +++ b/lib/x509/privkey_pkcs8.c @@ -39,6 +39,10 @@ #include "attributes.h" #include "prov-seed.h" +#ifdef HAVE_LIBOQS +#include +#endif + static int _decode_pkcs8_ecc_key(asn1_node pkcs8_asn, gnutls_x509_privkey_t pkey); static int pkcs8_key_info(const gnutls_datum_t *raw_key, @@ -78,6 +82,33 @@ inline static int _encode_privkey(gnutls_x509_privkey_t pkey, if (ret < 0) gnutls_assert(); return ret; +#ifdef HAVE_LIBOQS + case GNUTLS_PK_EXP_DILITHIUM2: + case GNUTLS_PK_EXP_DILITHIUM3: + case GNUTLS_PK_EXP_DILITHIUM5: + case GNUTLS_PK_EXP_FALCON512: + case GNUTLS_PK_EXP_FALCON1024: + case GNUTLS_PK_EXP_SPHINCS_SHA2_128F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_128S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256S: + // Dilithium public key is appended to private key + ret = _gnutls_x509_encode_string( + ASN1_ETYPE_OCTET_STRING, pkey->params.raw_priv.data, + pkey->params.raw_priv.size + pkey->params.raw_pub.size, + raw); + if (ret < 0) + gnutls_assert(); + return ret; +#endif case GNUTLS_PK_GOST_01: case GNUTLS_PK_GOST_12_256: @@ -1454,6 +1485,148 @@ error: return ret; } +#ifdef HAVE_LIBOQS +struct pqc_key_length_st { + gnutls_pk_algorithm_t algorithm; + int secret_key_length; + int public_key_length; +}; + +struct pqc_key_length_st pqc_key_lengths[] = { +#ifdef defined(GNUTLS_PK_EXP_DILITHIUM2) && \ + defined(OQS_SIG_dilithium_2_length_secret_key) && \ + defined(OQS_SIG_dilithium_2_length_public_key) + { GNUTLS_PK_EXP_DILITHIUM2, OQS_SIG_dilithium_2_length_secret_key, + OQS_SIG_dilithium_2_length_public_key }, +#endif +#ifdef defined(GNUTLS_PK_EXP_DILITHIUM3) && \ + defined(OQS_SIG_dilithium_3_length_secret_key) && \ + defined(OQS_SIG_dilithium_3_length_public_key) + { GNUTLS_PK_EXP_DILITHIUM3, OQS_SIG_dilithium_3_length_secret_key, + OQS_SIG_dilithium_3_length_public_key }, +#endif +#ifdef defined(GNUTLS_PK_EXP_DILITHIUM5) && \ + defined(OQS_SIG_dilithium_5_length_secret_key) && \ + defined(OQS_SIG_dilithium_5_length_public_key) + { GNUTLS_PK_EXP_DILITHIUM5, OQS_SIG_dilithium_5_length_secret_key, + OQS_SIG_dilithium_5_length_public_key }, +#endif + { GNUTLS_PK_EXP_FALCON512, OQS_SIG_falcon_512_length_secret_key, + OQS_SIG_falcon_512_length_public_key }, + { GNUTLS_PK_EXP_FALCON1024, OQS_SIG_falcon_1024_length_secret_key, + OQS_SIG_falcon_1024_length_public_key }, + { GNUTLS_PK_EXP_SPHINCS_SHA2_128F, + OQS_SIG_sphincs_sha2_128f_simple_length_secret_key, + OQS_SIG_sphincs_sha2_128f_simple_length_public_key }, + { GNUTLS_PK_EXP_SPHINCS_SHA2_128S, + OQS_SIG_sphincs_sha2_128s_simple_length_secret_key, + OQS_SIG_sphincs_sha2_128s_simple_length_public_key }, + { GNUTLS_PK_EXP_SPHINCS_SHA2_192F, + OQS_SIG_sphincs_sha2_192f_simple_length_secret_key, + OQS_SIG_sphincs_sha2_192f_simple_length_public_key }, + { GNUTLS_PK_EXP_SPHINCS_SHA2_192S, + OQS_SIG_sphincs_sha2_192s_simple_length_secret_key, + OQS_SIG_sphincs_sha2_192s_simple_length_public_key }, + { GNUTLS_PK_EXP_SPHINCS_SHA2_256F, + OQS_SIG_sphincs_sha2_256f_simple_length_secret_key, + OQS_SIG_sphincs_sha2_256f_simple_length_public_key }, + { GNUTLS_PK_EXP_SPHINCS_SHA2_256S, + OQS_SIG_sphincs_sha2_256s_simple_length_secret_key, + OQS_SIG_sphincs_sha2_256s_simple_length_public_key }, + { GNUTLS_PK_EXP_SPHINCS_SHAKE_128F, + OQS_SIG_sphincs_shake_128f_simple_length_secret_key, + OQS_SIG_sphincs_shake_128f_simple_length_public_key }, + { GNUTLS_PK_EXP_SPHINCS_SHAKE_128S, + OQS_SIG_sphincs_shake_128s_simple_length_secret_key, + OQS_SIG_sphincs_shake_128s_simple_length_public_key }, + { GNUTLS_PK_EXP_SPHINCS_SHAKE_192F, + OQS_SIG_sphincs_shake_192f_simple_length_secret_key, + OQS_SIG_sphincs_shake_192f_simple_length_public_key }, + { GNUTLS_PK_EXP_SPHINCS_SHAKE_192S, + OQS_SIG_sphincs_shake_192s_simple_length_secret_key, + OQS_SIG_sphincs_shake_192s_simple_length_public_key }, + { GNUTLS_PK_EXP_SPHINCS_SHAKE_256F, + OQS_SIG_sphincs_shake_256f_simple_length_secret_key, + OQS_SIG_sphincs_shake_256f_simple_length_public_key }, + { GNUTLS_PK_EXP_SPHINCS_SHAKE_256S, + OQS_SIG_sphincs_shake_256s_simple_length_secret_key, + OQS_SIG_sphincs_shake_256s_simple_length_public_key }, + + { GNUTLS_PK_UNKNOWN, 0, 0 } +}; + +static int _get_pqc_keys_length(gnutls_pk_algorithm_t algo, + int *pqc_alg_secret_key_length, + int *pqc_alg_public_key_length) +{ + struct pqc_key_length_st *pqc_key_length = pqc_key_lengths; + while (pqc_key_length->algorithm != algo && + pqc_key_length->algorithm != GNUTLS_PK_UNKNOWN) + pqc_key_length++; + + if (pqc_key_length->algorithm == GNUTLS_PK_UNKNOWN) + return GNUTLS_E_UNKNOWN_ALGORITHM; + + *pqc_alg_secret_key_length = pqc_key_length->secret_key_length; + *pqc_alg_public_key_length = pqc_key_length->public_key_length; + + return 0; +} + +static int _decode_pkcs8_pqc_alg_key(asn1_node pkcs8_asn, + gnutls_x509_privkey_t pkey, + const char *oid) +{ + int ret; + gnutls_datum_t private_key; + gnutls_pk_algorithm_t algo = pkey->params.algo; + int pqc_alg_secret_key_length; + int pqc_alg_public_key_length; + + ret = _get_pqc_keys_length(pkey->params.algo, + &pqc_alg_secret_key_length, + &pqc_alg_public_key_length); + if (ret < 0) { + gnutls_assert(); + goto error; + } + + /* TODO: support OneAsymmetricKey to read public key from a + * separate field + */ + + gnutls_pk_params_init(&pkey->params); + + ret = _gnutls_x509_read_string(pkcs8_asn, "privateKey", &private_key, + ASN1_ETYPE_OCTET_STRING, 1); + if (ret < 0) { + gnutls_assert(); + goto error; + } + + pkey->params.algo = algo; + pkey->params.raw_priv.data = private_key.data; + pkey->params.raw_priv.size = pqc_alg_secret_key_length; + + pkey->params.raw_pub.data = gnutls_malloc(pqc_alg_public_key_length); + memcpy(pkey->params.raw_pub.data, + &private_key.data[pqc_alg_secret_key_length], + pqc_alg_public_key_length); + pkey->params.raw_pub.size = pqc_alg_public_key_length; + + private_key.data = NULL; + + return GNUTLS_E_SUCCESS; + +error: + gnutls_free(pkey->params.raw_priv.data); + gnutls_pk_params_clear(&pkey->params); + gnutls_pk_params_release(&pkey->params); + + return ret; +} +#endif + static int decode_private_key_info(const gnutls_datum_t *der, gnutls_x509_privkey_t pkey) { @@ -1532,6 +1705,27 @@ static int decode_private_key_info(const gnutls_datum_t *der, result = _decode_pkcs8_gost_key(pkcs8_asn, pkey, pkey->params.algo); break; +#ifdef HAVE_LIBOQS + case GNUTLS_PK_EXP_DILITHIUM2: + case GNUTLS_PK_EXP_DILITHIUM3: + case GNUTLS_PK_EXP_DILITHIUM5: + case GNUTLS_PK_EXP_FALCON512: + case GNUTLS_PK_EXP_FALCON1024: + case GNUTLS_PK_EXP_SPHINCS_SHA2_128F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_128S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_192S: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256F: + case GNUTLS_PK_EXP_SPHINCS_SHA2_256S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_128S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_192S: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256F: + case GNUTLS_PK_EXP_SPHINCS_SHAKE_256S: + result = _decode_pkcs8_pqc_alg_key(pkcs8_asn, pkey, oid); + break; +#endif default: result = gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE); goto error; diff --git a/lib/x509/x509_int.h b/lib/x509/x509_int.h index 693a4dd924..5fea0ce76e 100644 --- a/lib/x509/x509_int.h +++ b/lib/x509/x509_int.h @@ -241,6 +241,23 @@ int _gnutls_privkey_decode_ecc_key(asn1_node *pkey_asn, gnutls_x509_privkey_t pkey, gnutls_ecc_curve_t curve); +#ifdef HAVE_LIBOQS +int _gnutls_decode_pqc_keys(asn1_node *pkey_asn, const gnutls_datum_t *raw_key, + gnutls_x509_privkey_t pkey, uint8_t *version); + +int _gnutls_privkey_decode_dilithium_key(asn1_node *pkey_asn, + const gnutls_datum_t *raw_key, + gnutls_x509_privkey_t pkey); + +int _gnutls_privkey_decode_falcon_key(asn1_node *pkey_asn, + const gnutls_datum_t *raw_key, + gnutls_x509_privkey_t pkey); + +int _gnutls_privkey_decode_sphincs_key(asn1_node *pkey_asn, + const gnutls_datum_t *raw_key, + gnutls_x509_privkey_t pkey); +#endif + int _gnutls_privkey_decode_eddsa_key(asn1_node *pkey_asn, const gnutls_datum_t *raw_key, gnutls_x509_privkey_t pkey, diff --git a/tests/privkey-keygen.c b/tests/privkey-keygen.c index 1eea0a473c..f835a7a0d4 100644 --- a/tests/privkey-keygen.c +++ b/tests/privkey-keygen.c @@ -177,7 +177,26 @@ void doit(void) continue; #endif } - +#ifndef HAVE_LIBOQS + if (algorithm == GNUTLS_PK_EXP_DILITHIUM2 || + algorithm == GNUTLS_PK_EXP_DILITHIUM3 || + algorithm == GNUTLS_PK_EXP_DILITHIUM5 || + algorithm == GNUTLS_PK_EXP_FALCON512 || + algorithm == GNUTLS_PK_EXP_FALCON1024 || + algorithm == GNUTLS_PK_EXP_SPHINCS_SHA2_128F || + algorithm == GNUTLS_PK_EXP_SPHINCS_SHA2_128S || + algorithm == GNUTLS_PK_EXP_SPHINCS_SHA2_192F || + algorithm == GNUTLS_PK_EXP_SPHINCS_SHA2_192S || + algorithm == GNUTLS_PK_EXP_SPHINCS_SHA2_256F || + algorithm == GNUTLS_PK_EXP_SPHINCS_SHA2_256S || + algorithm == GNUTLS_PK_EXP_SPHINCS_SHAKE_128F || + algorithm == GNUTLS_PK_EXP_SPHINCS_SHAKE_128S || + algorithm == GNUTLS_PK_EXP_SPHINCS_SHAKE_192F || + algorithm == GNUTLS_PK_EXP_SPHINCS_SHAKE_192S || + algorithm == GNUTLS_PK_EXP_SPHINCS_SHAKE_256F || + algorithm == GNUTLS_PK_EXP_SPHINCS_SHAKE_256S) + continue; +#endif ret = gnutls_x509_privkey_init(&pkey); if (ret < 0) { fail("gnutls_x509_privkey_init: %d\n", ret);