@@ -34,9 +34,13 @@ constexpr static PQCMapping pqc_mappings[] = { |
34 | 34 | {"ML-DSA-44", EVP_PKEY_ML_DSA_44}, |
35 | 35 | {"ML-DSA-65", EVP_PKEY_ML_DSA_65}, |
36 | 36 | {"ML-DSA-87", EVP_PKEY_ML_DSA_87}, |
37 | | - {"ML-KEM-512", EVP_PKEY_ML_KEM_512}, |
38 | 37 | {"ML-KEM-768", EVP_PKEY_ML_KEM_768}, |
39 | 38 | {"ML-KEM-1024", EVP_PKEY_ML_KEM_1024}, |
| 39 | + |
| 40 | +#if OPENSSL_WITH_PQC_ML_KEM_512 |
| 41 | + {"ML-KEM-512", EVP_PKEY_ML_KEM_512}, |
| 42 | +#endif |
| 43 | +#if OPENSSL_WITH_PQC_SLH_DSA |
40 | 44 | {"SLH-DSA-SHA2-128f", EVP_PKEY_SLH_DSA_SHA2_128F}, |
41 | 45 | {"SLH-DSA-SHA2-128s", EVP_PKEY_SLH_DSA_SHA2_128S}, |
42 | 46 | {"SLH-DSA-SHA2-192f", EVP_PKEY_SLH_DSA_SHA2_192F}, |
@@ -49,6 +53,7 @@ constexpr static PQCMapping pqc_mappings[] = { |
49 | 53 | {"SLH-DSA-SHAKE-192s", EVP_PKEY_SLH_DSA_SHAKE_192S}, |
50 | 54 | {"SLH-DSA-SHAKE-256f", EVP_PKEY_SLH_DSA_SHAKE_256F}, |
51 | 55 | {"SLH-DSA-SHAKE-256s", EVP_PKEY_SLH_DSA_SHAKE_256S}, |
| 56 | +#endif |
52 | 57 | }; |
53 | 58 |
|
54 | 59 | #endif |
@@ -2095,27 +2100,99 @@ EVPKeyPointer EVPKeyPointer::NewRawPrivate( |
2095 | 2100 | } |
2096 | 2101 |
|
2097 | 2102 | #if OPENSSL_WITH_PQC |
2098 | | -EVPKeyPointer EVPKeyPointer::NewRawSeed( |
2099 | | - int id, const Buffer<const unsigned char>& data) { |
2100 | | - if (id == 0) return {}; |
| 2103 | +namespace { |
| 2104 | +constexpr size_t kPqcMlDsaSeedSize = 32; |
| 2105 | +constexpr size_t kPqcMlKemSeedSize = 64; |
| 2106 | + |
| 2107 | +size_t GetPqcSeedSize(int id) { |
| 2108 | + switch (id) { |
| 2109 | + case EVP_PKEY_ML_DSA_44: |
| 2110 | + case EVP_PKEY_ML_DSA_65: |
| 2111 | + case EVP_PKEY_ML_DSA_87: |
| 2112 | + return kPqcMlDsaSeedSize; |
| 2113 | +#if OPENSSL_WITH_PQC_ML_KEM_512 |
| 2114 | + case EVP_PKEY_ML_KEM_512: |
| 2115 | +#endif |
| 2116 | + case EVP_PKEY_ML_KEM_768: |
| 2117 | + case EVP_PKEY_ML_KEM_1024: |
| 2118 | + return kPqcMlKemSeedSize; |
| 2119 | + default: |
| 2120 | + unreachable(); |
| 2121 | + } |
| 2122 | +} |
| 2123 | + |
| 2124 | +#if OPENSSL_WITH_BORINGSSL_PQC |
| 2125 | +const EVP_PKEY_ALG* GetPqcSeedAlg(int id) { |
| 2126 | + switch (id) { |
| 2127 | + case EVP_PKEY_ML_DSA_44: |
| 2128 | + return EVP_pkey_ml_dsa_44(); |
| 2129 | + case EVP_PKEY_ML_DSA_65: |
| 2130 | + return EVP_pkey_ml_dsa_65(); |
| 2131 | + case EVP_PKEY_ML_DSA_87: |
| 2132 | + return EVP_pkey_ml_dsa_87(); |
| 2133 | + case EVP_PKEY_ML_KEM_768: |
| 2134 | + return EVP_pkey_ml_kem_768(); |
| 2135 | + case EVP_PKEY_ML_KEM_1024: |
| 2136 | + return EVP_pkey_ml_kem_1024(); |
| 2137 | + default: |
| 2138 | + unreachable(); |
| 2139 | + } |
| 2140 | +} |
| 2141 | +#else |
| 2142 | +const char* GetPqcSeedParamName(int id) { |
| 2143 | + switch (id) { |
| 2144 | + case EVP_PKEY_ML_DSA_44: |
| 2145 | + case EVP_PKEY_ML_DSA_65: |
| 2146 | + case EVP_PKEY_ML_DSA_87: |
| 2147 | + return OSSL_PKEY_PARAM_ML_DSA_SEED; |
| 2148 | + case EVP_PKEY_ML_KEM_512: |
| 2149 | + case EVP_PKEY_ML_KEM_768: |
| 2150 | + case EVP_PKEY_ML_KEM_1024: |
| 2151 | + return OSSL_PKEY_PARAM_ML_KEM_SEED; |
| 2152 | + default: |
| 2153 | + unreachable(); |
| 2154 | + } |
| 2155 | +} |
| 2156 | +#endif |
2101 | 2157 |
|
| 2158 | +EVPKeyPointer NewPqcKeyFromSeed(int id, |
| 2159 | + const Buffer<const unsigned char>& data) { |
| 2160 | +#if OPENSSL_WITH_BORINGSSL_PQC |
| 2161 | + return EVPKeyPointer( |
| 2162 | + EVP_PKEY_from_private_seed(GetPqcSeedAlg(id), data.data, data.len)); |
| 2163 | +#else |
2102 | 2164 | OSSL_PARAM params[] = { |
2103 | | - OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_ML_DSA_SEED, |
| 2165 | + OSSL_PARAM_construct_octet_string(GetPqcSeedParamName(id), |
2104 | 2166 | const_cast<unsigned char*>(data.data), |
2105 | 2167 | data.len), |
2106 | 2168 | OSSL_PARAM_END}; |
2107 | 2169 |
|
2108 | | - EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_id(id, nullptr); |
2109 | | - if (ctx == nullptr) return {}; |
| 2170 | + auto ctx = EVPKeyCtxPointer::NewFromID(id); |
| 2171 | + if (!ctx) return {}; |
2110 | 2172 |
|
2111 | 2173 | EVP_PKEY* pkey = nullptr; |
2112 | | - if (ctx == nullptr || EVP_PKEY_fromdata_init(ctx) <= 0 || |
2113 | | - EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_KEYPAIR, params) <= 0) { |
2114 | | - EVP_PKEY_CTX_free(ctx); |
| 2174 | + if (EVP_PKEY_fromdata_init(ctx.get()) <= 0 || |
| 2175 | + EVP_PKEY_fromdata(ctx.get(), &pkey, EVP_PKEY_KEYPAIR, params) <= 0) { |
2115 | 2176 | return {}; |
2116 | 2177 | } |
2117 | | - |
2118 | 2178 | return EVPKeyPointer(pkey); |
| 2179 | +#endif |
| 2180 | +} |
| 2181 | + |
| 2182 | +bool GetPqcSeed(EVP_PKEY* pkey, int id, const Buffer<unsigned char>& out) { |
| 2183 | + size_t len = out.len; |
| 2184 | +#if OPENSSL_WITH_BORINGSSL_PQC |
| 2185 | + return EVP_PKEY_get_private_seed(pkey, out.data, &len) == 1; |
| 2186 | +#else |
| 2187 | + return EVP_PKEY_get_octet_string_param( |
| 2188 | + pkey, GetPqcSeedParamName(id), out.data, out.len, &len) == 1; |
| 2189 | +#endif |
| 2190 | +} |
| 2191 | +} // namespace |
| 2192 | + |
| 2193 | +EVPKeyPointer EVPKeyPointer::NewRawSeed( |
| 2194 | + int id, const Buffer<const unsigned char>& data) { |
| 2195 | + return NewPqcKeyFromSeed(id, data); |
2119 | 2196 | } |
2120 | 2197 | #endif |
2121 | 2198 |
|
@@ -2165,7 +2242,7 @@ EVP_PKEY* EVPKeyPointer::release() { |
2165 | 2242 | int EVPKeyPointer::id(const EVP_PKEY* key) { |
2166 | 2243 | if (key == nullptr) return 0; |
2167 | 2244 | int type = EVP_PKEY_id(key); |
2168 | | -#if OPENSSL_WITH_PQC |
| 2245 | +#if OPENSSL_WITH_OPENSSL_PQC |
2169 | 2246 | // EVP_PKEY_id returns -1 when EVP_PKEY_* is only implemented in a provider |
2170 | 2247 | // which is the case for all post-quantum NIST algorithms |
2171 | 2248 | // one suggested way would be to use a chain of `EVP_PKEY_is_a` |
@@ -2243,34 +2320,11 @@ DataPointer EVPKeyPointer::rawPublicKey() const { |
2243 | 2320 | DataPointer EVPKeyPointer::rawSeed() const { |
2244 | 2321 | if (!pkey_) return {}; |
2245 | 2322 |
|
2246 | | - // Determine seed length and parameter name based on key type |
2247 | | - size_t seed_len; |
2248 | | - const char* param_name; |
2249 | | - |
2250 | | - switch (id()) { |
2251 | | - case EVP_PKEY_ML_DSA_44: |
2252 | | - case EVP_PKEY_ML_DSA_65: |
2253 | | - case EVP_PKEY_ML_DSA_87: |
2254 | | - seed_len = 32; // ML-DSA uses 32-byte seeds |
2255 | | - param_name = OSSL_PKEY_PARAM_ML_DSA_SEED; |
2256 | | - break; |
2257 | | - case EVP_PKEY_ML_KEM_512: |
2258 | | - case EVP_PKEY_ML_KEM_768: |
2259 | | - case EVP_PKEY_ML_KEM_1024: |
2260 | | - seed_len = 64; // ML-KEM uses 64-byte seeds |
2261 | | - param_name = OSSL_PKEY_PARAM_ML_KEM_SEED; |
2262 | | - break; |
2263 | | - default: |
2264 | | - unreachable(); |
2265 | | - } |
| 2323 | + const size_t seed_len = GetPqcSeedSize(id()); |
2266 | 2324 |
|
2267 | 2325 | if (auto data = DataPointer::Alloc(seed_len)) { |
2268 | 2326 | const Buffer<unsigned char> buf = data; |
2269 | | - size_t len = data.size(); |
2270 | | - |
2271 | | - if (EVP_PKEY_get_octet_string_param( |
2272 | | - get(), param_name, buf.data, len, &seed_len) != 1) |
2273 | | - return {}; |
| 2327 | + if (!GetPqcSeed(get(), id(), buf)) return {}; |
2274 | 2328 | return data; |
2275 | 2329 | } |
2276 | 2330 | return {}; |
@@ -2312,6 +2366,7 @@ EVPKeyPointer::operator const EC_KEY*() const { |
2312 | 2366 | } |
2313 | 2367 |
|
2314 | 2368 | namespace { |
| 2369 | + |
2315 | 2370 | EVPKeyPointer::ParseKeyResult TryParsePublicKeyInner(const BIOPointer& bp, |
2316 | 2371 | const char* name, |
2317 | 2372 | auto&& parse) { |
@@ -2739,6 +2794,7 @@ bool EVPKeyPointer::isOneShotVariant() const { |
2739 | 2794 | case EVP_PKEY_ML_DSA_44: |
2740 | 2795 | case EVP_PKEY_ML_DSA_65: |
2741 | 2796 | case EVP_PKEY_ML_DSA_87: |
| 2797 | +#if OPENSSL_WITH_PQC_SLH_DSA |
2742 | 2798 | case EVP_PKEY_SLH_DSA_SHA2_128F: |
2743 | 2799 | case EVP_PKEY_SLH_DSA_SHA2_128S: |
2744 | 2800 | case EVP_PKEY_SLH_DSA_SHA2_192F: |
@@ -2751,6 +2807,7 @@ bool EVPKeyPointer::isOneShotVariant() const { |
2751 | 2807 | case EVP_PKEY_SLH_DSA_SHAKE_192S: |
2752 | 2808 | case EVP_PKEY_SLH_DSA_SHAKE_256F: |
2753 | 2809 | case EVP_PKEY_SLH_DSA_SHAKE_256S: |
| 2810 | +#endif |
2754 | 2811 | #endif |
2755 | 2812 | return true; |
2756 | 2813 | default: |
@@ -4401,7 +4458,17 @@ std::optional<EVP_PKEY_CTX*> EVPMDCtxPointer::signInitWithContext( |
4401 | 4458 | const EVPKeyPointer& key, |
4402 | 4459 | const Digest& digest, |
4403 | 4460 | const Buffer<const unsigned char>& context_string) { |
4404 | | -#ifdef OSSL_SIGNATURE_PARAM_CONTEXT_STRING |
| 4461 | +#ifdef OPENSSL_IS_BORINGSSL |
| 4462 | + EVP_PKEY_CTX* ctx = nullptr; |
| 4463 | + if (!EVP_DigestSignInit(ctx_.get(), &ctx, digest, nullptr, key.get())) { |
| 4464 | + return std::nullopt; |
| 4465 | + } |
| 4466 | + if (EVP_PKEY_CTX_set1_signature_context_string( |
| 4467 | + ctx, context_string.data, context_string.len) <= 0) { |
| 4468 | + return std::nullopt; |
| 4469 | + } |
| 4470 | + return ctx; |
| 4471 | +#elif defined(OSSL_SIGNATURE_PARAM_CONTEXT_STRING) |
4405 | 4472 | EVP_PKEY_CTX* ctx = nullptr; |
4406 | 4473 |
|
4407 | 4474 | #ifdef OSSL_SIGNATURE_PARAM_INSTANCE |
@@ -4446,7 +4513,17 @@ std::optional<EVP_PKEY_CTX*> EVPMDCtxPointer::verifyInitWithContext( |
4446 | 4513 | const EVPKeyPointer& key, |
4447 | 4514 | const Digest& digest, |
4448 | 4515 | const Buffer<const unsigned char>& context_string) { |
4449 | | -#ifdef OSSL_SIGNATURE_PARAM_CONTEXT_STRING |
| 4516 | +#ifdef OPENSSL_IS_BORINGSSL |
| 4517 | + EVP_PKEY_CTX* ctx = nullptr; |
| 4518 | + if (!EVP_DigestVerifyInit(ctx_.get(), &ctx, digest, nullptr, key.get())) { |
| 4519 | + return std::nullopt; |
| 4520 | + } |
| 4521 | + if (EVP_PKEY_CTX_set1_signature_context_string( |
| 4522 | + ctx, context_string.data, context_string.len) <= 0) { |
| 4523 | + return std::nullopt; |
| 4524 | + } |
| 4525 | + return ctx; |
| 4526 | +#elif defined(OSSL_SIGNATURE_PARAM_CONTEXT_STRING) |
4450 | 4527 | EVP_PKEY_CTX* ctx = nullptr; |
4451 | 4528 |
|
4452 | 4529 | #ifdef OSSL_SIGNATURE_PARAM_INSTANCE |
|