From 1c753008de9f5fa3b74a45ae760465d48dd07a3c Mon Sep 17 00:00:00 2001 From: Sean McGrail Date: Sat, 25 Jan 2025 00:03:59 +0000 Subject: [PATCH 1/3] Add EVP API Support for ED25519ph --- crypto/evp_extra/evp_asn1.c | 46 ++++-- crypto/evp_extra/evp_test.cc | 212 ++++++++++++++++++++++++++++ crypto/evp_extra/internal.h | 1 + crypto/evp_extra/p_ed25519_asn1.c | 32 ++++- crypto/evp_extra/p_methods.c | 3 +- crypto/fipsmodule/bcm.c | 1 + crypto/fipsmodule/evp/evp.c | 30 ++++ crypto/fipsmodule/evp/evp_ctx.c | 1 + crypto/fipsmodule/evp/internal.h | 15 +- crypto/fipsmodule/evp/p_ed25519.c | 21 ++- crypto/fipsmodule/evp/p_ed25519ph.c | 188 ++++++++++++++++++++++++ crypto/obj/obj_dat.h | 5 +- crypto/obj/obj_mac.num | 1 + crypto/obj/objects.txt | 1 + include/openssl/base.h | 1 + include/openssl/evp.h | 46 ++++++ include/openssl/nid.h | 3 + 17 files changed, 590 insertions(+), 17 deletions(-) create mode 100644 crypto/fipsmodule/evp/p_ed25519ph.c diff --git a/crypto/evp_extra/evp_asn1.c b/crypto/evp_extra/evp_asn1.c index 69d34a492d..2d071ec94b 100644 --- a/crypto/evp_extra/evp_asn1.c +++ b/crypto/evp_extra/evp_asn1.c @@ -70,6 +70,16 @@ #include "internal.h" #include "../pqdsa/internal.h" +// check_method_pkey_id returns whether the given method matches the desired |EVP_PKEY_*| type. +// Returns success if |desired_pkey_id| is NULL or if the value matches |method|'s |EVP_PKEY_*| type. +static int check_method_pkey_id(const EVP_PKEY_ASN1_METHOD *method, int *desired_pkey_id) { + GUARD_PTR(method); + if(desired_pkey_id == NULL) { + return 1; + } + return *desired_pkey_id == method->pkey_id; +} + // parse_key_type takes the algorithm cbs sequence |cbs| and extracts the OID. // The OID is then searched against ASN.1 methods for a method with that OID. // As the |OID| is read from |cbs| the buffer is advanced. @@ -78,7 +88,10 @@ // the OID is not returned (and the |cbs| buffer is advanced) we return the OID // as |cbs|. (This allows the specific OID, e.g. NID_MLDSA65 to be parsed by // the type-specific decoding functions within the algorithm parameter.) -static const EVP_PKEY_ASN1_METHOD *parse_key_type(CBS *cbs) { +// |desired_pkey_id| is used to further filter whether a matching |EVP_PKEY_ASN1_METHOD| +// will return |EVP_PKEY| of the desired |EVP_PKEY_*| type. This useful for EVP_PKEY types +// like ED25519 and ED25519PH where the OID is the same. +static const EVP_PKEY_ASN1_METHOD *parse_key_type(CBS *cbs, int *desired_pkey_id) { CBS oid; if (!CBS_get_asn1(cbs, &oid, CBS_ASN1_OBJECT)) { return NULL; @@ -89,14 +102,15 @@ static const EVP_PKEY_ASN1_METHOD *parse_key_type(CBS *cbs) { for (size_t i = 0; i < ASN1_EVP_PKEY_METHODS; i++) { const EVP_PKEY_ASN1_METHOD *method = asn1_methods[i]; if (CBS_len(&oid) == method->oid_len && - OPENSSL_memcmp(CBS_data(&oid), method->oid, method->oid_len) == 0) { + OPENSSL_memcmp(CBS_data(&oid), method->oid, method->oid_len) == 0 && + check_method_pkey_id(method, desired_pkey_id)) { return method; } } // Special logic to handle the rarer |NID_rsa|. // https://www.itu.int/ITU-T/formal-language/itu-t/x/x509/2008/AlgorithmObjectIdentifiers.html - if (OBJ_cbs2nid(&oid) == NID_rsa) { + if (OBJ_cbs2nid(&oid) == NID_rsa && check_method_pkey_id(&rsa_asn1_meth, desired_pkey_id)) { return &rsa_asn1_meth; } @@ -104,7 +118,7 @@ static const EVP_PKEY_ASN1_METHOD *parse_key_type(CBS *cbs) { // asn1 functions for pqdsa types. However, the incoming CBS has the OID for // the specific algorithm. So we must search explicitly for the algorithm. const EVP_PKEY_ASN1_METHOD * ret = PQDSA_find_asn1_by_nid(OBJ_cbs2nid(&oid)); - if (ret != NULL) { + if (ret != NULL && check_method_pkey_id(ret, desired_pkey_id)) { // if |cbs| is empty after parsing |oid| from it, we overwrite the contents // with |oid| so that we can call pub_decode/priv_decode with the |algorithm| // populated as |oid|. @@ -117,7 +131,7 @@ static const EVP_PKEY_ASN1_METHOD *parse_key_type(CBS *cbs) { return NULL; } -EVP_PKEY *EVP_parse_public_key(CBS *cbs) { +static EVP_PKEY *evp_parse_public_key_internal(CBS *cbs, int *desired_pkey_id) { // Parse the SubjectPublicKeyInfo. CBS spki, algorithm, key; uint8_t padding; @@ -129,7 +143,7 @@ EVP_PKEY *EVP_parse_public_key(CBS *cbs) { return NULL; } - const EVP_PKEY_ASN1_METHOD *method = parse_key_type(&algorithm); + const EVP_PKEY_ASN1_METHOD *method = parse_key_type(&algorithm, desired_pkey_id); if (method == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); return NULL; @@ -165,6 +179,14 @@ EVP_PKEY *EVP_parse_public_key(CBS *cbs) { return NULL; } +EVP_PKEY *EVP_parse_public_key(CBS *cbs) { + return evp_parse_public_key_internal(cbs, NULL); +} + +EVP_PKEY *EVP_parse_public_key_checked(int type, CBS *cbs) { + return evp_parse_public_key_internal(cbs, &type); +} + int EVP_marshal_public_key(CBB *cbb, const EVP_PKEY *key) { GUARD_PTR(cbb); GUARD_PTR(key); @@ -182,7 +204,7 @@ static const unsigned kAttributesTag = static const unsigned kPublicKeyTag = CBS_ASN1_CONTEXT_SPECIFIC | 1; -EVP_PKEY *EVP_parse_private_key(CBS *cbs) { +static EVP_PKEY *evp_parse_private_key_internal(CBS *cbs, int *desired_type) { // Parse the PrivateKeyInfo (RFC 5208) or OneAsymmetricKey (RFC 5958). CBS pkcs8, algorithm, key, public_key; uint64_t version; @@ -195,7 +217,7 @@ EVP_PKEY *EVP_parse_private_key(CBS *cbs) { return NULL; } - const EVP_PKEY_ASN1_METHOD *method = parse_key_type(&algorithm); + const EVP_PKEY_ASN1_METHOD *method = parse_key_type(&algorithm, desired_type); if (method == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); return NULL; @@ -248,6 +270,14 @@ EVP_PKEY *EVP_parse_private_key(CBS *cbs) { return NULL; } +EVP_PKEY *EVP_parse_private_key(CBS *cbs) { + return evp_parse_private_key_internal(cbs, NULL); +} + +EVP_PKEY *EVP_parse_private_key_checked(int type, CBS *cbs) { + return evp_parse_private_key_internal(cbs, &type); +} + int EVP_marshal_private_key(CBB *cbb, const EVP_PKEY *key) { if (key->ameth == NULL || key->ameth->priv_encode == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); diff --git a/crypto/evp_extra/evp_test.cc b/crypto/evp_extra/evp_test.cc index dc278256bb..e05df1bbb7 100644 --- a/crypto/evp_extra/evp_test.cc +++ b/crypto/evp_extra/evp_test.cc @@ -1529,3 +1529,215 @@ TEST(EVPTest, PKEY_asn1_find_str) { ASSERT_FALSE(ameth); ASSERT_FALSE(EVP_PKEY_asn1_get0_info(&pkey_id, &pkey_base_id, &pkey_flags, &pinfo, &pem_str, ameth)); } + +TEST(EVPTest, ED25519PH) { + const uint8_t message[] = {0x72, 0x61, 0x63, 0x63, 0x6f, 0x6f, 0x6e}; + const uint8_t context[] = {0x73, 0x6e, 0x65, 0x61, 0x6b, 0x79}; + + bssl::UniquePtr pkey(nullptr); + bssl::UniquePtr pubkey(nullptr); + bssl::ScopedCBB marshalled_private_key; + bssl::ScopedCBB marshalled_public_key; + uint8_t pure_signature[ED25519_SIGNATURE_LEN] = {0}; + size_t pure_signature_len = ED25519_SIGNATURE_LEN; + uint8_t prehash_signature[ED25519_SIGNATURE_LEN] = {0}; + size_t prehash_signature_len = ED25519_SIGNATURE_LEN; + uint8_t prehash_ctx_signature[ED25519_SIGNATURE_LEN] = {0}; + size_t prehash_ctx_signature_len = ED25519_SIGNATURE_LEN; + + { + bssl::UniquePtr ctx( + EVP_PKEY_CTX_new_id(EVP_PKEY_ED25519PH, nullptr)); + ASSERT_TRUE(EVP_PKEY_keygen_init(ctx.get())); + EVP_PKEY *pkey_ptr = nullptr; + ASSERT_TRUE(EVP_PKEY_keygen(ctx.get(), &pkey_ptr)); + ASSERT_NE(pkey_ptr, nullptr); + pkey.reset(pkey_ptr); // now owns pkey_ptr + // marshal the keys + ASSERT_TRUE(CBB_init(marshalled_private_key.get(), 0)); + ASSERT_TRUE(CBB_init(marshalled_public_key.get(), 0)); + ASSERT_TRUE( + EVP_marshal_private_key(marshalled_private_key.get(), pkey.get())); + ASSERT_TRUE( + EVP_marshal_public_key(marshalled_public_key.get(), pkey.get())); + } + + { + CBS cbs; + CBS_init(&cbs, CBB_data(marshalled_private_key.get()), + CBB_len(marshalled_private_key.get())); + EVP_PKEY *parsed = EVP_parse_private_key_checked(EVP_PKEY_ED25519PH, &cbs); + ASSERT_TRUE(parsed); + pkey.reset(parsed); + // Should have parsed and returned EVP_PKEY_ED25519 + ASSERT_EQ(EVP_PKEY_ED25519PH, EVP_PKEY_id(pkey.get())); + } + + { + CBS cbs; + CBS_init(&cbs, CBB_data(marshalled_public_key.get()), + CBB_len(marshalled_public_key.get())); + EVP_PKEY *parsed = EVP_parse_public_key_checked(EVP_PKEY_ED25519PH, &cbs); + ASSERT_TRUE(parsed); + pubkey.reset(parsed); + // Should have parsed and returned EVP_PKEY_ED25519 + ASSERT_EQ(EVP_PKEY_ED25519PH, EVP_PKEY_id(pubkey.get())); + } + + // prehash signature gen and verify + { + bssl::UniquePtr md_ctx(EVP_MD_CTX_new()); + EVP_PKEY_CTX *pctx; + + ASSERT_TRUE(EVP_DigestSignInit(md_ctx.get(), &pctx, EVP_sha512(), nullptr, + pkey.get())); + + const uint8_t *sctx = NULL; + size_t sctx_len = 0; + ASSERT_TRUE(EVP_PKEY_CTX_get0_signature_context(pctx, &sctx, &sctx_len)); + ASSERT_EQ(sctx, nullptr); + ASSERT_EQ(sctx_len, (size_t)0); + + ASSERT_TRUE(EVP_DigestSignUpdate(md_ctx.get(), &message[0], 3)); + ASSERT_TRUE( + EVP_DigestSignUpdate(md_ctx.get(), &message[3], sizeof(message) - 3)); + ASSERT_TRUE(EVP_DigestSignFinal(md_ctx.get(), prehash_signature, + &prehash_signature_len)); + ASSERT_EQ(prehash_signature_len, (size_t)ED25519_SIGNATURE_LEN); + + ASSERT_TRUE(EVP_DigestVerifyInit(md_ctx.get(), nullptr, EVP_sha512(), + nullptr, pubkey.get())); + ASSERT_TRUE(EVP_DigestVerifyUpdate(md_ctx.get(), &message[0], 3)); + ASSERT_TRUE( + EVP_DigestVerifyUpdate(md_ctx.get(), &message[3], sizeof(message) - 3)); + ASSERT_TRUE(EVP_DigestVerifyFinal(md_ctx.get(), &prehash_signature[0], + prehash_signature_len)); + } + + // prehash signature w/ context gen and verify + { + bssl::UniquePtr md_ctx(EVP_MD_CTX_new()); + EVP_PKEY_CTX *pctx = nullptr; + + ASSERT_TRUE(EVP_DigestSignInit(md_ctx.get(), &pctx, EVP_sha512(), nullptr, + pkey.get())); + + ASSERT_TRUE( + EVP_PKEY_CTX_set_signature_context(pctx, context, sizeof(context))); + const uint8_t *sctx = NULL; + size_t sctx_len = 0; + ASSERT_TRUE(EVP_PKEY_CTX_get0_signature_context(pctx, &sctx, &sctx_len)); + ASSERT_TRUE(sctx); + ASSERT_NE(sctx, context); + ASSERT_EQ(Bytes(context, sizeof(context)), Bytes(sctx, sctx_len)); + + ASSERT_TRUE(EVP_DigestSignUpdate(md_ctx.get(), &message[0], 3)); + ASSERT_TRUE( + EVP_DigestSignUpdate(md_ctx.get(), &message[3], sizeof(message) - 3)); + ASSERT_TRUE(EVP_DigestSignFinal(md_ctx.get(), prehash_ctx_signature, + &prehash_ctx_signature_len)); + ASSERT_EQ(prehash_ctx_signature_len, (size_t)ED25519_SIGNATURE_LEN); + + ASSERT_TRUE(EVP_DigestVerifyInit(md_ctx.get(), &pctx, EVP_sha512(), nullptr, + pubkey.get())); + ASSERT_TRUE( + EVP_PKEY_CTX_set_signature_context(pctx, context, sizeof(context))); + ASSERT_TRUE(EVP_DigestVerifyUpdate(md_ctx.get(), &message[0], 3)); + ASSERT_TRUE( + EVP_DigestVerifyUpdate(md_ctx.get(), &message[3], sizeof(message) - 3)); + ASSERT_TRUE(EVP_DigestVerifyFinal(md_ctx.get(), &prehash_ctx_signature[0], + prehash_ctx_signature_len)); + } + + ASSERT_NE(Bytes(prehash_signature, prehash_signature_len), + Bytes(prehash_ctx_signature, prehash_ctx_signature_len)); + + { + CBS cbs; + CBS_init(&cbs, CBB_data(marshalled_private_key.get()), + CBB_len(marshalled_private_key.get())); + EVP_PKEY *parsed = EVP_parse_private_key(&cbs); + ASSERT_TRUE(parsed); + pkey.reset(parsed); + // Should have parsed and returned EVP_PKEY_ED25519 + ASSERT_EQ(EVP_PKEY_ED25519, EVP_PKEY_id(pkey.get())); + } + + { + CBS cbs; + CBS_init(&cbs, CBB_data(marshalled_public_key.get()), + CBB_len(marshalled_public_key.get())); + EVP_PKEY *parsed = EVP_parse_public_key(&cbs); + ASSERT_TRUE(parsed); + pubkey.reset(parsed); + // Should have parsed and returned EVP_PKEY_ED25519 + ASSERT_EQ(EVP_PKEY_ED25519, EVP_PKEY_id(pubkey.get())); + } + + // pure signature gen and verify + { + bssl::UniquePtr md_ctx(EVP_MD_CTX_new()); + ASSERT_TRUE(EVP_DigestSignInit(md_ctx.get(), nullptr, nullptr, nullptr, + pkey.get())); + ASSERT_TRUE(EVP_DigestSign(md_ctx.get(), pure_signature, + &pure_signature_len, message, sizeof(message))); + ASSERT_EQ(pure_signature_len, (size_t)ED25519_SIGNATURE_LEN); + + ASSERT_TRUE(EVP_DigestVerifyInit(md_ctx.get(), nullptr, nullptr, nullptr, + pubkey.get())); + ASSERT_TRUE(EVP_DigestVerify(md_ctx.get(), &pure_signature[0], + pure_signature_len, message, sizeof(message))); + } + + ASSERT_NE(Bytes(pure_signature, pure_signature_len), + Bytes(prehash_signature, prehash_signature_len)); +} + +TEST(EVPTest, Ed25519phTestVectors) { + FileTestGTest("crypto/fipsmodule/curve25519/ed25519ph_tests.txt", [](FileTest *t) { + std::vector seed, q, message, context, expected_signature; + ASSERT_TRUE(t->GetBytes(&seed, "SEED")); + ASSERT_EQ(32u, seed.size()); + ASSERT_TRUE(t->GetBytes(&q, "Q")); + ASSERT_EQ(32u, q.size()); + ASSERT_TRUE(t->GetBytes(&message, "MESSAGE")); + ASSERT_TRUE(t->GetBytes(&expected_signature, "SIGNATURE")); + ASSERT_EQ(64u, expected_signature.size()); + + if (t->HasAttribute("CONTEXT")) { + t->GetBytes(&context, "CONTEXT"); + } else { + context = std::vector(); + } + + bssl::UniquePtr pkey(EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519PH, nullptr, seed.data(), seed.size())); + bssl::UniquePtr pubkey(EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519PH, nullptr, q.data(), q.size())); + ASSERT_TRUE(pkey.get()); + ASSERT_TRUE(pubkey.get()); + ASSERT_EQ(EVP_PKEY_ED25519PH, EVP_PKEY_id(pkey.get())); + ASSERT_EQ(EVP_PKEY_ED25519PH, EVP_PKEY_id(pubkey.get())); + + bssl::UniquePtr md_ctx(EVP_MD_CTX_new()); + EVP_PKEY_CTX *pctx = nullptr; + uint8_t signature[ED25519_SIGNATURE_LEN] = {}; + size_t signature_len = ED25519_SIGNATURE_LEN; + + ASSERT_TRUE(EVP_DigestSignInit(md_ctx.get(), &pctx, EVP_sha512(), nullptr, + pkey.get())); + ASSERT_TRUE( + EVP_PKEY_CTX_set_signature_context(pctx, context.data(), context.size())); + ASSERT_TRUE(EVP_DigestSignUpdate(md_ctx.get(), message.data(), message.size())); + ASSERT_TRUE(EVP_DigestSignFinal(md_ctx.get(), signature, + &signature_len)); + ASSERT_EQ(signature_len, (size_t)ED25519_SIGNATURE_LEN); + ASSERT_EQ(Bytes(expected_signature), Bytes(signature, signature_len)); + + ASSERT_TRUE(EVP_DigestVerifyInit(md_ctx.get(), &pctx, EVP_sha512(), nullptr, + pubkey.get())); + ASSERT_TRUE( + EVP_PKEY_CTX_set_signature_context(pctx, context.data(), context.size())); + ASSERT_TRUE(EVP_DigestVerifyUpdate(md_ctx.get(), message.data(), message.size())); + ASSERT_TRUE(EVP_DigestVerifyFinal(md_ctx.get(), signature, + signature_len)); + }); +} diff --git a/crypto/evp_extra/internal.h b/crypto/evp_extra/internal.h index f8cbff80a5..03cc9f7795 100644 --- a/crypto/evp_extra/internal.h +++ b/crypto/evp_extra/internal.h @@ -26,6 +26,7 @@ extern const EVP_PKEY_ASN1_METHOD ec_asn1_meth; extern const EVP_PKEY_ASN1_METHOD rsa_asn1_meth; extern const EVP_PKEY_ASN1_METHOD rsa_pss_asn1_meth; extern const EVP_PKEY_ASN1_METHOD ed25519_asn1_meth; +extern const EVP_PKEY_ASN1_METHOD ed25519ph_asn1_meth; extern const EVP_PKEY_ASN1_METHOD x25519_asn1_meth; extern const EVP_PKEY_ASN1_METHOD pqdsa_asn1_meth; extern const EVP_PKEY_ASN1_METHOD kem_asn1_meth; diff --git a/crypto/evp_extra/p_ed25519_asn1.c b/crypto/evp_extra/p_ed25519_asn1.c index 14c4cfdf8e..d489be4995 100644 --- a/crypto/evp_extra/p_ed25519_asn1.c +++ b/crypto/evp_extra/p_ed25519_asn1.c @@ -257,12 +257,40 @@ static int ed25519_size(const EVP_PKEY *pkey) { return 64; } static int ed25519_bits(const EVP_PKEY *pkey) { return 253; } +const char pem_str[] = "ED25519"; +const char info_str[] = "OpenSSL ED25519 algorithm"; + const EVP_PKEY_ASN1_METHOD ed25519_asn1_meth = { EVP_PKEY_ED25519, {0x2b, 0x65, 0x70}, 3, - "ED25519", - "OpenSSL ED25519 algorithm", + pem_str, + info_str, + ed25519_pub_decode, + ed25519_pub_encode, + ed25519_pub_cmp, + ed25519_priv_decode, + ed25519_priv_encode, + ed25519_priv_encode_v2, + ed25519_set_priv_raw, + ed25519_set_pub_raw, + ed25519_get_priv_raw, + ed25519_get_pub_raw, + NULL /* pkey_opaque */, + ed25519_size, + ed25519_bits, + NULL /* param_missing */, + NULL /* param_copy */, + NULL /* param_cmp */, + ed25519_free, +}; + +const EVP_PKEY_ASN1_METHOD ed25519ph_asn1_meth = { + EVP_PKEY_ED25519PH, + {0x2b, 0x65, 0x70}, + 3, + pem_str, + info_str, ed25519_pub_decode, ed25519_pub_encode, ed25519_pub_cmp, diff --git a/crypto/evp_extra/p_methods.c b/crypto/evp_extra/p_methods.c index 6dce228f19..cfcc739c49 100644 --- a/crypto/evp_extra/p_methods.c +++ b/crypto/evp_extra/p_methods.c @@ -24,7 +24,8 @@ const EVP_PKEY_ASN1_METHOD *const asn1_evp_pkey_methods[] = { &pqdsa_asn1_meth, &kem_asn1_meth, &hmac_asn1_meth, - &dh_asn1_meth + &dh_asn1_meth, + &ed25519ph_asn1_meth, }; const size_t asn1_evp_pkey_methods_size = sizeof(asn1_evp_pkey_methods)/sizeof(asn1_evp_pkey_methods[0]); diff --git a/crypto/fipsmodule/bcm.c b/crypto/fipsmodule/bcm.c index 31eabded4c..2ee9bbae5a 100644 --- a/crypto/fipsmodule/bcm.c +++ b/crypto/fipsmodule/bcm.c @@ -115,6 +115,7 @@ #include "evp/evp_ctx.c" #include "evp/p_ec.c" #include "evp/p_ed25519.c" +#include "evp/p_ed25519ph.c" #include "evp/p_hkdf.c" #include "evp/p_hmac.c" #include "evp/p_kem.c" diff --git a/crypto/fipsmodule/evp/evp.c b/crypto/fipsmodule/evp/evp.c index 496cb3b681..50ca9b6e33 100644 --- a/crypto/fipsmodule/evp/evp.c +++ b/crypto/fipsmodule/evp/evp.c @@ -479,6 +479,9 @@ EVP_PKEY *EVP_PKEY_new_raw_private_key(int type, ENGINE *unused, case EVP_PKEY_ED25519: method = &ed25519_asn1_meth; break; + case EVP_PKEY_ED25519PH: + method = &ed25519ph_asn1_meth; + break; case EVP_PKEY_HMAC: method = &hmac_asn1_meth; break; @@ -516,6 +519,9 @@ EVP_PKEY *EVP_PKEY_new_raw_public_key(int type, ENGINE *unused, case EVP_PKEY_ED25519: method = &ed25519_asn1_meth; break; + case EVP_PKEY_ED25519PH: + method = &ed25519ph_asn1_meth; + break; default: OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); return 0; @@ -589,6 +595,30 @@ int EVP_PKEY_CTX_get_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD **out_md) { 0, (void *)out_md); } +int EVP_PKEY_CTX_set_signature_context(EVP_PKEY_CTX *ctx, + const uint8_t *context, + size_t context_len) { + EVP_PKEY_CTX_SIGNATURE_CONTEXT_PARAMS params = {context, context_len}; + return EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG, + EVP_PKEY_CTRL_SIGNING_CONTEXT, 0, ¶ms); +} + +int EVP_PKEY_CTX_get0_signature_context(EVP_PKEY_CTX *ctx, + const uint8_t **context, + size_t *context_len) { + GUARD_PTR(context); + GUARD_PTR(context_len); + EVP_PKEY_CTX_SIGNATURE_CONTEXT_PARAMS params = {}; + if (!EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG, + EVP_PKEY_CTRL_GET_SIGNING_CONTEXT, 0, ¶ms)) { + return 0; + } + *context = params.context; + *context_len = params.context_len; + return 1; +} + + void *EVP_PKEY_get0(const EVP_PKEY *pkey) { SET_DIT_AUTO_RESET; GUARD_PTR(pkey); diff --git a/crypto/fipsmodule/evp/evp_ctx.c b/crypto/fipsmodule/evp/evp_ctx.c index 6e35a5ba7f..21299546e3 100644 --- a/crypto/fipsmodule/evp/evp_ctx.c +++ b/crypto/fipsmodule/evp/evp_ctx.c @@ -75,6 +75,7 @@ DEFINE_LOCAL_DATA(struct fips_evp_pkey_methods, AWSLC_fips_evp_pkey_methods) { out->methods[4] = EVP_PKEY_hmac_pkey_meth(); out->methods[5] = EVP_PKEY_ed25519_pkey_meth(); out->methods[6] = EVP_PKEY_kem_pkey_meth(); + out->methods[7] = EVP_PKEY_ed25519ph_pkey_meth(); } static const EVP_PKEY_METHOD *evp_pkey_meth_find(int type) { diff --git a/crypto/fipsmodule/evp/internal.h b/crypto/fipsmodule/evp/internal.h index 46ff161ba1..0b8bd35b49 100644 --- a/crypto/fipsmodule/evp/internal.h +++ b/crypto/fipsmodule/evp/internal.h @@ -207,6 +207,8 @@ int EVP_RSA_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int optype, int cmd, int p1, void * #define EVP_PKEY_CTRL_MD 1 #define EVP_PKEY_CTRL_GET_MD 2 +#define EVP_PKEY_CTRL_SIGNING_CONTEXT 3 +#define EVP_PKEY_CTRL_GET_SIGNING_CONTEXT 4 // EVP_PKEY_CTRL_PEER_KEY is called with different values of |p1|: // 0: Is called from |EVP_PKEY_derive_set_peer| and |p2| contains a peer key. @@ -376,14 +378,17 @@ typedef struct { char has_private; } ED25519_KEY; +// ed25519_keygen encapsulates ED25519 key generation logic for sharing between Ed25519 and Ed25519ph EVP_PKEY keygen +int ed25519_keygen(ED25519_KEY **ptr); + // evp_pkey_set_cb_translate translates |ctx|'s |pkey_gencb| and sets it as the // callback function for |cb|. void evp_pkey_set_cb_translate(BN_GENCB *cb, EVP_PKEY_CTX *ctx); #define ED25519_PUBLIC_KEY_OFFSET 32 -#define FIPS_EVP_PKEY_METHODS 7 +#define FIPS_EVP_PKEY_METHODS 8 #define NON_FIPS_EVP_PKEY_METHODS 4 -#define ASN1_EVP_PKEY_METHODS 10 +#define ASN1_EVP_PKEY_METHODS 11 struct fips_evp_pkey_methods { const EVP_PKEY_METHOD * methods[FIPS_EVP_PKEY_METHODS]; @@ -397,6 +402,12 @@ const EVP_PKEY_METHOD *EVP_PKEY_hmac_pkey_meth(void); const EVP_PKEY_METHOD *EVP_PKEY_ed25519_pkey_meth(void); const EVP_PKEY_METHOD *EVP_PKEY_kem_pkey_meth(void); const EVP_PKEY_METHOD *EVP_PKEY_pqdsa_pkey_meth(void); +const EVP_PKEY_METHOD *EVP_PKEY_ed25519ph_pkey_meth(void); + +struct evp_pkey_ctx_signature_context_params_st { + const uint8_t *context; + size_t context_len; +}; // EVP_PKEY_CTX_SIGNATURE_CONTEXT_PARAMS #if defined(__cplusplus) } // extern C diff --git a/crypto/fipsmodule/evp/p_ed25519.c b/crypto/fipsmodule/evp/p_ed25519.c index e8b98b80ba..3807c3e846 100644 --- a/crypto/fipsmodule/evp/p_ed25519.c +++ b/crypto/fipsmodule/evp/p_ed25519.c @@ -24,18 +24,33 @@ // Ed25519 has no parameters to copy. static int pkey_ed25519_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) { return 1; } -static int pkey_ed25519_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) { +int ed25519_keygen(ED25519_KEY **ptr) { + GUARD_PTR(ptr); + if(*ptr != NULL) { + // Free it if we were passed an already allocated-key for some reason. + OPENSSL_free(*ptr); + } + ED25519_KEY *key = OPENSSL_malloc(sizeof(ED25519_KEY)); if (key == NULL) { return 0; } - evp_pkey_set_method(pkey, &ed25519_asn1_meth); - uint8_t pubkey_unused[32]; ED25519_keypair(pubkey_unused, key->key); key->has_private = 1; + *ptr = key; + + return 1; +} + +static int pkey_ed25519_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) { + ED25519_KEY *key = NULL; + if (!ed25519_keygen(&key)) { + return 0; + } + evp_pkey_set_method(pkey, &ed25519_asn1_meth); OPENSSL_free(pkey->pkey.ptr); pkey->pkey.ptr = key; return 1; diff --git a/crypto/fipsmodule/evp/p_ed25519ph.c b/crypto/fipsmodule/evp/p_ed25519ph.c new file mode 100644 index 0000000000..2beb3291fb --- /dev/null +++ b/crypto/fipsmodule/evp/p_ed25519ph.c @@ -0,0 +1,188 @@ +/* Copyright (c) 2017, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#include +#include +#include + +#include "internal.h" + +typedef struct { + uint8_t context[255]; + size_t context_len; +} ED25519PH_PKEY_CTX; + +static int pkey_ed25519ph_init(EVP_PKEY_CTX *ctx) { + ED25519PH_PKEY_CTX *dctx = OPENSSL_zalloc(sizeof(ED25519PH_PKEY_CTX)); + if (dctx == NULL) { + return 0; + } + ctx->data = dctx; + return 1; +} + +static void pkey_ed25519ph_cleanup(EVP_PKEY_CTX *ctx) { + ED25519PH_PKEY_CTX *dctx = ctx->data; + if (!dctx) { + return; + } + + OPENSSL_free(dctx); +} + +static int pkey_ed25519ph_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) { + ED25519_KEY *key = NULL; + if (!ed25519_keygen(&key)) { + return 0; + } + evp_pkey_set_method(pkey, &ed25519ph_asn1_meth); + OPENSSL_free(pkey->pkey.ptr); + pkey->pkey.ptr = key; + return 1; +} + +static int pkey_ed25519ph_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) { + if (!pkey_ed25519ph_init(dst)) { + return 0; + } + + ED25519PH_PKEY_CTX *dctx = (ED25519PH_PKEY_CTX *)dst->data; + ED25519PH_PKEY_CTX *sctx = (ED25519PH_PKEY_CTX *)src->data; + OPENSSL_memcpy(dctx->context, sctx->context, sizeof(sctx->context)); + dctx->context_len = sctx->context_len; + + return 1; +} + +static int pkey_ed25519ph_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *siglen, + const uint8_t *tbs, size_t tbslen) { + ED25519_KEY *key = ctx->pkey->pkey.ptr; + if (!key->has_private) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY); + return 0; + } + + if (sig == NULL) { + *siglen = 64; + return 1; + } + + if (*siglen < 64) { + OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL); + return 0; + } + + if(tbslen < SHA512_DIGEST_LENGTH) { + OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL); + return 0; + } + + ED25519PH_PKEY_CTX *dctx = ctx->data; + GUARD_PTR(dctx); + + if (!ED25519ph_sign_digest(sig, tbs, key->key, dctx->context, dctx->context_len)) { + return 0; + } + + *siglen = 64; + return 1; +} + +static int pkey_ed25519ph_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig, + size_t siglen, const uint8_t *tbs, + size_t tbslen) { + ED25519_KEY *key = ctx->pkey->pkey.ptr; + ED25519PH_PKEY_CTX *dctx = ctx->data; + GUARD_PTR(dctx); + + if (siglen != 64 || tbslen < SHA512_DIGEST_LENGTH || + !ED25519ph_verify_digest(tbs, sig, + key->key + ED25519_PUBLIC_KEY_OFFSET, dctx->context, dctx->context_len)) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_SIGNATURE); + return 0; + } + + return 1; +} + +static int pkey_ed25519ph_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) { + GUARD_PTR(ctx); + ED25519PH_PKEY_CTX *dctx = (ED25519PH_PKEY_CTX *)ctx->data; + switch (type) { + case EVP_PKEY_CTRL_MD: { + const EVP_MD *md = p2; + int md_type = EVP_MD_type(md); + // MUST be SHA-512 + if (md_type != NID_sha512) { + OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED); + return 0; + } + break; + } + case EVP_PKEY_CTRL_SIGNING_CONTEXT: { + EVP_PKEY_CTX_SIGNATURE_CONTEXT_PARAMS *params = p2; + if (!params || !dctx || params->context_len > sizeof(dctx->context)) { + return 0; + } + OPENSSL_memcpy(dctx->context, params->context, params->context_len); + dctx->context_len = params->context_len; + break; + } + case EVP_PKEY_CTRL_GET_SIGNING_CONTEXT: { + EVP_PKEY_CTX_SIGNATURE_CONTEXT_PARAMS *params = p2; + if (!params || !dctx) { + return 0; + } + if(dctx->context_len == 0) { + params->context = NULL; + params->context = 0; + } else { + params->context = dctx->context; + params->context_len = dctx->context_len; + } + return 1; + } + default: + OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED); + return 0; + } + return 1; +} + +DEFINE_METHOD_FUNCTION(EVP_PKEY_METHOD, EVP_PKEY_ed25519ph_pkey_meth) { + out->pkey_id = EVP_PKEY_ED25519PH; + out->init = pkey_ed25519ph_init; + out->copy = pkey_ed25519ph_copy; + out->cleanup = pkey_ed25519ph_cleanup; + out->keygen = pkey_ed25519ph_keygen; + out->sign_init = NULL; + out->sign = pkey_ed25519ph_sign; + out->sign_message = NULL; + out->verify_init = NULL; + out->verify = pkey_ed25519ph_verify; + out->verify_message = NULL; + out->verify_recover = NULL; + out->encrypt = NULL; + out->decrypt = NULL; + out->derive = NULL; + out->paramgen = NULL; + out->ctrl = pkey_ed25519ph_ctrl; + out->ctrl_str = NULL; + out->keygen_deterministic = NULL; + out->encapsulate_deterministic = NULL; + out->encapsulate = NULL; + out->decapsulate = NULL; +} diff --git a/crypto/obj/obj_dat.h b/crypto/obj/obj_dat.h index eb284bb0d0..1f0120f9ca 100644 --- a/crypto/obj/obj_dat.h +++ b/crypto/obj/obj_dat.h @@ -56,7 +56,7 @@ /* This file is generated by crypto/obj/objects.go. */ -#define NUM_NID 997 +#define NUM_NID 998 static const uint8_t kObjectData[] = { /* NID_rsadsi */ @@ -9004,6 +9004,7 @@ static const ASN1_OBJECT kObjects[NUM_NID] = { {"MLDSA44", "MLDSA44", NID_MLDSA44, 9, &kObjectData[6333], 0}, {"MLDSA65", "MLDSA65", NID_MLDSA65, 9, &kObjectData[6342], 0}, {"MLDSA87", "MLDSA87", NID_MLDSA87, 9, &kObjectData[6351], 0}, + {"ED25519ph", "ED25519ph", NID_ED25519ph, 0, NULL, 0}, }; static const uint16_t kNIDsInShortNameOrder[] = { @@ -9101,6 +9102,7 @@ static const uint16_t kNIDsInShortNameOrder[] = { 67 /* DSA-old */, 297 /* DVCS */, 949 /* ED25519 */, + 997 /* ED25519ph */, 960 /* ED448 */, 99 /* GN */, 969 /* HKDF */, @@ -10012,6 +10014,7 @@ static const uint16_t kNIDsInLongNameOrder[] = { 392 /* Domain */, 132 /* E-mail Protection */, 949 /* ED25519 */, + 997 /* ED25519ph */, 960 /* ED448 */, 389 /* Enterprises */, 384 /* Experimental */, diff --git a/crypto/obj/obj_mac.num b/crypto/obj/obj_mac.num index 72782a89e7..b25bf8cb6d 100644 --- a/crypto/obj/obj_mac.num +++ b/crypto/obj/obj_mac.num @@ -984,3 +984,4 @@ PQDSA 993 MLDSA44 994 MLDSA65 995 MLDSA87 996 +ED25519ph 997 diff --git a/crypto/obj/objects.txt b/crypto/obj/objects.txt index 791704d5a3..c5d4c4e926 100644 --- a/crypto/obj/objects.txt +++ b/crypto/obj/objects.txt @@ -1353,6 +1353,7 @@ secg-scheme 14 3 : dhSinglePass-cofactorDH-sha512kdf-scheme 1 3 101 111 : X448 1 3 101 112 : ED25519 1 3 101 113 : ED448 + : ED25519ph : ChaCha20-Poly1305 : chacha20-poly1305 diff --git a/include/openssl/base.h b/include/openssl/base.h index 15a7d9e1fa..5e440da1ba 100644 --- a/include/openssl/base.h +++ b/include/openssl/base.h @@ -352,6 +352,7 @@ typedef struct kem_key_st KEM_KEY; typedef struct evp_pkey_ctx_st EVP_PKEY_CTX; typedef struct evp_pkey_asn1_method_st EVP_PKEY_ASN1_METHOD; typedef struct evp_pkey_st EVP_PKEY; +typedef struct evp_pkey_ctx_signature_context_params_st EVP_PKEY_CTX_SIGNATURE_CONTEXT_PARAMS; typedef struct hmac_ctx_st HMAC_CTX; typedef struct md4_state_st MD4_CTX; typedef struct md5_state_st MD5_CTX; diff --git a/include/openssl/evp.h b/include/openssl/evp.h index d7a18271a3..1b33df817d 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -194,6 +194,7 @@ OPENSSL_EXPORT int EVP_PKEY_CTX_set_dh_paramgen_generator(EVP_PKEY_CTX *ctx, int #define EVP_PKEY_RSA_PSS NID_rsassaPss #define EVP_PKEY_EC NID_X9_62_id_ecPublicKey #define EVP_PKEY_ED25519 NID_ED25519 +#define EVP_PKEY_ED25519PH NID_ED25519ph #define EVP_PKEY_X25519 NID_X25519 #define EVP_PKEY_HKDF NID_hkdf #define EVP_PKEY_HMAC NID_hmac @@ -226,6 +227,18 @@ OPENSSL_EXPORT int EVP_PKEY_cmp_parameters(const EVP_PKEY *a, // or EC curve. OPENSSL_EXPORT EVP_PKEY *EVP_parse_public_key(CBS *cbs); +// EVP_parse_public_key_checked decodes a DER-encoded SubjectPublicKeyInfo structure +// (RFC 5280) from |cbs| and advances |cbs|. It returns a newly-allocated +// |EVP_PKEY| or NULL on error. If the key is an EC key, the curve is guaranteed +// to be set. The EVP_PKEY returned is guaranteed to be of |type| if the key parsed +// from |cbs| is suitable. For example a parsed Ed25519 key can be used for either +// |EVP_PKEY_ED25519| or |EVP_PKEY_ED25519PH| types. +// +// The caller must perform further validation of parsed public key to ensure it is +// suitable and validate other desired key properties such as RSA modulus size +// or EC curve. +OPENSSL_EXPORT EVP_PKEY *EVP_parse_public_key_checked(int type, CBS *cbs); + // EVP_marshal_public_key marshals |key| as a DER-encoded SubjectPublicKeyInfo // structure (RFC 5280) and appends the result to |cbb|. It returns one on // success and zero on error. @@ -246,6 +259,23 @@ OPENSSL_EXPORT int EVP_marshal_public_key(CBB *cbb, const EVP_PKEY *key); // structure. OPENSSL_EXPORT EVP_PKEY *EVP_parse_private_key(CBS *cbs); +// EVP_parse_private_key_checked decodes a DER-encoded PrivateKeyInfo structure +// (RFC 5208) from |cbs| and advances |cbs|. It returns a newly-allocated +// |EVP_PKEY| or NULL on error. The EVP_PKEY returned is guaranteed to be of +// |type| if the key parsed from |cbs| is suitable. For example a parsed Ed25519 +// key can be used for either |EVP_PKEY_ED25519| or |EVP_PKEY_ED25519PH| types. +// +// The caller must check the parsed private key to ensure it is suitable and +// validate other desired key properties such as RSA modulus size or EC curve. +// In particular, RSA private key operations scale cubicly, so applications +// accepting RSA private keys from external sources may need to bound key sizes +// (use |EVP_PKEY_bits| or |RSA_bits|) to avoid a DoS vector. +// +// A PrivateKeyInfo ends with an optional set of attributes. These are not +// processed and so this function will silently ignore any trailing data in the +// structure. +OPENSSL_EXPORT EVP_PKEY *EVP_parse_private_key_checked(int type, CBS *cbs); + // EVP_marshal_private_key marshals |key| as a DER-encoded PrivateKeyInfo // structure (RFC 5208) and appends the result to |cbb|. It returns one on // success and zero on error. @@ -815,6 +845,22 @@ OPENSSL_EXPORT int EVP_PKEY_CTX_get_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD **out_md); +// EVP_PKEY_CTX_set_signature_context sets |context| of length |context_len| to +// be used as the context octet string for the signing operation. |context| will +// be copied to an internal buffer allowing for the caller to free it +// afterwards. It returns one on success or zero on error. +OPENSSL_EXPORT int EVP_PKEY_CTX_set_signature_context(EVP_PKEY_CTX *ctx, + const uint8_t *context, + size_t context_len); + +// EVP_PKEY_CTX_get0_signature_context sets |*context| to point to the internal +// buffer containing the signing context octet string (which may be NULL) and +// writes the length to |*context_len|. It returns one on +// success or zero on error. +OPENSSL_EXPORT int EVP_PKEY_CTX_get0_signature_context(EVP_PKEY_CTX *ctx, + const uint8_t **context, + size_t *context_len); + // RSA specific control functions. // EVP_PKEY_CTX_set_rsa_padding sets the padding type to use. It should be one diff --git a/include/openssl/nid.h b/include/openssl/nid.h index 2ec2a9105b..cefc0f6b95 100644 --- a/include/openssl/nid.h +++ b/include/openssl/nid.h @@ -4379,6 +4379,9 @@ extern "C" { #define NID_MLDSA87 996 #define OBJ_MLDSA87 2L, 16L, 840L, 1L, 101L, 3L, 4L, 3L, 19L +#define SN_ED25519ph "ED25519ph" +#define NID_ED25519ph 997 + #if defined(__cplusplus) } /* extern C */ #endif From 397bd4d1fafd0ea7a0d30551379c78474ade0ee2 Mon Sep 17 00:00:00 2001 From: Sean McGrail Date: Tue, 28 Jan 2025 22:22:33 +0000 Subject: [PATCH 2/3] Issues with FIPS arm build, so moving ed25519ph to evp_extra --- crypto/CMakeLists.txt | 1 + crypto/evp_extra/internal.h | 1 + .../evp => evp_extra}/p_ed25519ph.c | 35 ++++++------------- crypto/evp_extra/p_methods.c | 5 ++- crypto/fipsmodule/bcm.c | 1 - crypto/fipsmodule/evp/evp.c | 2 +- crypto/fipsmodule/evp/evp_ctx.c | 1 - crypto/fipsmodule/evp/internal.h | 4 +-- 8 files changed, 20 insertions(+), 30 deletions(-) rename crypto/{fipsmodule/evp => evp_extra}/p_ed25519ph.c (85%) diff --git a/crypto/CMakeLists.txt b/crypto/CMakeLists.txt index 3aed47cbe9..14db47c7bc 100644 --- a/crypto/CMakeLists.txt +++ b/crypto/CMakeLists.txt @@ -418,6 +418,7 @@ add_library( evp_extra/p_dsa.c evp_extra/p_dsa_asn1.c evp_extra/p_ec_asn1.c + evp_extra/p_ed25519ph.c evp_extra/p_ed25519_asn1.c evp_extra/p_hmac_asn1.c evp_extra/p_kem_asn1.c diff --git a/crypto/evp_extra/internal.h b/crypto/evp_extra/internal.h index 03cc9f7795..29edc2074c 100644 --- a/crypto/evp_extra/internal.h +++ b/crypto/evp_extra/internal.h @@ -39,6 +39,7 @@ extern const EVP_PKEY_METHOD hmac_pkey_meth; extern const EVP_PKEY_METHOD dh_pkey_meth; extern const EVP_PKEY_METHOD dsa_pkey_meth; extern const EVP_PKEY_METHOD pqdsa_pkey_meth; +extern const EVP_PKEY_METHOD ed25519ph_pkey_meth; // evp_pkey_set_method behaves like |EVP_PKEY_set_type|, but takes a pointer to // a method table. This avoids depending on every |EVP_PKEY_ASN1_METHOD|. diff --git a/crypto/fipsmodule/evp/p_ed25519ph.c b/crypto/evp_extra/p_ed25519ph.c similarity index 85% rename from crypto/fipsmodule/evp/p_ed25519ph.c rename to crypto/evp_extra/p_ed25519ph.c index 2beb3291fb..3c7170d02f 100644 --- a/crypto/fipsmodule/evp/p_ed25519ph.c +++ b/crypto/evp_extra/p_ed25519ph.c @@ -18,6 +18,7 @@ #include #include +#include "../internal.h" #include "internal.h" typedef struct { @@ -162,27 +163,13 @@ static int pkey_ed25519ph_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) { return 1; } -DEFINE_METHOD_FUNCTION(EVP_PKEY_METHOD, EVP_PKEY_ed25519ph_pkey_meth) { - out->pkey_id = EVP_PKEY_ED25519PH; - out->init = pkey_ed25519ph_init; - out->copy = pkey_ed25519ph_copy; - out->cleanup = pkey_ed25519ph_cleanup; - out->keygen = pkey_ed25519ph_keygen; - out->sign_init = NULL; - out->sign = pkey_ed25519ph_sign; - out->sign_message = NULL; - out->verify_init = NULL; - out->verify = pkey_ed25519ph_verify; - out->verify_message = NULL; - out->verify_recover = NULL; - out->encrypt = NULL; - out->decrypt = NULL; - out->derive = NULL; - out->paramgen = NULL; - out->ctrl = pkey_ed25519ph_ctrl; - out->ctrl_str = NULL; - out->keygen_deterministic = NULL; - out->encapsulate_deterministic = NULL; - out->encapsulate = NULL; - out->decapsulate = NULL; -} +const EVP_PKEY_METHOD ed25519ph_pkey_meth = { + .pkey_id = EVP_PKEY_ED25519PH, + .init = pkey_ed25519ph_init, + .cleanup = pkey_ed25519ph_cleanup, + .copy = pkey_ed25519ph_copy, + .keygen = pkey_ed25519ph_keygen, + .sign = pkey_ed25519ph_sign, + .verify = pkey_ed25519ph_verify, + .ctrl = pkey_ed25519ph_ctrl +}; diff --git a/crypto/evp_extra/p_methods.c b/crypto/evp_extra/p_methods.c index cfcc739c49..6540c50a14 100644 --- a/crypto/evp_extra/p_methods.c +++ b/crypto/evp_extra/p_methods.c @@ -11,7 +11,8 @@ static const EVP_PKEY_METHOD *const non_fips_pkey_evp_methods[] = { &x25519_pkey_meth, &dh_pkey_meth, &dsa_pkey_meth, - &pqdsa_pkey_meth + &pqdsa_pkey_meth, + &ed25519ph_pkey_meth }; const EVP_PKEY_ASN1_METHOD *const asn1_evp_pkey_methods[] = { @@ -25,6 +26,8 @@ const EVP_PKEY_ASN1_METHOD *const asn1_evp_pkey_methods[] = { &kem_asn1_meth, &hmac_asn1_meth, &dh_asn1_meth, + // Ed25519ph must come after Ed25519 so that Ed25519 pkey type is selected when parsing + // asn1 by default due to matching oids. Otherwise this would be a backwards incompatible change. &ed25519ph_asn1_meth, }; const size_t asn1_evp_pkey_methods_size = sizeof(asn1_evp_pkey_methods)/sizeof(asn1_evp_pkey_methods[0]); diff --git a/crypto/fipsmodule/bcm.c b/crypto/fipsmodule/bcm.c index 2ee9bbae5a..31eabded4c 100644 --- a/crypto/fipsmodule/bcm.c +++ b/crypto/fipsmodule/bcm.c @@ -115,7 +115,6 @@ #include "evp/evp_ctx.c" #include "evp/p_ec.c" #include "evp/p_ed25519.c" -#include "evp/p_ed25519ph.c" #include "evp/p_hkdf.c" #include "evp/p_hmac.c" #include "evp/p_kem.c" diff --git a/crypto/fipsmodule/evp/evp.c b/crypto/fipsmodule/evp/evp.c index 50ca9b6e33..f241054889 100644 --- a/crypto/fipsmodule/evp/evp.c +++ b/crypto/fipsmodule/evp/evp.c @@ -608,7 +608,7 @@ int EVP_PKEY_CTX_get0_signature_context(EVP_PKEY_CTX *ctx, size_t *context_len) { GUARD_PTR(context); GUARD_PTR(context_len); - EVP_PKEY_CTX_SIGNATURE_CONTEXT_PARAMS params = {}; + EVP_PKEY_CTX_SIGNATURE_CONTEXT_PARAMS params = {NULL, 0}; if (!EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG, EVP_PKEY_CTRL_GET_SIGNING_CONTEXT, 0, ¶ms)) { return 0; diff --git a/crypto/fipsmodule/evp/evp_ctx.c b/crypto/fipsmodule/evp/evp_ctx.c index 21299546e3..6e35a5ba7f 100644 --- a/crypto/fipsmodule/evp/evp_ctx.c +++ b/crypto/fipsmodule/evp/evp_ctx.c @@ -75,7 +75,6 @@ DEFINE_LOCAL_DATA(struct fips_evp_pkey_methods, AWSLC_fips_evp_pkey_methods) { out->methods[4] = EVP_PKEY_hmac_pkey_meth(); out->methods[5] = EVP_PKEY_ed25519_pkey_meth(); out->methods[6] = EVP_PKEY_kem_pkey_meth(); - out->methods[7] = EVP_PKEY_ed25519ph_pkey_meth(); } static const EVP_PKEY_METHOD *evp_pkey_meth_find(int type) { diff --git a/crypto/fipsmodule/evp/internal.h b/crypto/fipsmodule/evp/internal.h index 0b8bd35b49..6c1b5a8552 100644 --- a/crypto/fipsmodule/evp/internal.h +++ b/crypto/fipsmodule/evp/internal.h @@ -386,8 +386,8 @@ int ed25519_keygen(ED25519_KEY **ptr); void evp_pkey_set_cb_translate(BN_GENCB *cb, EVP_PKEY_CTX *ctx); #define ED25519_PUBLIC_KEY_OFFSET 32 -#define FIPS_EVP_PKEY_METHODS 8 -#define NON_FIPS_EVP_PKEY_METHODS 4 +#define FIPS_EVP_PKEY_METHODS 7 +#define NON_FIPS_EVP_PKEY_METHODS 5 #define ASN1_EVP_PKEY_METHODS 11 struct fips_evp_pkey_methods { From 54203b968fddfacaa41b056c67dde31b13ebb4f2 Mon Sep 17 00:00:00 2001 From: Sean McGrail Date: Wed, 29 Jan 2025 22:42:09 +0000 Subject: [PATCH 3/3] Address feedback --- crypto/evp_extra/p_ed25519ph.c | 10 +++++----- crypto/fipsmodule/evp/p_ed25519.c | 7 +++---- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/crypto/evp_extra/p_ed25519ph.c b/crypto/evp_extra/p_ed25519ph.c index 3c7170d02f..d1e5f3a7da 100644 --- a/crypto/evp_extra/p_ed25519ph.c +++ b/crypto/evp_extra/p_ed25519ph.c @@ -77,11 +77,11 @@ static int pkey_ed25519ph_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *siglen, } if (sig == NULL) { - *siglen = 64; + *siglen = ED25519_SIGNATURE_LEN; return 1; } - if (*siglen < 64) { + if (*siglen < ED25519_SIGNATURE_LEN) { OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL); return 0; } @@ -98,7 +98,7 @@ static int pkey_ed25519ph_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *siglen, return 0; } - *siglen = 64; + *siglen = ED25519_SIGNATURE_LEN; return 1; } @@ -109,7 +109,7 @@ static int pkey_ed25519ph_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig, ED25519PH_PKEY_CTX *dctx = ctx->data; GUARD_PTR(dctx); - if (siglen != 64 || tbslen < SHA512_DIGEST_LENGTH || + if (siglen != ED25519_SIGNATURE_LEN || tbslen < SHA512_DIGEST_LENGTH || !ED25519ph_verify_digest(tbs, sig, key->key + ED25519_PUBLIC_KEY_OFFSET, dctx->context, dctx->context_len)) { OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_SIGNATURE); @@ -149,7 +149,7 @@ static int pkey_ed25519ph_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) { } if(dctx->context_len == 0) { params->context = NULL; - params->context = 0; + params->context_len = 0; } else { params->context = dctx->context; params->context_len = dctx->context_len; diff --git a/crypto/fipsmodule/evp/p_ed25519.c b/crypto/fipsmodule/evp/p_ed25519.c index 3807c3e846..6bc698bfe5 100644 --- a/crypto/fipsmodule/evp/p_ed25519.c +++ b/crypto/fipsmodule/evp/p_ed25519.c @@ -26,10 +26,9 @@ static int pkey_ed25519_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) { return 1; } int ed25519_keygen(ED25519_KEY **ptr) { GUARD_PTR(ptr); - if(*ptr != NULL) { - // Free it if we were passed an already allocated-key for some reason. - OPENSSL_free(*ptr); - } + + // Free it if we were passed an already allocated-key for some reason. + OPENSSL_free(*ptr); ED25519_KEY *key = OPENSSL_malloc(sizeof(ED25519_KEY)); if (key == NULL) {