diff --git a/.gitignore b/.gitignore index 2c221ee7bd589..1ba96096a3388 100644 --- a/.gitignore +++ b/.gitignore @@ -77,6 +77,7 @@ providers/common/der/der_rsa_gen.c providers/common/der/der_wrap_gen.c providers/common/der/der_sm2_gen.c providers/common/der/der_ml_dsa_gen.c +providers/common/der/der_composite_gen.c providers/common/der/der_hkdf_gen.c providers/common/include/prov/der_slh_dsa.h providers/common/include/prov/der_dsa.h @@ -137,7 +138,9 @@ providers/implementations/keymgmt/ml_dsa_kmgmt.inc providers/implementations/keymgmt/ml_kem_kmgmt.inc providers/implementations/keymgmt/mlx_kmgmt.inc providers/implementations/keymgmt/slh_dsa_kmgmt.inc +providers/implementations/keymgmt/composite_kmgmt.inc providers/implementations/keymgmt/template_kmgmt.inc +providers/implementations/signature/composite_sig.inc providers/implementations/signature/eddsa_sig.inc providers/implementations/signature/mac_legacy_sig.inc providers/implementations/signature/ml_dsa_sig.inc diff --git a/CHANGES.md b/CHANGES.md index da1bfd15ec9d8..2d3d6419ed228 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -31,6 +31,21 @@ OpenSSL Releases ### Changes between 4.0 and 4.1 [xx XXX xxxx] + * Added 18 composite post-quantum signature algorithms combining ML-DSA with a + classical algorithm (RSA, ECDSA, or EdDSA), as defined in + [draft-ietf-lamps-pq-composite-sigs](https://datatracker.ietf.org/doc/draft-ietf-lamps-pq-composite-sigs): + id-MLDSA44-RSA2048-PSS-SHA256, id-MLDSA44-RSA2048-PKCS15-SHA256, + id-MLDSA44-Ed25519-SHA512, id-MLDSA44-ECDSA-P256-SHA256, + id-MLDSA65-RSA3072-PSS-SHA512, id-MLDSA65-RSA3072-PKCS15-SHA512, + id-MLDSA65-RSA4096-PSS-SHA512, id-MLDSA65-RSA4096-PKCS15-SHA512, + id-MLDSA65-ECDSA-P256-SHA512, id-MLDSA65-ECDSA-P384-SHA512, + id-MLDSA65-ECDSA-brainpoolP256r1-SHA512, id-MLDSA65-Ed25519-SHA512, + id-MLDSA87-ECDSA-P384-SHA512, id-MLDSA87-ECDSA-brainpoolP384r1-SHA512, + id-MLDSA87-Ed448-SHAKE256, id-MLDSA87-RSA3072-PSS-SHA512, + id-MLDSA87-RSA4096-PSS-SHA512, id-MLDSA87-ECDSA-P521-SHA512. + These algorithms are available in the default provider only. + + *Felipe Ventura* * Added AVX512 optimized SHAKE x4 operations for ML-DSA on x86_64. *Marcel Cornu and Tomasz Kantecki* diff --git a/Configure b/Configure index 5ee8597f2eda5..d055c3c48b9c7 100755 --- a/Configure +++ b/Configure @@ -477,6 +477,7 @@ my @disablables_algorithms = ( "mdc2", "ml-dsa", "ml-kem", + "composite", "lms", "ocb", "poly1305", @@ -674,7 +675,7 @@ my @disable_cascades = ( "ec", "ech", "filenames", "hmac-drbg-kdf", "idea", "ikev2kdf", "kbkdf", "krb5kdf", "ktls", "lms", - "md4", "ml-dsa", "ml-kem", "multiblock", + "md4", "ml-dsa", "ml-kem", "composite", "multiblock", "nextprotoneg", "ocsp", "ocb", "poly1305", "psk", "pvkkdf", "rc2", "rc4", "rmd160", "scrypt", "seed", "siphash", "siv", @@ -691,6 +692,7 @@ my @disable_cascades = ( "brotli" => [ "brotli-dynamic" ], "zstd" => [ "zstd-dynamic" ], "des" => [ "mdc2" ], + "ml-dsa" => [ "composite" ], "deprecated" => [ "tls-deprecated-ec" ], "ec" => [ qw(ec2m ec_explicit_curves sm2 gost ecx tls-deprecated-ec) ], "dgram" => [ "dtls", "quic", "sctp" ], diff --git a/build.info b/build.info index d7982a95536c3..2a030356549fc 100644 --- a/build.info +++ b/build.info @@ -84,6 +84,7 @@ DEPEND[]=include/openssl/asn1.h \ providers/implementations/keymgmt/ecx_kmgmt.inc \ providers/implementations/keymgmt/lms_kmgmt.inc \ providers/implementations/keymgmt/mac_legacy_kmgmt.inc \ + providers/implementations/keymgmt/composite_kmgmt.inc \ providers/implementations/keymgmt/ml_dsa_kmgmt.inc \ providers/implementations/keymgmt/ml_kem_kmgmt.inc \ providers/implementations/keymgmt/mlx_kmgmt.inc \ @@ -94,6 +95,7 @@ DEPEND[]=include/openssl/asn1.h \ providers/implementations/signature/eddsa_sig.inc \ providers/implementations/signature/mac_legacy_sig.inc \ providers/implementations/signature/ml_dsa_sig.inc \ + providers/implementations/signature/composite_sig.inc \ providers/implementations/signature/rsa_sig.inc \ providers/implementations/signature/slh_dsa_sig.inc \ providers/implementations/signature/sm2_sig.inc \ @@ -209,6 +211,7 @@ DEPEND[providers/implementations/asymciphers/rsa_enc.inc \ providers/implementations/keymgmt/ecx_kmgmt.inc \ providers/implementations/keymgmt/lms_kmgmt.inc \ providers/implementations/keymgmt/mac_legacy_kmgmt.inc \ + providers/implementations/keymgmt/composite_kmgmt.inc \ providers/implementations/keymgmt/ml_dsa_kmgmt.inc \ providers/implementations/keymgmt/ml_kem_kmgmt.inc \ providers/implementations/keymgmt/mlx_kmgmt.inc \ @@ -219,6 +222,7 @@ DEPEND[providers/implementations/asymciphers/rsa_enc.inc \ providers/implementations/signature/eddsa_sig.inc \ providers/implementations/signature/mac_legacy_sig.inc \ providers/implementations/signature/ml_dsa_sig.inc \ + providers/implementations/signature/composite_sig.inc \ providers/implementations/signature/rsa_sig.inc \ providers/implementations/signature/slh_dsa_sig.inc \ providers/implementations/signature/sm2_sig.inc \ @@ -342,6 +346,8 @@ GENERATE[providers/implementations/keymgmt/lms_kmgmt.inc]=\ providers/implementations/keymgmt/lms_kmgmt.inc.in GENERATE[providers/implementations/keymgmt/mac_legacy_kmgmt.inc]=\ providers/implementations/keymgmt/mac_legacy_kmgmt.inc.in +GENERATE[providers/implementations/keymgmt/composite_kmgmt.inc]=\ + providers/implementations/keymgmt/composite_kmgmt.inc.in GENERATE[providers/implementations/keymgmt/ml_dsa_kmgmt.inc]=\ providers/implementations/keymgmt/ml_dsa_kmgmt.inc.in GENERATE[providers/implementations/keymgmt/ml_kem_kmgmt.inc]=\ @@ -362,6 +368,8 @@ GENERATE[providers/implementations/signature/mac_legacy_sig.inc]=\ providers/implementations/signature/mac_legacy_sig.inc.in GENERATE[providers/implementations/signature/ml_dsa_sig.inc]=\ providers/implementations/signature/ml_dsa_sig.inc.in +GENERATE[providers/implementations/signature/composite_sig.inc]=\ + providers/implementations/signature/composite_sig.inc.in GENERATE[providers/implementations/signature/rsa_sig.inc]=\ providers/implementations/signature/rsa_sig.inc.in GENERATE[providers/implementations/signature/slh_dsa_sig.inc]=\ diff --git a/crypto/objects/obj_dat.h b/crypto/objects/obj_dat.h index c7925932d51bb..45f50a77f7146 100644 --- a/crypto/objects/obj_dat.h +++ b/crypto/objects/obj_dat.h @@ -20,7 +20,7 @@ #include /* Serialized OID's */ -static const unsigned char so[9582] = { +static const unsigned char so[9726] = { 0x2A,0x86,0x48,0x86,0xF7,0x0D, /* [ 0] OBJ_rsadsi */ 0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01, /* [ 6] OBJ_pkcs */ 0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x02, /* [ 13] OBJ_md2 */ @@ -1364,9 +1364,27 @@ static const unsigned char so[9582] = { 0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x0D, /* [ 9549] OBJ_id_smime_ori */ 0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x0D,0x03, /* [ 9559] OBJ_id_smime_ori_kem */ 0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x03,0x11, /* [ 9570] OBJ_id_alg_hss_lms_hashsig */ + 0x2B,0x06,0x01,0x05,0x05,0x07,0x06,0x25, /* [ 9581] OBJ_ML_DSA_44_RSA2048_PSS_SHA256 */ + 0x2B,0x06,0x01,0x05,0x05,0x07,0x06,0x26, /* [ 9589] OBJ_ML_DSA_44_RSA2048_PKCS15_SHA256 */ + 0x2B,0x06,0x01,0x05,0x05,0x07,0x06,0x27, /* [ 9597] OBJ_ML_DSA_44_Ed25519_SHA512 */ + 0x2B,0x06,0x01,0x05,0x05,0x07,0x06,0x28, /* [ 9605] OBJ_ML_DSA_44_ECDSA_P256_SHA256 */ + 0x2B,0x06,0x01,0x05,0x05,0x07,0x06,0x29, /* [ 9613] OBJ_ML_DSA_65_RSA3072_PSS_SHA512 */ + 0x2B,0x06,0x01,0x05,0x05,0x07,0x06,0x2A, /* [ 9621] OBJ_ML_DSA_65_RSA3072_PKCS15_SHA512 */ + 0x2B,0x06,0x01,0x05,0x05,0x07,0x06,0x2B, /* [ 9629] OBJ_ML_DSA_65_RSA4096_PSS_SHA512 */ + 0x2B,0x06,0x01,0x05,0x05,0x07,0x06,0x2C, /* [ 9637] OBJ_ML_DSA_65_RSA4096_PKCS15_SHA512 */ + 0x2B,0x06,0x01,0x05,0x05,0x07,0x06,0x2D, /* [ 9645] OBJ_ML_DSA_65_ECDSA_P256_SHA512 */ + 0x2B,0x06,0x01,0x05,0x05,0x07,0x06,0x2E, /* [ 9653] OBJ_ML_DSA_65_ECDSA_P384_SHA512 */ + 0x2B,0x06,0x01,0x05,0x05,0x07,0x06,0x2F, /* [ 9661] OBJ_ML_DSA_65_ECDSA_brainpoolP256r1_SHA512 */ + 0x2B,0x06,0x01,0x05,0x05,0x07,0x06,0x30, /* [ 9669] OBJ_ML_DSA_65_Ed25519_SHA512 */ + 0x2B,0x06,0x01,0x05,0x05,0x07,0x06,0x31, /* [ 9677] OBJ_ML_DSA_87_ECDSA_P384_SHA512 */ + 0x2B,0x06,0x01,0x05,0x05,0x07,0x06,0x32, /* [ 9685] OBJ_ML_DSA_87_ECDSA_brainpoolP384r1_SHA512 */ + 0x2B,0x06,0x01,0x05,0x05,0x07,0x06,0x33, /* [ 9693] OBJ_ML_DSA_87_Ed448_SHAKE256 */ + 0x2B,0x06,0x01,0x05,0x05,0x07,0x06,0x34, /* [ 9701] OBJ_ML_DSA_87_RSA3072_PSS_SHA512 */ + 0x2B,0x06,0x01,0x05,0x05,0x07,0x06,0x35, /* [ 9709] OBJ_ML_DSA_87_RSA4096_PSS_SHA512 */ + 0x2B,0x06,0x01,0x05,0x05,0x07,0x06,0x36, /* [ 9717] OBJ_ML_DSA_87_ECDSA_P521_SHA512 */ }; -#define NUM_NID 1502 +#define NUM_NID 1520 static const ASN1_OBJECT nid_objs[NUM_NID] = { {"UNDEF", "undefined", NID_undef}, {"rsadsi", "RSA Data Security, Inc.", NID_rsadsi, 6, &so[0]}, @@ -2870,9 +2888,27 @@ static const ASN1_OBJECT nid_objs[NUM_NID] = { {"id-smime-ori", "id-smime-ori", NID_id_smime_ori, 10, &so[9549]}, {"id-smime-ori-kem", "id-smime-ori-kem", NID_id_smime_ori_kem, 11, &so[9559]}, {"id-alg-hss-lms-hashsig", "id-alg-hss-lms-hashsig", NID_id_alg_hss_lms_hashsig, 11, &so[9570]}, + {"id-mldsa44-rsa2048-pss-sha256", "ML-DSA-44-RSA2048-PSS-SHA256", NID_ML_DSA_44_RSA2048_PSS_SHA256, 8, &so[9581]}, + {"id-mldsa44-rsa2048-pkcs15-sha256", "ML-DSA-44-RSA2048-PKCS15-SHA256", NID_ML_DSA_44_RSA2048_PKCS15_SHA256, 8, &so[9589]}, + {"id-mldsa44-ed25519-sha512", "ML-DSA-44-Ed25519-SHA512", NID_ML_DSA_44_Ed25519_SHA512, 8, &so[9597]}, + {"id-mldsa44-ecdsa-p256-sha256", "ML-DSA-44-ECDSA-P256-SHA256", NID_ML_DSA_44_ECDSA_P256_SHA256, 8, &so[9605]}, + {"id-mldsa65-rsa3072-pss-sha512", "ML-DSA-65-RSA3072-PSS-SHA512", NID_ML_DSA_65_RSA3072_PSS_SHA512, 8, &so[9613]}, + {"id-mldsa65-rsa3072-pkcs15-sha512", "ML-DSA-65-RSA3072-PKCS15-SHA512", NID_ML_DSA_65_RSA3072_PKCS15_SHA512, 8, &so[9621]}, + {"id-mldsa65-rsa4096-pss-sha512", "ML-DSA-65-RSA4096-PSS-SHA512", NID_ML_DSA_65_RSA4096_PSS_SHA512, 8, &so[9629]}, + {"id-mldsa65-rsa4096-pkcs15-sha512", "ML-DSA-65-RSA4096-PKCS15-SHA512", NID_ML_DSA_65_RSA4096_PKCS15_SHA512, 8, &so[9637]}, + {"id-mldsa65-ecdsa-p256-sha512", "ML-DSA-65-ECDSA-P256-SHA512", NID_ML_DSA_65_ECDSA_P256_SHA512, 8, &so[9645]}, + {"id-mldsa65-ecdsa-p384-sha512", "ML-DSA-65-ECDSA-P384-SHA512", NID_ML_DSA_65_ECDSA_P384_SHA512, 8, &so[9653]}, + {"id-mldsa65-ecdsa-brainpoolP256r1-sha512", "ML-DSA-65-ECDSA-brainpoolP256r1-SHA512", NID_ML_DSA_65_ECDSA_brainpoolP256r1_SHA512, 8, &so[9661]}, + {"id-mldsa65-ed25519-sha512", "ML-DSA-65-Ed25519-SHA512", NID_ML_DSA_65_Ed25519_SHA512, 8, &so[9669]}, + {"id-mldsa87-ecdsa-p384-sha512", "ML-DSA-87-ECDSA-P384-SHA512", NID_ML_DSA_87_ECDSA_P384_SHA512, 8, &so[9677]}, + {"id-mldsa87-ecdsa-brainpoolp384r1-sha512", "ML-DSA-87-ECDSA-brainpoolP384r1-SHA512", NID_ML_DSA_87_ECDSA_brainpoolP384r1_SHA512, 8, &so[9685]}, + {"id-mldsa87-ed448-shake256", "ML-DSA-87-Ed448-SHAKE256", NID_ML_DSA_87_Ed448_SHAKE256, 8, &so[9693]}, + {"id-mldsa87-rsa3072-pss-sha512", "ML-DSA-87-RSA3072-PSS-SHA512", NID_ML_DSA_87_RSA3072_PSS_SHA512, 8, &so[9701]}, + {"id-mldsa87-rsa4096-pss-sha512", "ML-DSA-87-RSA4096-PSS-SHA512", NID_ML_DSA_87_RSA4096_PSS_SHA512, 8, &so[9709]}, + {"id-mldsa87-ecdsa-p521-sha512", "ML-DSA-87-ECDSA-P521-SHA512", NID_ML_DSA_87_ECDSA_P521_SHA512, 8, &so[9717]}, }; -#define NUM_SN 1493 +#define NUM_SN 1511 static const unsigned int sn_objs[NUM_SN] = { 364, /* "AD_DVCS" */ 419, /* "AES-128-CBC" */ @@ -3615,6 +3651,24 @@ static const unsigned int sn_objs[NUM_SN] = { 1457, /* "id-ml-dsa-44" */ 1458, /* "id-ml-dsa-65" */ 1459, /* "id-ml-dsa-87" */ + 1505, /* "id-mldsa44-ecdsa-p256-sha256" */ + 1504, /* "id-mldsa44-ed25519-sha512" */ + 1503, /* "id-mldsa44-rsa2048-pkcs15-sha256" */ + 1502, /* "id-mldsa44-rsa2048-pss-sha256" */ + 1512, /* "id-mldsa65-ecdsa-brainpoolP256r1-sha512" */ + 1510, /* "id-mldsa65-ecdsa-p256-sha512" */ + 1511, /* "id-mldsa65-ecdsa-p384-sha512" */ + 1513, /* "id-mldsa65-ed25519-sha512" */ + 1507, /* "id-mldsa65-rsa3072-pkcs15-sha512" */ + 1506, /* "id-mldsa65-rsa3072-pss-sha512" */ + 1509, /* "id-mldsa65-rsa4096-pkcs15-sha512" */ + 1508, /* "id-mldsa65-rsa4096-pss-sha512" */ + 1515, /* "id-mldsa87-ecdsa-brainpoolp384r1-sha512" */ + 1514, /* "id-mldsa87-ecdsa-p384-sha512" */ + 1519, /* "id-mldsa87-ecdsa-p521-sha512" */ + 1516, /* "id-mldsa87-ed448-shake256" */ + 1517, /* "id-mldsa87-rsa3072-pss-sha512" */ + 1518, /* "id-mldsa87-rsa4096-pss-sha512" */ 280, /* "id-mod-attribute-cert" */ 274, /* "id-mod-cmc" */ 277, /* "id-mod-cmp" */ @@ -4369,7 +4423,7 @@ static const unsigned int sn_objs[NUM_SN] = { 1289, /* "zstd" */ }; -#define NUM_LN 1493 +#define NUM_LN 1511 static const unsigned int ln_objs[NUM_LN] = { 363, /* "AD Time Stamping" */ 405, /* "ANSI X9.62" */ @@ -4530,8 +4584,26 @@ static const unsigned int ln_objs[NUM_LN] = { 142, /* "Invalidity Date" */ 504, /* "MIME MHS" */ 1457, /* "ML-DSA-44" */ + 1505, /* "ML-DSA-44-ECDSA-P256-SHA256" */ + 1504, /* "ML-DSA-44-Ed25519-SHA512" */ + 1503, /* "ML-DSA-44-RSA2048-PKCS15-SHA256" */ + 1502, /* "ML-DSA-44-RSA2048-PSS-SHA256" */ 1458, /* "ML-DSA-65" */ + 1510, /* "ML-DSA-65-ECDSA-P256-SHA512" */ + 1511, /* "ML-DSA-65-ECDSA-P384-SHA512" */ + 1512, /* "ML-DSA-65-ECDSA-brainpoolP256r1-SHA512" */ + 1513, /* "ML-DSA-65-Ed25519-SHA512" */ + 1507, /* "ML-DSA-65-RSA3072-PKCS15-SHA512" */ + 1506, /* "ML-DSA-65-RSA3072-PSS-SHA512" */ + 1509, /* "ML-DSA-65-RSA4096-PKCS15-SHA512" */ + 1508, /* "ML-DSA-65-RSA4096-PSS-SHA512" */ 1459, /* "ML-DSA-87" */ + 1514, /* "ML-DSA-87-ECDSA-P384-SHA512" */ + 1519, /* "ML-DSA-87-ECDSA-P521-SHA512" */ + 1515, /* "ML-DSA-87-ECDSA-brainpoolP384r1-SHA512" */ + 1516, /* "ML-DSA-87-Ed448-SHAKE256" */ + 1517, /* "ML-DSA-87-RSA3072-PSS-SHA512" */ + 1518, /* "ML-DSA-87-RSA4096-PSS-SHA512" */ 1456, /* "ML-KEM-1024" */ 1454, /* "ML-KEM-512" */ 1455, /* "ML-KEM-768" */ @@ -5866,7 +5938,7 @@ static const unsigned int ln_objs[NUM_LN] = { 125, /* "zlib compression" */ }; -#define NUM_OBJ 1350 +#define NUM_OBJ 1368 static const unsigned int obj_objs[NUM_OBJ] = { 0, /* OBJ_undef 0 */ 181, /* OBJ_iso 1 */ @@ -6695,6 +6767,24 @@ static const unsigned int obj_objs[NUM_OBJ] = { 324, /* OBJ_id_alg_noSignature 1 3 6 1 5 5 7 6 2 */ 325, /* OBJ_id_alg_dh_sig_hmac_sha1 1 3 6 1 5 5 7 6 3 */ 326, /* OBJ_id_alg_dh_pop 1 3 6 1 5 5 7 6 4 */ + 1502, /* OBJ_ML_DSA_44_RSA2048_PSS_SHA256 1 3 6 1 5 5 7 6 37 */ + 1503, /* OBJ_ML_DSA_44_RSA2048_PKCS15_SHA256 1 3 6 1 5 5 7 6 38 */ + 1504, /* OBJ_ML_DSA_44_Ed25519_SHA512 1 3 6 1 5 5 7 6 39 */ + 1505, /* OBJ_ML_DSA_44_ECDSA_P256_SHA256 1 3 6 1 5 5 7 6 40 */ + 1506, /* OBJ_ML_DSA_65_RSA3072_PSS_SHA512 1 3 6 1 5 5 7 6 41 */ + 1507, /* OBJ_ML_DSA_65_RSA3072_PKCS15_SHA512 1 3 6 1 5 5 7 6 42 */ + 1508, /* OBJ_ML_DSA_65_RSA4096_PSS_SHA512 1 3 6 1 5 5 7 6 43 */ + 1509, /* OBJ_ML_DSA_65_RSA4096_PKCS15_SHA512 1 3 6 1 5 5 7 6 44 */ + 1510, /* OBJ_ML_DSA_65_ECDSA_P256_SHA512 1 3 6 1 5 5 7 6 45 */ + 1511, /* OBJ_ML_DSA_65_ECDSA_P384_SHA512 1 3 6 1 5 5 7 6 46 */ + 1512, /* OBJ_ML_DSA_65_ECDSA_brainpoolP256r1_SHA512 1 3 6 1 5 5 7 6 47 */ + 1513, /* OBJ_ML_DSA_65_Ed25519_SHA512 1 3 6 1 5 5 7 6 48 */ + 1514, /* OBJ_ML_DSA_87_ECDSA_P384_SHA512 1 3 6 1 5 5 7 6 49 */ + 1515, /* OBJ_ML_DSA_87_ECDSA_brainpoolP384r1_SHA512 1 3 6 1 5 5 7 6 50 */ + 1516, /* OBJ_ML_DSA_87_Ed448_SHAKE256 1 3 6 1 5 5 7 6 51 */ + 1517, /* OBJ_ML_DSA_87_RSA3072_PSS_SHA512 1 3 6 1 5 5 7 6 52 */ + 1518, /* OBJ_ML_DSA_87_RSA4096_PSS_SHA512 1 3 6 1 5 5 7 6 53 */ + 1519, /* OBJ_ML_DSA_87_ECDSA_P521_SHA512 1 3 6 1 5 5 7 6 54 */ 327, /* OBJ_id_cmc_statusInfo 1 3 6 1 5 5 7 7 1 */ 328, /* OBJ_id_cmc_identification 1 3 6 1 5 5 7 7 2 */ 329, /* OBJ_id_cmc_identityProof 1 3 6 1 5 5 7 7 3 */ diff --git a/crypto/objects/obj_mac.num b/crypto/objects/obj_mac.num index e72170b47f7d0..64cd1d25bca07 100644 --- a/crypto/objects/obj_mac.num +++ b/crypto/objects/obj_mac.num @@ -1499,3 +1499,21 @@ HKDF_SHA512 1498 id_smime_ori 1499 id_smime_ori_kem 1500 id_alg_hss_lms_hashsig 1501 +ML_DSA_44_RSA2048_PSS_SHA256 1502 +ML_DSA_44_RSA2048_PKCS15_SHA256 1503 +ML_DSA_44_Ed25519_SHA512 1504 +ML_DSA_44_ECDSA_P256_SHA256 1505 +ML_DSA_65_RSA3072_PSS_SHA512 1506 +ML_DSA_65_RSA3072_PKCS15_SHA512 1507 +ML_DSA_65_RSA4096_PSS_SHA512 1508 +ML_DSA_65_RSA4096_PKCS15_SHA512 1509 +ML_DSA_65_ECDSA_P256_SHA512 1510 +ML_DSA_65_ECDSA_P384_SHA512 1511 +ML_DSA_65_ECDSA_brainpoolP256r1_SHA512 1512 +ML_DSA_65_Ed25519_SHA512 1513 +ML_DSA_87_ECDSA_P384_SHA512 1514 +ML_DSA_87_ECDSA_brainpoolP384r1_SHA512 1515 +ML_DSA_87_Ed448_SHAKE256 1516 +ML_DSA_87_RSA3072_PSS_SHA512 1517 +ML_DSA_87_RSA4096_PSS_SHA512 1518 +ML_DSA_87_ECDSA_P521_SHA512 1519 diff --git a/crypto/objects/obj_xref.h b/crypto/objects/obj_xref.h index 955571e134f53..0de4108f78f23 100644 --- a/crypto/objects/obj_xref.h +++ b/crypto/objects/obj_xref.h @@ -105,6 +105,39 @@ static const nid_triple sigoid_srt[] = { {NID_SLH_DSA_SHAKE_192f, NID_undef, NID_SLH_DSA_SHAKE_192f}, {NID_SLH_DSA_SHAKE_256s, NID_undef, NID_SLH_DSA_SHAKE_256s}, {NID_SLH_DSA_SHAKE_256f, NID_undef, NID_SLH_DSA_SHAKE_256f}, + {NID_ML_DSA_44_RSA2048_PSS_SHA256, NID_undef, + NID_ML_DSA_44_RSA2048_PSS_SHA256}, + {NID_ML_DSA_44_RSA2048_PKCS15_SHA256, NID_undef, + NID_ML_DSA_44_RSA2048_PKCS15_SHA256}, + {NID_ML_DSA_44_Ed25519_SHA512, NID_undef, NID_ML_DSA_44_Ed25519_SHA512}, + {NID_ML_DSA_44_ECDSA_P256_SHA256, NID_undef, + NID_ML_DSA_44_ECDSA_P256_SHA256}, + {NID_ML_DSA_65_RSA3072_PSS_SHA512, NID_undef, + NID_ML_DSA_65_RSA3072_PSS_SHA512}, + {NID_ML_DSA_65_RSA3072_PKCS15_SHA512, NID_undef, + NID_ML_DSA_65_RSA3072_PKCS15_SHA512}, + {NID_ML_DSA_65_RSA4096_PSS_SHA512, NID_undef, + NID_ML_DSA_65_RSA4096_PSS_SHA512}, + {NID_ML_DSA_65_RSA4096_PKCS15_SHA512, NID_undef, + NID_ML_DSA_65_RSA4096_PKCS15_SHA512}, + {NID_ML_DSA_65_ECDSA_P256_SHA512, NID_undef, + NID_ML_DSA_65_ECDSA_P256_SHA512}, + {NID_ML_DSA_65_ECDSA_P384_SHA512, NID_undef, + NID_ML_DSA_65_ECDSA_P384_SHA512}, + {NID_ML_DSA_65_ECDSA_brainpoolP256r1_SHA512, NID_undef, + NID_ML_DSA_65_ECDSA_brainpoolP256r1_SHA512}, + {NID_ML_DSA_65_Ed25519_SHA512, NID_undef, NID_ML_DSA_65_Ed25519_SHA512}, + {NID_ML_DSA_87_ECDSA_P384_SHA512, NID_undef, + NID_ML_DSA_87_ECDSA_P384_SHA512}, + {NID_ML_DSA_87_ECDSA_brainpoolP384r1_SHA512, NID_undef, + NID_ML_DSA_87_ECDSA_brainpoolP384r1_SHA512}, + {NID_ML_DSA_87_Ed448_SHAKE256, NID_undef, NID_ML_DSA_87_Ed448_SHAKE256}, + {NID_ML_DSA_87_RSA3072_PSS_SHA512, NID_undef, + NID_ML_DSA_87_RSA3072_PSS_SHA512}, + {NID_ML_DSA_87_RSA4096_PSS_SHA512, NID_undef, + NID_ML_DSA_87_RSA4096_PSS_SHA512}, + {NID_ML_DSA_87_ECDSA_P521_SHA512, NID_undef, + NID_ML_DSA_87_ECDSA_P521_SHA512}, }; static const nid_triple *const sigoid_srt_xref[] = { diff --git a/crypto/objects/obj_xref.txt b/crypto/objects/obj_xref.txt index 71bc12af74541..7ad7b9cfa8ba2 100644 --- a/crypto/objects/obj_xref.txt +++ b/crypto/objects/obj_xref.txt @@ -38,6 +38,24 @@ SLH_DSA_SHAKE_192s undef SLH_DSA_SHAKE_192s SLH_DSA_SHAKE_192f undef SLH_DSA_SHAKE_192f SLH_DSA_SHAKE_256s undef SLH_DSA_SHAKE_256s SLH_DSA_SHAKE_256f undef SLH_DSA_SHAKE_256f +ML_DSA_44_RSA2048_PSS_SHA256 undef ML_DSA_44_RSA2048_PSS_SHA256 +ML_DSA_44_RSA2048_PKCS15_SHA256 undef ML_DSA_44_RSA2048_PKCS15_SHA256 +ML_DSA_44_Ed25519_SHA512 undef ML_DSA_44_Ed25519_SHA512 +ML_DSA_44_ECDSA_P256_SHA256 undef ML_DSA_44_ECDSA_P256_SHA256 +ML_DSA_65_RSA3072_PSS_SHA512 undef ML_DSA_65_RSA3072_PSS_SHA512 +ML_DSA_65_RSA3072_PKCS15_SHA512 undef ML_DSA_65_RSA3072_PKCS15_SHA512 +ML_DSA_65_RSA4096_PSS_SHA512 undef ML_DSA_65_RSA4096_PSS_SHA512 +ML_DSA_65_RSA4096_PKCS15_SHA512 undef ML_DSA_65_RSA4096_PKCS15_SHA512 +ML_DSA_65_ECDSA_P256_SHA512 undef ML_DSA_65_ECDSA_P256_SHA512 +ML_DSA_65_ECDSA_P384_SHA512 undef ML_DSA_65_ECDSA_P384_SHA512 +ML_DSA_65_ECDSA_brainpoolP256r1_SHA512 undef ML_DSA_65_ECDSA_brainpoolP256r1_SHA512 +ML_DSA_65_Ed25519_SHA512 undef ML_DSA_65_Ed25519_SHA512 +ML_DSA_87_ECDSA_P384_SHA512 undef ML_DSA_87_ECDSA_P384_SHA512 +ML_DSA_87_ECDSA_brainpoolP384r1_SHA512 undef ML_DSA_87_ECDSA_brainpoolP384r1_SHA512 +ML_DSA_87_Ed448_SHAKE256 undef ML_DSA_87_Ed448_SHAKE256 +ML_DSA_87_RSA3072_PSS_SHA512 undef ML_DSA_87_RSA3072_PSS_SHA512 +ML_DSA_87_RSA4096_PSS_SHA512 undef ML_DSA_87_RSA4096_PSS_SHA512 +ML_DSA_87_ECDSA_P521_SHA512 undef ML_DSA_87_ECDSA_P521_SHA512 # Alternative deprecated OIDs. By using the older "rsa" OID this # type will be recognized by not normally used. diff --git a/crypto/objects/objects.txt b/crypto/objects/objects.txt index 946cdf5ec68cd..7cf4ae7290b03 100644 --- a/crypto/objects/objects.txt +++ b/crypto/objects/objects.txt @@ -641,6 +641,26 @@ id-alg 2 : id-alg-noSignature id-alg 3 : id-alg-dh-sig-hmac-sha1 id-alg 4 : id-alg-dh-pop +# Composite signature algorithms (draft-ietf-lamps-pq-composite-sigs) +id-alg 37 : id-mldsa44-rsa2048-pss-sha256 : ML-DSA-44-RSA2048-PSS-SHA256 +id-alg 38 : id-mldsa44-rsa2048-pkcs15-sha256 : ML-DSA-44-RSA2048-PKCS15-SHA256 +id-alg 39 : id-mldsa44-ed25519-sha512 : ML-DSA-44-Ed25519-SHA512 +id-alg 40 : id-mldsa44-ecdsa-p256-sha256 : ML-DSA-44-ECDSA-P256-SHA256 +id-alg 41 : id-mldsa65-rsa3072-pss-sha512 : ML-DSA-65-RSA3072-PSS-SHA512 +id-alg 42 : id-mldsa65-rsa3072-pkcs15-sha512 : ML-DSA-65-RSA3072-PKCS15-SHA512 +id-alg 43 : id-mldsa65-rsa4096-pss-sha512 : ML-DSA-65-RSA4096-PSS-SHA512 +id-alg 44 : id-mldsa65-rsa4096-pkcs15-sha512 : ML-DSA-65-RSA4096-PKCS15-SHA512 +id-alg 45 : id-mldsa65-ecdsa-p256-sha512 : ML-DSA-65-ECDSA-P256-SHA512 +id-alg 46 : id-mldsa65-ecdsa-p384-sha512 : ML-DSA-65-ECDSA-P384-SHA512 +id-alg 47 : id-mldsa65-ecdsa-brainpoolP256r1-sha512 : ML-DSA-65-ECDSA-brainpoolP256r1-SHA512 +id-alg 48 : id-mldsa65-ed25519-sha512 : ML-DSA-65-Ed25519-SHA512 +id-alg 49 : id-mldsa87-ecdsa-p384-sha512 : ML-DSA-87-ECDSA-P384-SHA512 +id-alg 50 : id-mldsa87-ecdsa-brainpoolp384r1-sha512 : ML-DSA-87-ECDSA-brainpoolP384r1-SHA512 +id-alg 51 : id-mldsa87-ed448-shake256 : ML-DSA-87-Ed448-SHAKE256 +id-alg 52 : id-mldsa87-rsa3072-pss-sha512 : ML-DSA-87-RSA3072-PSS-SHA512 +id-alg 53 : id-mldsa87-rsa4096-pss-sha512 : ML-DSA-87-RSA4096-PSS-SHA512 +id-alg 54 : id-mldsa87-ecdsa-p521-sha512 : ML-DSA-87-ECDSA-P521-SHA512 + # CMC controls id-cmc 1 : id-cmc-statusInfo id-cmc 2 : id-cmc-identification diff --git a/fuzz/oids.txt b/fuzz/oids.txt index 5fac3e1c88b43..6c8c1903b7921 100644 --- a/fuzz/oids.txt +++ b/fuzz/oids.txt @@ -1350,3 +1350,21 @@ OBJ_HKDF_SHA512="\x2A\x86\x48\x86\xF7\x0D\x01\x09\x10\x03\x1E" OBJ_id_smime_ori="\x2A\x86\x48\x86\xF7\x0D\x01\x09\x10\x0D" OBJ_id_smime_ori_kem="\x2A\x86\x48\x86\xF7\x0D\x01\x09\x10\x0D\x03" OBJ_id_alg_hss_lms_hashsig="\x2A\x86\x48\x86\xF7\x0D\x01\x09\x10\x03\x11" +OBJ_ML_DSA_44_RSA2048_PSS_SHA256="\x2B\x06\x01\x05\x05\x07\x06\x25" +OBJ_ML_DSA_44_RSA2048_PKCS15_SHA256="\x2B\x06\x01\x05\x05\x07\x06\x26" +OBJ_ML_DSA_44_Ed25519_SHA512="\x2B\x06\x01\x05\x05\x07\x06\x27" +OBJ_ML_DSA_44_ECDSA_P256_SHA256="\x2B\x06\x01\x05\x05\x07\x06\x28" +OBJ_ML_DSA_65_RSA3072_PSS_SHA512="\x2B\x06\x01\x05\x05\x07\x06\x29" +OBJ_ML_DSA_65_RSA3072_PKCS15_SHA512="\x2B\x06\x01\x05\x05\x07\x06\x2A" +OBJ_ML_DSA_65_RSA4096_PSS_SHA512="\x2B\x06\x01\x05\x05\x07\x06\x2B" +OBJ_ML_DSA_65_RSA4096_PKCS15_SHA512="\x2B\x06\x01\x05\x05\x07\x06\x2C" +OBJ_ML_DSA_65_ECDSA_P256_SHA512="\x2B\x06\x01\x05\x05\x07\x06\x2D" +OBJ_ML_DSA_65_ECDSA_P384_SHA512="\x2B\x06\x01\x05\x05\x07\x06\x2E" +OBJ_ML_DSA_65_ECDSA_brainpoolP256r1_SHA512="\x2B\x06\x01\x05\x05\x07\x06\x2F" +OBJ_ML_DSA_65_Ed25519_SHA512="\x2B\x06\x01\x05\x05\x07\x06\x30" +OBJ_ML_DSA_87_ECDSA_P384_SHA512="\x2B\x06\x01\x05\x05\x07\x06\x31" +OBJ_ML_DSA_87_ECDSA_brainpoolP384r1_SHA512="\x2B\x06\x01\x05\x05\x07\x06\x32" +OBJ_ML_DSA_87_Ed448_SHAKE256="\x2B\x06\x01\x05\x05\x07\x06\x33" +OBJ_ML_DSA_87_RSA3072_PSS_SHA512="\x2B\x06\x01\x05\x05\x07\x06\x34" +OBJ_ML_DSA_87_RSA4096_PSS_SHA512="\x2B\x06\x01\x05\x05\x07\x06\x35" +OBJ_ML_DSA_87_ECDSA_P521_SHA512="\x2B\x06\x01\x05\x05\x07\x06\x36" diff --git a/include/openssl/obj_mac.h b/include/openssl/obj_mac.h index fd43b9077ad0c..68a8bfb3fe45e 100644 --- a/include/openssl/obj_mac.h +++ b/include/openssl/obj_mac.h @@ -1965,6 +1965,96 @@ #define NID_id_alg_dh_pop 326 #define OBJ_id_alg_dh_pop OBJ_id_alg,4L +#define SN_ML_DSA_44_RSA2048_PSS_SHA256 "id-mldsa44-rsa2048-pss-sha256" +#define LN_ML_DSA_44_RSA2048_PSS_SHA256 "ML-DSA-44-RSA2048-PSS-SHA256" +#define NID_ML_DSA_44_RSA2048_PSS_SHA256 1502 +#define OBJ_ML_DSA_44_RSA2048_PSS_SHA256 OBJ_id_alg,37L + +#define SN_ML_DSA_44_RSA2048_PKCS15_SHA256 "id-mldsa44-rsa2048-pkcs15-sha256" +#define LN_ML_DSA_44_RSA2048_PKCS15_SHA256 "ML-DSA-44-RSA2048-PKCS15-SHA256" +#define NID_ML_DSA_44_RSA2048_PKCS15_SHA256 1503 +#define OBJ_ML_DSA_44_RSA2048_PKCS15_SHA256 OBJ_id_alg,38L + +#define SN_ML_DSA_44_Ed25519_SHA512 "id-mldsa44-ed25519-sha512" +#define LN_ML_DSA_44_Ed25519_SHA512 "ML-DSA-44-Ed25519-SHA512" +#define NID_ML_DSA_44_Ed25519_SHA512 1504 +#define OBJ_ML_DSA_44_Ed25519_SHA512 OBJ_id_alg,39L + +#define SN_ML_DSA_44_ECDSA_P256_SHA256 "id-mldsa44-ecdsa-p256-sha256" +#define LN_ML_DSA_44_ECDSA_P256_SHA256 "ML-DSA-44-ECDSA-P256-SHA256" +#define NID_ML_DSA_44_ECDSA_P256_SHA256 1505 +#define OBJ_ML_DSA_44_ECDSA_P256_SHA256 OBJ_id_alg,40L + +#define SN_ML_DSA_65_RSA3072_PSS_SHA512 "id-mldsa65-rsa3072-pss-sha512" +#define LN_ML_DSA_65_RSA3072_PSS_SHA512 "ML-DSA-65-RSA3072-PSS-SHA512" +#define NID_ML_DSA_65_RSA3072_PSS_SHA512 1506 +#define OBJ_ML_DSA_65_RSA3072_PSS_SHA512 OBJ_id_alg,41L + +#define SN_ML_DSA_65_RSA3072_PKCS15_SHA512 "id-mldsa65-rsa3072-pkcs15-sha512" +#define LN_ML_DSA_65_RSA3072_PKCS15_SHA512 "ML-DSA-65-RSA3072-PKCS15-SHA512" +#define NID_ML_DSA_65_RSA3072_PKCS15_SHA512 1507 +#define OBJ_ML_DSA_65_RSA3072_PKCS15_SHA512 OBJ_id_alg,42L + +#define SN_ML_DSA_65_RSA4096_PSS_SHA512 "id-mldsa65-rsa4096-pss-sha512" +#define LN_ML_DSA_65_RSA4096_PSS_SHA512 "ML-DSA-65-RSA4096-PSS-SHA512" +#define NID_ML_DSA_65_RSA4096_PSS_SHA512 1508 +#define OBJ_ML_DSA_65_RSA4096_PSS_SHA512 OBJ_id_alg,43L + +#define SN_ML_DSA_65_RSA4096_PKCS15_SHA512 "id-mldsa65-rsa4096-pkcs15-sha512" +#define LN_ML_DSA_65_RSA4096_PKCS15_SHA512 "ML-DSA-65-RSA4096-PKCS15-SHA512" +#define NID_ML_DSA_65_RSA4096_PKCS15_SHA512 1509 +#define OBJ_ML_DSA_65_RSA4096_PKCS15_SHA512 OBJ_id_alg,44L + +#define SN_ML_DSA_65_ECDSA_P256_SHA512 "id-mldsa65-ecdsa-p256-sha512" +#define LN_ML_DSA_65_ECDSA_P256_SHA512 "ML-DSA-65-ECDSA-P256-SHA512" +#define NID_ML_DSA_65_ECDSA_P256_SHA512 1510 +#define OBJ_ML_DSA_65_ECDSA_P256_SHA512 OBJ_id_alg,45L + +#define SN_ML_DSA_65_ECDSA_P384_SHA512 "id-mldsa65-ecdsa-p384-sha512" +#define LN_ML_DSA_65_ECDSA_P384_SHA512 "ML-DSA-65-ECDSA-P384-SHA512" +#define NID_ML_DSA_65_ECDSA_P384_SHA512 1511 +#define OBJ_ML_DSA_65_ECDSA_P384_SHA512 OBJ_id_alg,46L + +#define SN_ML_DSA_65_ECDSA_brainpoolP256r1_SHA512 "id-mldsa65-ecdsa-brainpoolP256r1-sha512" +#define LN_ML_DSA_65_ECDSA_brainpoolP256r1_SHA512 "ML-DSA-65-ECDSA-brainpoolP256r1-SHA512" +#define NID_ML_DSA_65_ECDSA_brainpoolP256r1_SHA512 1512 +#define OBJ_ML_DSA_65_ECDSA_brainpoolP256r1_SHA512 OBJ_id_alg,47L + +#define SN_ML_DSA_65_Ed25519_SHA512 "id-mldsa65-ed25519-sha512" +#define LN_ML_DSA_65_Ed25519_SHA512 "ML-DSA-65-Ed25519-SHA512" +#define NID_ML_DSA_65_Ed25519_SHA512 1513 +#define OBJ_ML_DSA_65_Ed25519_SHA512 OBJ_id_alg,48L + +#define SN_ML_DSA_87_ECDSA_P384_SHA512 "id-mldsa87-ecdsa-p384-sha512" +#define LN_ML_DSA_87_ECDSA_P384_SHA512 "ML-DSA-87-ECDSA-P384-SHA512" +#define NID_ML_DSA_87_ECDSA_P384_SHA512 1514 +#define OBJ_ML_DSA_87_ECDSA_P384_SHA512 OBJ_id_alg,49L + +#define SN_ML_DSA_87_ECDSA_brainpoolP384r1_SHA512 "id-mldsa87-ecdsa-brainpoolp384r1-sha512" +#define LN_ML_DSA_87_ECDSA_brainpoolP384r1_SHA512 "ML-DSA-87-ECDSA-brainpoolP384r1-SHA512" +#define NID_ML_DSA_87_ECDSA_brainpoolP384r1_SHA512 1515 +#define OBJ_ML_DSA_87_ECDSA_brainpoolP384r1_SHA512 OBJ_id_alg,50L + +#define SN_ML_DSA_87_Ed448_SHAKE256 "id-mldsa87-ed448-shake256" +#define LN_ML_DSA_87_Ed448_SHAKE256 "ML-DSA-87-Ed448-SHAKE256" +#define NID_ML_DSA_87_Ed448_SHAKE256 1516 +#define OBJ_ML_DSA_87_Ed448_SHAKE256 OBJ_id_alg,51L + +#define SN_ML_DSA_87_RSA3072_PSS_SHA512 "id-mldsa87-rsa3072-pss-sha512" +#define LN_ML_DSA_87_RSA3072_PSS_SHA512 "ML-DSA-87-RSA3072-PSS-SHA512" +#define NID_ML_DSA_87_RSA3072_PSS_SHA512 1517 +#define OBJ_ML_DSA_87_RSA3072_PSS_SHA512 OBJ_id_alg,52L + +#define SN_ML_DSA_87_RSA4096_PSS_SHA512 "id-mldsa87-rsa4096-pss-sha512" +#define LN_ML_DSA_87_RSA4096_PSS_SHA512 "ML-DSA-87-RSA4096-PSS-SHA512" +#define NID_ML_DSA_87_RSA4096_PSS_SHA512 1518 +#define OBJ_ML_DSA_87_RSA4096_PSS_SHA512 OBJ_id_alg,53L + +#define SN_ML_DSA_87_ECDSA_P521_SHA512 "id-mldsa87-ecdsa-p521-sha512" +#define LN_ML_DSA_87_ECDSA_P521_SHA512 "ML-DSA-87-ECDSA-P521-SHA512" +#define NID_ML_DSA_87_ECDSA_P521_SHA512 1519 +#define OBJ_ML_DSA_87_ECDSA_P521_SHA512 OBJ_id_alg,54L + #define SN_id_cmc_statusInfo "id-cmc-statusInfo" #define NID_id_cmc_statusInfo 327 #define OBJ_id_cmc_statusInfo OBJ_id_cmc,1L diff --git a/providers/common/der/build.info b/providers/common/der/build.info index efa34700d1020..bee94fbe4bc65 100644 --- a/providers/common/der/build.info +++ b/providers/common/der/build.info @@ -86,6 +86,19 @@ IF[{- !$disabled{'ml-dsa'} -}] DEPEND[$DER_ML_DSA_H]=oids_to_c.pm ML_DSA.asn1 ENDIF +#----- composite +IF[{- !$disabled{'ml-dsa'} -}] + $COMPOSITE_H=$INCDIR/composite.h + $DER_COMPOSITE_GEN=der_composite_gen.c + + GENERATE[$COMPOSITE_H]=$INCDIR/composite.h.in + DEPEND[$COMPOSITE_H]=oids_to_c.pm composite.asn1 + + GENERATE[$DER_COMPOSITE_GEN]=der_composite_gen.c.in + DEPEND[$DER_COMPOSITE_GEN]=oids_to_c.pm composite.asn1 + DEPEND[${DER_COMPOSITE_GEN/.c/.o}]=$COMPOSITE_H +ENDIF + #----- KEY WRAP $DER_WRAP_H=$INCDIR/der_wrap.h $DER_WRAP_GEN=der_wrap_gen.c @@ -165,6 +178,10 @@ IF[{- !$disabled{'slh-dsa'} -}] $COMMON = $COMMON $DER_SLH_DSA_GEN $DER_SLH_DSA_AUX ENDIF +IF[{- !$disabled{'ml-dsa'} -}] + $COMMON = $COMMON $DER_COMPOSITE_GEN +ENDIF + SOURCE[../../libcommon.a]= $COMMON SOURCE[../../libfips.a]= $DER_RSA_FIPSABLE SOURCE[../../libdefault.a]= $DER_RSA_FIPSABLE $NONFIPS diff --git a/providers/common/der/composite.asn1 b/providers/common/der/composite.asn1 new file mode 100644 index 0000000000000..d6500c9f7a22d --- /dev/null +++ b/providers/common/der/composite.asn1 @@ -0,0 +1,31 @@ +-- Copyright 2026 The OpenSSL Project Authors. All Rights Reserved. +-- +-- Licensed under the Apache License 2.0 (the "License"). You may not use +-- this file except in compliance with the License. You can obtain a copy +-- in the file LICENSE in the source distribution or at +-- https://www.openssl.org/source/license.html + +-- ------------------------------------------------------------------- + +-- Taken from https://datatracker.ietf.org/doc/draft-ietf-lamps-pq-composite-sigs/ + +sigAlgs OBJECT IDENTIFIER ::= { 1 3 6 1 5 5 7 6 } + +id-mldsa44-rsa2048-pss-sha256 OBJECT IDENTIFIER ::= { sigAlgs 37 } +id-mldsa44-rsa2048-pkcs15-sha256 OBJECT IDENTIFIER ::= { sigAlgs 38 } +id-mldsa44-ed25519-sha512 OBJECT IDENTIFIER ::= { sigAlgs 39 } +id-mldsa44-ecdsa-p256-sha256 OBJECT IDENTIFIER ::= { sigAlgs 40 } +id-mldsa65-rsa3072-pss-sha512 OBJECT IDENTIFIER ::= { sigAlgs 41 } +id-mldsa65-rsa3072-pkcs15-sha512 OBJECT IDENTIFIER ::= { sigAlgs 42 } +id-mldsa65-rsa4096-pss-sha512 OBJECT IDENTIFIER ::= { sigAlgs 43 } +id-mldsa65-rsa4096-pkcs15-sha512 OBJECT IDENTIFIER ::= { sigAlgs 44 } +id-mldsa65-ecdsa-p256-sha512 OBJECT IDENTIFIER ::= { sigAlgs 45 } +id-mldsa65-ecdsa-p384-sha512 OBJECT IDENTIFIER ::= { sigAlgs 46 } +id-mldsa65-ecdsa-brainpoolP256r1-sha512 OBJECT IDENTIFIER ::= { sigAlgs 47 } +id-mldsa65-ed25519-sha512 OBJECT IDENTIFIER ::= { sigAlgs 48 } +id-mldsa87-ecdsa-p384-sha512 OBJECT IDENTIFIER ::= { sigAlgs 49 } +id-mldsa87-ecdsa-brainpoolp384r1-sha512 OBJECT IDENTIFIER ::= { sigAlgs 50 } +id-mldsa87-ed448-shake256 OBJECT IDENTIFIER ::= { sigAlgs 51 } +id-mldsa87-rsa3072-pss-sha512 OBJECT IDENTIFIER ::= { sigAlgs 52 } +id-mldsa87-rsa4096-pss-sha512 OBJECT IDENTIFIER ::= { sigAlgs 53 } +id-mldsa87-ecdsa-p521-sha512 OBJECT IDENTIFIER ::= { sigAlgs 54 } \ No newline at end of file diff --git a/providers/common/der/der_composite_gen.c.in b/providers/common/der/der_composite_gen.c.in new file mode 100644 index 0000000000000..57dbbc03e5104 --- /dev/null +++ b/providers/common/der/der_composite_gen.c.in @@ -0,0 +1,21 @@ +/* + * {- join("\n * ", @autowarntext) -} + * + * Copyright 2026 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "prov/composite.h" + +/* Well known OIDs precompiled */ +/* clang-format off */ +{- + $OUT = oids_to_c::process_leaves('providers/common/der/composite.asn1', + { dir => $config{sourcedir}, + filter => \&oids_to_c::filter_to_C }); +-} +/* clang-format on */ diff --git a/providers/common/include/prov/composite.h.in b/providers/common/include/prov/composite.h.in new file mode 100644 index 0000000000000..743acd3d7cfbd --- /dev/null +++ b/providers/common/include/prov/composite.h.in @@ -0,0 +1,55 @@ +/* + * {- join("\n * ", @autowarntext) -} + * + * Copyright 2026 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef PROV_COMPOSITE_H +#define PROV_COMPOSITE_H + +#include "internal/der.h" +#include "crypto/ml_dsa.h" +#include "prov/provider_ctx.h" + +#define COMPOSITE_PREFIX "436F6D706F73697465416C676F726974686D5369676E61747572657332303235" + +/* Well known OIDs precompiled */ +/* clang-format off */ +{- + $OUT = oids_to_c::process_leaves('providers/common/der/composite.asn1', + { dir => $config{sourcedir}, + filter => \&oids_to_c::filter_to_H }); +-} +/* clang-format on */ + +typedef struct { + ML_DSA_KEY *ml_dsa_key; + EVP_PKEY *classic_key; +} COMPOSITE_KEY; + +typedef struct { + OSSL_LIB_CTX *libctx; + const char *alg; + const unsigned char *oid; + size_t oid_sz; + uint8_t context_string[255]; /* ML_DSA_MAX_CONTEXT_STRING_LEN */ + size_t context_string_len; + const char *prehash_alg; + size_t prehash_len; + + /* CLASSIC */ + EVP_PKEY_CTX *classic_ctx; + + COMPOSITE_KEY *key; +} PROV_COMPOSITE_CTX; + +COMPOSITE_KEY *ossl_prov_composite_new(PROV_CTX *ctx, const char *propq, + int ml_dsa_evp_type); +void ossl_composite_key_free(COMPOSITE_KEY *key); + +#endif /* PROV_COMPOSITE_H */ diff --git a/providers/decoders.inc b/providers/decoders.inc index 767df65997634..70649cc6971d5 100644 --- a/providers/decoders.inc +++ b/providers/decoders.inc @@ -126,6 +126,45 @@ DECODER_w_structure("ML-DSA-65", der, SubjectPublicKeyInfo, ml_dsa_65, yes, "SPK DECODER_w_structure("ML-DSA-87", der, SubjectPublicKeyInfo, ml_dsa_87, yes, "SPKItoML-DSA-87-DER"), #endif /* OPENSSL_NO_ML_DSA */ +#ifndef OPENSSL_NO_COMPOSITE +DECODER_w_structure("ML-DSA-44-RSA2048-PSS-SHA256", der, PrivateKeyInfo, mldsa44_rsa2048_pss_sha256, no, "PKItoMLDSA44-RSA2048-PSS-SHA256-DER"), +DECODER_w_structure("ML-DSA-44-RSA2048-PSS-SHA256", der, SubjectPublicKeyInfo, mldsa44_rsa2048_pss_sha256, no, "SPKItoMLDSA44-RSA2048-PSS-SHA256-DER"), +DECODER_w_structure("ML-DSA-44-RSA2048-PKCS15-SHA256", der, PrivateKeyInfo, mldsa44_rsa2048_pkcs15_sha256, no, "PKItoMLDSA44-RSA2048-PKCS15-SHA256-DER"), +DECODER_w_structure("ML-DSA-44-RSA2048-PKCS15-SHA256", der, SubjectPublicKeyInfo, mldsa44_rsa2048_pkcs15_sha256, no, "SPKItoMLDSA44-RSA2048-PKCS15-SHA256-DER"), +DECODER_w_structure("ML-DSA-44-Ed25519-SHA512", der, PrivateKeyInfo, mldsa44_ed25519_sha512, no, "PKItoMLDSA44-Ed25519-SHA512-DER"), +DECODER_w_structure("ML-DSA-44-Ed25519-SHA512", der, SubjectPublicKeyInfo, mldsa44_ed25519_sha512, no, "SPKItoMLDSA44-Ed25519-SHA512-DER"), +DECODER_w_structure("ML-DSA-44-ECDSA-P256-SHA256", der, PrivateKeyInfo, mldsa44_ecdsa_p256_sha256, no, "PKItoMLDSA44-ECDSA-P256-SHA256-DER"), +DECODER_w_structure("ML-DSA-44-ECDSA-P256-SHA256", der, SubjectPublicKeyInfo, mldsa44_ecdsa_p256_sha256, no, "SPKItoMLDSA44-ECDSA-P256-SHA256-DER"), +DECODER_w_structure("ML-DSA-65-RSA3072-PSS-SHA512", der, PrivateKeyInfo, mldsa65_rsa3072_pss_sha512, no, "PKItoMLDSA65-RSA3072-PSS-SHA512-DER"), +DECODER_w_structure("ML-DSA-65-RSA3072-PSS-SHA512", der, SubjectPublicKeyInfo, mldsa65_rsa3072_pss_sha512, no, "SPKItoMLDSA65-RSA3072-PSS-SHA512-DER"), +DECODER_w_structure("ML-DSA-65-RSA3072-PKCS15-SHA512", der, PrivateKeyInfo, mldsa65_rsa3072_pkcs15_sha512, no, "PKItoMLDSA65-RSA3072-PKCS15-SHA512-DER"), +DECODER_w_structure("ML-DSA-65-RSA3072-PKCS15-SHA512", der, SubjectPublicKeyInfo, mldsa65_rsa3072_pkcs15_sha512, no, "SPKItoMLDSA65-RSA3072-PKCS15-SHA512-DER"), +DECODER_w_structure("ML-DSA-65-RSA4096-PSS-SHA512", der, PrivateKeyInfo, mldsa65_rsa4096_pss_sha512, no, "PKItoMLDSA65-RSA4096-PSS-SHA512-DER"), +DECODER_w_structure("ML-DSA-65-RSA4096-PSS-SHA512", der, SubjectPublicKeyInfo, mldsa65_rsa4096_pss_sha512, no, "SPKItoMLDSA65-RSA4096-PSS-SHA512-DER"), +DECODER_w_structure("ML-DSA-65-RSA4096-PKCS15-SHA512", der, PrivateKeyInfo, mldsa65_rsa4096_pkcs15_sha512, no, "PKItoMLDSA65-RSA4096-PKCS15-SHA512-DER"), +DECODER_w_structure("ML-DSA-65-RSA4096-PKCS15-SHA512", der, SubjectPublicKeyInfo, mldsa65_rsa4096_pkcs15_sha512, no, "SPKItoMLDSA65-RSA4096-PKCS15-SHA512-DER"), +DECODER_w_structure("ML-DSA-65-ECDSA-P256-SHA512", der, PrivateKeyInfo, mldsa65_ecdsa_p256_sha512, no, "PKItoMLDSA65-ECDSA-P256-SHA512-DER"), +DECODER_w_structure("ML-DSA-65-ECDSA-P256-SHA512", der, SubjectPublicKeyInfo, mldsa65_ecdsa_p256_sha512, no, "SPKItoMLDSA65-ECDSA-P256-SHA512-DER"), +DECODER_w_structure("ML-DSA-65-ECDSA-P384-SHA512", der, PrivateKeyInfo, mldsa65_ecdsa_p384_sha512, no, "PKItoMLDSA65-ECDSA-P384-SHA512-DER"), +DECODER_w_structure("ML-DSA-65-ECDSA-P384-SHA512", der, SubjectPublicKeyInfo, mldsa65_ecdsa_p384_sha512, no, "SPKItoMLDSA65-ECDSA-P384-SHA512-DER"), +DECODER_w_structure("ML-DSA-65-ECDSA-brainpoolP256r1-SHA512", der, PrivateKeyInfo, mldsa65_ecdsa_brainpoolP256r1_sha512, no, "PKItoMLDSA65-ECDSA-brainpoolP256r1-SHA512-DER"), +DECODER_w_structure("ML-DSA-65-ECDSA-brainpoolP256r1-SHA512", der, SubjectPublicKeyInfo, mldsa65_ecdsa_brainpoolP256r1_sha512, no, "SPKItoMLDSA65-ECDSA-brainpoolP256r1-SHA512-DER"), +DECODER_w_structure("ML-DSA-65-Ed25519-SHA512", der, PrivateKeyInfo, mldsa65_ed25519_sha512, no, "PKItoMLDSA65-Ed25519-SHA512-DER"), +DECODER_w_structure("ML-DSA-65-Ed25519-SHA512", der, SubjectPublicKeyInfo, mldsa65_ed25519_sha512, no, "SPKItoMLDSA65-Ed25519-SHA512-DER"), +DECODER_w_structure("ML-DSA-87-ECDSA-P384-SHA512", der, PrivateKeyInfo, mldsa87_ecdsa_p384_sha512, no, "PKItoMLDSA87-ECDSA-P384-SHA512-DER"), +DECODER_w_structure("ML-DSA-87-ECDSA-P384-SHA512", der, SubjectPublicKeyInfo, mldsa87_ecdsa_p384_sha512, no, "SPKItoMLDSA87-ECDSA-P384-SHA512-DER"), +DECODER_w_structure("ML-DSA-87-ECDSA-brainpoolP384r1-SHA512", der, PrivateKeyInfo, mldsa87_ecdsa_brainpoolP384r1_sha512, no, "PKItoMLDSA87-ECDSA-brainpoolP384r1-SHA512-DER"), +DECODER_w_structure("ML-DSA-87-ECDSA-brainpoolP384r1-SHA512", der, SubjectPublicKeyInfo, mldsa87_ecdsa_brainpoolP384r1_sha512, no, "SPKItoMLDSA87-ECDSA-brainpoolP384r1-SHA512-DER"), +DECODER_w_structure("ML-DSA-87-Ed448-SHAKE256", der, PrivateKeyInfo, mldsa87_ed448_shake256, no, "PKItoMLDSA87-Ed448-SHAKE256-DER"), +DECODER_w_structure("ML-DSA-87-Ed448-SHAKE256", der, SubjectPublicKeyInfo, mldsa87_ed448_shake256, no, "SPKItoMLDSA87-Ed448-SHAKE256-DER"), +DECODER_w_structure("ML-DSA-87-RSA3072-PSS-SHA512", der, PrivateKeyInfo, mldsa87_rsa3072_pss_sha512, no, "PKItoMLDSA87-RSA3072-PSS-SHA512-DER"), +DECODER_w_structure("ML-DSA-87-RSA3072-PSS-SHA512", der, SubjectPublicKeyInfo, mldsa87_rsa3072_pss_sha512, no, "SPKItoMLDSA87-RSA3072-PSS-SHA512-DER"), +DECODER_w_structure("ML-DSA-87-RSA4096-PSS-SHA512", der, PrivateKeyInfo, mldsa87_rsa4096_pss_sha512, no, "PKItoMLDSA87-RSA4096-PSS-SHA512-DER"), +DECODER_w_structure("ML-DSA-87-RSA4096-PSS-SHA512", der, SubjectPublicKeyInfo, mldsa87_rsa4096_pss_sha512, no, "SPKItoMLDSA87-RSA4096-PSS-SHA512-DER"), +DECODER_w_structure("ML-DSA-87-ECDSA-P521-SHA512", der, PrivateKeyInfo, mldsa87_ecdsa_p521_sha512, no, "PKItoMLDSA87-ECDSA-P521-SHA512-DER"), +DECODER_w_structure("ML-DSA-87-ECDSA-P521-SHA512", der, SubjectPublicKeyInfo, mldsa87_ecdsa_p521_sha512, no, "SPKItoMLDSA87-ECDSA-P521-SHA512-DER"), +#endif /* OPENSSL_NO_COMPOSITE */ + #ifndef OPENSSL_NO_LMS DECODER("LMS", xdr, lms, yes, "XDRtoLMS"), DECODER_w_structure("LMS", der, SubjectPublicKeyInfo, lms, yes, "SPKItoLMS-DER"), diff --git a/providers/defltprov.c b/providers/defltprov.c index 1f39b34d6e1f6..4c5313709cae4 100644 --- a/providers/defltprov.c +++ b/providers/defltprov.c @@ -499,7 +499,63 @@ static const OSSL_ALGORITHM deflt_signature[] = { { PROV_NAMES_ML_DSA_44, "provider=default", ossl_ml_dsa_44_signature_functions }, { PROV_NAMES_ML_DSA_65, "provider=default", ossl_ml_dsa_65_signature_functions }, { PROV_NAMES_ML_DSA_87, "provider=default", ossl_ml_dsa_87_signature_functions }, -#endif +#ifndef OPENSSL_NO_COMPOSITE + { PROV_NAMES_MLDSA44_RSA2048_PSS_SHA256, "provider=default", + ossl_mldsa44_rsa2048_pss_sha256_signature_functions, + PROV_DESCS_MLDSA44_RSA2048_PSS_SHA256 }, + { PROV_NAMES_MLDSA44_RSA2048_PKCS15_SHA256, "provider=default", + ossl_mldsa44_rsa2048_pkcs15_sha256_signature_functions, + PROV_DESCS_MLDSA44_RSA2048_PKCS15_SHA256 }, + { PROV_NAMES_MLDSA44_ED25519_SHA512, "provider=default", + ossl_mldsa44_ed25519_sha512_signature_functions, + PROV_DESCS_MLDSA44_ED25519_SHA512 }, + { PROV_NAMES_MLDSA44_ECDSA_P256_SHA256, "provider=default", + ossl_mldsa44_ecdsa_p256_sha256_signature_functions, + PROV_DESCS_MLDSA44_ECDSA_P256_SHA256 }, + { PROV_NAMES_MLDSA65_RSA3072_PSS_SHA512, "provider=default", + ossl_mldsa65_rsa3072_pss_sha512_signature_functions, + PROV_DESCS_MLDSA65_RSA3072_PSS_SHA512 }, + { PROV_NAMES_MLDSA65_RSA3072_PKCS15_SHA512, "provider=default", + ossl_mldsa65_rsa3072_pkcs15_sha512_signature_functions, + PROV_DESCS_MLDSA65_RSA3072_PKCS15_SHA512 }, + { PROV_NAMES_MLDSA65_RSA4096_PSS_SHA512, "provider=default", + ossl_mldsa65_rsa4096_pss_sha512_signature_functions, + PROV_DESCS_MLDSA65_RSA4096_PSS_SHA512 }, + { PROV_NAMES_MLDSA65_RSA4096_PKCS15_SHA512, "provider=default", + ossl_mldsa65_rsa4096_pkcs15_sha512_signature_functions, + PROV_DESCS_MLDSA65_RSA4096_PKCS15_SHA512 }, + { PROV_NAMES_MLDSA65_ECDSA_P256_SHA512, "provider=default", + ossl_mldsa65_ecdsa_p256_sha512_signature_functions, + PROV_DESCS_MLDSA65_ECDSA_P256_SHA512 }, + { PROV_NAMES_MLDSA65_ECDSA_P384_SHA512, "provider=default", + ossl_mldsa65_ecdsa_p384_sha512_signature_functions, + PROV_DESCS_MLDSA65_ECDSA_P384_SHA512 }, + { PROV_NAMES_MLDSA65_ECDSA_BRAINPOOLP256R1_SHA512, "provider=default", + ossl_mldsa65_ecdsa_brainpoolP256r1_sha512_signature_functions, + PROV_DESCS_MLDSA65_ECDSA_BRAINPOOLP256R1_SHA512 }, + { PROV_NAMES_MLDSA65_ED25519_SHA512, "provider=default", + ossl_mldsa65_ed25519_sha512_signature_functions, + PROV_DESCS_MLDSA65_ED25519_SHA512 }, + { PROV_NAMES_MLDSA87_ECDSA_P384_SHA512, "provider=default", + ossl_mldsa87_ecdsa_p384_sha512_signature_functions, + PROV_DESCS_MLDSA87_ECDSA_P384_SHA512 }, + { PROV_NAMES_MLDSA87_ECDSA_BRAINPOOLP384R1_SHA512, "provider=default", + ossl_mldsa87_ecdsa_brainpoolP384r1_sha512_signature_functions, + PROV_DESCS_MLDSA87_ECDSA_BRAINPOOLP384R1_SHA512 }, + { PROV_NAMES_MLDSA87_ED448_SHAKE256, "provider=default", + ossl_mldsa87_ed448_shake256_signature_functions, + PROV_DESCS_MLDSA87_ED448_SHAKE256 }, + { PROV_NAMES_MLDSA87_RSA3072_PSS_SHA512, "provider=default", + ossl_mldsa87_rsa3072_pss_sha512_signature_functions, + PROV_DESCS_MLDSA87_RSA3072_PSS_SHA512 }, + { PROV_NAMES_MLDSA87_RSA4096_PSS_SHA512, "provider=default", + ossl_mldsa87_rsa4096_pss_sha512_signature_functions, + PROV_DESCS_MLDSA87_RSA4096_PSS_SHA512 }, + { PROV_NAMES_MLDSA87_ECDSA_P521_SHA512, "provider=default", + ossl_mldsa87_ecdsa_p521_sha512_signature_functions, + PROV_DESCS_MLDSA87_ECDSA_P521_SHA512 }, +#endif /* OPENSSL_NO_COMPOSITE */ +#endif /* OPENSSL_NO_ML_DSA */ { PROV_NAMES_HMAC, "provider=default", ossl_mac_legacy_hmac_signature_functions }, #ifndef OPENSSL_NO_SIPHASH { PROV_NAMES_SIPHASH, "provider=default", @@ -616,6 +672,26 @@ static const OSSL_ALGORITHM deflt_keymgmt[] = { PROV_DESCS_ML_DSA_65 }, { PROV_NAMES_ML_DSA_87, "provider=default", ossl_ml_dsa_87_keymgmt_functions, PROV_DESCS_ML_DSA_87 }, +#ifndef OPENSSL_NO_COMPOSITE + { PROV_NAMES_MLDSA44_RSA2048_PSS_SHA256, "provider=default", ossl_mldsa44_rsa2048_pss_sha256_keymgmt_functions, PROV_DESCS_MLDSA44_RSA2048_PSS_SHA256 }, + { PROV_NAMES_MLDSA44_RSA2048_PKCS15_SHA256, "provider=default", ossl_mldsa44_rsa2048_pkcs15_sha256_keymgmt_functions, PROV_DESCS_MLDSA44_RSA2048_PKCS15_SHA256 }, + { PROV_NAMES_MLDSA44_ED25519_SHA512, "provider=default", ossl_mldsa44_ed25519_sha512_keymgmt_functions, PROV_DESCS_MLDSA44_ED25519_SHA512 }, + { PROV_NAMES_MLDSA44_ECDSA_P256_SHA256, "provider=default", ossl_mldsa44_ecdsa_p256_sha256_keymgmt_functions, PROV_DESCS_MLDSA44_ECDSA_P256_SHA256 }, + { PROV_NAMES_MLDSA65_RSA3072_PSS_SHA512, "provider=default", ossl_mldsa65_rsa3072_pss_sha512_keymgmt_functions, PROV_DESCS_MLDSA65_RSA3072_PSS_SHA512 }, + { PROV_NAMES_MLDSA65_RSA3072_PKCS15_SHA512, "provider=default", ossl_mldsa65_rsa3072_pkcs15_sha512_keymgmt_functions, PROV_DESCS_MLDSA65_RSA3072_PKCS15_SHA512 }, + { PROV_NAMES_MLDSA65_RSA4096_PSS_SHA512, "provider=default", ossl_mldsa65_rsa4096_pss_sha512_keymgmt_functions, PROV_DESCS_MLDSA65_RSA4096_PSS_SHA512 }, + { PROV_NAMES_MLDSA65_RSA4096_PKCS15_SHA512, "provider=default", ossl_mldsa65_rsa4096_pkcs15_sha512_keymgmt_functions, PROV_DESCS_MLDSA65_RSA4096_PKCS15_SHA512 }, + { PROV_NAMES_MLDSA65_ECDSA_P256_SHA512, "provider=default", ossl_mldsa65_ecdsa_p256_sha512_keymgmt_functions, PROV_DESCS_MLDSA65_ECDSA_P256_SHA512 }, + { PROV_NAMES_MLDSA65_ECDSA_P384_SHA512, "provider=default", ossl_mldsa65_ecdsa_p384_sha512_keymgmt_functions, PROV_DESCS_MLDSA65_ECDSA_P384_SHA512 }, + { PROV_NAMES_MLDSA65_ECDSA_BRAINPOOLP256R1_SHA512, "provider=default", ossl_mldsa65_ecdsa_brainpoolP256r1_sha512_keymgmt_functions, PROV_DESCS_MLDSA65_ECDSA_BRAINPOOLP256R1_SHA512 }, + { PROV_NAMES_MLDSA65_ED25519_SHA512, "provider=default", ossl_mldsa65_ed25519_sha512_keymgmt_functions, PROV_DESCS_MLDSA65_ED25519_SHA512 }, + { PROV_NAMES_MLDSA87_ECDSA_P384_SHA512, "provider=default", ossl_mldsa87_ecdsa_p384_sha512_keymgmt_functions, PROV_DESCS_MLDSA87_ECDSA_P384_SHA512 }, + { PROV_NAMES_MLDSA87_ECDSA_BRAINPOOLP384R1_SHA512, "provider=default", ossl_mldsa87_ecdsa_brainpoolP384r1_sha512_keymgmt_functions, PROV_DESCS_MLDSA87_ECDSA_BRAINPOOLP384R1_SHA512 }, + { PROV_NAMES_MLDSA87_ED448_SHAKE256, "provider=default", ossl_mldsa87_ed448_shake256_keymgmt_functions, PROV_DESCS_MLDSA87_ED448_SHAKE256 }, + { PROV_NAMES_MLDSA87_RSA3072_PSS_SHA512, "provider=default", ossl_mldsa87_rsa3072_pss_sha512_keymgmt_functions, PROV_DESCS_MLDSA87_RSA3072_PSS_SHA512 }, + { PROV_NAMES_MLDSA87_RSA4096_PSS_SHA512, "provider=default", ossl_mldsa87_rsa4096_pss_sha512_keymgmt_functions, PROV_DESCS_MLDSA87_RSA4096_PSS_SHA512 }, + { PROV_NAMES_MLDSA87_ECDSA_P521_SHA512, "provider=default", ossl_mldsa87_ecdsa_p521_sha512_keymgmt_functions, PROV_DESCS_MLDSA87_ECDSA_P521_SHA512 }, +#endif /* OPENSSL_NO_COMPOSITE */ #endif /* OPENSSL_NO_ML_DSA */ { PROV_NAMES_TLS1_PRF, "provider=default", ossl_kdf_keymgmt_functions, PROV_DESCS_TLS1_PRF_SIGN }, diff --git a/providers/encoders.inc b/providers/encoders.inc index 1ab0d3a75d67b..04c5baa885da3 100644 --- a/providers/encoders.inc +++ b/providers/encoders.inc @@ -375,6 +375,152 @@ ENCODER_w_structure("ML-DSA-87", ml_dsa_87, yes, der, SubjectPublicKeyInfo), ENCODER_w_structure("ML-DSA-87", ml_dsa_87, yes, pem, SubjectPublicKeyInfo), # endif /* OPENSSL_NO_ML_DSA */ +# ifndef OPENSSL_NO_COMPOSITE +ENCODER_w_structure("ML-DSA-44-RSA2048-PSS-SHA256", mldsa44_rsa2048_pss_sha256, yes, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-44-RSA2048-PSS-SHA256", mldsa44_rsa2048_pss_sha256, yes, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-44-RSA2048-PSS-SHA256", mldsa44_rsa2048_pss_sha256, yes, der, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-44-RSA2048-PSS-SHA256", mldsa44_rsa2048_pss_sha256, yes, pem, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-44-RSA2048-PSS-SHA256", mldsa44_rsa2048_pss_sha256, yes, der, SubjectPublicKeyInfo), +ENCODER_w_structure("ML-DSA-44-RSA2048-PSS-SHA256", mldsa44_rsa2048_pss_sha256, yes, pem, SubjectPublicKeyInfo), +ENCODER_TEXT("ML-DSA-44-RSA2048-PSS-SHA256", mldsa44_rsa2048_pss_sha256, yes), + +ENCODER_w_structure("ML-DSA-44-RSA2048-PKCS15-SHA256", mldsa44_rsa2048_pkcs15_sha256, yes, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-44-RSA2048-PKCS15-SHA256", mldsa44_rsa2048_pkcs15_sha256, yes, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-44-RSA2048-PKCS15-SHA256", mldsa44_rsa2048_pkcs15_sha256, yes, der, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-44-RSA2048-PKCS15-SHA256", mldsa44_rsa2048_pkcs15_sha256, yes, pem, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-44-RSA2048-PKCS15-SHA256", mldsa44_rsa2048_pkcs15_sha256, yes, der, SubjectPublicKeyInfo), +ENCODER_w_structure("ML-DSA-44-RSA2048-PKCS15-SHA256", mldsa44_rsa2048_pkcs15_sha256, yes, pem, SubjectPublicKeyInfo), +ENCODER_TEXT("ML-DSA-44-RSA2048-PKCS15-SHA256", mldsa44_rsa2048_pkcs15_sha256, yes), + +ENCODER_w_structure("ML-DSA-44-Ed25519-SHA512", mldsa44_ed25519_sha512, yes, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-44-Ed25519-SHA512", mldsa44_ed25519_sha512, yes, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-44-Ed25519-SHA512", mldsa44_ed25519_sha512, yes, der, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-44-Ed25519-SHA512", mldsa44_ed25519_sha512, yes, pem, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-44-Ed25519-SHA512", mldsa44_ed25519_sha512, yes, der, SubjectPublicKeyInfo), +ENCODER_w_structure("ML-DSA-44-Ed25519-SHA512", mldsa44_ed25519_sha512, yes, pem, SubjectPublicKeyInfo), +ENCODER_TEXT("ML-DSA-44-Ed25519-SHA512", mldsa44_ed25519_sha512, yes), + +ENCODER_w_structure("ML-DSA-44-ECDSA-P256-SHA256", mldsa44_ecdsa_p256_sha256, yes, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-44-ECDSA-P256-SHA256", mldsa44_ecdsa_p256_sha256, yes, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-44-ECDSA-P256-SHA256", mldsa44_ecdsa_p256_sha256, yes, der, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-44-ECDSA-P256-SHA256", mldsa44_ecdsa_p256_sha256, yes, pem, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-44-ECDSA-P256-SHA256", mldsa44_ecdsa_p256_sha256, yes, der, SubjectPublicKeyInfo), +ENCODER_w_structure("ML-DSA-44-ECDSA-P256-SHA256", mldsa44_ecdsa_p256_sha256, yes, pem, SubjectPublicKeyInfo), +ENCODER_TEXT("ML-DSA-44-ECDSA-P256-SHA256", mldsa44_ecdsa_p256_sha256, yes), + +ENCODER_w_structure("ML-DSA-65-RSA3072-PSS-SHA512", mldsa65_rsa3072_pss_sha512, yes, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-65-RSA3072-PSS-SHA512", mldsa65_rsa3072_pss_sha512, yes, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-65-RSA3072-PSS-SHA512", mldsa65_rsa3072_pss_sha512, yes, der, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-65-RSA3072-PSS-SHA512", mldsa65_rsa3072_pss_sha512, yes, pem, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-65-RSA3072-PSS-SHA512", mldsa65_rsa3072_pss_sha512, yes, der, SubjectPublicKeyInfo), +ENCODER_w_structure("ML-DSA-65-RSA3072-PSS-SHA512", mldsa65_rsa3072_pss_sha512, yes, pem, SubjectPublicKeyInfo), +ENCODER_TEXT("ML-DSA-65-RSA3072-PSS-SHA512", mldsa65_rsa3072_pss_sha512, yes), + +ENCODER_w_structure("ML-DSA-65-RSA3072-PKCS15-SHA512", mldsa65_rsa3072_pkcs15_sha512, yes, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-65-RSA3072-PKCS15-SHA512", mldsa65_rsa3072_pkcs15_sha512, yes, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-65-RSA3072-PKCS15-SHA512", mldsa65_rsa3072_pkcs15_sha512, yes, der, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-65-RSA3072-PKCS15-SHA512", mldsa65_rsa3072_pkcs15_sha512, yes, pem, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-65-RSA3072-PKCS15-SHA512", mldsa65_rsa3072_pkcs15_sha512, yes, der, SubjectPublicKeyInfo), +ENCODER_w_structure("ML-DSA-65-RSA3072-PKCS15-SHA512", mldsa65_rsa3072_pkcs15_sha512, yes, pem, SubjectPublicKeyInfo), +ENCODER_TEXT("ML-DSA-65-RSA3072-PKCS15-SHA512", mldsa65_rsa3072_pkcs15_sha512, yes), + +ENCODER_w_structure("ML-DSA-65-RSA4096-PSS-SHA512", mldsa65_rsa4096_pss_sha512, yes, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-65-RSA4096-PSS-SHA512", mldsa65_rsa4096_pss_sha512, yes, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-65-RSA4096-PSS-SHA512", mldsa65_rsa4096_pss_sha512, yes, der, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-65-RSA4096-PSS-SHA512", mldsa65_rsa4096_pss_sha512, yes, pem, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-65-RSA4096-PSS-SHA512", mldsa65_rsa4096_pss_sha512, yes, der, SubjectPublicKeyInfo), +ENCODER_w_structure("ML-DSA-65-RSA4096-PSS-SHA512", mldsa65_rsa4096_pss_sha512, yes, pem, SubjectPublicKeyInfo), +ENCODER_TEXT("ML-DSA-65-RSA4096-PSS-SHA512", mldsa65_rsa4096_pss_sha512, yes), + +ENCODER_w_structure("ML-DSA-65-RSA4096-PKCS15-SHA512", mldsa65_rsa4096_pkcs15_sha512, yes, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-65-RSA4096-PKCS15-SHA512", mldsa65_rsa4096_pkcs15_sha512, yes, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-65-RSA4096-PKCS15-SHA512", mldsa65_rsa4096_pkcs15_sha512, yes, der, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-65-RSA4096-PKCS15-SHA512", mldsa65_rsa4096_pkcs15_sha512, yes, pem, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-65-RSA4096-PKCS15-SHA512", mldsa65_rsa4096_pkcs15_sha512, yes, der, SubjectPublicKeyInfo), +ENCODER_w_structure("ML-DSA-65-RSA4096-PKCS15-SHA512", mldsa65_rsa4096_pkcs15_sha512, yes, pem, SubjectPublicKeyInfo), +ENCODER_TEXT("ML-DSA-65-RSA4096-PKCS15-SHA512", mldsa65_rsa4096_pkcs15_sha512, yes), + +ENCODER_w_structure("ML-DSA-65-ECDSA-P256-SHA512", mldsa65_ecdsa_p256_sha512, yes, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-65-ECDSA-P256-SHA512", mldsa65_ecdsa_p256_sha512, yes, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-65-ECDSA-P256-SHA512", mldsa65_ecdsa_p256_sha512, yes, der, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-65-ECDSA-P256-SHA512", mldsa65_ecdsa_p256_sha512, yes, pem, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-65-ECDSA-P256-SHA512", mldsa65_ecdsa_p256_sha512, yes, der, SubjectPublicKeyInfo), +ENCODER_w_structure("ML-DSA-65-ECDSA-P256-SHA512", mldsa65_ecdsa_p256_sha512, yes, pem, SubjectPublicKeyInfo), +ENCODER_TEXT("ML-DSA-65-ECDSA-P256-SHA512", mldsa65_ecdsa_p256_sha512, yes), + +ENCODER_w_structure("ML-DSA-65-ECDSA-P384-SHA512", mldsa65_ecdsa_p384_sha512, yes, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-65-ECDSA-P384-SHA512", mldsa65_ecdsa_p384_sha512, yes, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-65-ECDSA-P384-SHA512", mldsa65_ecdsa_p384_sha512, yes, der, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-65-ECDSA-P384-SHA512", mldsa65_ecdsa_p384_sha512, yes, pem, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-65-ECDSA-P384-SHA512", mldsa65_ecdsa_p384_sha512, yes, der, SubjectPublicKeyInfo), +ENCODER_w_structure("ML-DSA-65-ECDSA-P384-SHA512", mldsa65_ecdsa_p384_sha512, yes, pem, SubjectPublicKeyInfo), +ENCODER_TEXT("ML-DSA-65-ECDSA-P384-SHA512", mldsa65_ecdsa_p384_sha512, yes), + +ENCODER_w_structure("ML-DSA-65-ECDSA-brainpoolP256r1-SHA512", mldsa65_ecdsa_brainpoolP256r1_sha512, yes, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-65-ECDSA-brainpoolP256r1-SHA512", mldsa65_ecdsa_brainpoolP256r1_sha512, yes, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-65-ECDSA-brainpoolP256r1-SHA512", mldsa65_ecdsa_brainpoolP256r1_sha512, yes, der, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-65-ECDSA-brainpoolP256r1-SHA512", mldsa65_ecdsa_brainpoolP256r1_sha512, yes, pem, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-65-ECDSA-brainpoolP256r1-SHA512", mldsa65_ecdsa_brainpoolP256r1_sha512, yes, der, SubjectPublicKeyInfo), +ENCODER_w_structure("ML-DSA-65-ECDSA-brainpoolP256r1-SHA512", mldsa65_ecdsa_brainpoolP256r1_sha512, yes, pem, SubjectPublicKeyInfo), +ENCODER_TEXT("ML-DSA-65-ECDSA-brainpoolP256r1-SHA512", mldsa65_ecdsa_brainpoolP256r1_sha512, yes), + +ENCODER_w_structure("ML-DSA-65-Ed25519-SHA512", mldsa65_ed25519_sha512, yes, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-65-Ed25519-SHA512", mldsa65_ed25519_sha512, yes, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-65-Ed25519-SHA512", mldsa65_ed25519_sha512, yes, der, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-65-Ed25519-SHA512", mldsa65_ed25519_sha512, yes, pem, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-65-Ed25519-SHA512", mldsa65_ed25519_sha512, yes, der, SubjectPublicKeyInfo), +ENCODER_w_structure("ML-DSA-65-Ed25519-SHA512", mldsa65_ed25519_sha512, yes, pem, SubjectPublicKeyInfo), +ENCODER_TEXT("ML-DSA-65-Ed25519-SHA512", mldsa65_ed25519_sha512, yes), + +ENCODER_w_structure("ML-DSA-87-ECDSA-P384-SHA512", mldsa87_ecdsa_p384_sha512, yes, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-87-ECDSA-P384-SHA512", mldsa87_ecdsa_p384_sha512, yes, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-87-ECDSA-P384-SHA512", mldsa87_ecdsa_p384_sha512, yes, der, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-87-ECDSA-P384-SHA512", mldsa87_ecdsa_p384_sha512, yes, pem, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-87-ECDSA-P384-SHA512", mldsa87_ecdsa_p384_sha512, yes, der, SubjectPublicKeyInfo), +ENCODER_w_structure("ML-DSA-87-ECDSA-P384-SHA512", mldsa87_ecdsa_p384_sha512, yes, pem, SubjectPublicKeyInfo), +ENCODER_TEXT("ML-DSA-87-ECDSA-P384-SHA512", mldsa87_ecdsa_p384_sha512, yes), + +ENCODER_w_structure("ML-DSA-87-ECDSA-brainpoolP384r1-SHA512", mldsa87_ecdsa_brainpoolP384r1_sha512, yes, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-87-ECDSA-brainpoolP384r1-SHA512", mldsa87_ecdsa_brainpoolP384r1_sha512, yes, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-87-ECDSA-brainpoolP384r1-SHA512", mldsa87_ecdsa_brainpoolP384r1_sha512, yes, der, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-87-ECDSA-brainpoolP384r1-SHA512", mldsa87_ecdsa_brainpoolP384r1_sha512, yes, pem, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-87-ECDSA-brainpoolP384r1-SHA512", mldsa87_ecdsa_brainpoolP384r1_sha512, yes, der, SubjectPublicKeyInfo), +ENCODER_w_structure("ML-DSA-87-ECDSA-brainpoolP384r1-SHA512", mldsa87_ecdsa_brainpoolP384r1_sha512, yes, pem, SubjectPublicKeyInfo), +ENCODER_TEXT("ML-DSA-87-ECDSA-brainpoolP384r1-SHA512", mldsa87_ecdsa_brainpoolP384r1_sha512, yes), + +ENCODER_w_structure("ML-DSA-87-Ed448-SHAKE256", mldsa87_ed448_shake256, yes, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-87-Ed448-SHAKE256", mldsa87_ed448_shake256, yes, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-87-Ed448-SHAKE256", mldsa87_ed448_shake256, yes, der, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-87-Ed448-SHAKE256", mldsa87_ed448_shake256, yes, pem, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-87-Ed448-SHAKE256", mldsa87_ed448_shake256, yes, der, SubjectPublicKeyInfo), +ENCODER_w_structure("ML-DSA-87-Ed448-SHAKE256", mldsa87_ed448_shake256, yes, pem, SubjectPublicKeyInfo), +ENCODER_TEXT("ML-DSA-87-Ed448-SHAKE256", mldsa87_ed448_shake256, yes), + +ENCODER_w_structure("ML-DSA-87-RSA3072-PSS-SHA512", mldsa87_rsa3072_pss_sha512, yes, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-87-RSA3072-PSS-SHA512", mldsa87_rsa3072_pss_sha512, yes, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-87-RSA3072-PSS-SHA512", mldsa87_rsa3072_pss_sha512, yes, der, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-87-RSA3072-PSS-SHA512", mldsa87_rsa3072_pss_sha512, yes, pem, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-87-RSA3072-PSS-SHA512", mldsa87_rsa3072_pss_sha512, yes, der, SubjectPublicKeyInfo), +ENCODER_w_structure("ML-DSA-87-RSA3072-PSS-SHA512", mldsa87_rsa3072_pss_sha512, yes, pem, SubjectPublicKeyInfo), +ENCODER_TEXT("ML-DSA-87-RSA3072-PSS-SHA512", mldsa87_rsa3072_pss_sha512, yes), + +ENCODER_w_structure("ML-DSA-87-RSA4096-PSS-SHA512", mldsa87_rsa4096_pss_sha512, yes, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-87-RSA4096-PSS-SHA512", mldsa87_rsa4096_pss_sha512, yes, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-87-RSA4096-PSS-SHA512", mldsa87_rsa4096_pss_sha512, yes, der, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-87-RSA4096-PSS-SHA512", mldsa87_rsa4096_pss_sha512, yes, pem, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-87-RSA4096-PSS-SHA512", mldsa87_rsa4096_pss_sha512, yes, der, SubjectPublicKeyInfo), +ENCODER_w_structure("ML-DSA-87-RSA4096-PSS-SHA512", mldsa87_rsa4096_pss_sha512, yes, pem, SubjectPublicKeyInfo), +ENCODER_TEXT("ML-DSA-87-RSA4096-PSS-SHA512", mldsa87_rsa4096_pss_sha512, yes), + +ENCODER_w_structure("ML-DSA-87-ECDSA-P521-SHA512", mldsa87_ecdsa_p521_sha512, yes, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-87-ECDSA-P521-SHA512", mldsa87_ecdsa_p521_sha512, yes, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("ML-DSA-87-ECDSA-P521-SHA512", mldsa87_ecdsa_p521_sha512, yes, der, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-87-ECDSA-P521-SHA512", mldsa87_ecdsa_p521_sha512, yes, pem, PrivateKeyInfo), +ENCODER_w_structure("ML-DSA-87-ECDSA-P521-SHA512", mldsa87_ecdsa_p521_sha512, yes, der, SubjectPublicKeyInfo), +ENCODER_w_structure("ML-DSA-87-ECDSA-P521-SHA512", mldsa87_ecdsa_p521_sha512, yes, pem, SubjectPublicKeyInfo), +ENCODER_TEXT("ML-DSA-87-ECDSA-P521-SHA512", mldsa87_ecdsa_p521_sha512, yes), +# endif /* OPENSSL_NO_COMPOSITE */ + /* * Entries for key type specific output formats. These are exactly the * same as the type specific above, except that they use the key type diff --git a/providers/implementations/encode_decode/build.info b/providers/implementations/encode_decode/build.info index 2347ef865f3c8..08e301de17842 100644 --- a/providers/implementations/encode_decode/build.info +++ b/providers/implementations/encode_decode/build.info @@ -34,3 +34,11 @@ ENDIF IF[{- !$disabled{'ml-dsa'} || !$disabled{'ml-kem'} -}] SOURCE[$DECODER_GOAL]=ml_common_codecs.c ENDIF + +IF[{- !$disabled{'ml-dsa'} -}] + SOURCE[$DECODER_GOAL]=composite_codecs.c + DEPEND[composite_codecs.o]=../../common/include/prov/composite.h + DEPEND[decode_der2key.o]=../../common/include/prov/composite.h + DEPEND[encode_key2any.o]=../../common/include/prov/composite.h + DEPEND[encode_key2text.o]=../../common/include/prov/composite.h +ENDIF diff --git a/providers/implementations/encode_decode/composite_codecs.c b/providers/implementations/encode_decode/composite_codecs.c new file mode 100644 index 0000000000000..ac2545f2c7cce --- /dev/null +++ b/providers/implementations/encode_decode/composite_codecs.c @@ -0,0 +1,487 @@ +/* + * Copyright 2026 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include "crypto/ml_dsa.h" +#include "prov/composite_codecs.h" +#include "prov/ml_dsa_codecs.h" +#include "prov/provider_ctx.h" + +#ifndef OPENSSL_NO_COMPOSITE + +/* + * Encode the classic sub-key public component to its raw wire format + * (draft-ietf-lamps-pq-composite-sigs): + * + * RSA: RSAPublicKey DER (PKCS#1) + * EC: Uncompressed X9.62 point 0x04||x||y + * Ed25519: raw 32 bytes + * Ed448: raw 57 bytes + * + * On success, *out is a newly-allocated buffer of *out_len bytes. + * Caller must OPENSSL_free(*out). + */ +static int composite_encode_classic_pub(const EVP_PKEY *pkey, + unsigned char **out, + size_t *out_len) +{ + int keytype = EVP_PKEY_get_base_id(pkey); + OSSL_ENCODER_CTX *ectx; + size_t len; + + *out = NULL; + *out_len = 0; + + if (keytype == EVP_PKEY_RSA) { + ectx = OSSL_ENCODER_CTX_new_for_pkey( + pkey, OSSL_KEYMGMT_SELECT_PUBLIC_KEY, + "DER", "type-specific", NULL); + if (ectx == NULL) + return 0; + if (!OSSL_ENCODER_to_data(ectx, out, out_len)) + *out = NULL; + OSSL_ENCODER_CTX_free(ectx); + } else if (keytype == EVP_PKEY_EC) { + /* Uncompressed point: 0x04 || x || y */ + if (!EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, + NULL, 0, &len)) + return 0; + *out = OPENSSL_malloc(len); + if (*out == NULL) + return 0; + if (!EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, + *out, len, out_len)) { + OPENSSL_free(*out); + *out = NULL; + } + } else if (keytype == EVP_PKEY_ED25519 || keytype == EVP_PKEY_ED448) { + if (!EVP_PKEY_get_raw_public_key(pkey, NULL, &len)) + return 0; + *out = OPENSSL_malloc(len); + if (*out == NULL) + return 0; + if (!EVP_PKEY_get_raw_public_key(pkey, *out, &len)) { + OPENSSL_free(*out); + *out = NULL; + } else { + *out_len = len; + } + } else { + ERR_raise_data(ERR_LIB_PROV, PROV_R_NOT_SUPPORTED, + "unsupported classic key type %d", keytype); + return 0; + } + + return *out != NULL; +} + +/* + * Encode the classic sub-key private component to its raw wire format: + * + * RSA: RSAPrivateKey DER (PKCS#1) + * EC: ECPrivateKey DER with NamedCurve (RFC5915) + * Ed25519: raw 32 bytes + * Ed448: raw 57 bytes + * + * On success, *out is a newly-allocated buffer of *out_len bytes. + * Caller must OPENSSL_clear_free(*out, *out_len). + */ +static int composite_encode_classic_priv(const EVP_PKEY *pkey, + unsigned char **out, + size_t *out_len) +{ + int keytype = EVP_PKEY_get_base_id(pkey); + OSSL_ENCODER_CTX *ectx; + size_t len; + + *out = NULL; + *out_len = 0; + + if (keytype == EVP_PKEY_RSA) { + ectx = OSSL_ENCODER_CTX_new_for_pkey( + pkey, OSSL_KEYMGMT_SELECT_PRIVATE_KEY, + "DER", "type-specific", NULL); + if (ectx == NULL) + return 0; + if (!OSSL_ENCODER_to_data(ectx, out, out_len)) + *out = NULL; + OSSL_ENCODER_CTX_free(ectx); + } else if (keytype == EVP_PKEY_EC) { + /* + * ECPrivateKey DER (RFC5915) with NamedCurve but WITHOUT publicKey, + * per composite draft section 4: + * "The private key MUST be encoded as ECPrivateKey specified in + * [RFC5915] with the 'NamedCurve' parameter set to the OID of + * the curve, but without the 'publicKey' field." + */ + int include_pub = 0; + OSSL_PARAM params[] = { + OSSL_PARAM_construct_int(OSSL_PKEY_PARAM_EC_INCLUDE_PUBLIC, + &include_pub), + OSSL_PARAM_construct_end() + }; + EVP_PKEY *ec_copy = EVP_PKEY_dup((EVP_PKEY *)pkey); + + if (ec_copy == NULL) + return 0; + if (!EVP_PKEY_set_params(ec_copy, params)) { + EVP_PKEY_free(ec_copy); + return 0; + } + ectx = OSSL_ENCODER_CTX_new_for_pkey( + ec_copy, OSSL_KEYMGMT_SELECT_PRIVATE_KEY, + "DER", "type-specific", NULL); + if (ectx != NULL) { + if (!OSSL_ENCODER_to_data(ectx, out, out_len)) + *out = NULL; + OSSL_ENCODER_CTX_free(ectx); + } + EVP_PKEY_free(ec_copy); + } else if (keytype == EVP_PKEY_ED25519 || keytype == EVP_PKEY_ED448) { + if (!EVP_PKEY_get_raw_private_key(pkey, NULL, &len)) + return 0; + *out = OPENSSL_malloc(len); + if (*out == NULL) + return 0; + if (!EVP_PKEY_get_raw_private_key(pkey, *out, &len)) { + OPENSSL_clear_free(*out, len); + *out = NULL; + } else { + *out_len = len; + } + } else { + ERR_raise_data(ERR_LIB_PROV, PROV_R_NOT_SUPPORTED, + "unsupported classic key type %d", keytype); + return 0; + } + + return *out != NULL; +} + +/* + * Encode the composite public key: mldsaPK || tradPK + * Returns total byte length (>0) on success, 0 on error. + * If |out| is NULL, only the length is computed (no allocation). + */ +int ossl_composite_i2d_pubkey(const COMPOSITE_KEY *key, unsigned char **out) +{ + const ML_DSA_PARAMS *kp; + const uint8_t *ml_dsa_pub; + unsigned char *classic_pub = NULL; + size_t classic_pub_len = 0; + int total, ret = 0; + + if (key == NULL || key->classic_key == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PUBLIC_KEY); + return 0; + } + + kp = ossl_ml_dsa_key_params(key->ml_dsa_key); + ml_dsa_pub = ossl_ml_dsa_key_get_pub(key->ml_dsa_key); + if (ml_dsa_pub == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PUBLIC_KEY); + return 0; + } + + if (!composite_encode_classic_pub(key->classic_key, + &classic_pub, &classic_pub_len)) + return 0; + + total = (int)(kp->pk_len + classic_pub_len); + + if (out != NULL) { + *out = OPENSSL_malloc((size_t)total); + if (*out == NULL) + goto done; + memcpy(*out, ml_dsa_pub, kp->pk_len); + memcpy(*out + kp->pk_len, classic_pub, classic_pub_len); + } + + ret = total; +done: + OPENSSL_free(classic_pub); + return ret; +} + +/* + * Encode the composite private key: mldsaSeed[32] || tradSK + * Returns total byte length (>0) on success, 0 on error. + * If |out| is NULL, only the length is computed (no allocation). + */ +int ossl_composite_i2d_prvkey(const COMPOSITE_KEY *key, unsigned char **out) +{ + const uint8_t *seed; + unsigned char *classic_priv = NULL; + size_t classic_priv_len = 0; + int total, ret = 0; + + if (key == NULL || key->classic_key == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PRIVATE_KEY); + return 0; + } + + seed = ossl_ml_dsa_key_get_seed(key->ml_dsa_key); + if (seed == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PRIVATE_KEY); + return 0; + } + + if (!composite_encode_classic_priv(key->classic_key, + &classic_priv, &classic_priv_len)) + return 0; + + total = (int)(ML_DSA_SEED_BYTES + classic_priv_len); + + if (out != NULL) { + *out = OPENSSL_malloc((size_t)total); + if (*out == NULL) + goto done; + memcpy(*out, seed, ML_DSA_SEED_BYTES); + memcpy(*out + ML_DSA_SEED_BYTES, classic_priv, classic_priv_len); + } + + ret = total; +done: + OPENSSL_clear_free(classic_priv, classic_priv_len); + return ret; +} + +/* + * Print a human-readable description of a composite key to |out|. + */ +int ossl_composite_key_to_text(BIO *out, const COMPOSITE_KEY *key, + int selection) +{ + const ML_DSA_PARAMS *kp; + int is_priv = (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0; + int ret = 0; + + if (out == NULL || key == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + kp = ossl_ml_dsa_key_params(key->ml_dsa_key); + + if (BIO_printf(out, "Composite %s Key (%s)\n", + is_priv ? "Private" : "Public", + kp != NULL ? kp->alg : "unknown") + <= 0) + return 0; + + /* ML-DSA component */ + if (BIO_printf(out, "ML-DSA component:\n") <= 0) + return 0; + if (!ossl_ml_dsa_key_to_text(out, key->ml_dsa_key, selection)) + return 0; + + /* Classic component */ + if (BIO_printf(out, "Classic component:\n") <= 0) + return 0; + if (key->classic_key == NULL) { + if (BIO_printf(out, " (none)\n") <= 0) + return 0; + } else { + if (is_priv) + ret = EVP_PKEY_print_private(out, key->classic_key, 4, NULL); + else + ret = EVP_PKEY_print_public(out, key->classic_key, 4, NULL); + if (ret <= 0) + return 0; + } + + return 1; +} + +/* + * Decode the classic sub-key from its raw wire format. + * Used by ossl_composite_d2i_pubkey() and ossl_composite_d2i_prvkey(). + */ +static EVP_PKEY *composite_codecs_decode_classic_pub(OSSL_LIB_CTX *libctx, + const char *classic_alg, + const char *ec_curve, + const unsigned char *buf, + size_t buf_len) +{ + EVP_PKEY *pkey = NULL; + const unsigned char *ptr = buf; + size_t ptrlen = buf_len; + OSSL_DECODER_CTX *dctx; + OSSL_PARAM params[3]; + EVP_PKEY_CTX *pctx; + + if (strcmp(classic_alg, "RSA") == 0) { + dctx = OSSL_DECODER_CTX_new_for_pkey( + &pkey, "DER", "type-specific", "RSA", + OSSL_KEYMGMT_SELECT_PUBLIC_KEY, libctx, NULL); + if (dctx == NULL) + return NULL; + if (!OSSL_DECODER_from_data(dctx, &ptr, &ptrlen)) + pkey = NULL; + OSSL_DECODER_CTX_free(dctx); + } else if (strcmp(classic_alg, "EC") == 0) { + params[0] = OSSL_PARAM_construct_utf8_string( + OSSL_PKEY_PARAM_GROUP_NAME, (char *)ec_curve, 0); + params[1] = OSSL_PARAM_construct_octet_string( + OSSL_PKEY_PARAM_PUB_KEY, (void *)buf, buf_len); + params[2] = OSSL_PARAM_construct_end(); + pctx = EVP_PKEY_CTX_new_from_name(libctx, "EC", NULL); + if (pctx == NULL) + return NULL; + if (EVP_PKEY_fromdata_init(pctx) <= 0 + || EVP_PKEY_fromdata(pctx, &pkey, + EVP_PKEY_PUBLIC_KEY, params) + <= 0) + pkey = NULL; + EVP_PKEY_CTX_free(pctx); + } else if (strcmp(classic_alg, "ED25519") == 0) { + pkey = EVP_PKEY_new_raw_public_key_ex(libctx, "ED25519", NULL, + buf, buf_len); + } else if (strcmp(classic_alg, "ED448") == 0) { + pkey = EVP_PKEY_new_raw_public_key_ex(libctx, "ED448", NULL, + buf, buf_len); + } + return pkey; +} + +static EVP_PKEY *composite_codecs_decode_classic_priv(OSSL_LIB_CTX *libctx, + const char *classic_alg, + const char *ec_curve, + const unsigned char *buf, + size_t buf_len) +{ + EVP_PKEY *pkey = NULL; + const unsigned char *ptr = buf; + size_t ptrlen = buf_len; + OSSL_DECODER_CTX *dctx; + + if (strcmp(classic_alg, "RSA") == 0) { + dctx = OSSL_DECODER_CTX_new_for_pkey( + &pkey, "DER", "type-specific", "RSA", + OSSL_KEYMGMT_SELECT_PRIVATE_KEY, libctx, NULL); + if (dctx == NULL) + return NULL; + if (!OSSL_DECODER_from_data(dctx, &ptr, &ptrlen)) + pkey = NULL; + OSSL_DECODER_CTX_free(dctx); + } else if (strcmp(classic_alg, "EC") == 0) { + dctx = OSSL_DECODER_CTX_new_for_pkey( + &pkey, "DER", "type-specific", "EC", + OSSL_KEYMGMT_SELECT_PRIVATE_KEY, libctx, NULL); + if (dctx == NULL) + return NULL; + if (!OSSL_DECODER_from_data(dctx, &ptr, &ptrlen)) + pkey = NULL; + OSSL_DECODER_CTX_free(dctx); + } else if (strcmp(classic_alg, "ED25519") == 0) { + pkey = EVP_PKEY_new_raw_private_key_ex(libctx, "ED25519", NULL, + buf, buf_len); + } else if (strcmp(classic_alg, "ED448") == 0) { + pkey = EVP_PKEY_new_raw_private_key_ex(libctx, "ED448", NULL, + buf, buf_len); + } + return pkey; +} + +COMPOSITE_KEY *ossl_composite_d2i_pubkey(const unsigned char *pk, + int pk_len, + int ml_dsa_evp_type, + const char *classic_alg, + const char *ec_curve, + PROV_CTX *provctx, + const char *propq) +{ + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(provctx); + const ML_DSA_PARAMS *kp; + COMPOSITE_KEY *key; + size_t ml_dsa_len; + + if (pk == NULL || pk_len <= 0 || classic_alg == NULL) + return NULL; + + key = ossl_prov_composite_new(provctx, propq, ml_dsa_evp_type); + if (key == NULL) + return NULL; + + kp = ossl_ml_dsa_key_params(key->ml_dsa_key); + if (kp == NULL) + goto err; + + ml_dsa_len = kp->pk_len; + if ((size_t)pk_len <= ml_dsa_len) + goto err; + + if (!ossl_ml_dsa_pk_decode(key->ml_dsa_key, pk, ml_dsa_len)) { + ERR_raise(ERR_LIB_PROV, PROV_R_BAD_ENCODING); + goto err; + } + + key->classic_key = composite_codecs_decode_classic_pub( + libctx, classic_alg, ec_curve, + pk + ml_dsa_len, (size_t)pk_len - ml_dsa_len); + if (key->classic_key == NULL) + goto err; + + return key; + +err: + ossl_composite_key_free(key); + return NULL; +} + +COMPOSITE_KEY *ossl_composite_d2i_prvkey(const unsigned char *priv, + int priv_len, + int ml_dsa_evp_type, + const char *classic_alg, + const char *ec_curve, + PROV_CTX *provctx, + const char *propq) +{ + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(provctx); + COMPOSITE_KEY *key; + + if (priv == NULL || priv_len <= ML_DSA_SEED_BYTES || classic_alg == NULL) + return NULL; + + key = ossl_prov_composite_new(provctx, propq, ml_dsa_evp_type); + if (key == NULL) + return NULL; + + /* Load the 32-byte seed and derive the full ML-DSA key pair */ + if (!ossl_ml_dsa_set_prekey(key->ml_dsa_key, 0, 0, + priv, ML_DSA_SEED_BYTES, NULL, 0)) { + ERR_raise(ERR_LIB_PROV, PROV_R_BAD_ENCODING); + goto err; + } + if (!ossl_ml_dsa_generate_key(key->ml_dsa_key)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GENERATE_KEY); + goto err; + } + + key->classic_key = composite_codecs_decode_classic_priv( + libctx, classic_alg, ec_curve, + priv + ML_DSA_SEED_BYTES, + (size_t)priv_len - ML_DSA_SEED_BYTES); + if (key->classic_key == NULL) + goto err; + + return key; + +err: + ossl_composite_key_free(key); + return NULL; +} + +#endif /* OPENSSL_NO_COMPOSITE */ diff --git a/providers/implementations/encode_decode/decode_der2key.c b/providers/implementations/encode_decode/decode_der2key.c index 6ed99e68fa5c7..98d05811eaac1 100644 --- a/providers/implementations/encode_decode/decode_der2key.c +++ b/providers/implementations/encode_decode/decode_der2key.c @@ -45,6 +45,7 @@ #include "prov/ml_dsa_codecs.h" #include "prov/ml_kem_codecs.h" #include "prov/lms_codecs.h" +#include "prov/composite_codecs.h" #include "providers/implementations/encode_decode/decode_der2key.inc" #ifndef OPENSSL_NO_SLH_DSA @@ -1042,6 +1043,332 @@ static ossl_inline void *ml_dsa_d2i_PUBKEY(const uint8_t **der, long der_len, /* ---------------------------------------------------------------------- */ +#ifndef OPENSSL_NO_COMPOSITE +/* + * Composite SPKI/PKCS8 decoder helpers. + * The d2i_PUBKEY callback receives the full SubjectPublicKeyInfo DER. + * The d2i_PKCS8 callback receives the full PrivateKeyInfo DER. + */ + +/* + * Parse SubjectPublicKeyInfo by hand to extract the BIT STRING body + * (mldsaPK || tradPK) without calling d2i_X509_PUBKEY (which would + * re-enter the OSSL_DECODER chain and recurse infinitely). + * + * SubjectPublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * subjectPublicKey BIT STRING + * } + * + * On success returns a pointer into |der| at the start of the BIT STRING + * payload and sets |*out_len|. Returns NULL on parse failure. + */ +static const unsigned char * +composite_spki_bitstring_body(const unsigned char *der, long der_len, + int *out_len) +{ + const unsigned char *p = der; + long outer_len, algo_len, bs_len; + int tag, xclass, inf; + + /* Outer SEQUENCE */ + inf = ASN1_get_object(&p, &outer_len, &tag, &xclass, der_len); + if ((inf & 0x80) || tag != V_ASN1_SEQUENCE || (size_t)(p + outer_len) > (size_t)(der + der_len)) + return NULL; + + /* AlgorithmIdentifier (SEQUENCE) — skip it */ + { + const unsigned char *save = p; + inf = ASN1_get_object(&p, &algo_len, &tag, &xclass, outer_len); + if ((inf & 0x80) || tag != V_ASN1_SEQUENCE) + return NULL; + p += algo_len; /* skip AlgorithmIdentifier body */ + outer_len -= (long)(p - save); + } + + /* BIT STRING */ + inf = ASN1_get_object(&p, &bs_len, &tag, &xclass, outer_len); + if ((inf & 0x80) || tag != V_ASN1_BIT_STRING || bs_len < 1) + return NULL; + + /* First byte is the unused-bits count; payload starts at p+1 */ + *out_len = (int)(bs_len - 1); + return p + 1; +} + +static COMPOSITE_KEY * +composite_d2i_pubkey_common(const unsigned char *der, long der_len, + int ml_dsa_evp_type, + const char *classic_alg, const char *ec_curve, + struct der2key_ctx_st *ctx) +{ + const unsigned char *pk; + const unsigned char *p = der; + long outer_len, algo_len; + int tag, xclass, inf, pk_len; + ASN1_OBJECT *oid = NULL; + + /* + * Peek at the AlgorithmIdentifier OID to reject structures that don't + * belong to this composite variant, without calling d2i_X509_PUBKEY + * (which would re-enter the OSSL_DECODER chain and recurse infinitely). + */ + + /* Outer SEQUENCE */ + inf = ASN1_get_object(&p, &outer_len, &tag, &xclass, der_len); + if ((inf & 0x80) || tag != V_ASN1_SEQUENCE) + return NULL; + + /* AlgorithmIdentifier SEQUENCE header */ + inf = ASN1_get_object(&p, &algo_len, &tag, &xclass, outer_len); + if ((inf & 0x80) || tag != V_ASN1_SEQUENCE || algo_len <= 0) + return NULL; + + /* OID inside AlgorithmIdentifier */ + oid = d2i_ASN1_OBJECT(NULL, &p, algo_len); + if (oid == NULL) + return NULL; + if (OBJ_obj2nid(oid) != ctx->desc->evp_type) { + ASN1_OBJECT_free(oid); + return NULL; + } + ASN1_OBJECT_free(oid); + + pk = composite_spki_bitstring_body(der, der_len, &pk_len); + if (pk == NULL) + return NULL; + + return ossl_composite_d2i_pubkey(pk, pk_len, ml_dsa_evp_type, + classic_alg, ec_curve, + ctx->provctx, ctx->propq); +} + +static COMPOSITE_KEY * +composite_d2i_prvkey_common(const unsigned char *der, long der_len, + int ml_dsa_evp_type, + const char *classic_alg, const char *ec_curve, + struct der2key_ctx_st *ctx) +{ + PKCS8_PRIV_KEY_INFO *p8inf = NULL; + const unsigned char *ptr = der; + COMPOSITE_KEY *key = NULL; + const unsigned char *privbytes; + const X509_ALGOR *alg = NULL; + int privlen; + + p8inf = d2i_PKCS8_PRIV_KEY_INFO(NULL, &ptr, der_len); + if (p8inf == NULL) + return NULL; + + if (!PKCS8_pkey_get0(NULL, &privbytes, &privlen, &alg, p8inf)) + goto done; + + /* Reject structures whose OID doesn't match this composite variant. */ + if (alg == NULL || OBJ_obj2nid(alg->algorithm) != ctx->desc->evp_type) + goto done; + + key = ossl_composite_d2i_prvkey(privbytes, privlen, ml_dsa_evp_type, + classic_alg, ec_curve, + ctx->provctx, ctx->propq); +done: + PKCS8_PRIV_KEY_INFO_free(p8inf); + return key; +} + +/* + * MAKE_COMPOSITE_D2I: per-algorithm d2i_PUBKEY, d2i_PKCS8, and the + * supporting #defines consumed by MAKE_DECODER. + */ +#define MAKE_COMPOSITE_D2I(alg, ml_dsa_evp_type_, classic_alg_, ec_curve_) \ + static void * \ + alg##_d2i_PUBKEY(const unsigned char **der, long der_len, \ + struct der2key_ctx_st *ctx) \ + { \ + COMPOSITE_KEY *key = composite_d2i_pubkey_common(*der, der_len, ml_dsa_evp_type_, \ + classic_alg_, ec_curve_, ctx); \ + if (key != NULL) \ + *der += der_len; \ + return key; \ + } \ + static void * \ + alg##_d2i_PKCS8(const unsigned char **der, long der_len, \ + struct der2key_ctx_st *ctx) \ + { \ + COMPOSITE_KEY *key = composite_d2i_prvkey_common(*der, der_len, ml_dsa_evp_type_, \ + classic_alg_, ec_curve_, ctx); \ + if (key != NULL) \ + *der += der_len; \ + return key; \ + } + +MAKE_COMPOSITE_D2I(mldsa44_rsa2048_pss_sha256, EVP_PKEY_ML_DSA_44, "RSA", NULL) +MAKE_COMPOSITE_D2I(mldsa44_rsa2048_pkcs15_sha256, EVP_PKEY_ML_DSA_44, "RSA", NULL) +MAKE_COMPOSITE_D2I(mldsa44_ed25519_sha512, EVP_PKEY_ML_DSA_44, "ED25519", NULL) +MAKE_COMPOSITE_D2I(mldsa44_ecdsa_p256_sha256, EVP_PKEY_ML_DSA_44, "EC", "P-256") +MAKE_COMPOSITE_D2I(mldsa65_rsa3072_pss_sha512, EVP_PKEY_ML_DSA_65, "RSA", NULL) +MAKE_COMPOSITE_D2I(mldsa65_rsa3072_pkcs15_sha512, EVP_PKEY_ML_DSA_65, "RSA", NULL) +MAKE_COMPOSITE_D2I(mldsa65_rsa4096_pss_sha512, EVP_PKEY_ML_DSA_65, "RSA", NULL) +MAKE_COMPOSITE_D2I(mldsa65_rsa4096_pkcs15_sha512, EVP_PKEY_ML_DSA_65, "RSA", NULL) +MAKE_COMPOSITE_D2I(mldsa65_ecdsa_p256_sha512, EVP_PKEY_ML_DSA_65, "EC", "P-256") +MAKE_COMPOSITE_D2I(mldsa65_ecdsa_p384_sha512, EVP_PKEY_ML_DSA_65, "EC", "P-384") +MAKE_COMPOSITE_D2I(mldsa65_ecdsa_brainpoolP256r1_sha512, EVP_PKEY_ML_DSA_65, "EC", "brainpoolP256r1") +MAKE_COMPOSITE_D2I(mldsa65_ed25519_sha512, EVP_PKEY_ML_DSA_65, "ED25519", NULL) +MAKE_COMPOSITE_D2I(mldsa87_ecdsa_p384_sha512, EVP_PKEY_ML_DSA_87, "EC", "P-384") +MAKE_COMPOSITE_D2I(mldsa87_ecdsa_brainpoolP384r1_sha512, EVP_PKEY_ML_DSA_87, "EC", "brainpoolP384r1") +MAKE_COMPOSITE_D2I(mldsa87_ed448_shake256, EVP_PKEY_ML_DSA_87, "ED448", NULL) +MAKE_COMPOSITE_D2I(mldsa87_rsa3072_pss_sha512, EVP_PKEY_ML_DSA_87, "RSA", NULL) +MAKE_COMPOSITE_D2I(mldsa87_rsa4096_pss_sha512, EVP_PKEY_ML_DSA_87, "RSA", NULL) +MAKE_COMPOSITE_D2I(mldsa87_ecdsa_p521_sha512, EVP_PKEY_ML_DSA_87, "EC", "P-521") + +/* Supporting #defines consumed by DO_SubjectPublicKeyInfo / DO_PrivateKeyInfo macros */ +#define mldsa44_rsa2048_pss_sha256_evp_type NID_ML_DSA_44_RSA2048_PSS_SHA256 +#define mldsa44_rsa2048_pss_sha256_d2i_private_key NULL +#define mldsa44_rsa2048_pss_sha256_d2i_public_key NULL +#define mldsa44_rsa2048_pss_sha256_d2i_key_params NULL +#define mldsa44_rsa2048_pss_sha256_check NULL +#define mldsa44_rsa2048_pss_sha256_adjust NULL +#define mldsa44_rsa2048_pss_sha256_free (free_key_fn *)ossl_composite_key_free + +#define mldsa44_rsa2048_pkcs15_sha256_evp_type NID_ML_DSA_44_RSA2048_PKCS15_SHA256 +#define mldsa44_rsa2048_pkcs15_sha256_d2i_private_key NULL +#define mldsa44_rsa2048_pkcs15_sha256_d2i_public_key NULL +#define mldsa44_rsa2048_pkcs15_sha256_d2i_key_params NULL +#define mldsa44_rsa2048_pkcs15_sha256_check NULL +#define mldsa44_rsa2048_pkcs15_sha256_adjust NULL +#define mldsa44_rsa2048_pkcs15_sha256_free (free_key_fn *)ossl_composite_key_free + +#define mldsa44_ed25519_sha512_evp_type NID_ML_DSA_44_Ed25519_SHA512 +#define mldsa44_ed25519_sha512_d2i_private_key NULL +#define mldsa44_ed25519_sha512_d2i_public_key NULL +#define mldsa44_ed25519_sha512_d2i_key_params NULL +#define mldsa44_ed25519_sha512_check NULL +#define mldsa44_ed25519_sha512_adjust NULL +#define mldsa44_ed25519_sha512_free (free_key_fn *)ossl_composite_key_free + +#define mldsa44_ecdsa_p256_sha256_evp_type NID_ML_DSA_44_ECDSA_P256_SHA256 +#define mldsa44_ecdsa_p256_sha256_d2i_private_key NULL +#define mldsa44_ecdsa_p256_sha256_d2i_public_key NULL +#define mldsa44_ecdsa_p256_sha256_d2i_key_params NULL +#define mldsa44_ecdsa_p256_sha256_check NULL +#define mldsa44_ecdsa_p256_sha256_adjust NULL +#define mldsa44_ecdsa_p256_sha256_free (free_key_fn *)ossl_composite_key_free + +#define mldsa65_rsa3072_pss_sha512_evp_type NID_ML_DSA_65_RSA3072_PSS_SHA512 +#define mldsa65_rsa3072_pss_sha512_d2i_private_key NULL +#define mldsa65_rsa3072_pss_sha512_d2i_public_key NULL +#define mldsa65_rsa3072_pss_sha512_d2i_key_params NULL +#define mldsa65_rsa3072_pss_sha512_check NULL +#define mldsa65_rsa3072_pss_sha512_adjust NULL +#define mldsa65_rsa3072_pss_sha512_free (free_key_fn *)ossl_composite_key_free + +#define mldsa65_rsa3072_pkcs15_sha512_evp_type NID_ML_DSA_65_RSA3072_PKCS15_SHA512 +#define mldsa65_rsa3072_pkcs15_sha512_d2i_private_key NULL +#define mldsa65_rsa3072_pkcs15_sha512_d2i_public_key NULL +#define mldsa65_rsa3072_pkcs15_sha512_d2i_key_params NULL +#define mldsa65_rsa3072_pkcs15_sha512_check NULL +#define mldsa65_rsa3072_pkcs15_sha512_adjust NULL +#define mldsa65_rsa3072_pkcs15_sha512_free (free_key_fn *)ossl_composite_key_free + +#define mldsa65_rsa4096_pss_sha512_evp_type NID_ML_DSA_65_RSA4096_PSS_SHA512 +#define mldsa65_rsa4096_pss_sha512_d2i_private_key NULL +#define mldsa65_rsa4096_pss_sha512_d2i_public_key NULL +#define mldsa65_rsa4096_pss_sha512_d2i_key_params NULL +#define mldsa65_rsa4096_pss_sha512_check NULL +#define mldsa65_rsa4096_pss_sha512_adjust NULL +#define mldsa65_rsa4096_pss_sha512_free (free_key_fn *)ossl_composite_key_free + +#define mldsa65_rsa4096_pkcs15_sha512_evp_type NID_ML_DSA_65_RSA4096_PKCS15_SHA512 +#define mldsa65_rsa4096_pkcs15_sha512_d2i_private_key NULL +#define mldsa65_rsa4096_pkcs15_sha512_d2i_public_key NULL +#define mldsa65_rsa4096_pkcs15_sha512_d2i_key_params NULL +#define mldsa65_rsa4096_pkcs15_sha512_check NULL +#define mldsa65_rsa4096_pkcs15_sha512_adjust NULL +#define mldsa65_rsa4096_pkcs15_sha512_free (free_key_fn *)ossl_composite_key_free + +#define mldsa65_ecdsa_p256_sha512_evp_type NID_ML_DSA_65_ECDSA_P256_SHA512 +#define mldsa65_ecdsa_p256_sha512_d2i_private_key NULL +#define mldsa65_ecdsa_p256_sha512_d2i_public_key NULL +#define mldsa65_ecdsa_p256_sha512_d2i_key_params NULL +#define mldsa65_ecdsa_p256_sha512_check NULL +#define mldsa65_ecdsa_p256_sha512_adjust NULL +#define mldsa65_ecdsa_p256_sha512_free (free_key_fn *)ossl_composite_key_free + +#define mldsa65_ecdsa_p384_sha512_evp_type NID_ML_DSA_65_ECDSA_P384_SHA512 +#define mldsa65_ecdsa_p384_sha512_d2i_private_key NULL +#define mldsa65_ecdsa_p384_sha512_d2i_public_key NULL +#define mldsa65_ecdsa_p384_sha512_d2i_key_params NULL +#define mldsa65_ecdsa_p384_sha512_check NULL +#define mldsa65_ecdsa_p384_sha512_adjust NULL +#define mldsa65_ecdsa_p384_sha512_free (free_key_fn *)ossl_composite_key_free + +#define mldsa65_ecdsa_brainpoolP256r1_sha512_evp_type NID_ML_DSA_65_ECDSA_brainpoolP256r1_SHA512 +#define mldsa65_ecdsa_brainpoolP256r1_sha512_d2i_private_key NULL +#define mldsa65_ecdsa_brainpoolP256r1_sha512_d2i_public_key NULL +#define mldsa65_ecdsa_brainpoolP256r1_sha512_d2i_key_params NULL +#define mldsa65_ecdsa_brainpoolP256r1_sha512_check NULL +#define mldsa65_ecdsa_brainpoolP256r1_sha512_adjust NULL +#define mldsa65_ecdsa_brainpoolP256r1_sha512_free (free_key_fn *)ossl_composite_key_free + +#define mldsa65_ed25519_sha512_evp_type NID_ML_DSA_65_Ed25519_SHA512 +#define mldsa65_ed25519_sha512_d2i_private_key NULL +#define mldsa65_ed25519_sha512_d2i_public_key NULL +#define mldsa65_ed25519_sha512_d2i_key_params NULL +#define mldsa65_ed25519_sha512_check NULL +#define mldsa65_ed25519_sha512_adjust NULL +#define mldsa65_ed25519_sha512_free (free_key_fn *)ossl_composite_key_free + +#define mldsa87_ecdsa_p384_sha512_evp_type NID_ML_DSA_87_ECDSA_P384_SHA512 +#define mldsa87_ecdsa_p384_sha512_d2i_private_key NULL +#define mldsa87_ecdsa_p384_sha512_d2i_public_key NULL +#define mldsa87_ecdsa_p384_sha512_d2i_key_params NULL +#define mldsa87_ecdsa_p384_sha512_check NULL +#define mldsa87_ecdsa_p384_sha512_adjust NULL +#define mldsa87_ecdsa_p384_sha512_free (free_key_fn *)ossl_composite_key_free + +#define mldsa87_ecdsa_brainpoolP384r1_sha512_evp_type NID_ML_DSA_87_ECDSA_brainpoolP384r1_SHA512 +#define mldsa87_ecdsa_brainpoolP384r1_sha512_d2i_private_key NULL +#define mldsa87_ecdsa_brainpoolP384r1_sha512_d2i_public_key NULL +#define mldsa87_ecdsa_brainpoolP384r1_sha512_d2i_key_params NULL +#define mldsa87_ecdsa_brainpoolP384r1_sha512_check NULL +#define mldsa87_ecdsa_brainpoolP384r1_sha512_adjust NULL +#define mldsa87_ecdsa_brainpoolP384r1_sha512_free (free_key_fn *)ossl_composite_key_free + +#define mldsa87_ed448_shake256_evp_type NID_ML_DSA_87_Ed448_SHAKE256 +#define mldsa87_ed448_shake256_d2i_private_key NULL +#define mldsa87_ed448_shake256_d2i_public_key NULL +#define mldsa87_ed448_shake256_d2i_key_params NULL +#define mldsa87_ed448_shake256_check NULL +#define mldsa87_ed448_shake256_adjust NULL +#define mldsa87_ed448_shake256_free (free_key_fn *)ossl_composite_key_free + +#define mldsa87_rsa3072_pss_sha512_evp_type NID_ML_DSA_87_RSA3072_PSS_SHA512 +#define mldsa87_rsa3072_pss_sha512_d2i_private_key NULL +#define mldsa87_rsa3072_pss_sha512_d2i_public_key NULL +#define mldsa87_rsa3072_pss_sha512_d2i_key_params NULL +#define mldsa87_rsa3072_pss_sha512_check NULL +#define mldsa87_rsa3072_pss_sha512_adjust NULL +#define mldsa87_rsa3072_pss_sha512_free (free_key_fn *)ossl_composite_key_free + +#define mldsa87_rsa4096_pss_sha512_evp_type NID_ML_DSA_87_RSA4096_PSS_SHA512 +#define mldsa87_rsa4096_pss_sha512_d2i_private_key NULL +#define mldsa87_rsa4096_pss_sha512_d2i_public_key NULL +#define mldsa87_rsa4096_pss_sha512_d2i_key_params NULL +#define mldsa87_rsa4096_pss_sha512_check NULL +#define mldsa87_rsa4096_pss_sha512_adjust NULL +#define mldsa87_rsa4096_pss_sha512_free (free_key_fn *)ossl_composite_key_free + +#define mldsa87_ecdsa_p521_sha512_evp_type NID_ML_DSA_87_ECDSA_P521_SHA512 +#define mldsa87_ecdsa_p521_sha512_d2i_private_key NULL +#define mldsa87_ecdsa_p521_sha512_d2i_public_key NULL +#define mldsa87_ecdsa_p521_sha512_d2i_key_params NULL +#define mldsa87_ecdsa_p521_sha512_check NULL +#define mldsa87_ecdsa_p521_sha512_adjust NULL +#define mldsa87_ecdsa_p521_sha512_free (free_key_fn *)ossl_composite_key_free + +#endif /* OPENSSL_NO_COMPOSITE */ + +/* ---------------------------------------------------------------------- */ + #ifndef OPENSSL_NO_LMS static void lms_free_key(void *key) { @@ -1369,6 +1696,45 @@ MAKE_DECODER("ML-DSA-87", ml_dsa_87, ml_dsa_87, PrivateKeyInfo); MAKE_DECODER("ML-DSA-87", ml_dsa_87, ml_dsa_87, SubjectPublicKeyInfo); #endif +#ifndef OPENSSL_NO_COMPOSITE +MAKE_DECODER("ML-DSA-44-RSA2048-PSS-SHA256", mldsa44_rsa2048_pss_sha256, mldsa44_rsa2048_pss_sha256, PrivateKeyInfo); +MAKE_DECODER("ML-DSA-44-RSA2048-PSS-SHA256", mldsa44_rsa2048_pss_sha256, mldsa44_rsa2048_pss_sha256, SubjectPublicKeyInfo); +MAKE_DECODER("ML-DSA-44-RSA2048-PKCS15-SHA256", mldsa44_rsa2048_pkcs15_sha256, mldsa44_rsa2048_pkcs15_sha256, PrivateKeyInfo); +MAKE_DECODER("ML-DSA-44-RSA2048-PKCS15-SHA256", mldsa44_rsa2048_pkcs15_sha256, mldsa44_rsa2048_pkcs15_sha256, SubjectPublicKeyInfo); +MAKE_DECODER("ML-DSA-44-Ed25519-SHA512", mldsa44_ed25519_sha512, mldsa44_ed25519_sha512, PrivateKeyInfo); +MAKE_DECODER("ML-DSA-44-Ed25519-SHA512", mldsa44_ed25519_sha512, mldsa44_ed25519_sha512, SubjectPublicKeyInfo); +MAKE_DECODER("ML-DSA-44-ECDSA-P256-SHA256", mldsa44_ecdsa_p256_sha256, mldsa44_ecdsa_p256_sha256, PrivateKeyInfo); +MAKE_DECODER("ML-DSA-44-ECDSA-P256-SHA256", mldsa44_ecdsa_p256_sha256, mldsa44_ecdsa_p256_sha256, SubjectPublicKeyInfo); +MAKE_DECODER("ML-DSA-65-RSA3072-PSS-SHA512", mldsa65_rsa3072_pss_sha512, mldsa65_rsa3072_pss_sha512, PrivateKeyInfo); +MAKE_DECODER("ML-DSA-65-RSA3072-PSS-SHA512", mldsa65_rsa3072_pss_sha512, mldsa65_rsa3072_pss_sha512, SubjectPublicKeyInfo); +MAKE_DECODER("ML-DSA-65-RSA3072-PKCS15-SHA512", mldsa65_rsa3072_pkcs15_sha512, mldsa65_rsa3072_pkcs15_sha512, PrivateKeyInfo); +MAKE_DECODER("ML-DSA-65-RSA3072-PKCS15-SHA512", mldsa65_rsa3072_pkcs15_sha512, mldsa65_rsa3072_pkcs15_sha512, SubjectPublicKeyInfo); +MAKE_DECODER("ML-DSA-65-RSA4096-PSS-SHA512", mldsa65_rsa4096_pss_sha512, mldsa65_rsa4096_pss_sha512, PrivateKeyInfo); +MAKE_DECODER("ML-DSA-65-RSA4096-PSS-SHA512", mldsa65_rsa4096_pss_sha512, mldsa65_rsa4096_pss_sha512, SubjectPublicKeyInfo); +MAKE_DECODER("ML-DSA-65-RSA4096-PKCS15-SHA512", mldsa65_rsa4096_pkcs15_sha512, mldsa65_rsa4096_pkcs15_sha512, PrivateKeyInfo); +MAKE_DECODER("ML-DSA-65-RSA4096-PKCS15-SHA512", mldsa65_rsa4096_pkcs15_sha512, mldsa65_rsa4096_pkcs15_sha512, SubjectPublicKeyInfo); +MAKE_DECODER("ML-DSA-65-ECDSA-P256-SHA512", mldsa65_ecdsa_p256_sha512, mldsa65_ecdsa_p256_sha512, PrivateKeyInfo); +MAKE_DECODER("ML-DSA-65-ECDSA-P256-SHA512", mldsa65_ecdsa_p256_sha512, mldsa65_ecdsa_p256_sha512, SubjectPublicKeyInfo); +MAKE_DECODER("ML-DSA-65-ECDSA-P384-SHA512", mldsa65_ecdsa_p384_sha512, mldsa65_ecdsa_p384_sha512, PrivateKeyInfo); +MAKE_DECODER("ML-DSA-65-ECDSA-P384-SHA512", mldsa65_ecdsa_p384_sha512, mldsa65_ecdsa_p384_sha512, SubjectPublicKeyInfo); +MAKE_DECODER("ML-DSA-65-ECDSA-brainpoolP256r1-SHA512", mldsa65_ecdsa_brainpoolP256r1_sha512, mldsa65_ecdsa_brainpoolP256r1_sha512, PrivateKeyInfo); +MAKE_DECODER("ML-DSA-65-ECDSA-brainpoolP256r1-SHA512", mldsa65_ecdsa_brainpoolP256r1_sha512, mldsa65_ecdsa_brainpoolP256r1_sha512, SubjectPublicKeyInfo); +MAKE_DECODER("ML-DSA-65-Ed25519-SHA512", mldsa65_ed25519_sha512, mldsa65_ed25519_sha512, PrivateKeyInfo); +MAKE_DECODER("ML-DSA-65-Ed25519-SHA512", mldsa65_ed25519_sha512, mldsa65_ed25519_sha512, SubjectPublicKeyInfo); +MAKE_DECODER("ML-DSA-87-ECDSA-P384-SHA512", mldsa87_ecdsa_p384_sha512, mldsa87_ecdsa_p384_sha512, PrivateKeyInfo); +MAKE_DECODER("ML-DSA-87-ECDSA-P384-SHA512", mldsa87_ecdsa_p384_sha512, mldsa87_ecdsa_p384_sha512, SubjectPublicKeyInfo); +MAKE_DECODER("ML-DSA-87-ECDSA-brainpoolP384r1-SHA512", mldsa87_ecdsa_brainpoolP384r1_sha512, mldsa87_ecdsa_brainpoolP384r1_sha512, PrivateKeyInfo); +MAKE_DECODER("ML-DSA-87-ECDSA-brainpoolP384r1-SHA512", mldsa87_ecdsa_brainpoolP384r1_sha512, mldsa87_ecdsa_brainpoolP384r1_sha512, SubjectPublicKeyInfo); +MAKE_DECODER("ML-DSA-87-Ed448-SHAKE256", mldsa87_ed448_shake256, mldsa87_ed448_shake256, PrivateKeyInfo); +MAKE_DECODER("ML-DSA-87-Ed448-SHAKE256", mldsa87_ed448_shake256, mldsa87_ed448_shake256, SubjectPublicKeyInfo); +MAKE_DECODER("ML-DSA-87-RSA3072-PSS-SHA512", mldsa87_rsa3072_pss_sha512, mldsa87_rsa3072_pss_sha512, PrivateKeyInfo); +MAKE_DECODER("ML-DSA-87-RSA3072-PSS-SHA512", mldsa87_rsa3072_pss_sha512, mldsa87_rsa3072_pss_sha512, SubjectPublicKeyInfo); +MAKE_DECODER("ML-DSA-87-RSA4096-PSS-SHA512", mldsa87_rsa4096_pss_sha512, mldsa87_rsa4096_pss_sha512, PrivateKeyInfo); +MAKE_DECODER("ML-DSA-87-RSA4096-PSS-SHA512", mldsa87_rsa4096_pss_sha512, mldsa87_rsa4096_pss_sha512, SubjectPublicKeyInfo); +MAKE_DECODER("ML-DSA-87-ECDSA-P521-SHA512", mldsa87_ecdsa_p521_sha512, mldsa87_ecdsa_p521_sha512, PrivateKeyInfo); +MAKE_DECODER("ML-DSA-87-ECDSA-P521-SHA512", mldsa87_ecdsa_p521_sha512, mldsa87_ecdsa_p521_sha512, SubjectPublicKeyInfo); +#endif + #ifndef OPENSSL_NO_LMS MAKE_DECODER("LMS", lms, lms, SubjectPublicKeyInfo); #endif diff --git a/providers/implementations/encode_decode/encode_key2any.c b/providers/implementations/encode_decode/encode_key2any.c index 1d12bf1e9e720..16be335861539 100644 --- a/providers/implementations/encode_decode/encode_key2any.c +++ b/providers/implementations/encode_decode/encode_key2any.c @@ -42,6 +42,10 @@ #include "prov/ml_dsa_codecs.h" #include "prov/ml_kem_codecs.h" #include "prov/lms_codecs.h" +#ifndef OPENSSL_NO_COMPOSITE +#include "prov/composite_codecs.h" +#include +#endif #include "providers/implementations/encode_decode/encode_key2any.inc" #include @@ -1787,3 +1791,185 @@ MAKE_ENCODER(ml_dsa_87, ml_dsa, SubjectPublicKeyInfo, pem); MAKE_ENCODER(lms, lms, SubjectPublicKeyInfo, der); MAKE_ENCODER(lms, lms, SubjectPublicKeyInfo, pem); #endif + +#ifndef OPENSSL_NO_COMPOSITE +static int composite_spki_pub_to_der(const void *vkey, unsigned char **pder, + ossl_unused void *ctx) +{ + return ossl_composite_i2d_pubkey((const COMPOSITE_KEY *)vkey, pder); +} + +static int composite_pki_priv_to_der(const void *vkey, unsigned char **pder, + ossl_unused void *ctx) +{ + return ossl_composite_i2d_prvkey((const COMPOSITE_KEY *)vkey, pder); +} + +#define composite_epki_priv_to_der composite_pki_priv_to_der +#define prepare_composite_params NULL +#define composite_check_key_type NULL + +/* evp_type and pem_type defines for all 18 composite variants */ +#define mldsa44_rsa2048_pss_sha256_evp_type NID_ML_DSA_44_RSA2048_PSS_SHA256 +#define mldsa44_rsa2048_pss_sha256_pem_type LN_ML_DSA_44_RSA2048_PSS_SHA256 +#define mldsa44_rsa2048_pkcs15_sha256_evp_type NID_ML_DSA_44_RSA2048_PKCS15_SHA256 +#define mldsa44_rsa2048_pkcs15_sha256_pem_type LN_ML_DSA_44_RSA2048_PKCS15_SHA256 +#define mldsa44_ed25519_sha512_evp_type NID_ML_DSA_44_Ed25519_SHA512 +#define mldsa44_ed25519_sha512_pem_type LN_ML_DSA_44_Ed25519_SHA512 +#define mldsa44_ecdsa_p256_sha256_evp_type NID_ML_DSA_44_ECDSA_P256_SHA256 +#define mldsa44_ecdsa_p256_sha256_pem_type LN_ML_DSA_44_ECDSA_P256_SHA256 +#define mldsa65_rsa3072_pss_sha512_evp_type NID_ML_DSA_65_RSA3072_PSS_SHA512 +#define mldsa65_rsa3072_pss_sha512_pem_type LN_ML_DSA_65_RSA3072_PSS_SHA512 +#define mldsa65_rsa3072_pkcs15_sha512_evp_type NID_ML_DSA_65_RSA3072_PKCS15_SHA512 +#define mldsa65_rsa3072_pkcs15_sha512_pem_type LN_ML_DSA_65_RSA3072_PKCS15_SHA512 +#define mldsa65_rsa4096_pss_sha512_evp_type NID_ML_DSA_65_RSA4096_PSS_SHA512 +#define mldsa65_rsa4096_pss_sha512_pem_type LN_ML_DSA_65_RSA4096_PSS_SHA512 +#define mldsa65_rsa4096_pkcs15_sha512_evp_type NID_ML_DSA_65_RSA4096_PKCS15_SHA512 +#define mldsa65_rsa4096_pkcs15_sha512_pem_type LN_ML_DSA_65_RSA4096_PKCS15_SHA512 +#define mldsa65_ecdsa_p256_sha512_evp_type NID_ML_DSA_65_ECDSA_P256_SHA512 +#define mldsa65_ecdsa_p256_sha512_pem_type LN_ML_DSA_65_ECDSA_P256_SHA512 +#define mldsa65_ecdsa_p384_sha512_evp_type NID_ML_DSA_65_ECDSA_P384_SHA512 +#define mldsa65_ecdsa_p384_sha512_pem_type LN_ML_DSA_65_ECDSA_P384_SHA512 +#define mldsa65_ecdsa_brainpoolP256r1_sha512_evp_type NID_ML_DSA_65_ECDSA_brainpoolP256r1_SHA512 +#define mldsa65_ecdsa_brainpoolP256r1_sha512_pem_type LN_ML_DSA_65_ECDSA_brainpoolP256r1_SHA512 +#define mldsa65_ed25519_sha512_evp_type NID_ML_DSA_65_Ed25519_SHA512 +#define mldsa65_ed25519_sha512_pem_type LN_ML_DSA_65_Ed25519_SHA512 +#define mldsa87_ecdsa_p384_sha512_evp_type NID_ML_DSA_87_ECDSA_P384_SHA512 +#define mldsa87_ecdsa_p384_sha512_pem_type LN_ML_DSA_87_ECDSA_P384_SHA512 +#define mldsa87_ecdsa_brainpoolP384r1_sha512_evp_type NID_ML_DSA_87_ECDSA_brainpoolP384r1_SHA512 +#define mldsa87_ecdsa_brainpoolP384r1_sha512_pem_type LN_ML_DSA_87_ECDSA_brainpoolP384r1_SHA512 +#define mldsa87_ed448_shake256_evp_type NID_ML_DSA_87_Ed448_SHAKE256 +#define mldsa87_ed448_shake256_pem_type LN_ML_DSA_87_Ed448_SHAKE256 +#define mldsa87_rsa3072_pss_sha512_evp_type NID_ML_DSA_87_RSA3072_PSS_SHA512 +#define mldsa87_rsa3072_pss_sha512_pem_type LN_ML_DSA_87_RSA3072_PSS_SHA512 +#define mldsa87_rsa4096_pss_sha512_evp_type NID_ML_DSA_87_RSA4096_PSS_SHA512 +#define mldsa87_rsa4096_pss_sha512_pem_type LN_ML_DSA_87_RSA4096_PSS_SHA512 +#define mldsa87_ecdsa_p521_sha512_evp_type NID_ML_DSA_87_ECDSA_P521_SHA512 +#define mldsa87_ecdsa_p521_sha512_pem_type LN_ML_DSA_87_ECDSA_P521_SHA512 + +MAKE_ENCODER(mldsa44_rsa2048_pss_sha256, composite, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(mldsa44_rsa2048_pss_sha256, composite, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(mldsa44_rsa2048_pss_sha256, composite, PrivateKeyInfo, der); +MAKE_ENCODER(mldsa44_rsa2048_pss_sha256, composite, PrivateKeyInfo, pem); +MAKE_ENCODER(mldsa44_rsa2048_pss_sha256, composite, SubjectPublicKeyInfo, der); +MAKE_ENCODER(mldsa44_rsa2048_pss_sha256, composite, SubjectPublicKeyInfo, pem); + +MAKE_ENCODER(mldsa44_rsa2048_pkcs15_sha256, composite, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(mldsa44_rsa2048_pkcs15_sha256, composite, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(mldsa44_rsa2048_pkcs15_sha256, composite, PrivateKeyInfo, der); +MAKE_ENCODER(mldsa44_rsa2048_pkcs15_sha256, composite, PrivateKeyInfo, pem); +MAKE_ENCODER(mldsa44_rsa2048_pkcs15_sha256, composite, SubjectPublicKeyInfo, der); +MAKE_ENCODER(mldsa44_rsa2048_pkcs15_sha256, composite, SubjectPublicKeyInfo, pem); + +MAKE_ENCODER(mldsa44_ed25519_sha512, composite, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(mldsa44_ed25519_sha512, composite, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(mldsa44_ed25519_sha512, composite, PrivateKeyInfo, der); +MAKE_ENCODER(mldsa44_ed25519_sha512, composite, PrivateKeyInfo, pem); +MAKE_ENCODER(mldsa44_ed25519_sha512, composite, SubjectPublicKeyInfo, der); +MAKE_ENCODER(mldsa44_ed25519_sha512, composite, SubjectPublicKeyInfo, pem); + +MAKE_ENCODER(mldsa44_ecdsa_p256_sha256, composite, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(mldsa44_ecdsa_p256_sha256, composite, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(mldsa44_ecdsa_p256_sha256, composite, PrivateKeyInfo, der); +MAKE_ENCODER(mldsa44_ecdsa_p256_sha256, composite, PrivateKeyInfo, pem); +MAKE_ENCODER(mldsa44_ecdsa_p256_sha256, composite, SubjectPublicKeyInfo, der); +MAKE_ENCODER(mldsa44_ecdsa_p256_sha256, composite, SubjectPublicKeyInfo, pem); + +MAKE_ENCODER(mldsa65_rsa3072_pss_sha512, composite, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(mldsa65_rsa3072_pss_sha512, composite, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(mldsa65_rsa3072_pss_sha512, composite, PrivateKeyInfo, der); +MAKE_ENCODER(mldsa65_rsa3072_pss_sha512, composite, PrivateKeyInfo, pem); +MAKE_ENCODER(mldsa65_rsa3072_pss_sha512, composite, SubjectPublicKeyInfo, der); +MAKE_ENCODER(mldsa65_rsa3072_pss_sha512, composite, SubjectPublicKeyInfo, pem); + +MAKE_ENCODER(mldsa65_rsa3072_pkcs15_sha512, composite, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(mldsa65_rsa3072_pkcs15_sha512, composite, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(mldsa65_rsa3072_pkcs15_sha512, composite, PrivateKeyInfo, der); +MAKE_ENCODER(mldsa65_rsa3072_pkcs15_sha512, composite, PrivateKeyInfo, pem); +MAKE_ENCODER(mldsa65_rsa3072_pkcs15_sha512, composite, SubjectPublicKeyInfo, der); +MAKE_ENCODER(mldsa65_rsa3072_pkcs15_sha512, composite, SubjectPublicKeyInfo, pem); + +MAKE_ENCODER(mldsa65_rsa4096_pss_sha512, composite, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(mldsa65_rsa4096_pss_sha512, composite, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(mldsa65_rsa4096_pss_sha512, composite, PrivateKeyInfo, der); +MAKE_ENCODER(mldsa65_rsa4096_pss_sha512, composite, PrivateKeyInfo, pem); +MAKE_ENCODER(mldsa65_rsa4096_pss_sha512, composite, SubjectPublicKeyInfo, der); +MAKE_ENCODER(mldsa65_rsa4096_pss_sha512, composite, SubjectPublicKeyInfo, pem); + +MAKE_ENCODER(mldsa65_rsa4096_pkcs15_sha512, composite, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(mldsa65_rsa4096_pkcs15_sha512, composite, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(mldsa65_rsa4096_pkcs15_sha512, composite, PrivateKeyInfo, der); +MAKE_ENCODER(mldsa65_rsa4096_pkcs15_sha512, composite, PrivateKeyInfo, pem); +MAKE_ENCODER(mldsa65_rsa4096_pkcs15_sha512, composite, SubjectPublicKeyInfo, der); +MAKE_ENCODER(mldsa65_rsa4096_pkcs15_sha512, composite, SubjectPublicKeyInfo, pem); + +MAKE_ENCODER(mldsa65_ecdsa_p256_sha512, composite, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(mldsa65_ecdsa_p256_sha512, composite, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(mldsa65_ecdsa_p256_sha512, composite, PrivateKeyInfo, der); +MAKE_ENCODER(mldsa65_ecdsa_p256_sha512, composite, PrivateKeyInfo, pem); +MAKE_ENCODER(mldsa65_ecdsa_p256_sha512, composite, SubjectPublicKeyInfo, der); +MAKE_ENCODER(mldsa65_ecdsa_p256_sha512, composite, SubjectPublicKeyInfo, pem); + +MAKE_ENCODER(mldsa65_ecdsa_p384_sha512, composite, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(mldsa65_ecdsa_p384_sha512, composite, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(mldsa65_ecdsa_p384_sha512, composite, PrivateKeyInfo, der); +MAKE_ENCODER(mldsa65_ecdsa_p384_sha512, composite, PrivateKeyInfo, pem); +MAKE_ENCODER(mldsa65_ecdsa_p384_sha512, composite, SubjectPublicKeyInfo, der); +MAKE_ENCODER(mldsa65_ecdsa_p384_sha512, composite, SubjectPublicKeyInfo, pem); + +MAKE_ENCODER(mldsa65_ecdsa_brainpoolP256r1_sha512, composite, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(mldsa65_ecdsa_brainpoolP256r1_sha512, composite, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(mldsa65_ecdsa_brainpoolP256r1_sha512, composite, PrivateKeyInfo, der); +MAKE_ENCODER(mldsa65_ecdsa_brainpoolP256r1_sha512, composite, PrivateKeyInfo, pem); +MAKE_ENCODER(mldsa65_ecdsa_brainpoolP256r1_sha512, composite, SubjectPublicKeyInfo, der); +MAKE_ENCODER(mldsa65_ecdsa_brainpoolP256r1_sha512, composite, SubjectPublicKeyInfo, pem); + +MAKE_ENCODER(mldsa65_ed25519_sha512, composite, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(mldsa65_ed25519_sha512, composite, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(mldsa65_ed25519_sha512, composite, PrivateKeyInfo, der); +MAKE_ENCODER(mldsa65_ed25519_sha512, composite, PrivateKeyInfo, pem); +MAKE_ENCODER(mldsa65_ed25519_sha512, composite, SubjectPublicKeyInfo, der); +MAKE_ENCODER(mldsa65_ed25519_sha512, composite, SubjectPublicKeyInfo, pem); + +MAKE_ENCODER(mldsa87_ecdsa_p384_sha512, composite, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(mldsa87_ecdsa_p384_sha512, composite, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(mldsa87_ecdsa_p384_sha512, composite, PrivateKeyInfo, der); +MAKE_ENCODER(mldsa87_ecdsa_p384_sha512, composite, PrivateKeyInfo, pem); +MAKE_ENCODER(mldsa87_ecdsa_p384_sha512, composite, SubjectPublicKeyInfo, der); +MAKE_ENCODER(mldsa87_ecdsa_p384_sha512, composite, SubjectPublicKeyInfo, pem); + +MAKE_ENCODER(mldsa87_ecdsa_brainpoolP384r1_sha512, composite, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(mldsa87_ecdsa_brainpoolP384r1_sha512, composite, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(mldsa87_ecdsa_brainpoolP384r1_sha512, composite, PrivateKeyInfo, der); +MAKE_ENCODER(mldsa87_ecdsa_brainpoolP384r1_sha512, composite, PrivateKeyInfo, pem); +MAKE_ENCODER(mldsa87_ecdsa_brainpoolP384r1_sha512, composite, SubjectPublicKeyInfo, der); +MAKE_ENCODER(mldsa87_ecdsa_brainpoolP384r1_sha512, composite, SubjectPublicKeyInfo, pem); + +MAKE_ENCODER(mldsa87_ed448_shake256, composite, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(mldsa87_ed448_shake256, composite, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(mldsa87_ed448_shake256, composite, PrivateKeyInfo, der); +MAKE_ENCODER(mldsa87_ed448_shake256, composite, PrivateKeyInfo, pem); +MAKE_ENCODER(mldsa87_ed448_shake256, composite, SubjectPublicKeyInfo, der); +MAKE_ENCODER(mldsa87_ed448_shake256, composite, SubjectPublicKeyInfo, pem); + +MAKE_ENCODER(mldsa87_rsa3072_pss_sha512, composite, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(mldsa87_rsa3072_pss_sha512, composite, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(mldsa87_rsa3072_pss_sha512, composite, PrivateKeyInfo, der); +MAKE_ENCODER(mldsa87_rsa3072_pss_sha512, composite, PrivateKeyInfo, pem); +MAKE_ENCODER(mldsa87_rsa3072_pss_sha512, composite, SubjectPublicKeyInfo, der); +MAKE_ENCODER(mldsa87_rsa3072_pss_sha512, composite, SubjectPublicKeyInfo, pem); + +MAKE_ENCODER(mldsa87_rsa4096_pss_sha512, composite, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(mldsa87_rsa4096_pss_sha512, composite, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(mldsa87_rsa4096_pss_sha512, composite, PrivateKeyInfo, der); +MAKE_ENCODER(mldsa87_rsa4096_pss_sha512, composite, PrivateKeyInfo, pem); +MAKE_ENCODER(mldsa87_rsa4096_pss_sha512, composite, SubjectPublicKeyInfo, der); +MAKE_ENCODER(mldsa87_rsa4096_pss_sha512, composite, SubjectPublicKeyInfo, pem); + +MAKE_ENCODER(mldsa87_ecdsa_p521_sha512, composite, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(mldsa87_ecdsa_p521_sha512, composite, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(mldsa87_ecdsa_p521_sha512, composite, PrivateKeyInfo, der); +MAKE_ENCODER(mldsa87_ecdsa_p521_sha512, composite, PrivateKeyInfo, pem); +MAKE_ENCODER(mldsa87_ecdsa_p521_sha512, composite, SubjectPublicKeyInfo, der); +MAKE_ENCODER(mldsa87_ecdsa_p521_sha512, composite, SubjectPublicKeyInfo, pem); +#endif /* OPENSSL_NO_COMPOSITE */ diff --git a/providers/implementations/encode_decode/encode_key2text.c b/providers/implementations/encode_decode/encode_key2text.c index 965113426b200..17c5e27aa45ea 100644 --- a/providers/implementations/encode_decode/encode_key2text.c +++ b/providers/implementations/encode_decode/encode_key2text.c @@ -34,6 +34,9 @@ #include "prov/ml_dsa_codecs.h" #include "prov/ml_kem_codecs.h" #include "prov/lms_codecs.h" +#ifndef OPENSSL_NO_COMPOSITE +#include "prov/composite_codecs.h" +#endif DEFINE_SPECIAL_STACK_OF_CONST(BIGNUM_const, BIGNUM) @@ -630,6 +633,14 @@ static int lms_to_text(BIO *out, const void *key, int selection) } #endif /* OPENSSL_NO_LMS */ +#ifndef OPENSSL_NO_COMPOSITE +static int composite_to_text(BIO *out, const void *key, int selection) +{ + return ossl_composite_key_to_text(out, (const COMPOSITE_KEY *)key, + selection); +} +#endif /* OPENSSL_NO_COMPOSITE */ + /* ---------------------------------------------------------------------- */ static void *key2text_newctx(void *provctx) @@ -756,3 +767,24 @@ MAKE_TEXT_ENCODER(slh_dsa_shake_256f, slh_dsa); #ifndef OPENSSL_NO_LMS MAKE_TEXT_ENCODER(lms, lms); #endif + +#ifndef OPENSSL_NO_COMPOSITE +MAKE_TEXT_ENCODER(mldsa44_rsa2048_pss_sha256, composite); +MAKE_TEXT_ENCODER(mldsa44_rsa2048_pkcs15_sha256, composite); +MAKE_TEXT_ENCODER(mldsa44_ed25519_sha512, composite); +MAKE_TEXT_ENCODER(mldsa44_ecdsa_p256_sha256, composite); +MAKE_TEXT_ENCODER(mldsa65_rsa3072_pss_sha512, composite); +MAKE_TEXT_ENCODER(mldsa65_rsa3072_pkcs15_sha512, composite); +MAKE_TEXT_ENCODER(mldsa65_rsa4096_pss_sha512, composite); +MAKE_TEXT_ENCODER(mldsa65_rsa4096_pkcs15_sha512, composite); +MAKE_TEXT_ENCODER(mldsa65_ecdsa_p256_sha512, composite); +MAKE_TEXT_ENCODER(mldsa65_ecdsa_p384_sha512, composite); +MAKE_TEXT_ENCODER(mldsa65_ecdsa_brainpoolP256r1_sha512, composite); +MAKE_TEXT_ENCODER(mldsa65_ed25519_sha512, composite); +MAKE_TEXT_ENCODER(mldsa87_ecdsa_p384_sha512, composite); +MAKE_TEXT_ENCODER(mldsa87_ecdsa_brainpoolP384r1_sha512, composite); +MAKE_TEXT_ENCODER(mldsa87_ed448_shake256, composite); +MAKE_TEXT_ENCODER(mldsa87_rsa3072_pss_sha512, composite); +MAKE_TEXT_ENCODER(mldsa87_rsa4096_pss_sha512, composite); +MAKE_TEXT_ENCODER(mldsa87_ecdsa_p521_sha512, composite); +#endif /* OPENSSL_NO_COMPOSITE */ diff --git a/providers/implementations/include/prov/composite_codecs.h b/providers/implementations/include/prov/composite_codecs.h new file mode 100644 index 0000000000000..34c18898faa90 --- /dev/null +++ b/providers/implementations/include/prov/composite_codecs.h @@ -0,0 +1,77 @@ +/* + * Copyright 2026 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef PROV_COMPOSITE_CODECS_H +#define PROV_COMPOSITE_CODECS_H +#pragma once + +#ifndef OPENSSL_NO_COMPOSITE +#include +#include +#include "prov/composite.h" +#include "prov/provider_ctx.h" + +/* + * Encode the composite public key (mldsaPK || tradPK) into *out. + * Returns the total byte length on success, 0 on error. + * If out is NULL, only the length is returned (no allocation). + */ +__owur int ossl_composite_i2d_pubkey(const COMPOSITE_KEY *key, + unsigned char **out); + +/* + * Encode the composite private key (mldsaSeed[32] || tradSK) into *out. + * Returns the total byte length on success, 0 on error. + * If out is NULL, only the length is returned (no allocation). + */ +__owur int ossl_composite_i2d_prvkey(const COMPOSITE_KEY *key, + unsigned char **out); + +/* + * Print a human-readable description of the composite key to |out|. + * |selection| is an OSSL_KEYMGMT_SELECT_* mask. + */ +__owur int ossl_composite_key_to_text(BIO *out, const COMPOSITE_KEY *key, + int selection); + +/* + * Decode a composite public key from its wire format (mldsaPK || tradPK). + * |pk|/|pk_len|: raw concatenated public key bytes (BIT STRING content + * from SubjectPublicKeyInfo). + * |ml_dsa_evp_type|: EVP_PKEY_ML_DSA_44/65/87 selecting the ML-DSA variant. + * |classic_alg|: "RSA", "EC", "ED25519", or "ED448". + * |ec_curve|: curve name for EC (e.g. "P-256"), NULL for non-EC. + * |provctx|: provider context for library context and propq. + * |propq|: property query string (may be NULL). + * Returns a newly allocated COMPOSITE_KEY on success, NULL on failure. + */ +__owur COMPOSITE_KEY *ossl_composite_d2i_pubkey(const unsigned char *pk, + int pk_len, + int ml_dsa_evp_type, + const char *classic_alg, + const char *ec_curve, + PROV_CTX *provctx, + const char *propq); + +/* + * Decode a composite private key from its wire format (mldsaSeed[32] || tradSK). + * |priv|/|priv_len|: raw concatenated private key bytes. + * Other params: same as ossl_composite_d2i_pubkey. + * Returns a newly allocated COMPOSITE_KEY on success, NULL on failure. + */ +__owur COMPOSITE_KEY *ossl_composite_d2i_prvkey(const unsigned char *priv, + int priv_len, + int ml_dsa_evp_type, + const char *classic_alg, + const char *ec_curve, + PROV_CTX *provctx, + const char *propq); + +#endif /* OPENSSL_NO_COMPOSITE */ +#endif /* PROV_COMPOSITE_CODECS_H */ diff --git a/providers/implementations/include/prov/implementations.h b/providers/implementations/include/prov/implementations.h index 2b0782bd0b46a..fdddb8c3c84ab 100644 --- a/providers/implementations/include/prov/implementations.h +++ b/providers/implementations/include/prov/implementations.h @@ -470,6 +470,45 @@ extern const OSSL_DISPATCH ossl_slh_dsa_shake_256s_signature_functions[]; extern const OSSL_DISPATCH ossl_slh_dsa_shake_256f_signature_functions[]; #endif /* OPENSSL_NO_SLH_DSA */ +/* Composite signature algorithms (draft-ietf-lamps-pq-composite-sigs) */ +extern const OSSL_DISPATCH ossl_mldsa44_rsa2048_pss_sha256_signature_functions[]; +extern const OSSL_DISPATCH ossl_mldsa44_rsa2048_pkcs15_sha256_signature_functions[]; +extern const OSSL_DISPATCH ossl_mldsa44_ed25519_sha512_signature_functions[]; +extern const OSSL_DISPATCH ossl_mldsa44_ecdsa_p256_sha256_signature_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_rsa3072_pss_sha512_signature_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_rsa3072_pkcs15_sha512_signature_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_rsa4096_pss_sha512_signature_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_rsa4096_pkcs15_sha512_signature_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_ecdsa_p256_sha512_signature_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_ecdsa_p384_sha512_signature_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_ecdsa_brainpoolP256r1_sha512_signature_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_ed25519_sha512_signature_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_ecdsa_p384_sha512_signature_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_ecdsa_brainpoolP384r1_sha512_signature_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_ed448_shake256_signature_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_rsa3072_pss_sha512_signature_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_rsa4096_pss_sha512_signature_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_ecdsa_p521_sha512_signature_functions[]; +/* Composite key management */ +extern const OSSL_DISPATCH ossl_mldsa44_rsa2048_pss_sha256_keymgmt_functions[]; +extern const OSSL_DISPATCH ossl_mldsa44_rsa2048_pkcs15_sha256_keymgmt_functions[]; +extern const OSSL_DISPATCH ossl_mldsa44_ed25519_sha512_keymgmt_functions[]; +extern const OSSL_DISPATCH ossl_mldsa44_ecdsa_p256_sha256_keymgmt_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_rsa3072_pss_sha512_keymgmt_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_rsa3072_pkcs15_sha512_keymgmt_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_rsa4096_pss_sha512_keymgmt_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_rsa4096_pkcs15_sha512_keymgmt_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_ecdsa_p256_sha512_keymgmt_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_ecdsa_p384_sha512_keymgmt_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_ecdsa_brainpoolP256r1_sha512_keymgmt_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_ed25519_sha512_keymgmt_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_ecdsa_p384_sha512_keymgmt_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_ecdsa_brainpoolP384r1_sha512_keymgmt_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_ed448_shake256_keymgmt_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_rsa3072_pss_sha512_keymgmt_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_rsa4096_pss_sha512_keymgmt_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_ecdsa_p521_sha512_keymgmt_functions[]; + /* Asym Cipher */ extern const OSSL_DISPATCH ossl_rsa_asym_cipher_functions[]; #ifndef OPENSSL_NO_SM2 @@ -653,6 +692,150 @@ extern const OSSL_DISPATCH ossl_ml_dsa_87_to_SubjectPublicKeyInfo_pem_encoder_fu extern const OSSL_DISPATCH ossl_ml_dsa_87_to_OSSL_current_der_encoder_functions[]; extern const OSSL_DISPATCH ossl_ml_dsa_87_to_text_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa44_rsa2048_pss_sha256_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa44_rsa2048_pss_sha256_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa44_rsa2048_pss_sha256_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa44_rsa2048_pss_sha256_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa44_rsa2048_pss_sha256_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa44_rsa2048_pss_sha256_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa44_rsa2048_pss_sha256_to_text_encoder_functions[]; + +extern const OSSL_DISPATCH ossl_mldsa44_rsa2048_pkcs15_sha256_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa44_rsa2048_pkcs15_sha256_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa44_rsa2048_pkcs15_sha256_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa44_rsa2048_pkcs15_sha256_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa44_rsa2048_pkcs15_sha256_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa44_rsa2048_pkcs15_sha256_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa44_rsa2048_pkcs15_sha256_to_text_encoder_functions[]; + +extern const OSSL_DISPATCH ossl_mldsa44_ed25519_sha512_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa44_ed25519_sha512_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa44_ed25519_sha512_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa44_ed25519_sha512_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa44_ed25519_sha512_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa44_ed25519_sha512_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa44_ed25519_sha512_to_text_encoder_functions[]; + +extern const OSSL_DISPATCH ossl_mldsa44_ecdsa_p256_sha256_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa44_ecdsa_p256_sha256_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa44_ecdsa_p256_sha256_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa44_ecdsa_p256_sha256_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa44_ecdsa_p256_sha256_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa44_ecdsa_p256_sha256_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa44_ecdsa_p256_sha256_to_text_encoder_functions[]; + +extern const OSSL_DISPATCH ossl_mldsa65_rsa3072_pss_sha512_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_rsa3072_pss_sha512_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_rsa3072_pss_sha512_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_rsa3072_pss_sha512_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_rsa3072_pss_sha512_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_rsa3072_pss_sha512_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_rsa3072_pss_sha512_to_text_encoder_functions[]; + +extern const OSSL_DISPATCH ossl_mldsa65_rsa3072_pkcs15_sha512_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_rsa3072_pkcs15_sha512_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_rsa3072_pkcs15_sha512_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_rsa3072_pkcs15_sha512_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_rsa3072_pkcs15_sha512_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_rsa3072_pkcs15_sha512_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_rsa3072_pkcs15_sha512_to_text_encoder_functions[]; + +extern const OSSL_DISPATCH ossl_mldsa65_rsa4096_pss_sha512_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_rsa4096_pss_sha512_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_rsa4096_pss_sha512_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_rsa4096_pss_sha512_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_rsa4096_pss_sha512_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_rsa4096_pss_sha512_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_rsa4096_pss_sha512_to_text_encoder_functions[]; + +extern const OSSL_DISPATCH ossl_mldsa65_rsa4096_pkcs15_sha512_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_rsa4096_pkcs15_sha512_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_rsa4096_pkcs15_sha512_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_rsa4096_pkcs15_sha512_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_rsa4096_pkcs15_sha512_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_rsa4096_pkcs15_sha512_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_rsa4096_pkcs15_sha512_to_text_encoder_functions[]; + +extern const OSSL_DISPATCH ossl_mldsa65_ecdsa_p256_sha512_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_ecdsa_p256_sha512_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_ecdsa_p256_sha512_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_ecdsa_p256_sha512_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_ecdsa_p256_sha512_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_ecdsa_p256_sha512_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_ecdsa_p256_sha512_to_text_encoder_functions[]; + +extern const OSSL_DISPATCH ossl_mldsa65_ecdsa_p384_sha512_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_ecdsa_p384_sha512_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_ecdsa_p384_sha512_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_ecdsa_p384_sha512_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_ecdsa_p384_sha512_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_ecdsa_p384_sha512_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_ecdsa_p384_sha512_to_text_encoder_functions[]; + +extern const OSSL_DISPATCH ossl_mldsa65_ecdsa_brainpoolP256r1_sha512_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_ecdsa_brainpoolP256r1_sha512_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_ecdsa_brainpoolP256r1_sha512_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_ecdsa_brainpoolP256r1_sha512_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_ecdsa_brainpoolP256r1_sha512_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_ecdsa_brainpoolP256r1_sha512_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_ecdsa_brainpoolP256r1_sha512_to_text_encoder_functions[]; + +extern const OSSL_DISPATCH ossl_mldsa65_ed25519_sha512_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_ed25519_sha512_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_ed25519_sha512_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_ed25519_sha512_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_ed25519_sha512_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_ed25519_sha512_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa65_ed25519_sha512_to_text_encoder_functions[]; + +extern const OSSL_DISPATCH ossl_mldsa87_ecdsa_p384_sha512_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_ecdsa_p384_sha512_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_ecdsa_p384_sha512_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_ecdsa_p384_sha512_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_ecdsa_p384_sha512_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_ecdsa_p384_sha512_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_ecdsa_p384_sha512_to_text_encoder_functions[]; + +extern const OSSL_DISPATCH ossl_mldsa87_ecdsa_brainpoolP384r1_sha512_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_ecdsa_brainpoolP384r1_sha512_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_ecdsa_brainpoolP384r1_sha512_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_ecdsa_brainpoolP384r1_sha512_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_ecdsa_brainpoolP384r1_sha512_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_ecdsa_brainpoolP384r1_sha512_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_ecdsa_brainpoolP384r1_sha512_to_text_encoder_functions[]; + +extern const OSSL_DISPATCH ossl_mldsa87_ed448_shake256_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_ed448_shake256_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_ed448_shake256_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_ed448_shake256_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_ed448_shake256_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_ed448_shake256_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_ed448_shake256_to_text_encoder_functions[]; + +extern const OSSL_DISPATCH ossl_mldsa87_rsa3072_pss_sha512_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_rsa3072_pss_sha512_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_rsa3072_pss_sha512_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_rsa3072_pss_sha512_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_rsa3072_pss_sha512_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_rsa3072_pss_sha512_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_rsa3072_pss_sha512_to_text_encoder_functions[]; + +extern const OSSL_DISPATCH ossl_mldsa87_rsa4096_pss_sha512_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_rsa4096_pss_sha512_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_rsa4096_pss_sha512_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_rsa4096_pss_sha512_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_rsa4096_pss_sha512_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_rsa4096_pss_sha512_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_rsa4096_pss_sha512_to_text_encoder_functions[]; + +extern const OSSL_DISPATCH ossl_mldsa87_ecdsa_p521_sha512_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_ecdsa_p521_sha512_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_ecdsa_p521_sha512_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_ecdsa_p521_sha512_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_ecdsa_p521_sha512_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_ecdsa_p521_sha512_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH ossl_mldsa87_ecdsa_p521_sha512_to_text_encoder_functions[]; + extern const OSSL_DISPATCH ossl_slh_dsa_sha2_128s_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; extern const OSSL_DISPATCH ossl_slh_dsa_sha2_128f_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; extern const OSSL_DISPATCH ossl_slh_dsa_sha2_192s_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; @@ -885,6 +1068,44 @@ extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_ml_dsa_65_decoder_fu extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_ml_dsa_87_decoder_functions[]; extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_ml_dsa_87_decoder_functions[]; +/* Composite decoders (all 18 variants) */ +extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_mldsa44_rsa2048_pss_sha256_decoder_functions[]; +extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_mldsa44_rsa2048_pss_sha256_decoder_functions[]; +extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_mldsa44_rsa2048_pkcs15_sha256_decoder_functions[]; +extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_mldsa44_rsa2048_pkcs15_sha256_decoder_functions[]; +extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_mldsa44_ed25519_sha512_decoder_functions[]; +extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_mldsa44_ed25519_sha512_decoder_functions[]; +extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_mldsa44_ecdsa_p256_sha256_decoder_functions[]; +extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_mldsa44_ecdsa_p256_sha256_decoder_functions[]; +extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_mldsa65_rsa3072_pss_sha512_decoder_functions[]; +extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_mldsa65_rsa3072_pss_sha512_decoder_functions[]; +extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_mldsa65_rsa3072_pkcs15_sha512_decoder_functions[]; +extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_mldsa65_rsa3072_pkcs15_sha512_decoder_functions[]; +extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_mldsa65_rsa4096_pss_sha512_decoder_functions[]; +extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_mldsa65_rsa4096_pss_sha512_decoder_functions[]; +extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_mldsa65_rsa4096_pkcs15_sha512_decoder_functions[]; +extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_mldsa65_rsa4096_pkcs15_sha512_decoder_functions[]; +extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_mldsa65_ecdsa_p256_sha512_decoder_functions[]; +extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_mldsa65_ecdsa_p256_sha512_decoder_functions[]; +extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_mldsa65_ecdsa_p384_sha512_decoder_functions[]; +extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_mldsa65_ecdsa_p384_sha512_decoder_functions[]; +extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_mldsa65_ecdsa_brainpoolP256r1_sha512_decoder_functions[]; +extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_mldsa65_ecdsa_brainpoolP256r1_sha512_decoder_functions[]; +extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_mldsa65_ed25519_sha512_decoder_functions[]; +extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_mldsa65_ed25519_sha512_decoder_functions[]; +extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_mldsa87_ecdsa_p384_sha512_decoder_functions[]; +extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_mldsa87_ecdsa_p384_sha512_decoder_functions[]; +extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_mldsa87_ecdsa_brainpoolP384r1_sha512_decoder_functions[]; +extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_mldsa87_ecdsa_brainpoolP384r1_sha512_decoder_functions[]; +extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_mldsa87_ed448_shake256_decoder_functions[]; +extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_mldsa87_ed448_shake256_decoder_functions[]; +extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_mldsa87_rsa3072_pss_sha512_decoder_functions[]; +extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_mldsa87_rsa3072_pss_sha512_decoder_functions[]; +extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_mldsa87_rsa4096_pss_sha512_decoder_functions[]; +extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_mldsa87_rsa4096_pss_sha512_decoder_functions[]; +extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_mldsa87_ecdsa_p521_sha512_decoder_functions[]; +extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_mldsa87_ecdsa_p521_sha512_decoder_functions[]; + extern const OSSL_DISPATCH ossl_generic_skeymgmt_functions[]; extern const OSSL_DISPATCH ossl_aes_skeymgmt_functions[]; diff --git a/providers/implementations/include/prov/names.h b/providers/implementations/include/prov/names.h index 09146dd01ed72..22304f3af80a1 100644 --- a/providers/implementations/include/prov/names.h +++ b/providers/implementations/include/prov/names.h @@ -469,4 +469,78 @@ #define PROV_DESCS_SLH_DSA_SHAKE_256S "OpenSSL SLH-DSA-SHAKE-256s implementation" #define PROV_DESCS_SLH_DSA_SHAKE_256F "OpenSSL SLH-DSA-SHAKE-256f implementation" +/* Composite signature algorithms (draft-ietf-lamps-pq-composite-sigs) */ +#define PROV_NAMES_MLDSA44_RSA2048_PSS_SHA256 \ + "ML-DSA-44-RSA2048-PSS-SHA256:id-mldsa44-rsa2048-pss-sha256:1.3.6.1.5.5.7.6.37" +#define PROV_DESCS_MLDSA44_RSA2048_PSS_SHA256 \ + "OpenSSL ML-DSA-44-RSA2048-PSS-SHA256 composite implementation" +#define PROV_NAMES_MLDSA44_RSA2048_PKCS15_SHA256 \ + "ML-DSA-44-RSA2048-PKCS15-SHA256:id-mldsa44-rsa2048-pkcs15-sha256:1.3.6.1.5.5.7.6.38" +#define PROV_DESCS_MLDSA44_RSA2048_PKCS15_SHA256 \ + "OpenSSL ML-DSA-44-RSA2048-PKCS15-SHA256 composite implementation" +#define PROV_NAMES_MLDSA44_ED25519_SHA512 \ + "ML-DSA-44-Ed25519-SHA512:id-mldsa44-ed25519-sha512:1.3.6.1.5.5.7.6.39" +#define PROV_DESCS_MLDSA44_ED25519_SHA512 \ + "OpenSSL ML-DSA-44-Ed25519-SHA512 composite implementation" +#define PROV_NAMES_MLDSA44_ECDSA_P256_SHA256 \ + "ML-DSA-44-ECDSA-P256-SHA256:id-mldsa44-ecdsa-p256-sha256:1.3.6.1.5.5.7.6.40" +#define PROV_DESCS_MLDSA44_ECDSA_P256_SHA256 \ + "OpenSSL ML-DSA-44-ECDSA-P256-SHA256 composite implementation" +#define PROV_NAMES_MLDSA65_RSA3072_PSS_SHA512 \ + "ML-DSA-65-RSA3072-PSS-SHA512:id-mldsa65-rsa3072-pss-sha512:1.3.6.1.5.5.7.6.41" +#define PROV_DESCS_MLDSA65_RSA3072_PSS_SHA512 \ + "OpenSSL ML-DSA-65-RSA3072-PSS-SHA512 composite implementation" +#define PROV_NAMES_MLDSA65_RSA3072_PKCS15_SHA512 \ + "ML-DSA-65-RSA3072-PKCS15-SHA512:id-mldsa65-rsa3072-pkcs15-sha512:1.3.6.1.5.5.7.6.42" +#define PROV_DESCS_MLDSA65_RSA3072_PKCS15_SHA512 \ + "OpenSSL ML-DSA-65-RSA3072-PKCS15-SHA512 composite implementation" +#define PROV_NAMES_MLDSA65_RSA4096_PSS_SHA512 \ + "ML-DSA-65-RSA4096-PSS-SHA512:id-mldsa65-rsa4096-pss-sha512:1.3.6.1.5.5.7.6.43" +#define PROV_DESCS_MLDSA65_RSA4096_PSS_SHA512 \ + "OpenSSL ML-DSA-65-RSA4096-PSS-SHA512 composite implementation" +#define PROV_NAMES_MLDSA65_RSA4096_PKCS15_SHA512 \ + "ML-DSA-65-RSA4096-PKCS15-SHA512:id-mldsa65-rsa4096-pkcs15-sha512:1.3.6.1.5.5.7.6.44" +#define PROV_DESCS_MLDSA65_RSA4096_PKCS15_SHA512 \ + "OpenSSL ML-DSA-65-RSA4096-PKCS15-SHA512 composite implementation" +#define PROV_NAMES_MLDSA65_ECDSA_P256_SHA512 \ + "ML-DSA-65-ECDSA-P256-SHA512:id-mldsa65-ecdsa-p256-sha512:1.3.6.1.5.5.7.6.45" +#define PROV_DESCS_MLDSA65_ECDSA_P256_SHA512 \ + "OpenSSL ML-DSA-65-ECDSA-P256-SHA512 composite implementation" +#define PROV_NAMES_MLDSA65_ECDSA_P384_SHA512 \ + "ML-DSA-65-ECDSA-P384-SHA512:id-mldsa65-ecdsa-p384-sha512:1.3.6.1.5.5.7.6.46" +#define PROV_DESCS_MLDSA65_ECDSA_P384_SHA512 \ + "OpenSSL ML-DSA-65-ECDSA-P384-SHA512 composite implementation" +#define PROV_NAMES_MLDSA65_ECDSA_BRAINPOOLP256R1_SHA512 \ + "ML-DSA-65-ECDSA-brainpoolP256r1-SHA512:id-mldsa65-ecdsa-brainpoolP256r1-sha512:1.3.6.1.5.5.7.6.47" +#define PROV_DESCS_MLDSA65_ECDSA_BRAINPOOLP256R1_SHA512 \ + "OpenSSL ML-DSA-65-ECDSA-brainpoolP256r1-SHA512 composite implementation" +#define PROV_NAMES_MLDSA65_ED25519_SHA512 \ + "ML-DSA-65-Ed25519-SHA512:id-mldsa65-ed25519-sha512:1.3.6.1.5.5.7.6.48" +#define PROV_DESCS_MLDSA65_ED25519_SHA512 \ + "OpenSSL ML-DSA-65-Ed25519-SHA512 composite implementation" +#define PROV_NAMES_MLDSA87_ECDSA_P384_SHA512 \ + "ML-DSA-87-ECDSA-P384-SHA512:id-mldsa87-ecdsa-p384-sha512:1.3.6.1.5.5.7.6.49" +#define PROV_DESCS_MLDSA87_ECDSA_P384_SHA512 \ + "OpenSSL ML-DSA-87-ECDSA-P384-SHA512 composite implementation" +#define PROV_NAMES_MLDSA87_ECDSA_BRAINPOOLP384R1_SHA512 \ + "ML-DSA-87-ECDSA-brainpoolP384r1-SHA512:id-mldsa87-ecdsa-brainpoolp384r1-sha512:1.3.6.1.5.5.7.6.50" +#define PROV_DESCS_MLDSA87_ECDSA_BRAINPOOLP384R1_SHA512 \ + "OpenSSL ML-DSA-87-ECDSA-brainpoolP384r1-SHA512 composite implementation" +#define PROV_NAMES_MLDSA87_ED448_SHAKE256 \ + "ML-DSA-87-Ed448-SHAKE256:id-mldsa87-ed448-shake256:1.3.6.1.5.5.7.6.51" +#define PROV_DESCS_MLDSA87_ED448_SHAKE256 \ + "OpenSSL ML-DSA-87-Ed448-SHAKE256 composite implementation" +#define PROV_NAMES_MLDSA87_RSA3072_PSS_SHA512 \ + "ML-DSA-87-RSA3072-PSS-SHA512:id-mldsa87-rsa3072-pss-sha512:1.3.6.1.5.5.7.6.52" +#define PROV_DESCS_MLDSA87_RSA3072_PSS_SHA512 \ + "OpenSSL ML-DSA-87-RSA3072-PSS-SHA512 composite implementation" +#define PROV_NAMES_MLDSA87_RSA4096_PSS_SHA512 \ + "ML-DSA-87-RSA4096-PSS-SHA512:id-mldsa87-rsa4096-pss-sha512:1.3.6.1.5.5.7.6.53" +#define PROV_DESCS_MLDSA87_RSA4096_PSS_SHA512 \ + "OpenSSL ML-DSA-87-RSA4096-PSS-SHA512 composite implementation" +#define PROV_NAMES_MLDSA87_ECDSA_P521_SHA512 \ + "ML-DSA-87-ECDSA-P521-SHA512:id-mldsa87-ecdsa-p521-sha512:1.3.6.1.5.5.7.6.54" +#define PROV_DESCS_MLDSA87_ECDSA_P521_SHA512 \ + "OpenSSL ML-DSA-87-ECDSA-P521-SHA512 composite implementation" + #endif /* !defined(OSSL_PROVIDERS_IMPLEMENTATIONS_INCLUDE_PROV_NAMES_H) */ diff --git a/providers/implementations/keymgmt/build.info b/providers/implementations/keymgmt/build.info index 347904c7e7580..f13d0d18aa1ab 100644 --- a/providers/implementations/keymgmt/build.info +++ b/providers/implementations/keymgmt/build.info @@ -14,6 +14,7 @@ $ML_DSA_GOAL=../../libdefault.a ../../libfips.a $ML_KEM_GOAL=../../libdefault.a ../../libfips.a $TLS_ML_KEM_HYBRID_GOAL=../../libdefault.a ../../libfips.a $SLH_DSA_GOAL=../../libdefault.a ../../libfips.a +$COMPOSITE_GOAL=../../libdefault.a IF[{- !$disabled{dh} -}] SOURCE[$DH_GOAL]=dh_kmgmt.c @@ -69,3 +70,8 @@ ENDIF IF[{- !$disabled{'slh-dsa'} -}] SOURCE[$SLH_DSA_GOAL]=slh_dsa_kmgmt.c ENDIF + +IF[{- !$disabled{'ml-dsa'} -}] + SOURCE[$COMPOSITE_GOAL]=composite_kmgmt.c + DEPEND[composite_kmgmt.o]=../../common/include/prov/composite.h +ENDIF \ No newline at end of file diff --git a/providers/implementations/keymgmt/composite_kmgmt.c b/providers/implementations/keymgmt/composite_kmgmt.c new file mode 100644 index 0000000000000..2a5fdd9171816 --- /dev/null +++ b/providers/implementations/keymgmt/composite_kmgmt.c @@ -0,0 +1,911 @@ +/* + * Copyright 2026 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "crypto/evp.h" +#include "crypto/ml_dsa.h" +#include "internal/param_build_set.h" +#include "prov/implementations.h" +#include "prov/providercommon.h" +#include "prov/provider_ctx.h" +#include "prov/ml_dsa.h" +#include "prov/composite.h" +#include "providers/implementations/keymgmt/composite_kmgmt.inc" + +/* + * Per-algorithm generation context. + * Allocated in composite_gen_init(), freed in composite_gen_cleanup(). + */ +typedef struct { + PROV_CTX *provctx; /* full provider context (not just libctx) */ + char *propq; + /* Algorithm-specific constants are passed directly to composite_gen() + * from the per-algorithm wrapper in MAKE_KEYMGMT_FUNCTIONS; they are + * compile-time literals and do not need to live in the context. */ +} COMPOSITE_GEN_CTX; + +/* Forward declarations of all static keymgmt functions */ +static OSSL_FUNC_keymgmt_free_fn composite_free_key; +static OSSL_FUNC_keymgmt_has_fn composite_has; +static OSSL_FUNC_keymgmt_match_fn composite_match; +static OSSL_FUNC_keymgmt_dup_fn composite_dup_key; +static OSSL_FUNC_keymgmt_validate_fn composite_validate; +static OSSL_FUNC_keymgmt_export_fn composite_export; +static OSSL_FUNC_keymgmt_import_types_fn composite_import_types; +static OSSL_FUNC_keymgmt_export_types_fn composite_export_types; +static OSSL_FUNC_keymgmt_gettable_params_fn composite_gettable_params; +static OSSL_FUNC_keymgmt_get_params_fn composite_get_params; +static OSSL_FUNC_keymgmt_load_fn composite_load; +static OSSL_FUNC_keymgmt_gen_init_fn composite_gen_init; +static OSSL_FUNC_keymgmt_gen_cleanup_fn composite_gen_cleanup; +static OSSL_FUNC_keymgmt_gen_set_params_fn composite_gen_set_params; +static OSSL_FUNC_keymgmt_gen_settable_params_fn composite_gen_settable_params; + +/* ========================================================================= + * Key management helpers + * ========================================================================= */ + +static COMPOSITE_KEY *ossl_composite_key_new(OSSL_LIB_CTX *libctx, + const char *propq, + int ml_dsa_evp_type) +{ + COMPOSITE_KEY *key = OPENSSL_zalloc(sizeof(*key)); + + if (key == NULL) + return NULL; + key->ml_dsa_key = ossl_ml_dsa_key_new(libctx, propq, ml_dsa_evp_type); + if (key->ml_dsa_key == NULL) { + OPENSSL_free(key); + return NULL; + } + return key; +} + +void ossl_composite_key_free(COMPOSITE_KEY *key) +{ + if (key == NULL) + return; + ossl_ml_dsa_key_free(key->ml_dsa_key); + EVP_PKEY_free(key->classic_key); + OPENSSL_free(key); +} + +static int ossl_composite_key_has(const COMPOSITE_KEY *key, int selection) +{ + if (!ossl_ml_dsa_key_has(key->ml_dsa_key, selection)) + return 0; + if (key->classic_key == NULL) + return 0; + return 1; +} + +/* + * Returns the combined public key length in bytes: ML-DSA pk_len plus the + * classic component public key size. Used to report OSSL_PKEY_PARAM_BITS. + */ +static size_t ossl_composite_key_get_pub_len(const COMPOSITE_KEY *key) +{ + size_t ml_dsa_len = ossl_ml_dsa_key_get_pub_len(key->ml_dsa_key); + + if (key->classic_key == NULL) + return ml_dsa_len; // if there is not classic key, composite is malformed + return ml_dsa_len + (size_t)((EVP_PKEY_get_bits(key->classic_key) + 7) / 8); +} + +/* + * Security bits of the composite = minimum of ML-DSA collision strength and + * the classic component's security bits. + */ +static int ossl_composite_key_get_security_bits(const COMPOSITE_KEY *key) +{ + size_t ml_dsa_sec = ossl_ml_dsa_key_get_collision_strength_bits(key->ml_dsa_key); + int classic_sec = (key->classic_key != NULL) + ? EVP_PKEY_get_security_bits(key->classic_key) + : 0; + + if (classic_sec <= 0) + return (int)ml_dsa_sec; + return (int)ml_dsa_sec < classic_sec ? (int)ml_dsa_sec : classic_sec; +} + +/* + * Maximum composite signature size: ML-DSA fixed sig_len plus the classic + * component's maximum signature size. + */ +static int ossl_composite_key_get_max_size(const COMPOSITE_KEY *key) +{ + size_t ml_dsa_sig = ossl_ml_dsa_key_get_sig_len(key->ml_dsa_key); + int classic_sig = (key->classic_key != NULL) + ? EVP_PKEY_get_size(key->classic_key) + : 0; + + return (int)ml_dsa_sig + (classic_sig > 0 ? classic_sig : 0); +} + +/* + * The composite public and private key bytes are not stored as a contiguous + * pre-assembled buffer inside COMPOSITE_KEY; use composite_export() for full + * serialization. These stubs let composite_get_params() skip the pub/priv + * params gracefully when the buffer is not available. + */ +static const uint8_t *ossl_composite_key_get_priv(const COMPOSITE_KEY *key, + size_t *len) +{ + *len = 0; + return NULL; +} + +static const uint8_t *ossl_composite_key_get_pub(const COMPOSITE_KEY *key, + size_t *len) +{ + *len = 0; + return NULL; +} + +COMPOSITE_KEY *ossl_prov_composite_new(PROV_CTX *ctx, const char *propq, + int ml_dsa_evp_type) +{ + if (!ossl_prov_is_running()) + return NULL; + + return ossl_composite_key_new(PROV_LIBCTX_OF(ctx), propq, ml_dsa_evp_type); +} + +static void composite_free_key(void *keydata) +{ + ossl_composite_key_free((COMPOSITE_KEY *)keydata); +} + +static int composite_has(const void *keydata, int selection) +{ + const COMPOSITE_KEY *key = keydata; + + if (!ossl_prov_is_running() || key == NULL) + return 0; + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0) + return 1; /* the selection is not missing */ + + return ossl_composite_key_has(key, selection); +} + +static void *composite_gen_init(void *provctx, int selection, + const OSSL_PARAM params[]) +{ + COMPOSITE_GEN_CTX *gctx = NULL; + + if (!ossl_prov_is_running()) + return NULL; + + if ((gctx = OPENSSL_zalloc(sizeof(*gctx))) != NULL) { + gctx->provctx = provctx; + if (!composite_gen_set_params(gctx, params)) { + OPENSSL_free(gctx); + gctx = NULL; + } + } + + return gctx; +} + +static void composite_gen_cleanup(void *genctx) +{ + COMPOSITE_GEN_CTX *gctx = genctx; + + if (gctx == NULL) + return; + + OPENSSL_free(gctx->propq); + OPENSSL_free(gctx); +} + +static const OSSL_PARAM *composite_gen_settable_params(void *genctx, + void *provctx) +{ + return composite_gen_set_params_list; +} + +static int composite_gen_set_params(void *genctx, const OSSL_PARAM params[]) +{ + COMPOSITE_GEN_CTX *gctx = genctx; + struct composite_gen_set_params_st p; + + if (gctx == NULL || !composite_gen_set_params_decoder(params, &p)) + return 0; + + if (p.propq != NULL) { + OPENSSL_free(gctx->propq); + gctx->propq = NULL; + if (!OSSL_PARAM_get_utf8_string(p.propq, &gctx->propq, 0)) + return 0; + } + return 1; +} + +static void *composite_gen(void *genctx, int evp_type, + const char *classic_alg, int classic_bits, + const char *ec_curve) +{ + COMPOSITE_GEN_CTX *gctx = genctx; + COMPOSITE_KEY *key = NULL; + EVP_PKEY_CTX *ctx = NULL; + + if (!ossl_prov_is_running()) + return NULL; + + key = ossl_prov_composite_new(gctx->provctx, gctx->propq, evp_type); + if (key == NULL) + return NULL; + + key->ml_dsa_key = ossl_prov_ml_dsa_new(gctx->provctx, gctx->propq, evp_type); + if (key->ml_dsa_key == NULL) + goto err; + + if (!ossl_ml_dsa_generate_key(key->ml_dsa_key)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GENERATE_KEY); + goto err; + } + + if (strcmp(classic_alg, "RSA") == 0) { + unsigned int rsa_bits = (unsigned int)classic_bits; + OSSL_PARAM rsa_params[2]; + + rsa_params[0] = OSSL_PARAM_construct_uint(OSSL_PKEY_PARAM_RSA_BITS, + &rsa_bits); + rsa_params[1] = OSSL_PARAM_construct_end(); + ctx = EVP_PKEY_CTX_new_from_name(PROV_LIBCTX_OF(gctx->provctx), + "RSA", gctx->propq); + if (ctx == NULL) + goto err; + if (EVP_PKEY_keygen_init(ctx) <= 0) + goto err; + if (EVP_PKEY_CTX_set_params(ctx, rsa_params) <= 0) + goto err; + if (EVP_PKEY_keygen(ctx, &key->classic_key) <= 0) + goto err; + } else if (strcmp(classic_alg, "EC") == 0) { + ctx = EVP_PKEY_CTX_new_from_name(PROV_LIBCTX_OF(gctx->provctx), + "EC", gctx->propq); + if (ctx == NULL) + goto err; + if (EVP_PKEY_keygen_init(ctx) <= 0) + goto err; + if (EVP_PKEY_CTX_set_group_name(ctx, ec_curve) <= 0) + goto err; + if (EVP_PKEY_keygen(ctx, &key->classic_key) <= 0) + goto err; + } else if (strcmp(classic_alg, "ED25519") == 0 + || strcmp(classic_alg, "ED448") == 0) { + ctx = EVP_PKEY_CTX_new_from_name(PROV_LIBCTX_OF(gctx->provctx), + classic_alg, gctx->propq); + if (ctx == NULL) + goto err; + if (EVP_PKEY_keygen_init(ctx) <= 0) + goto err; + if (EVP_PKEY_keygen(ctx, &key->classic_key) <= 0) + goto err; + } else { + ERR_raise_data(ERR_LIB_PROV, PROV_R_NOT_SUPPORTED, + "unsupported classic algorithm: %s", classic_alg); + goto err; + } + + EVP_PKEY_CTX_free(ctx); + return key; +err: + EVP_PKEY_CTX_free(ctx); + ossl_composite_key_free(key); + return NULL; +} + +static const OSSL_PARAM *composite_gettable_params(void *provctx) +{ + return composite_get_params_list; +} + +static int composite_get_params(void *keydata, OSSL_PARAM params[]) +{ + COMPOSITE_KEY *key = keydata; + const uint8_t *d; + size_t len; + struct composite_get_params_st p; + + if (key == NULL || !composite_get_params_decoder(params, &p)) + return 0; + + if (p.bits != NULL && !OSSL_PARAM_set_int(p.bits, (int)(8 * ossl_composite_key_get_pub_len(key)))) + return 0; + + if (p.secbits != NULL && !OSSL_PARAM_set_int(p.secbits, ossl_composite_key_get_security_bits(key))) + return 0; + + if (p.maxsize != NULL && !OSSL_PARAM_set_int(p.maxsize, ossl_composite_key_get_max_size(key))) + return 0; + + if (p.privkey != NULL) { + d = ossl_composite_key_get_priv(key, &len); + if (d != NULL && !OSSL_PARAM_set_octet_string(p.privkey, d, len)) + return 0; + } + + if (p.pubkey != NULL) { + d = ossl_composite_key_get_pub(key, &len); + if (d != NULL && !OSSL_PARAM_set_octet_string(p.pubkey, d, len)) + return 0; + } + + return 1; +} + +static int composite_validate(const void *keydata, int selection, + int check_type) +{ + const COMPOSITE_KEY *key = keydata; + + if (!composite_has(keydata, selection)) + return 0; + + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == OSSL_KEYMGMT_SELECT_KEYPAIR) { + if (!ossl_ml_dsa_key_pairwise_check(key->ml_dsa_key)) + return 0; + + if (key->classic_key == NULL || !evp_pkey_is_provided(key->classic_key)) + return 0; + return evp_keymgmt_validate(key->classic_key->keymgmt, + key->classic_key->keydata, + selection, check_type); + } + return 1; +} + +static const OSSL_PARAM *composite_import_types(int selection) +{ + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0) + return NULL; + return composite_import_params_list; +} + +static const OSSL_PARAM *composite_export_types(int selection) +{ + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0) + return NULL; + return composite_export_params_list; +} + +/* + * Decode the traditional sub-key from its raw wire format as defined in + * draft-ietf-lamps-pq-composite-sigs: + * + * RSA: RSAPublicKey DER (pub) / RSAPrivateKey DER (priv) — PKCS#1 + * EC: Uncompressed X9.62 point 0x04||x||y (pub) + * / ECPrivateKey DER with NamedCurve (priv) — RFC5915 + * Ed25519: raw 32 bytes + * Ed448: raw 57 bytes + */ +static EVP_PKEY *composite_decode_classic_key(OSSL_LIB_CTX *libctx, + const char *classic_alg, + const char *ec_curve, + int include_priv, + const unsigned char *buf, + size_t buf_len) +{ + EVP_PKEY *pkey = NULL; + const unsigned char *ptr; + size_t ptrlen; + OSSL_DECODER_CTX *dctx; + OSSL_PARAM params[3]; + EVP_PKEY_CTX *pctx; + + if (strcmp(classic_alg, "RSA") == 0) { + /* + * RSAPublicKey (pub) or RSAPrivateKey (priv) — PKCS#1 DER. + * The "type-specific" OSSL_DECODER structure handles both via + * d2i_RSAPublicKey / d2i_RSAPrivateKey. + */ + ptr = buf; + ptrlen = buf_len; + dctx = OSSL_DECODER_CTX_new_for_pkey( + &pkey, "DER", "type-specific", "RSA", + include_priv ? OSSL_KEYMGMT_SELECT_PRIVATE_KEY + : OSSL_KEYMGMT_SELECT_PUBLIC_KEY, + libctx, NULL); + if (dctx == NULL) + return NULL; + if (!OSSL_DECODER_from_data(dctx, &ptr, &ptrlen)) + pkey = NULL; + OSSL_DECODER_CTX_free(dctx); + } else if (strcmp(classic_alg, "EC") == 0) { + if (include_priv) { + /* + * ECPrivateKey DER (RFC5915) with embedded NamedCurve. + * The "type-specific" OSSL_DECODER for EC handles this via + * d2i_ECPrivateKey. + */ + ptr = buf; + ptrlen = buf_len; + dctx = OSSL_DECODER_CTX_new_for_pkey( + &pkey, "DER", "type-specific", "EC", + OSSL_KEYMGMT_SELECT_PRIVATE_KEY, + libctx, NULL); + if (dctx == NULL) + return NULL; + if (!OSSL_DECODER_from_data(dctx, &ptr, &ptrlen)) + pkey = NULL; + OSSL_DECODER_CTX_free(dctx); + } else { + /* + * Uncompressed X9.62 public key point: 0x04 || x || y. + * No DER wrapper — import directly via EVP_PKEY_fromdata with + * the curve name and raw point bytes. + */ + params[0] = OSSL_PARAM_construct_utf8_string( + OSSL_PKEY_PARAM_GROUP_NAME, (char *)ec_curve, 0); + params[1] = OSSL_PARAM_construct_octet_string( + OSSL_PKEY_PARAM_PUB_KEY, (void *)buf, buf_len); + params[2] = OSSL_PARAM_construct_end(); + + pctx = EVP_PKEY_CTX_new_from_name(libctx, "EC", NULL); + if (pctx == NULL) + return NULL; + if (EVP_PKEY_fromdata_init(pctx) <= 0 + || EVP_PKEY_fromdata(pctx, &pkey, + OSSL_KEYMGMT_SELECT_PUBLIC_KEY, + params) + <= 0) + pkey = NULL; + EVP_PKEY_CTX_free(pctx); + } + } else if (strcmp(classic_alg, "ED25519") == 0) { + /* Raw 32-byte public or private key per RFC8032 */ + if (include_priv) + pkey = EVP_PKEY_new_raw_private_key_ex(libctx, "ED25519", NULL, + buf, buf_len); + else + pkey = EVP_PKEY_new_raw_public_key_ex(libctx, "ED25519", NULL, + buf, buf_len); + } else if (strcmp(classic_alg, "ED448") == 0) { + /* Raw 57-byte public or private key per RFC8032 */ + if (include_priv) + pkey = EVP_PKEY_new_raw_private_key_ex(libctx, "ED448", NULL, + buf, buf_len); + else + pkey = EVP_PKEY_new_raw_public_key_ex(libctx, "ED448", NULL, + buf, buf_len); + } + + return pkey; +} + +/* + * Reconstruct a COMPOSITE_KEY from raw bytes in params[], using the wire + * format defined in draft-ietf-lamps-pq-composite-sigs: + * + * Public key: mldsaPK(fixed size) || tradPK(raw) + * Private key: mldsaSeed(32 bytes) || tradSK(raw) + * + * classic_alg: "RSA", "EC", "ED25519", or "ED448" + * ec_curve: curve name for EC (e.g. "P-256"), NULL for non-EC + */ +static int composite_import_internal(void *keydata, int selection, + const OSSL_PARAM params[], + const char *classic_alg, + const char *ec_curve) +{ + COMPOSITE_KEY *key = keydata; + const ML_DSA_PARAMS *kp; + const uint8_t *buf; + size_t buf_len, ml_dsa_len; + OSSL_LIB_CTX *libctx; + const char *pname; + const OSSL_PARAM *p; + int include_priv; + + if (!ossl_prov_is_running() || key == NULL) + return 0; + + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0) + return 0; + + include_priv = ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0); + kp = ossl_ml_dsa_key_params(key->ml_dsa_key); + libctx = ossl_ml_dsa_key_get0_libctx(key->ml_dsa_key); + + /* 1. Extract the combined octet string (ml_dsa_bytes || classic_bytes) */ + pname = include_priv ? OSSL_PKEY_PARAM_PRIV_KEY : OSSL_PKEY_PARAM_PUB_KEY; + p = OSSL_PARAM_locate_const(params, pname); + if (p == NULL + || !OSSL_PARAM_get_octet_string_ptr(p, (const void **)&buf, &buf_len)) + return 0; + + /* + * 2. Split at the ML-DSA boundary per the draft spec: + * - Private key: first ML_DSA_SEED_BYTES (32) bytes are the seed, + * NOT the expanded key (sk_len is 4032/3936/etc.). + * - Public key: first kp->pk_len bytes (1312/1952/2592). + */ + ml_dsa_len = include_priv ? ML_DSA_SEED_BYTES : kp->pk_len; + if (buf_len <= ml_dsa_len) + return 0; + + if (include_priv) { + /* + * Load the 32-byte seed and expand it into the full key pair. + * ossl_ml_dsa_set_prekey stores the seed; ossl_ml_dsa_generate_key + * derives rho, K, A, s1, s2, t0, t1 from it. + */ + if (!ossl_ml_dsa_set_prekey(key->ml_dsa_key, 0, 0, + buf, ML_DSA_SEED_BYTES, NULL, 0)) + return 0; + if (!ossl_ml_dsa_generate_key(key->ml_dsa_key)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GENERATE_KEY); + return 0; + } + } else { + if (!ossl_ml_dsa_pk_decode(key->ml_dsa_key, buf, ml_dsa_len)) + return 0; + } + + /* 3. Decode the classic portion from its raw wire format */ + key->classic_key = composite_decode_classic_key(libctx, + classic_alg, ec_curve, + include_priv, + buf + ml_dsa_len, + buf_len - ml_dsa_len); + return key->classic_key != NULL; +} + +/* + * Encode the traditional sub-key to its raw wire format per + * draft-ietf-lamps-pq-composite-sigs: + * + * RSA: RSAPublicKey DER (pub) / RSAPrivateKey DER (priv) — PKCS#1 + * EC: Uncompressed X9.62 point 0x04||x||y (pub) + * / ECPrivateKey DER (priv) — RFC5915 + * Ed25519: raw 32 bytes + * Ed448: raw 57 bytes + * + * On success, *out points to a newly-allocated buffer and *out_len holds its + * length. The caller must OPENSSL_free(*out) (or OPENSSL_clear_free for priv). + */ +static int composite_encode_classic_key(const EVP_PKEY *pkey, + int include_priv, + unsigned char **out, + size_t *out_len) +{ + int keytype = EVP_PKEY_get_base_id(pkey); + OSSL_ENCODER_CTX *ectx; + size_t len; + + *out = NULL; + *out_len = 0; + + if (keytype == EVP_PKEY_RSA) { + /* + * RSAPublicKey (pub) or RSAPrivateKey (priv) — PKCS#1 DER. + * OSSL_ENCODER "type-specific" uses i2d_RSAPublicKey / i2d_RSAPrivateKey. + */ + ectx = OSSL_ENCODER_CTX_new_for_pkey( + pkey, + include_priv ? OSSL_KEYMGMT_SELECT_PRIVATE_KEY + : OSSL_KEYMGMT_SELECT_PUBLIC_KEY, + "DER", "type-specific", NULL); + if (ectx == NULL) + return 0; + if (!OSSL_ENCODER_to_data(ectx, out, out_len)) + *out = NULL; + OSSL_ENCODER_CTX_free(ectx); + } else if (keytype == EVP_PKEY_EC) { + if (include_priv) { + /* + * ECPrivateKey DER (RFC5915) with NamedCurve. + * OSSL_ENCODER "type-specific" uses i2d_ECPrivateKey. + */ + ectx = OSSL_ENCODER_CTX_new_for_pkey( + pkey, + OSSL_KEYMGMT_SELECT_PRIVATE_KEY, + "DER", "type-specific", NULL); + if (ectx == NULL) + return 0; + if (!OSSL_ENCODER_to_data(ectx, out, out_len)) + *out = NULL; + OSSL_ENCODER_CTX_free(ectx); + } else { + /* + * Uncompressed X9.62 point: 0x04 || x || y. + * OSSL_PKEY_PARAM_PUB_KEY returns the point in uncompressed form. + * (There is no "type-specific" EC public encoder.) + */ + if (!EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, + NULL, 0, &len)) + return 0; + *out = OPENSSL_malloc(len); + if (*out == NULL) + return 0; + if (!EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, + *out, len, out_len)) { + OPENSSL_free(*out); + *out = NULL; + } + } + } else if (keytype == EVP_PKEY_ED25519 || keytype == EVP_PKEY_ED448) { + /* Raw 32-byte (Ed25519) or 57-byte (Ed448) key per RFC8032 */ + if (include_priv) { + if (!EVP_PKEY_get_raw_private_key(pkey, NULL, &len)) + return 0; + *out = OPENSSL_malloc(len); + if (*out == NULL) + return 0; + if (!EVP_PKEY_get_raw_private_key(pkey, *out, &len)) { + OPENSSL_free(*out); + *out = NULL; + } else { + *out_len = len; + } + } else { + if (!EVP_PKEY_get_raw_public_key(pkey, NULL, &len)) + return 0; + *out = OPENSSL_malloc(len); + if (*out == NULL) + return 0; + if (!EVP_PKEY_get_raw_public_key(pkey, *out, &len)) { + OPENSSL_free(*out); + *out = NULL; + } else { + *out_len = len; + } + } + } else { + return 0; + } + + return *out != NULL; +} + +/* + * composite_export: + * Serialize both sub-keys into the caller's OSSL_PARAM array. + * Wire format per draft-ietf-lamps-pq-composite-sigs: + * Public key: mldsaPK(pk_len bytes) || tradPK(raw) + * Private key: mldsaSeed(32 bytes) || tradSK(raw) + */ +static int composite_export(void *keydata, int selection, + OSSL_CALLBACK *param_cb, void *cbarg) +{ + COMPOSITE_KEY *key = keydata; + const ML_DSA_PARAMS *kp; + const uint8_t *ml_dsa_bytes; + unsigned char *priv_buf = NULL, *pub_buf = NULL; + unsigned char *classic_priv = NULL, *classic_pub = NULL; + size_t classic_priv_len = 0, classic_pub_len = 0; + size_t priv_len = 0, pub_len = 0; + OSSL_PARAM params[3]; + int include_priv, pnum = 0, ret = 0; + + if (!ossl_prov_is_running() || key == NULL) + return 0; + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0) + return 0; + if (!composite_has(keydata, selection)) + return 0; + + kp = ossl_ml_dsa_key_params(key->ml_dsa_key); + include_priv = ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0); + + /* ---- Private key: mldsaSeed(32) || tradSK(raw) ---- */ + if (include_priv) { + ml_dsa_bytes = ossl_ml_dsa_key_get_seed(key->ml_dsa_key); + if (ml_dsa_bytes == NULL) + goto done; /* seed required; key was not loaded from seed */ + if (!composite_encode_classic_key(key->classic_key, 1, + &classic_priv, &classic_priv_len)) + goto done; + priv_len = ML_DSA_SEED_BYTES + classic_priv_len; + priv_buf = OPENSSL_secure_malloc(priv_len); + if (priv_buf == NULL) + goto done; + memcpy(priv_buf, ml_dsa_bytes, ML_DSA_SEED_BYTES); + memcpy(priv_buf + ML_DSA_SEED_BYTES, classic_priv, classic_priv_len); + params[pnum++] = OSSL_PARAM_construct_octet_string( + OSSL_PKEY_PARAM_PRIV_KEY, priv_buf, priv_len); + } + + /* ---- Public key: mldsaPK(pk_len) || tradPK(raw) ---- */ + if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) { + ml_dsa_bytes = ossl_ml_dsa_key_get_pub(key->ml_dsa_key); + if (ml_dsa_bytes == NULL) + goto done; + if (!composite_encode_classic_key(key->classic_key, 0, + &classic_pub, &classic_pub_len)) + goto done; + pub_len = kp->pk_len + classic_pub_len; + pub_buf = OPENSSL_malloc(pub_len); + if (pub_buf == NULL) + goto done; + memcpy(pub_buf, ml_dsa_bytes, kp->pk_len); + memcpy(pub_buf + kp->pk_len, classic_pub, classic_pub_len); + params[pnum++] = OSSL_PARAM_construct_octet_string( + OSSL_PKEY_PARAM_PUB_KEY, pub_buf, pub_len); + } + + if (pnum == 0) + goto done; + params[pnum] = OSSL_PARAM_construct_end(); + ret = param_cb(params, cbarg); + +done: + if (priv_buf != NULL) + OPENSSL_secure_clear_free(priv_buf, priv_len); + if (classic_priv != NULL) + OPENSSL_clear_free(classic_priv, classic_priv_len); + OPENSSL_free(pub_buf); + OPENSSL_free(classic_pub); + return ret; +} + +static void *composite_dup_key(const void *keydata_from, int selection) +{ + const COMPOSITE_KEY *src = keydata_from; + COMPOSITE_KEY *key; + + if (!ossl_prov_is_running() || src == NULL) + return NULL; + + key = OPENSSL_zalloc(sizeof(*key)); + if (key == NULL) + return NULL; + + key->ml_dsa_key = ossl_ml_dsa_key_dup(src->ml_dsa_key, selection); + if (key->ml_dsa_key == NULL) + goto err; + + key->classic_key = EVP_PKEY_dup(src->classic_key); + if (key->classic_key == NULL) + goto err; + + return key; +err: + ossl_ml_dsa_key_free(key->ml_dsa_key); + OPENSSL_free(key); + return NULL; +} + +static int composite_match(const void *keydata1, const void *keydata2, + int selection) +{ + const COMPOSITE_KEY *key1 = keydata1; + const COMPOSITE_KEY *key2 = keydata2; + + if (!ossl_prov_is_running()) + return 0; + if (key1 == NULL || key2 == NULL) + return 0; + if (!ossl_ml_dsa_key_equal(key1->ml_dsa_key, key2->ml_dsa_key, selection)) + return 0; + if (!EVP_PKEY_eq(key1->classic_key, key2->classic_key)) + return 0; + return 1; +} + +static void *composite_load(const void *reference, size_t reference_sz) +{ + COMPOSITE_KEY *key = NULL; + const uint8_t *seed; + + if (!ossl_prov_is_running() || reference == NULL + || reference_sz != sizeof(key)) + return NULL; + + /* The contents of the reference is the address to our object */ + key = *(COMPOSITE_KEY **)reference; + /* We grabbed, so we detach it */ + *(COMPOSITE_KEY **)reference = NULL; + + if (key == NULL) + return NULL; + + /* + * Classic half must be a fully-loaded, provider-side key. + * Unlike ML-DSA there is no "prekey" mechanism for EVP_PKEY — + * the classic component must already be complete in the reference. + */ + if (key->classic_key == NULL || !evp_pkey_is_provided(key->classic_key)) + goto err; + + /* All done if the ML-DSA public key is already present. */ + if (ossl_ml_dsa_key_get_pub(key->ml_dsa_key) != NULL) + return key; + + /* + * Handle ML-DSA prekey: composite wire format stores only the 32-byte + * seed (never the expanded sk), so the only valid prekey state here is + * seed-present. Expand it to derive the full key pair. + */ + seed = ossl_ml_dsa_key_get_seed(key->ml_dsa_key); + if (seed != NULL) { + if (ossl_ml_dsa_generate_key(key->ml_dsa_key)) + return key; + } else { + /* No pub and no seed: public-key-only reference, return as-is. */ + return key; + } + +err: + ossl_ml_dsa_key_free(key->ml_dsa_key); + EVP_PKEY_free(key->classic_key); + OPENSSL_free(key); + return NULL; +} + +#define MAKE_KEYMGMT_FUNCTIONS(alg, ml_dsa_evp_type, classic_alg_, classic_bits_, ec_curve_) \ + static OSSL_FUNC_keymgmt_new_fn composite_##alg##_new_key; \ + static OSSL_FUNC_keymgmt_gen_fn composite_##alg##_gen; \ + static OSSL_FUNC_keymgmt_import_fn composite_##alg##_import; \ + static void *composite_##alg##_new_key(void *provctx) \ + { \ + return ossl_prov_composite_new(provctx, NULL, ml_dsa_evp_type); \ + } \ + static void *composite_##alg##_gen(void *genctx, \ + OSSL_CALLBACK *osslcb, void *cbarg) \ + { \ + return composite_gen(genctx, ml_dsa_evp_type, \ + classic_alg_, classic_bits_, ec_curve_); \ + } \ + static int composite_##alg##_import(void *keydata, int selection, \ + const OSSL_PARAM params[]) \ + { \ + return composite_import_internal(keydata, selection, params, \ + classic_alg_, ec_curve_); \ + } \ + const OSSL_DISPATCH ossl_##alg##_keymgmt_functions[] = { \ + { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))composite_##alg##_new_key }, \ + { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))composite_free_key }, \ + { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))composite_has }, \ + { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))composite_match }, \ + { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))composite_##alg##_import }, \ + { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))composite_import_types }, \ + { OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))composite_export }, \ + { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))composite_export_types }, \ + { OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))composite_load }, \ + { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*)(void))composite_get_params }, \ + { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*)(void))composite_gettable_params }, \ + { OSSL_FUNC_KEYMGMT_VALIDATE, (void (*)(void))composite_validate }, \ + { OSSL_FUNC_KEYMGMT_GEN_INIT, (void (*)(void))composite_gen_init }, \ + { OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))composite_##alg##_gen }, \ + { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (void (*)(void))composite_gen_cleanup }, \ + { OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS, (void (*)(void))composite_gen_set_params }, \ + { OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS, (void (*)(void))composite_gen_settable_params }, \ + { OSSL_FUNC_KEYMGMT_DUP, (void (*)(void))composite_dup_key }, \ + OSSL_DISPATCH_END \ + } + +/* alg ml_dsa_evp_type classic_alg bits ec_curve */ +MAKE_KEYMGMT_FUNCTIONS(mldsa44_rsa2048_pss_sha256, EVP_PKEY_ML_DSA_44, "RSA", 2048, NULL); +MAKE_KEYMGMT_FUNCTIONS(mldsa44_rsa2048_pkcs15_sha256, EVP_PKEY_ML_DSA_44, "RSA", 2048, NULL); +MAKE_KEYMGMT_FUNCTIONS(mldsa44_ed25519_sha512, EVP_PKEY_ML_DSA_44, "ED25519", 0, NULL); +MAKE_KEYMGMT_FUNCTIONS(mldsa44_ecdsa_p256_sha256, EVP_PKEY_ML_DSA_44, "EC", 256, "P-256"); +MAKE_KEYMGMT_FUNCTIONS(mldsa65_rsa3072_pss_sha512, EVP_PKEY_ML_DSA_65, "RSA", 3072, NULL); +MAKE_KEYMGMT_FUNCTIONS(mldsa65_rsa3072_pkcs15_sha512, EVP_PKEY_ML_DSA_65, "RSA", 3072, NULL); +MAKE_KEYMGMT_FUNCTIONS(mldsa65_rsa4096_pss_sha512, EVP_PKEY_ML_DSA_65, "RSA", 4096, NULL); +MAKE_KEYMGMT_FUNCTIONS(mldsa65_rsa4096_pkcs15_sha512, EVP_PKEY_ML_DSA_65, "RSA", 4096, NULL); +MAKE_KEYMGMT_FUNCTIONS(mldsa65_ecdsa_p256_sha512, EVP_PKEY_ML_DSA_65, "EC", 256, "P-256"); +MAKE_KEYMGMT_FUNCTIONS(mldsa65_ecdsa_p384_sha512, EVP_PKEY_ML_DSA_65, "EC", 384, "P-384"); +MAKE_KEYMGMT_FUNCTIONS(mldsa65_ecdsa_brainpoolP256r1_sha512, EVP_PKEY_ML_DSA_65, "EC", 256, "brainpoolP256r1"); +MAKE_KEYMGMT_FUNCTIONS(mldsa65_ed25519_sha512, EVP_PKEY_ML_DSA_65, "ED25519", 0, NULL); +MAKE_KEYMGMT_FUNCTIONS(mldsa87_ecdsa_p384_sha512, EVP_PKEY_ML_DSA_87, "EC", 384, "P-384"); +MAKE_KEYMGMT_FUNCTIONS(mldsa87_ecdsa_brainpoolP384r1_sha512, EVP_PKEY_ML_DSA_87, "EC", 384, "brainpoolP384r1"); +MAKE_KEYMGMT_FUNCTIONS(mldsa87_ed448_shake256, EVP_PKEY_ML_DSA_87, "ED448", 0, NULL); +MAKE_KEYMGMT_FUNCTIONS(mldsa87_rsa3072_pss_sha512, EVP_PKEY_ML_DSA_87, "RSA", 3072, NULL); +MAKE_KEYMGMT_FUNCTIONS(mldsa87_rsa4096_pss_sha512, EVP_PKEY_ML_DSA_87, "RSA", 4096, NULL); +MAKE_KEYMGMT_FUNCTIONS(mldsa87_ecdsa_p521_sha512, EVP_PKEY_ML_DSA_87, "EC", 521, "P-521"); diff --git a/providers/implementations/keymgmt/composite_kmgmt.inc.in b/providers/implementations/keymgmt/composite_kmgmt.inc.in new file mode 100644 index 0000000000000..6c91cd5f04bcd --- /dev/null +++ b/providers/implementations/keymgmt/composite_kmgmt.inc.in @@ -0,0 +1,51 @@ +/* + * Copyright 2025 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +{- +use OpenSSL::paramnames qw(produce_param_decoder); +-} + +/* + * composite_import_params: only the list and struct are needed. + * Params are parsed manually in composite_import_internal() via + * OSSL_PARAM_locate_const(), so the generated decoder is omitted. + */ +#ifndef composite_import_params_list +static const OSSL_PARAM composite_import_params_list[] = { + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0), + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_END +}; +#endif + +/* + * composite_export_params: only the list is needed. + * Params are assembled manually in composite_export(), so the generated + * decoder is omitted. + */ +#ifndef composite_export_params_list +static const OSSL_PARAM composite_export_params_list[] = { + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0), + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0), + OSSL_PARAM_END +}; +#endif + +{- produce_param_decoder('composite_get_params', + (['OSSL_PKEY_PARAM_BITS', 'bits', 'int'], + ['OSSL_PKEY_PARAM_SECURITY_BITS', 'secbits', 'int'], + ['OSSL_PKEY_PARAM_MAX_SIZE', 'maxsize', 'int'], + ['OSSL_PKEY_PARAM_PUB_KEY', 'pubkey', 'octet_string'], + ['OSSL_PKEY_PARAM_PRIV_KEY', 'privkey', 'octet_string'], + )); -} + +{- produce_param_decoder('composite_gen_set_params', + (['OSSL_PKEY_PARAM_PROPERTIES', 'propq', 'utf8_string'], + )); -} diff --git a/providers/implementations/signature/build.info b/providers/implementations/signature/build.info index 579045f2c58a2..180b49806bfe7 100644 --- a/providers/implementations/signature/build.info +++ b/providers/implementations/signature/build.info @@ -9,6 +9,7 @@ $SM2_GOAL=../../libdefault.a $LMS_GOAL=../../libdefault.a ../../libfips.a $ML_DSA_GOAL=../../libdefault.a ../../libfips.a $SLH_DSA_GOAL=../../libdefault.a ../../libfips.a +$COMPOSITE_GOAL=../../libdefault.a IF[{- !$disabled{dsa} -}] SOURCE[$DSA_GOAL]=dsa_sig.c @@ -48,3 +49,8 @@ ENDIF IF[{- !$disabled{'slh-dsa'} -}] SOURCE[$DSA_GOAL]=slh_dsa_sig.c ENDIF + +IF[{- !$disabled{'ml-dsa'} -}] + SOURCE[$COMPOSITE_GOAL]=composite_sig.c + DEPEND[composite_sig.o]=../../common/include/prov/composite.h +ENDIF \ No newline at end of file diff --git a/providers/implementations/signature/composite_sig.c b/providers/implementations/signature/composite_sig.c new file mode 100644 index 0000000000000..ce1e1e462f958 --- /dev/null +++ b/providers/implementations/signature/composite_sig.c @@ -0,0 +1,784 @@ +/* + * Copyright 2026 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "internal/deprecated.h" + +#include +#include +#include +#include +#include "crypto/evp.h" +#include "crypto/ml_dsa.h" +#include "prov/implementations.h" +#include "prov/provider_ctx.h" +#include "prov/providercommon.h" +#include "prov/composite.h" +#include "prov/names.h" +#include "providers/implementations/signature/composite_sig.inc" +#include +#include +#include + +/* + * Fixed 32-byte domain separation prefix per draft-ietf-lamps-pq-composite-sigs. + * Byte encoding of the ASCII string "CompositeAlgorithmSignatures2025": + * 436F6D706F73697465416C676F726974686D5369676E61747572657332303235 + */ +static const uint8_t composite_sig_prefix[32] = { + 0x43, 0x6F, 0x6D, 0x70, 0x6F, 0x73, 0x69, 0x74, /* Composit */ // codespell:ignore + 0x65, 0x41, 0x6C, 0x67, 0x6F, 0x72, 0x69, 0x74, /* eAlgorit */ + 0x68, 0x6D, 0x53, 0x69, 0x67, 0x6E, 0x61, 0x74, /* hmSignat */ + 0x75, 0x72, 0x65, 0x73, 0x32, 0x30, 0x32, 0x35 /* ures2025 */ +}; + +static OSSL_FUNC_signature_sign_fn composite_sign; + +static void *composite_newctx(void *provctx, int evp_type, const char *propq) +{ + PROV_COMPOSITE_CTX *ctx; + + if (!ossl_prov_is_running()) + return NULL; + + ctx = OPENSSL_zalloc(sizeof(PROV_COMPOSITE_CTX)); + if (ctx == NULL) + return NULL; + + ctx->libctx = PROV_LIBCTX_OF(provctx); + return ctx; +} + +typedef enum { + COMPOSITE_CLASSIC_RSA_PSS, + COMPOSITE_CLASSIC_RSA_PKCS15, + COMPOSITE_CLASSIC_ECDSA, + COMPOSITE_CLASSIC_ED25519, + COMPOSITE_CLASSIC_ED448 +} COMPOSITE_CLASSIC_TYPE; + +typedef struct { + const char *name; + const char *label; /* ASCII label for M' and ML-DSA ctx per draft §6 */ + const unsigned char *oid; + size_t oid_sz; + const char *prehash_alg; /* hash for composite PH(M) only */ + size_t prehash_len; /* prehash output length in bytes */ + const char *classic_hash; /* hash for traditional component signing (may differ + * from prehash_alg per draft-ietf-lamps-pq-composite-sigs §6); + * NULL for EdDSA (no digest arg needed) */ + COMPOSITE_CLASSIC_TYPE classic_type; + int pss_salt_len; /* RSA-PSS only; 0 otherwise */ + const char *mgf1_hash; /* RSA-PSS MGF1 hash; NULL = same as classic_hash */ +} COMPOSITE_ALG_INFO; + +/* + * prehash_alg: hash used for the composite PH(M) step. + * classic_hash: hash used by the traditional component signature algorithm, + * which may differ from prehash_alg per draft-ietf-lamps-pq-composite-sigs §6; + * NULL for EdDSA variants (no digest argument). + * mgf1_hash: RSA-PSS MGF1 hash override; NULL = same as classic_hash. + */ +static const COMPOSITE_ALG_INFO composite_alg_table[] = { + /* name, label, oid, oid_sz, prehash, phlen, classic_hash, + classic_type, pss_salt_len, mgf1_hash */ + { "ML-DSA-44-RSA2048-PSS-SHA256", + "COMPSIG-MLDSA44-RSA2048-PSS-SHA256", + ossl_der_oid_id_mldsa44_rsa2048_pss_sha256, + DER_OID_SZ_id_mldsa44_rsa2048_pss_sha256, + "SHA-256", 32, "SHA-256", COMPOSITE_CLASSIC_RSA_PSS, 32, NULL }, + { "ML-DSA-44-RSA2048-PKCS15-SHA256", + "COMPSIG-MLDSA44-RSA2048-PKCS15-SHA256", + ossl_der_oid_id_mldsa44_rsa2048_pkcs15_sha256, + DER_OID_SZ_id_mldsa44_rsa2048_pkcs15_sha256, + "SHA-256", 32, "SHA-256", COMPOSITE_CLASSIC_RSA_PKCS15, 0, NULL }, + { "ML-DSA-44-Ed25519-SHA512", + "COMPSIG-MLDSA44-Ed25519-SHA512", + ossl_der_oid_id_mldsa44_ed25519_sha512, + DER_OID_SZ_id_mldsa44_ed25519_sha512, + "SHA-512", 64, NULL, COMPOSITE_CLASSIC_ED25519, 0, NULL }, + { "ML-DSA-44-ECDSA-P256-SHA256", + "COMPSIG-MLDSA44-ECDSA-P256-SHA256", + ossl_der_oid_id_mldsa44_ecdsa_p256_sha256, + DER_OID_SZ_id_mldsa44_ecdsa_p256_sha256, + "SHA-256", 32, "SHA-256", COMPOSITE_CLASSIC_ECDSA, 0, NULL }, + { "ML-DSA-65-RSA3072-PSS-SHA512", + "COMPSIG-MLDSA65-RSA3072-PSS-SHA512", + ossl_der_oid_id_mldsa65_rsa3072_pss_sha512, + DER_OID_SZ_id_mldsa65_rsa3072_pss_sha512, + "SHA-512", 64, "SHA-256", COMPOSITE_CLASSIC_RSA_PSS, 32, NULL }, + { "ML-DSA-65-RSA3072-PKCS15-SHA512", /* sha256WithRSAEncryption */ + "COMPSIG-MLDSA65-RSA3072-PKCS15-SHA512", + ossl_der_oid_id_mldsa65_rsa3072_pkcs15_sha512, + DER_OID_SZ_id_mldsa65_rsa3072_pkcs15_sha512, + "SHA-512", 64, "SHA-256", COMPOSITE_CLASSIC_RSA_PKCS15, 0, NULL }, + { "ML-DSA-65-RSA4096-PSS-SHA512", + "COMPSIG-MLDSA65-RSA4096-PSS-SHA512", + ossl_der_oid_id_mldsa65_rsa4096_pss_sha512, + DER_OID_SZ_id_mldsa65_rsa4096_pss_sha512, + "SHA-512", 64, "SHA-384", COMPOSITE_CLASSIC_RSA_PSS, 48, NULL }, + { "ML-DSA-65-RSA4096-PKCS15-SHA512", /* sha384WithRSAEncryption */ + "COMPSIG-MLDSA65-RSA4096-PKCS15-SHA512", + ossl_der_oid_id_mldsa65_rsa4096_pkcs15_sha512, + DER_OID_SZ_id_mldsa65_rsa4096_pkcs15_sha512, + "SHA-512", 64, "SHA-384", COMPOSITE_CLASSIC_RSA_PKCS15, 0, NULL }, + { "ML-DSA-65-ECDSA-P256-SHA512", /* ecdsa-with-SHA256 */ + "COMPSIG-MLDSA65-ECDSA-P256-SHA512", + ossl_der_oid_id_mldsa65_ecdsa_p256_sha512, + DER_OID_SZ_id_mldsa65_ecdsa_p256_sha512, + "SHA-512", 64, "SHA-256", COMPOSITE_CLASSIC_ECDSA, 0, NULL }, + { "ML-DSA-65-ECDSA-P384-SHA512", /* ecdsa-with-SHA384 */ + "COMPSIG-MLDSA65-ECDSA-P384-SHA512", + ossl_der_oid_id_mldsa65_ecdsa_p384_sha512, + DER_OID_SZ_id_mldsa65_ecdsa_p384_sha512, + "SHA-512", 64, "SHA-384", COMPOSITE_CLASSIC_ECDSA, 0, NULL }, + { "ML-DSA-65-ECDSA-brainpoolP256r1-SHA512", /* ecdsa-with-SHA256 */ + "COMPSIG-MLDSA65-ECDSA-BP256-SHA512", + ossl_der_oid_id_mldsa65_ecdsa_brainpoolP256r1_sha512, + DER_OID_SZ_id_mldsa65_ecdsa_brainpoolP256r1_sha512, + "SHA-512", 64, "SHA-256", COMPOSITE_CLASSIC_ECDSA, 0, NULL }, + { "ML-DSA-65-Ed25519-SHA512", + "COMPSIG-MLDSA65-Ed25519-SHA512", + ossl_der_oid_id_mldsa65_ed25519_sha512, + DER_OID_SZ_id_mldsa65_ed25519_sha512, + "SHA-512", 64, NULL, COMPOSITE_CLASSIC_ED25519, 0, NULL }, + { "ML-DSA-87-ECDSA-P384-SHA512", /* ecdsa-with-SHA384 */ + "COMPSIG-MLDSA87-ECDSA-P384-SHA512", + ossl_der_oid_id_mldsa87_ecdsa_p384_sha512, + DER_OID_SZ_id_mldsa87_ecdsa_p384_sha512, + "SHA-512", 64, "SHA-384", COMPOSITE_CLASSIC_ECDSA, 0, NULL }, + { "ML-DSA-87-ECDSA-brainpoolP384r1-SHA512", /* ecdsa-with-SHA384 */ + "COMPSIG-MLDSA87-ECDSA-BP384-SHA512", + ossl_der_oid_id_mldsa87_ecdsa_brainpoolp384r1_sha512, + DER_OID_SZ_id_mldsa87_ecdsa_brainpoolp384r1_sha512, + "SHA-512", 64, "SHA-384", COMPOSITE_CLASSIC_ECDSA, 0, NULL }, + { "ML-DSA-87-Ed448-SHAKE256", + "COMPSIG-MLDSA87-Ed448-SHAKE256", + ossl_der_oid_id_mldsa87_ed448_shake256, + DER_OID_SZ_id_mldsa87_ed448_shake256, + "SHAKE256", 64, NULL, COMPOSITE_CLASSIC_ED448, 0, NULL }, + { "ML-DSA-87-RSA3072-PSS-SHA512", + "COMPSIG-MLDSA87-RSA3072-PSS-SHA512", + ossl_der_oid_id_mldsa87_rsa3072_pss_sha512, + DER_OID_SZ_id_mldsa87_rsa3072_pss_sha512, + "SHA-512", 64, "SHA-256", COMPOSITE_CLASSIC_RSA_PSS, 32, NULL }, + { "ML-DSA-87-RSA4096-PSS-SHA512", + "COMPSIG-MLDSA87-RSA4096-PSS-SHA512", + ossl_der_oid_id_mldsa87_rsa4096_pss_sha512, + DER_OID_SZ_id_mldsa87_rsa4096_pss_sha512, + "SHA-512", 64, "SHA-384", COMPOSITE_CLASSIC_RSA_PSS, 48, NULL }, + { "ML-DSA-87-ECDSA-P521-SHA512", /* ecdsa-with-SHA512 */ + "COMPSIG-MLDSA87-ECDSA-P521-SHA512", + ossl_der_oid_id_mldsa87_ecdsa_p521_sha512, + DER_OID_SZ_id_mldsa87_ecdsa_p521_sha512, + "SHA-512", 64, "SHA-512", COMPOSITE_CLASSIC_ECDSA, 0, NULL }, +}; +#define COMPOSITE_NUM_ALGS \ + (sizeof(composite_alg_table) / sizeof(composite_alg_table[0])) + +static const COMPOSITE_ALG_INFO *composite_find_alg_info(const char *name) +{ + size_t i; + + if (name == NULL) + return NULL; + for (i = 0; i < COMPOSITE_NUM_ALGS; i++) { + if (OPENSSL_strcasecmp(name, composite_alg_table[i].name) == 0) + return &composite_alg_table[i]; + } + return NULL; +} + +/* + * Compute PH(M) for M' construction. Handles both regular digests and the + * SHAKE256 XOF used by ML-DSA-87-Ed448-SHAKE256. + */ +static int composite_compute_prehash(OSSL_LIB_CTX *libctx, + const COMPOSITE_ALG_INFO *info, + const uint8_t *msg, size_t msg_len, + uint8_t *out) +{ + if (OPENSSL_strcasecmp(info->prehash_alg, "SHAKE256") == 0) { + EVP_MD_CTX *mctx = EVP_MD_CTX_new(); + EVP_MD *md = EVP_MD_fetch(libctx, "SHAKE256", NULL); + int ok = (mctx != NULL && md != NULL + && EVP_DigestInit_ex(mctx, md, NULL) + && EVP_DigestUpdate(mctx, msg, msg_len) + && EVP_DigestFinalXOF(mctx, out, info->prehash_len)); + EVP_MD_CTX_free(mctx); + EVP_MD_free(md); + return ok; + } + return EVP_Q_digest(libctx, info->prehash_alg, NULL, msg, msg_len, out, NULL); +} + +/* + * Sign tbs/tbs_len with the traditional (non-ML-DSA) component key. + */ +static int composite_classic_sign(PROV_COMPOSITE_CTX *ctx, + const COMPOSITE_ALG_INFO *info, + const uint8_t *tbs, size_t tbs_len, + uint8_t *sig, size_t *siglen) +{ + EVP_MD_CTX *md_ctx = EVP_MD_CTX_new(); + EVP_PKEY_CTX *pctx = NULL; + int ret = 0; + + if (md_ctx == NULL) + return 0; + + switch (info->classic_type) { + case COMPOSITE_CLASSIC_ED25519: + case COMPOSITE_CLASSIC_ED448: + /* Pure EdDSA: no external digest */ + if (!EVP_DigestSignInit_ex(md_ctx, NULL, NULL, + ctx->libctx, NULL, + ctx->key->classic_key, NULL)) + goto err; + break; + + case COMPOSITE_CLASSIC_ECDSA: + if (!EVP_DigestSignInit_ex(md_ctx, NULL, info->classic_hash, + ctx->libctx, NULL, + ctx->key->classic_key, NULL)) + goto err; + break; + + case COMPOSITE_CLASSIC_RSA_PSS: + if (!EVP_DigestSignInit_ex(md_ctx, &pctx, info->classic_hash, + ctx->libctx, NULL, + ctx->key->classic_key, NULL)) + goto err; + { + const char *mgf1 = (info->mgf1_hash != NULL) + ? info->mgf1_hash + : info->classic_hash; + if (EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) <= 0 + || EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, info->pss_salt_len) <= 0 + || EVP_PKEY_CTX_set_rsa_mgf1_md_name(pctx, mgf1, NULL) <= 0) + goto err; + } + break; + + case COMPOSITE_CLASSIC_RSA_PKCS15: + if (!EVP_DigestSignInit_ex(md_ctx, &pctx, info->classic_hash, + ctx->libctx, NULL, + ctx->key->classic_key, NULL)) + goto err; + if (EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PADDING) <= 0) + goto err; + break; + + default: + ERR_raise(ERR_LIB_PROV, ERR_R_UNSUPPORTED); + goto err; + } + + if (!EVP_DigestSign(md_ctx, sig, siglen, tbs, tbs_len)) + goto err; + + ret = 1; +err: + EVP_MD_CTX_free(md_ctx); + return ret; +} + +static int composite_sign(void *vctx, uint8_t *sig, size_t *siglen, size_t sigsize, + const uint8_t *msg, size_t msg_len) +{ + PROV_COMPOSITE_CTX *ctx = (PROV_COMPOSITE_CTX *)vctx; + const COMPOSITE_ALG_INFO *info; + uint8_t *tbs = NULL; + uint8_t prehash[64]; /* max prehash output size */ + size_t tbs_len = 0; + size_t offset; + uint8_t rnd[32]; + size_t ml_dsa_siglen, classic_siglen, ml_dsa_sig_max; + int ret = 0; + + if (!ossl_prov_is_running()) + return 0; + + if (ctx->key == NULL || ctx->alg == NULL) + return 0; + + info = composite_find_alg_info(ctx->alg); + if (info == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_UNSUPPORTED); + return 0; + } + + ml_dsa_sig_max = ossl_ml_dsa_key_get_sig_len(ctx->key->ml_dsa_key); + + /* Size query */ + if (sig == NULL) { + *siglen = ml_dsa_sig_max + + (size_t)EVP_PKEY_get_size(ctx->key->classic_key); + return 1; + } + + /* Compute PH(M) */ + if (!composite_compute_prehash(ctx->libctx, info, msg, msg_len, prehash)) + goto err; + + /* + * Build M' = Prefix(32) || Label || uint8(ctx_len) || ctx || PH(M) + * per draft-ietf-lamps-pq-composite-sigs §2.2. + * Label is the ASCII string from §6, e.g. "COMPSIG-MLDSA44-RSA2048-PSS-SHA256". + */ + tbs_len = 32 + strlen(info->label) + 1 + ctx->context_string_len + info->prehash_len; + tbs = OPENSSL_malloc(tbs_len); + if (tbs == NULL) + goto err; + + offset = 0; + memcpy(tbs + offset, composite_sig_prefix, 32); + offset += 32; + memcpy(tbs + offset, info->label, strlen(info->label)); + offset += strlen(info->label); + tbs[offset++] = (uint8_t)ctx->context_string_len; + if (ctx->context_string_len > 0) { + memcpy(tbs + offset, ctx->context_string, ctx->context_string_len); + offset += ctx->context_string_len; + } + memcpy(tbs + offset, prehash, info->prehash_len); + + /* ML-DSA component: pure ML-DSA on M', with Label as mldsa_ctx per §3.1 */ + if (RAND_priv_bytes_ex(ctx->libctx, rnd, sizeof(rnd), 0) <= 0) + goto err; + + ml_dsa_siglen = ml_dsa_sig_max; + if (!ossl_ml_dsa_sign(ctx->key->ml_dsa_key, 0, + tbs, tbs_len, + (const unsigned char *)info->label, strlen(info->label), + rnd, sizeof(rnd), 1, + sig, &ml_dsa_siglen, sigsize)) + goto err; + + /* Traditional component: sign M' with the classic key */ + classic_siglen = sigsize - ml_dsa_siglen; + if (!composite_classic_sign(ctx, info, tbs, tbs_len, + sig + ml_dsa_siglen, &classic_siglen)) + goto err; + + /* Wire format: mldsaSig || tradSig (flat concatenation) */ + *siglen = ml_dsa_siglen + classic_siglen; + ret = 1; + +err: + OPENSSL_clear_free(tbs, tbs_len); + return ret; +} + +static void composite_freectx(void *vctx) +{ + PROV_COMPOSITE_CTX *ctx = (PROV_COMPOSITE_CTX *)vctx; + + OPENSSL_free(ctx); +} + +static void *composite_dupctx(void *vctx) +{ + PROV_COMPOSITE_CTX *src = (PROV_COMPOSITE_CTX *)vctx; + PROV_COMPOSITE_CTX *dst; + + dst = OPENSSL_memdup(src, sizeof(*src)); + return dst; +} + +static int composite_sign_init(void *vctx, void *vkey, const OSSL_PARAM params[]) +{ + PROV_COMPOSITE_CTX *ctx = (PROV_COMPOSITE_CTX *)vctx; + const COMPOSITE_ALG_INFO *info; + + if (ctx == NULL || vkey == NULL) + return 0; + + ctx->key = (COMPOSITE_KEY *)vkey; + + info = composite_find_alg_info(ctx->alg); + if (info == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_UNSUPPORTED); + return 0; + } + + ctx->oid = info->oid; + ctx->oid_sz = info->oid_sz; + ctx->prehash_alg = info->prehash_alg; + ctx->prehash_len = info->prehash_len; + + return 1; +} + +static int composite_verify_init(void *vctx, void *vkey, const OSSL_PARAM params[]) +{ + PROV_COMPOSITE_CTX *ctx = (PROV_COMPOSITE_CTX *)vctx; + const COMPOSITE_ALG_INFO *info; + + if (ctx == NULL || vkey == NULL) + return 0; + + ctx->key = (COMPOSITE_KEY *)vkey; + + info = composite_find_alg_info(ctx->alg); + if (info == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_UNSUPPORTED); + return 0; + } + + ctx->oid = info->oid; + ctx->oid_sz = info->oid_sz; + ctx->prehash_alg = info->prehash_alg; + ctx->prehash_len = info->prehash_len; + + return 1; +} + +static int composite_verify(void *vctx, const uint8_t *sig, size_t siglen, + const uint8_t *msg, size_t msg_len) +{ + PROV_COMPOSITE_CTX *ctx = (PROV_COMPOSITE_CTX *)vctx; + const COMPOSITE_ALG_INFO *info; + uint8_t *tbs = NULL; + uint8_t prehash[64]; /* max prehash output size */ + size_t tbs_len = 0; + size_t offset; + size_t ml_dsa_sig_len; + EVP_MD_CTX *md_ctx = NULL; + EVP_PKEY_CTX *pctx = NULL; + int ret = 0; + + if (!ossl_prov_is_running()) + return 0; + + if (ctx->key == NULL || ctx->alg == NULL || sig == NULL || msg == NULL) + return 0; + + info = composite_find_alg_info(ctx->alg); + if (info == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_UNSUPPORTED); + return 0; + } + + ml_dsa_sig_len = ossl_ml_dsa_key_get_sig_len(ctx->key->ml_dsa_key); + if (siglen <= ml_dsa_sig_len) { + ERR_raise(ERR_LIB_PROV, PROV_R_BAD_ENCODING); + return 0; + } + + /* Compute PH(M) */ + if (!composite_compute_prehash(ctx->libctx, info, msg, msg_len, prehash)) + goto err; + + /* Reconstruct M' — identical to sign path */ + tbs_len = 32 + strlen(info->label) + 1 + ctx->context_string_len + info->prehash_len; + tbs = OPENSSL_malloc(tbs_len); + if (tbs == NULL) + goto err; + + offset = 0; + memcpy(tbs + offset, composite_sig_prefix, 32); + offset += 32; + memcpy(tbs + offset, info->label, strlen(info->label)); + offset += strlen(info->label); + tbs[offset++] = (uint8_t)ctx->context_string_len; + if (ctx->context_string_len > 0) { + memcpy(tbs + offset, ctx->context_string, ctx->context_string_len); + offset += ctx->context_string_len; + } + memcpy(tbs + offset, prehash, info->prehash_len); + + /* Verify ML-DSA component, with Label as mldsa_ctx per §3.2 */ + if (!ossl_ml_dsa_verify(ctx->key->ml_dsa_key, 0, + tbs, tbs_len, + (const unsigned char *)info->label, strlen(info->label), + 1, sig, ml_dsa_sig_len)) + goto err; + + /* Verify classic component */ + md_ctx = EVP_MD_CTX_new(); + if (md_ctx == NULL) + goto err; + + switch (info->classic_type) { + case COMPOSITE_CLASSIC_ED25519: + case COMPOSITE_CLASSIC_ED448: + if (!EVP_DigestVerifyInit_ex(md_ctx, NULL, NULL, + ctx->libctx, NULL, + ctx->key->classic_key, NULL)) + goto err; + break; + + case COMPOSITE_CLASSIC_ECDSA: + if (!EVP_DigestVerifyInit_ex(md_ctx, NULL, info->classic_hash, + ctx->libctx, NULL, + ctx->key->classic_key, NULL)) + goto err; + break; + + case COMPOSITE_CLASSIC_RSA_PSS: + if (!EVP_DigestVerifyInit_ex(md_ctx, &pctx, info->classic_hash, + ctx->libctx, NULL, + ctx->key->classic_key, NULL)) + goto err; + { + const char *mgf1 = (info->mgf1_hash != NULL) + ? info->mgf1_hash + : info->classic_hash; + if (EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) <= 0 + || EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, info->pss_salt_len) <= 0 + || EVP_PKEY_CTX_set_rsa_mgf1_md_name(pctx, mgf1, NULL) <= 0) + goto err; + } + break; + + case COMPOSITE_CLASSIC_RSA_PKCS15: + if (!EVP_DigestVerifyInit_ex(md_ctx, &pctx, info->classic_hash, + ctx->libctx, NULL, + ctx->key->classic_key, NULL)) + goto err; + if (EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PADDING) <= 0) + goto err; + break; + + default: + ERR_raise(ERR_LIB_PROV, ERR_R_UNSUPPORTED); + goto err; + } + + if (EVP_DigestVerify(md_ctx, + sig + ml_dsa_sig_len, + siglen - ml_dsa_sig_len, + tbs, tbs_len) + != 1) + goto err; + + ret = 1; +err: + EVP_MD_CTX_free(md_ctx); + OPENSSL_clear_free(tbs, tbs_len); + return ret; +} + +static int composite_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + PROV_COMPOSITE_CTX *ctx = (PROV_COMPOSITE_CTX *)vctx; + struct composite_get_ctx_params_st p; + + if (ctx == NULL || !composite_get_ctx_params_decoder(params, &p)) + return 0; + + if (p.id != NULL) { + /* + * Build DER AlgorithmIdentifier = SEQUENCE { OID } + * = 0x30 || oid_sz || oid_bytes (total = oid_sz + 2 bytes) + */ + uint8_t aid[12]; /* 2 header bytes + up to 10 OID bytes */ + size_t aid_len; + + if (ctx->oid == NULL || ctx->oid_sz == 0 + || ctx->oid_sz > sizeof(aid) - 2) + return 0; + + aid[0] = 0x30; /* SEQUENCE tag */ + aid[1] = (uint8_t)ctx->oid_sz; + memcpy(aid + 2, ctx->oid, ctx->oid_sz); + aid_len = 2 + ctx->oid_sz; + + if (!OSSL_PARAM_set_octet_string(p.id, aid, aid_len)) + return 0; + } + + return 1; +} + +static const OSSL_PARAM *composite_gettable_ctx_params(void *vctx, void *provctx) +{ + return composite_get_ctx_params_list; +} + +static int composite_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + PROV_COMPOSITE_CTX *ctx = (PROV_COMPOSITE_CTX *)vctx; + struct composite_set_ctx_params_st p; + + if (ctx == NULL || !composite_set_ctx_params_decoder(params, &p)) + return 0; + + if (p.ctx != NULL) { + void *vp = ctx->context_string; + + if (!OSSL_PARAM_get_octet_string(p.ctx, &vp, sizeof(ctx->context_string), + &ctx->context_string_len)) { + ctx->context_string_len = 0; + return 0; + } + } + + return 1; +} + +static const OSSL_PARAM *composite_settable_ctx_params(void *vctx, void *provctx) +{ + return composite_set_ctx_params_list; +} + +static int composite_sign_msg_init(void *vctx, void *vkey, + const OSSL_PARAM params[]) +{ + return composite_sign_init(vctx, vkey, params); +} + +static int composite_signverify_msg_update(void *vctx, + const unsigned char *data, + size_t datalen) +{ + ERR_raise(ERR_LIB_PROV, ERR_R_UNSUPPORTED); + return 0; +} + +static int composite_sign_msg_final(void *vctx, unsigned char *sig, + size_t *siglen, size_t sigsize) +{ + ERR_raise(ERR_LIB_PROV, ERR_R_UNSUPPORTED); + return 0; +} + +static int composite_verify_msg_init(void *vctx, void *vkey, + const OSSL_PARAM params[]) +{ + return composite_verify_init(vctx, vkey, params); +} + +static int composite_verify_msg_final(void *vctx) +{ + ERR_raise(ERR_LIB_PROV, ERR_R_UNSUPPORTED); + return 0; +} + +static int composite_digest_signverify_init(void *vctx, const char *mdname, + void *vkey, + const OSSL_PARAM params[]) +{ + if (mdname != NULL && mdname[0] != '\0') { + ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_DIGEST, + "Explicit digest not supported for composite " + "signature operations"); + return 0; + } + return composite_sign_init(vctx, vkey, params); +} + +static int composite_digest_sign(void *vctx, uint8_t *sig, size_t *siglen, + size_t sigsize, const uint8_t *tbs, + size_t tbslen) +{ + return composite_sign(vctx, sig, siglen, sigsize, tbs, tbslen); +} + +static int composite_digest_verify(void *vctx, const uint8_t *sig, + size_t siglen, const uint8_t *tbs, + size_t tbslen) +{ + return composite_verify(vctx, sig, siglen, tbs, tbslen); +} + +/* + * Per-algorithm newctx functions and dispatch tables. + * The alg string is stored in the context for domain separator selection. + */ +#define MAKE_COMPOSITE_FUNCTIONS(name, namestr) \ + static void *composite_##name##_newctx(void *provctx, const char *propq) \ + { \ + PROV_COMPOSITE_CTX *ctx = composite_newctx(provctx, 0, propq); \ + if (ctx != NULL) \ + ctx->alg = namestr; \ + return ctx; \ + } \ + const OSSL_DISPATCH ossl_##name##_signature_functions[] = { \ + { OSSL_FUNC_SIGNATURE_NEWCTX, \ + (void (*)(void))composite_##name##_newctx }, \ + { OSSL_FUNC_SIGNATURE_FREECTX, \ + (void (*)(void))composite_freectx }, \ + { OSSL_FUNC_SIGNATURE_DUPCTX, \ + (void (*)(void))composite_dupctx }, \ + { OSSL_FUNC_SIGNATURE_SIGN_INIT, \ + (void (*)(void))composite_sign_init }, \ + { OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_INIT, \ + (void (*)(void))composite_sign_msg_init }, \ + { OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_UPDATE, \ + (void (*)(void))composite_signverify_msg_update }, \ + { OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_FINAL, \ + (void (*)(void))composite_sign_msg_final }, \ + { OSSL_FUNC_SIGNATURE_SIGN, \ + (void (*)(void))composite_sign }, \ + { OSSL_FUNC_SIGNATURE_VERIFY_INIT, \ + (void (*)(void))composite_verify_init }, \ + { OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_INIT, \ + (void (*)(void))composite_verify_msg_init }, \ + { OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_UPDATE, \ + (void (*)(void))composite_signverify_msg_update }, \ + { OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_FINAL, \ + (void (*)(void))composite_verify_msg_final }, \ + { OSSL_FUNC_SIGNATURE_VERIFY, \ + (void (*)(void))composite_verify }, \ + { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, \ + (void (*)(void))composite_digest_signverify_init }, \ + { OSSL_FUNC_SIGNATURE_DIGEST_SIGN, \ + (void (*)(void))composite_digest_sign }, \ + { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT, \ + (void (*)(void))composite_digest_signverify_init }, \ + { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY, \ + (void (*)(void))composite_digest_verify }, \ + { OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, \ + (void (*)(void))composite_get_ctx_params }, \ + { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, \ + (void (*)(void))composite_gettable_ctx_params }, \ + { OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, \ + (void (*)(void))composite_set_ctx_params }, \ + { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, \ + (void (*)(void))composite_settable_ctx_params }, \ + OSSL_DISPATCH_END \ + } + +MAKE_COMPOSITE_FUNCTIONS(mldsa44_rsa2048_pss_sha256, + "ML-DSA-44-RSA2048-PSS-SHA256"); +MAKE_COMPOSITE_FUNCTIONS(mldsa44_rsa2048_pkcs15_sha256, + "ML-DSA-44-RSA2048-PKCS15-SHA256"); +MAKE_COMPOSITE_FUNCTIONS(mldsa44_ed25519_sha512, + "ML-DSA-44-Ed25519-SHA512"); +MAKE_COMPOSITE_FUNCTIONS(mldsa44_ecdsa_p256_sha256, + "ML-DSA-44-ECDSA-P256-SHA256"); +MAKE_COMPOSITE_FUNCTIONS(mldsa65_rsa3072_pss_sha512, + "ML-DSA-65-RSA3072-PSS-SHA512"); +MAKE_COMPOSITE_FUNCTIONS(mldsa65_rsa3072_pkcs15_sha512, + "ML-DSA-65-RSA3072-PKCS15-SHA512"); +MAKE_COMPOSITE_FUNCTIONS(mldsa65_rsa4096_pss_sha512, + "ML-DSA-65-RSA4096-PSS-SHA512"); +MAKE_COMPOSITE_FUNCTIONS(mldsa65_rsa4096_pkcs15_sha512, + "ML-DSA-65-RSA4096-PKCS15-SHA512"); +MAKE_COMPOSITE_FUNCTIONS(mldsa65_ecdsa_p256_sha512, + "ML-DSA-65-ECDSA-P256-SHA512"); +MAKE_COMPOSITE_FUNCTIONS(mldsa65_ecdsa_p384_sha512, + "ML-DSA-65-ECDSA-P384-SHA512"); +MAKE_COMPOSITE_FUNCTIONS(mldsa65_ecdsa_brainpoolP256r1_sha512, + "ML-DSA-65-ECDSA-brainpoolP256r1-SHA512"); +MAKE_COMPOSITE_FUNCTIONS(mldsa65_ed25519_sha512, + "ML-DSA-65-Ed25519-SHA512"); +MAKE_COMPOSITE_FUNCTIONS(mldsa87_ecdsa_p384_sha512, + "ML-DSA-87-ECDSA-P384-SHA512"); +MAKE_COMPOSITE_FUNCTIONS(mldsa87_ecdsa_brainpoolP384r1_sha512, + "ML-DSA-87-ECDSA-brainpoolP384r1-SHA512"); +MAKE_COMPOSITE_FUNCTIONS(mldsa87_ed448_shake256, + "ML-DSA-87-Ed448-SHAKE256"); +MAKE_COMPOSITE_FUNCTIONS(mldsa87_rsa3072_pss_sha512, + "ML-DSA-87-RSA3072-PSS-SHA512"); +MAKE_COMPOSITE_FUNCTIONS(mldsa87_rsa4096_pss_sha512, + "ML-DSA-87-RSA4096-PSS-SHA512"); +MAKE_COMPOSITE_FUNCTIONS(mldsa87_ecdsa_p521_sha512, + "ML-DSA-87-ECDSA-P521-SHA512"); diff --git a/providers/implementations/signature/composite_sig.inc.in b/providers/implementations/signature/composite_sig.inc.in new file mode 100644 index 0000000000000..640f4ba87d4c5 --- /dev/null +++ b/providers/implementations/signature/composite_sig.inc.in @@ -0,0 +1,20 @@ +/* + * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +{- +use OpenSSL::paramnames qw(produce_param_decoder); +-} + +{- produce_param_decoder('composite_set_ctx_params', + (['OSSL_SIGNATURE_PARAM_CONTEXT_STRING', 'ctx', 'octet_string'], + )); -} + +{- produce_param_decoder('composite_get_ctx_params', + (['OSSL_SIGNATURE_PARAM_ALGORITHM_ID', 'id', 'octet_string'], + )); -}