/src/boringssl/crypto/evp/p_mlkem.cc
Line | Count | Source |
1 | | // Copyright 2026 The BoringSSL Authors |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | #include <openssl/evp.h> |
16 | | |
17 | | #include <assert.h> |
18 | | #include <stddef.h> |
19 | | #include <stdint.h> |
20 | | |
21 | | #include <type_traits> |
22 | | |
23 | | #include <openssl/bytestring.h> |
24 | | #include <openssl/err.h> |
25 | | #include <openssl/evp_errors.h> |
26 | | #include <openssl/mlkem.h> |
27 | | #include <openssl/nid.h> |
28 | | #include <openssl/span.h> |
29 | | |
30 | | #include "../fipsmodule/bcm_interface.h" |
31 | | #include "../internal.h" |
32 | | #include "../mem_internal.h" |
33 | | #include "internal.h" |
34 | | |
35 | | using namespace bssl; |
36 | | |
37 | | namespace { |
38 | | |
39 | | constexpr CBS_ASN1_TAG kSeedTag = CBS_ASN1_CONTEXT_SPECIFIC | 0; |
40 | | |
41 | | constexpr uint8_t kMLKEM768OID[] = {OBJ_ENC_ML_KEM_768}; |
42 | | constexpr uint8_t kMLKEM1024OID[] = {OBJ_ENC_ML_KEM_1024}; |
43 | | |
44 | | // Generate EVP bindings for multiple ML-KEM algorithms. |
45 | | #define MAKE_MLKEM_TRAITS(x) \ |
46 | | struct MLKEM##x##Traits { \ |
47 | | using PublicKey = MLKEM##x##_public_key; \ |
48 | | using PrivateKey = MLKEM##x##_private_key; \ |
49 | | static constexpr size_t kPublicKeyBytes = MLKEM##x##_PUBLIC_KEY_BYTES; \ |
50 | | static constexpr size_t kCiphertextBytes = MLKEM##x##_CIPHERTEXT_BYTES; \ |
51 | | static constexpr int kType = EVP_PKEY_ML_KEM_##x; \ |
52 | | static constexpr Span<const uint8_t> kOID = kMLKEM##x##OID; \ |
53 | | static constexpr auto GenerateKey = &MLKEM##x##_generate_key; \ |
54 | | static constexpr auto PrivateKeyFromSeed = \ |
55 | | &MLKEM##x##_private_key_from_seed; \ |
56 | | static constexpr auto PublicOfPrivate = &BCM_mlkem##x##_public_of_private; \ |
57 | | static constexpr auto PublicKeysEqual = &BCM_mlkem##x##_public_keys_equal; \ |
58 | | static constexpr auto Encap = &MLKEM##x##_encap; \ |
59 | | static constexpr auto Decap = &MLKEM##x##_decap; \ |
60 | | static constexpr auto MarshalPublicKey = &MLKEM##x##_marshal_public_key; \ |
61 | | static constexpr auto ParsePublicKey = &MLKEM##x##_parse_public_key; \ |
62 | | static_assert(std::is_trivially_copyable_v<PublicKey>, \ |
63 | | "PublicKey type must be trivially copyable."); \ |
64 | | }; |
65 | | |
66 | | MAKE_MLKEM_TRAITS(768) |
67 | | MAKE_MLKEM_TRAITS(1024) |
68 | | |
69 | | template <typename Traits> |
70 | | class PrivateKeyData; |
71 | | |
72 | | // The private key type contains the public key struct in it, so we use a |
73 | | // pointer to either a PrivateKeyData<Traits> or PublicKeyData<Traits>, with a |
74 | | // common base class to dispatch between them. |
75 | | template <typename Traits> |
76 | | class KeyData { |
77 | | public: |
78 | | // Returns the underlying public key for the key. |
79 | | const typename Traits::PublicKey *GetPublicKey() const; |
80 | | |
81 | | // Returns the PrivateKeyData struct for the key, or nullptr if this is a |
82 | | // public key. |
83 | | PrivateKeyData<Traits> *AsPrivateKeyData(); |
84 | 95 | const PrivateKeyData<Traits> *AsPrivateKeyData() const { |
85 | 95 | return const_cast<KeyData *>(this)->AsPrivateKeyData(); |
86 | 95 | } p_mlkem.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLKEM768Traits>::AsPrivateKeyData() const Line | Count | Source | 84 | 32 | const PrivateKeyData<Traits> *AsPrivateKeyData() const { | 85 | 32 | return const_cast<KeyData *>(this)->AsPrivateKeyData(); | 86 | 32 | } |
p_mlkem.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLKEM1024Traits>::AsPrivateKeyData() const Line | Count | Source | 84 | 63 | const PrivateKeyData<Traits> *AsPrivateKeyData() const { | 85 | 63 | return const_cast<KeyData *>(this)->AsPrivateKeyData(); | 86 | 63 | } |
|
87 | | |
88 | | // A KeyData cannot be freed directly. Rather, it must use this wrapper which |
89 | | // calls the correct subclass's destructor. |
90 | | static void Free(KeyData *data); |
91 | | |
92 | | protected: |
93 | 307 | explicit KeyData(bool is_private) : is_private_(is_private) {}p_mlkem.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLKEM768Traits>::KeyData(bool) Line | Count | Source | 93 | 133 | explicit KeyData(bool is_private) : is_private_(is_private) {} |
p_mlkem.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLKEM1024Traits>::KeyData(bool) Line | Count | Source | 93 | 174 | explicit KeyData(bool is_private) : is_private_(is_private) {} |
|
94 | | ~KeyData() = default; |
95 | | bool is_private_; |
96 | | }; |
97 | | |
98 | | template <typename Traits> |
99 | | class PublicKeyData : public KeyData<Traits> { |
100 | | public: |
101 | | enum { kAllowUniquePtr = true }; |
102 | 159 | PublicKeyData() : KeyData<Traits>(/*is_private=*/false) {}p_mlkem.cc:(anonymous namespace)::PublicKeyData<(anonymous namespace)::MLKEM768Traits>::PublicKeyData() Line | Count | Source | 102 | 70 | PublicKeyData() : KeyData<Traits>(/*is_private=*/false) {} |
p_mlkem.cc:(anonymous namespace)::PublicKeyData<(anonymous namespace)::MLKEM1024Traits>::PublicKeyData() Line | Count | Source | 102 | 89 | PublicKeyData() : KeyData<Traits>(/*is_private=*/false) {} |
|
103 | | |
104 | | // Allows copying the PublicKey. |
105 | | explicit PublicKeyData(const typename Traits::PublicKey &key) |
106 | 0 | : KeyData<Traits>(/*is_private=*/false), pub(key) {}Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::PublicKeyData<(anonymous namespace)::MLKEM768Traits>::PublicKeyData(MLKEM768_public_key const&) Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::PublicKeyData<(anonymous namespace)::MLKEM1024Traits>::PublicKeyData(MLKEM1024_public_key const&) |
107 | | |
108 | | typename Traits::PublicKey pub; |
109 | | }; |
110 | | |
111 | | template <typename Traits> |
112 | | class PrivateKeyData : public KeyData<Traits> { |
113 | | public: |
114 | | enum { kAllowUniquePtr = true }; |
115 | 148 | PrivateKeyData() : KeyData<Traits>(/*is_private=*/true) {}p_mlkem.cc:(anonymous namespace)::PrivateKeyData<(anonymous namespace)::MLKEM768Traits>::PrivateKeyData() Line | Count | Source | 115 | 63 | PrivateKeyData() : KeyData<Traits>(/*is_private=*/true) {} |
p_mlkem.cc:(anonymous namespace)::PrivateKeyData<(anonymous namespace)::MLKEM1024Traits>::PrivateKeyData() Line | Count | Source | 115 | 85 | PrivateKeyData() : KeyData<Traits>(/*is_private=*/true) {} |
|
116 | | typename Traits::PrivateKey priv; |
117 | | uint8_t seed[MLKEM_SEED_BYTES]; |
118 | | }; |
119 | | |
120 | | template <typename Traits> |
121 | 0 | const typename Traits::PublicKey *KeyData<Traits>::GetPublicKey() const { |
122 | 0 | auto *priv_data = AsPrivateKeyData(); |
123 | 0 | if (priv_data != nullptr) { |
124 | 0 | return Traits::PublicOfPrivate(&priv_data->priv); |
125 | 0 | } |
126 | 0 | return &static_cast<const PublicKeyData<Traits> *>(this)->pub; |
127 | 0 | } Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLKEM768Traits>::GetPublicKey() const Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLKEM1024Traits>::GetPublicKey() const |
128 | | |
129 | | template <typename Traits> |
130 | 213 | PrivateKeyData<Traits> *KeyData<Traits>::AsPrivateKeyData() { |
131 | 213 | if (is_private_) { |
132 | 190 | return static_cast<PrivateKeyData<Traits> *>(this); |
133 | 190 | } |
134 | 23 | return nullptr; |
135 | 213 | } p_mlkem.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLKEM768Traits>::AsPrivateKeyData() Line | Count | Source | 130 | 75 | PrivateKeyData<Traits> *KeyData<Traits>::AsPrivateKeyData() { | 131 | 75 | if (is_private_) { | 132 | 64 | return static_cast<PrivateKeyData<Traits> *>(this); | 133 | 64 | } | 134 | 11 | return nullptr; | 135 | 75 | } |
p_mlkem.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLKEM1024Traits>::AsPrivateKeyData() Line | Count | Source | 130 | 138 | PrivateKeyData<Traits> *KeyData<Traits>::AsPrivateKeyData() { | 131 | 138 | if (is_private_) { | 132 | 126 | return static_cast<PrivateKeyData<Traits> *>(this); | 133 | 126 | } | 134 | 12 | return nullptr; | 135 | 138 | } |
|
136 | | |
137 | | template <typename Traits> |
138 | 118 | void KeyData<Traits>::Free(KeyData<Traits> *data) { |
139 | 118 | if (data == nullptr) { |
140 | 0 | return; |
141 | 0 | } |
142 | | // Delete the more specific subclass. This is moot for now, because neither |
143 | | // type has a non-trivial destructor. |
144 | 118 | auto *priv_data = data->AsPrivateKeyData(); |
145 | 118 | if (priv_data) { |
146 | 95 | Delete(priv_data); |
147 | 95 | } else { |
148 | 23 | Delete(static_cast<PublicKeyData<Traits> *>(data)); |
149 | 23 | } |
150 | 118 | } p_mlkem.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLKEM768Traits>::Free((anonymous namespace)::KeyData<(anonymous namespace)::MLKEM768Traits>*) Line | Count | Source | 138 | 43 | void KeyData<Traits>::Free(KeyData<Traits> *data) { | 139 | 43 | if (data == nullptr) { | 140 | 0 | return; | 141 | 0 | } | 142 | | // Delete the more specific subclass. This is moot for now, because neither | 143 | | // type has a non-trivial destructor. | 144 | 43 | auto *priv_data = data->AsPrivateKeyData(); | 145 | 43 | if (priv_data) { | 146 | 32 | Delete(priv_data); | 147 | 32 | } else { | 148 | 11 | Delete(static_cast<PublicKeyData<Traits> *>(data)); | 149 | 11 | } | 150 | 43 | } |
p_mlkem.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLKEM1024Traits>::Free((anonymous namespace)::KeyData<(anonymous namespace)::MLKEM1024Traits>*) Line | Count | Source | 138 | 75 | void KeyData<Traits>::Free(KeyData<Traits> *data) { | 139 | 75 | if (data == nullptr) { | 140 | 0 | return; | 141 | 0 | } | 142 | | // Delete the more specific subclass. This is moot for now, because neither | 143 | | // type has a non-trivial destructor. | 144 | 75 | auto *priv_data = data->AsPrivateKeyData(); | 145 | 75 | if (priv_data) { | 146 | 63 | Delete(priv_data); | 147 | 63 | } else { | 148 | 12 | Delete(static_cast<PublicKeyData<Traits> *>(data)); | 149 | 12 | } | 150 | 75 | } |
|
151 | | |
152 | | template <typename Traits> |
153 | | struct MLKEMImplementation { |
154 | 213 | static KeyData<Traits> *GetKeyData(EvpPkey *pkey) { |
155 | 213 | assert(pkey->ameth == &asn1_method); |
156 | 213 | return static_cast<KeyData<Traits> *>(pkey->pkey); |
157 | 213 | } p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM768Traits>::GetKeyData(bssl::EvpPkey*) Line | Count | Source | 154 | 75 | static KeyData<Traits> *GetKeyData(EvpPkey *pkey) { | 155 | 75 | assert(pkey->ameth == &asn1_method); | 156 | 75 | return static_cast<KeyData<Traits> *>(pkey->pkey); | 157 | 75 | } |
p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM1024Traits>::GetKeyData(bssl::EvpPkey*) Line | Count | Source | 154 | 138 | static KeyData<Traits> *GetKeyData(EvpPkey *pkey) { | 155 | 138 | assert(pkey->ameth == &asn1_method); | 156 | 138 | return static_cast<KeyData<Traits> *>(pkey->pkey); | 157 | 138 | } |
|
158 | | |
159 | 95 | static const KeyData<Traits> *GetKeyData(const EvpPkey *pkey) { |
160 | 95 | return GetKeyData(const_cast<EvpPkey *>(pkey)); |
161 | 95 | } p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM768Traits>::GetKeyData(bssl::EvpPkey const*) Line | Count | Source | 159 | 32 | static const KeyData<Traits> *GetKeyData(const EvpPkey *pkey) { | 160 | 32 | return GetKeyData(const_cast<EvpPkey *>(pkey)); | 161 | 32 | } |
p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM1024Traits>::GetKeyData(bssl::EvpPkey const*) Line | Count | Source | 159 | 63 | static const KeyData<Traits> *GetKeyData(const EvpPkey *pkey) { | 160 | 63 | return GetKeyData(const_cast<EvpPkey *>(pkey)); | 161 | 63 | } |
|
162 | | |
163 | 118 | static void PkeyFree(EvpPkey *pkey) { |
164 | 118 | KeyData<Traits>::Free(GetKeyData(pkey)); |
165 | 118 | pkey->pkey = nullptr; |
166 | 118 | } p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM768Traits>::PkeyFree(bssl::EvpPkey*) Line | Count | Source | 163 | 43 | static void PkeyFree(EvpPkey *pkey) { | 164 | 43 | KeyData<Traits>::Free(GetKeyData(pkey)); | 165 | 43 | pkey->pkey = nullptr; | 166 | 43 | } |
p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM1024Traits>::PkeyFree(bssl::EvpPkey*) Line | Count | Source | 163 | 75 | static void PkeyFree(EvpPkey *pkey) { | 164 | 75 | KeyData<Traits>::Free(GetKeyData(pkey)); | 165 | 75 | pkey->pkey = nullptr; | 166 | 75 | } |
|
167 | | |
168 | 148 | static int SetPrivateSeed(EvpPkey *pkey, const uint8_t *in, size_t len) { |
169 | 148 | auto priv = MakeUnique<PrivateKeyData<Traits>>(); |
170 | 148 | if (priv == nullptr) { |
171 | 0 | return 0; |
172 | 0 | } |
173 | | |
174 | 148 | if (len != MLKEM_SEED_BYTES || |
175 | 95 | !Traits::PrivateKeyFromSeed(&priv->priv, in, len)) { |
176 | 53 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); |
177 | 53 | return 0; |
178 | 53 | } |
179 | 95 | OPENSSL_memcpy(priv->seed, in, len); |
180 | 95 | evp_pkey_set0(pkey, &asn1_method, priv.release()); |
181 | 95 | return 1; |
182 | 148 | } p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM768Traits>::SetPrivateSeed(bssl::EvpPkey*, unsigned char const*, unsigned long) Line | Count | Source | 168 | 63 | static int SetPrivateSeed(EvpPkey *pkey, const uint8_t *in, size_t len) { | 169 | 63 | auto priv = MakeUnique<PrivateKeyData<Traits>>(); | 170 | 63 | if (priv == nullptr) { | 171 | 0 | return 0; | 172 | 0 | } | 173 | | | 174 | 63 | if (len != MLKEM_SEED_BYTES || | 175 | 32 | !Traits::PrivateKeyFromSeed(&priv->priv, in, len)) { | 176 | 31 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); | 177 | 31 | return 0; | 178 | 31 | } | 179 | 32 | OPENSSL_memcpy(priv->seed, in, len); | 180 | 32 | evp_pkey_set0(pkey, &asn1_method, priv.release()); | 181 | 32 | return 1; | 182 | 63 | } |
p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM1024Traits>::SetPrivateSeed(bssl::EvpPkey*, unsigned char const*, unsigned long) Line | Count | Source | 168 | 85 | static int SetPrivateSeed(EvpPkey *pkey, const uint8_t *in, size_t len) { | 169 | 85 | auto priv = MakeUnique<PrivateKeyData<Traits>>(); | 170 | 85 | if (priv == nullptr) { | 171 | 0 | return 0; | 172 | 0 | } | 173 | | | 174 | 85 | if (len != MLKEM_SEED_BYTES || | 175 | 63 | !Traits::PrivateKeyFromSeed(&priv->priv, in, len)) { | 176 | 22 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); | 177 | 22 | return 0; | 178 | 22 | } | 179 | 63 | OPENSSL_memcpy(priv->seed, in, len); | 180 | 63 | evp_pkey_set0(pkey, &asn1_method, priv.release()); | 181 | 63 | return 1; | 182 | 85 | } |
|
183 | | |
184 | 159 | static int SetRawPublic(EvpPkey *pkey, const uint8_t *in, size_t len) { |
185 | 159 | auto pub = MakeUnique<PublicKeyData<Traits>>(); |
186 | 159 | if (pub == nullptr) { |
187 | 0 | return 0; |
188 | 0 | } |
189 | 159 | CBS cbs; |
190 | 159 | CBS_init(&cbs, in, len); |
191 | 159 | if (!Traits::ParsePublicKey(&pub->pub, &cbs) || CBS_len(&cbs) != 0) { |
192 | 136 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); |
193 | 136 | return 0; |
194 | 136 | } |
195 | 23 | evp_pkey_set0(pkey, &asn1_method, pub.release()); |
196 | 23 | return 1; |
197 | 159 | } p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM768Traits>::SetRawPublic(bssl::EvpPkey*, unsigned char const*, unsigned long) Line | Count | Source | 184 | 70 | static int SetRawPublic(EvpPkey *pkey, const uint8_t *in, size_t len) { | 185 | 70 | auto pub = MakeUnique<PublicKeyData<Traits>>(); | 186 | 70 | if (pub == nullptr) { | 187 | 0 | return 0; | 188 | 0 | } | 189 | 70 | CBS cbs; | 190 | 70 | CBS_init(&cbs, in, len); | 191 | 70 | if (!Traits::ParsePublicKey(&pub->pub, &cbs) || CBS_len(&cbs) != 0) { | 192 | 59 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); | 193 | 59 | return 0; | 194 | 59 | } | 195 | 11 | evp_pkey_set0(pkey, &asn1_method, pub.release()); | 196 | 11 | return 1; | 197 | 70 | } |
p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM1024Traits>::SetRawPublic(bssl::EvpPkey*, unsigned char const*, unsigned long) Line | Count | Source | 184 | 89 | static int SetRawPublic(EvpPkey *pkey, const uint8_t *in, size_t len) { | 185 | 89 | auto pub = MakeUnique<PublicKeyData<Traits>>(); | 186 | 89 | if (pub == nullptr) { | 187 | 0 | return 0; | 188 | 0 | } | 189 | 89 | CBS cbs; | 190 | 89 | CBS_init(&cbs, in, len); | 191 | 89 | if (!Traits::ParsePublicKey(&pub->pub, &cbs) || CBS_len(&cbs) != 0) { | 192 | 77 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); | 193 | 77 | return 0; | 194 | 77 | } | 195 | 12 | evp_pkey_set0(pkey, &asn1_method, pub.release()); | 196 | 12 | return 1; | 197 | 89 | } |
|
198 | | |
199 | | static int GetPrivateSeed(const EvpPkey *pkey, uint8_t *out, |
200 | 0 | size_t *out_len) { |
201 | 0 | const auto *priv = GetKeyData(pkey)->AsPrivateKeyData(); |
202 | 0 | if (priv == nullptr) { |
203 | 0 | OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY); |
204 | 0 | return 0; |
205 | 0 | } |
206 | 0 | if (out == nullptr) { |
207 | 0 | *out_len = MLKEM_SEED_BYTES; |
208 | 0 | return 1; |
209 | 0 | } |
210 | 0 | if (*out_len < MLKEM_SEED_BYTES) { |
211 | 0 | OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL); |
212 | 0 | return 0; |
213 | 0 | } |
214 | 0 | OPENSSL_memcpy(out, priv->seed, MLKEM_SEED_BYTES); |
215 | 0 | *out_len = MLKEM_SEED_BYTES; |
216 | 0 | return 1; |
217 | 0 | } Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM768Traits>::GetPrivateSeed(bssl::EvpPkey const*, unsigned char*, unsigned long*) Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM1024Traits>::GetPrivateSeed(bssl::EvpPkey const*, unsigned char*, unsigned long*) |
218 | | |
219 | 0 | static int GetRawPublic(const EvpPkey *pkey, uint8_t *out, size_t *out_len) { |
220 | 0 | const auto *pub = GetKeyData(pkey)->GetPublicKey(); |
221 | 0 | if (out == nullptr) { |
222 | 0 | *out_len = Traits::kPublicKeyBytes; |
223 | 0 | return 1; |
224 | 0 | } |
225 | 0 | if (*out_len < Traits::kPublicKeyBytes) { |
226 | 0 | OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL); |
227 | 0 | return 0; |
228 | 0 | } |
229 | 0 | CBB cbb; |
230 | 0 | CBB_init_fixed(&cbb, out, Traits::kPublicKeyBytes); |
231 | 0 | BSSL_CHECK(Traits::MarshalPublicKey(&cbb, pub)); |
232 | 0 | BSSL_CHECK(CBB_len(&cbb) == Traits::kPublicKeyBytes); |
233 | 0 | *out_len = Traits::kPublicKeyBytes; |
234 | 0 | return 1; |
235 | 0 | } Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM768Traits>::GetRawPublic(bssl::EvpPkey const*, unsigned char*, unsigned long*) Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM1024Traits>::GetRawPublic(bssl::EvpPkey const*, unsigned char*, unsigned long*) |
236 | | |
237 | | static evp_decode_result_t DecodePublic(const EVP_PKEY_ALG *alg, EvpPkey *out, |
238 | 255 | CBS *params, CBS *key) { |
239 | | // Parameters must be absent. See RFC 9935, section 3. |
240 | 255 | if (CBS_len(params) != 0) { |
241 | 96 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); |
242 | 96 | return evp_decode_error; |
243 | 96 | } |
244 | 159 | return SetRawPublic(out, CBS_data(key), CBS_len(key)) ? evp_decode_ok |
245 | 159 | : evp_decode_error; |
246 | 255 | } p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM768Traits>::DecodePublic(evp_pkey_alg_st const*, bssl::EvpPkey*, cbs_st*, cbs_st*) Line | Count | Source | 238 | 106 | CBS *params, CBS *key) { | 239 | | // Parameters must be absent. See RFC 9935, section 3. | 240 | 106 | if (CBS_len(params) != 0) { | 241 | 36 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); | 242 | 36 | return evp_decode_error; | 243 | 36 | } | 244 | 70 | return SetRawPublic(out, CBS_data(key), CBS_len(key)) ? evp_decode_ok | 245 | 70 | : evp_decode_error; | 246 | 106 | } |
p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM1024Traits>::DecodePublic(evp_pkey_alg_st const*, bssl::EvpPkey*, cbs_st*, cbs_st*) Line | Count | Source | 238 | 149 | CBS *params, CBS *key) { | 239 | | // Parameters must be absent. See RFC 9935, section 3. | 240 | 149 | if (CBS_len(params) != 0) { | 241 | 60 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); | 242 | 60 | return evp_decode_error; | 243 | 60 | } | 244 | 89 | return SetRawPublic(out, CBS_data(key), CBS_len(key)) ? evp_decode_ok | 245 | 89 | : evp_decode_error; | 246 | 149 | } |
|
247 | | |
248 | 0 | static int EncodePublic(CBB *out, const EvpPkey *pkey) { |
249 | 0 | const auto *pub = GetKeyData(pkey)->GetPublicKey(); |
250 | | // See RFC 9935, section 4. |
251 | 0 | CBB spki, algorithm, key_bitstring; |
252 | 0 | if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) || |
253 | 0 | !CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) || |
254 | 0 | !CBB_add_asn1_element(&algorithm, CBS_ASN1_OBJECT, Traits::kOID.data(), |
255 | 0 | Traits::kOID.size()) || |
256 | 0 | !CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) || |
257 | 0 | !CBB_add_u8(&key_bitstring, 0 /* no unused bits */) || |
258 | 0 | !Traits::MarshalPublicKey(&key_bitstring, pub) || // |
259 | 0 | !CBB_flush(out)) { |
260 | 0 | OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR); |
261 | 0 | return 0; |
262 | 0 | } |
263 | 0 | return 1; |
264 | 0 | } Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM768Traits>::EncodePublic(cbb_st*, bssl::EvpPkey const*) Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM1024Traits>::EncodePublic(cbb_st*, bssl::EvpPkey const*) |
265 | | |
266 | 0 | static bool EqualPublic(const EvpPkey *a, const EvpPkey *b) { |
267 | 0 | const auto *a_pub = GetKeyData(a)->GetPublicKey(); |
268 | 0 | const auto *b_pub = GetKeyData(b)->GetPublicKey(); |
269 | 0 | return Traits::PublicKeysEqual(a_pub, b_pub); |
270 | 0 | } Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM768Traits>::EqualPublic(bssl::EvpPkey const*, bssl::EvpPkey const*) Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM1024Traits>::EqualPublic(bssl::EvpPkey const*, bssl::EvpPkey const*) |
271 | | |
272 | 0 | static bool HasPublic(const EvpPkey *pk) { return true; }Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM768Traits>::HasPublic(bssl::EvpPkey const*) Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM1024Traits>::HasPublic(bssl::EvpPkey const*) |
273 | | |
274 | 0 | static bool CopyPublic(EvpPkey *out, const EvpPkey *pk) { |
275 | 0 | auto *public_copy = |
276 | 0 | New<PublicKeyData<Traits>>(*GetKeyData(pk)->GetPublicKey()); |
277 | 0 | if (public_copy == nullptr) { |
278 | 0 | return false; |
279 | 0 | } |
280 | 0 | evp_pkey_set0(out, pk->ameth, public_copy); |
281 | 0 | return true; |
282 | 0 | } Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM768Traits>::CopyPublic(bssl::EvpPkey*, bssl::EvpPkey const*) Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM1024Traits>::CopyPublic(bssl::EvpPkey*, bssl::EvpPkey const*) |
283 | | |
284 | | static evp_decode_result_t DecodePrivate(const EVP_PKEY_ALG *alg, |
285 | | EvpPkey *out, CBS *params, |
286 | 255 | CBS *key) { |
287 | | // Parameters must be absent. See RFC 9935, section 3. |
288 | 255 | if (CBS_len(params) != 0) { |
289 | 49 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); |
290 | 49 | return evp_decode_error; |
291 | 49 | } |
292 | | |
293 | | // See RFC 9935, section 6. Three different encodings are specified. We only |
294 | | // implement the "seed" representation. |
295 | 206 | CBS seed; |
296 | 206 | if (!CBS_get_asn1(key, &seed, kSeedTag)) { |
297 | 8 | OPENSSL_PUT_ERROR(EVP, EVP_R_PRIVATE_KEY_WAS_NOT_SEED); |
298 | 8 | return evp_decode_error; |
299 | 8 | } |
300 | 198 | if (CBS_len(key) != 0) { |
301 | 50 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); |
302 | 50 | return evp_decode_error; |
303 | 50 | } |
304 | 148 | return SetPrivateSeed(out, CBS_data(&seed), CBS_len(&seed)) |
305 | 148 | ? evp_decode_ok |
306 | 148 | : evp_decode_error; |
307 | 198 | } p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM768Traits>::DecodePrivate(evp_pkey_alg_st const*, bssl::EvpPkey*, cbs_st*, cbs_st*) Line | Count | Source | 286 | 114 | CBS *key) { | 287 | | // Parameters must be absent. See RFC 9935, section 3. | 288 | 114 | if (CBS_len(params) != 0) { | 289 | 21 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); | 290 | 21 | return evp_decode_error; | 291 | 21 | } | 292 | | | 293 | | // See RFC 9935, section 6. Three different encodings are specified. We only | 294 | | // implement the "seed" representation. | 295 | 93 | CBS seed; | 296 | 93 | if (!CBS_get_asn1(key, &seed, kSeedTag)) { | 297 | 4 | OPENSSL_PUT_ERROR(EVP, EVP_R_PRIVATE_KEY_WAS_NOT_SEED); | 298 | 4 | return evp_decode_error; | 299 | 4 | } | 300 | 89 | if (CBS_len(key) != 0) { | 301 | 26 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); | 302 | 26 | return evp_decode_error; | 303 | 26 | } | 304 | 63 | return SetPrivateSeed(out, CBS_data(&seed), CBS_len(&seed)) | 305 | 63 | ? evp_decode_ok | 306 | 63 | : evp_decode_error; | 307 | 89 | } |
p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM1024Traits>::DecodePrivate(evp_pkey_alg_st const*, bssl::EvpPkey*, cbs_st*, cbs_st*) Line | Count | Source | 286 | 141 | CBS *key) { | 287 | | // Parameters must be absent. See RFC 9935, section 3. | 288 | 141 | if (CBS_len(params) != 0) { | 289 | 28 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); | 290 | 28 | return evp_decode_error; | 291 | 28 | } | 292 | | | 293 | | // See RFC 9935, section 6. Three different encodings are specified. We only | 294 | | // implement the "seed" representation. | 295 | 113 | CBS seed; | 296 | 113 | if (!CBS_get_asn1(key, &seed, kSeedTag)) { | 297 | 4 | OPENSSL_PUT_ERROR(EVP, EVP_R_PRIVATE_KEY_WAS_NOT_SEED); | 298 | 4 | return evp_decode_error; | 299 | 4 | } | 300 | 109 | if (CBS_len(key) != 0) { | 301 | 24 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); | 302 | 24 | return evp_decode_error; | 303 | 24 | } | 304 | 85 | return SetPrivateSeed(out, CBS_data(&seed), CBS_len(&seed)) | 305 | 85 | ? evp_decode_ok | 306 | 85 | : evp_decode_error; | 307 | 109 | } |
|
308 | | |
309 | 95 | static int EncodePrivate(CBB *out, const EvpPkey *pkey) { |
310 | 95 | const auto *priv = GetKeyData(pkey)->AsPrivateKeyData(); |
311 | 95 | if (priv == nullptr) { |
312 | 0 | OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY); |
313 | 0 | return 0; |
314 | 0 | } |
315 | | |
316 | | // See RFC 9935, section 6. Three different encodings are specified. We only |
317 | | // implement the "seed" representation. |
318 | 95 | CBB pkcs8, algorithm, private_key; |
319 | 95 | if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) || |
320 | 95 | !CBB_add_asn1_uint64(&pkcs8, 0 /* version */) || |
321 | 95 | !CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) || |
322 | 95 | !CBB_add_asn1_element(&algorithm, CBS_ASN1_OBJECT, Traits::kOID.data(), |
323 | 95 | Traits::kOID.size()) || |
324 | 95 | !CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) || |
325 | 95 | !CBB_add_asn1_element(&private_key, kSeedTag, priv->seed, |
326 | 95 | sizeof(priv->seed)) || |
327 | 95 | !CBB_flush(out)) { |
328 | 0 | OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR); |
329 | 0 | return 0; |
330 | 0 | } |
331 | 95 | return 1; |
332 | 95 | } p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM768Traits>::EncodePrivate(cbb_st*, bssl::EvpPkey const*) Line | Count | Source | 309 | 32 | static int EncodePrivate(CBB *out, const EvpPkey *pkey) { | 310 | 32 | const auto *priv = GetKeyData(pkey)->AsPrivateKeyData(); | 311 | 32 | if (priv == nullptr) { | 312 | 0 | OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY); | 313 | 0 | return 0; | 314 | 0 | } | 315 | | | 316 | | // See RFC 9935, section 6. Three different encodings are specified. We only | 317 | | // implement the "seed" representation. | 318 | 32 | CBB pkcs8, algorithm, private_key; | 319 | 32 | if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) || | 320 | 32 | !CBB_add_asn1_uint64(&pkcs8, 0 /* version */) || | 321 | 32 | !CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) || | 322 | 32 | !CBB_add_asn1_element(&algorithm, CBS_ASN1_OBJECT, Traits::kOID.data(), | 323 | 32 | Traits::kOID.size()) || | 324 | 32 | !CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) || | 325 | 32 | !CBB_add_asn1_element(&private_key, kSeedTag, priv->seed, | 326 | 32 | sizeof(priv->seed)) || | 327 | 32 | !CBB_flush(out)) { | 328 | 0 | OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR); | 329 | 0 | return 0; | 330 | 0 | } | 331 | 32 | return 1; | 332 | 32 | } |
p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM1024Traits>::EncodePrivate(cbb_st*, bssl::EvpPkey const*) Line | Count | Source | 309 | 63 | static int EncodePrivate(CBB *out, const EvpPkey *pkey) { | 310 | 63 | const auto *priv = GetKeyData(pkey)->AsPrivateKeyData(); | 311 | 63 | if (priv == nullptr) { | 312 | 0 | OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY); | 313 | 0 | return 0; | 314 | 0 | } | 315 | | | 316 | | // See RFC 9935, section 6. Three different encodings are specified. We only | 317 | | // implement the "seed" representation. | 318 | 63 | CBB pkcs8, algorithm, private_key; | 319 | 63 | if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) || | 320 | 63 | !CBB_add_asn1_uint64(&pkcs8, 0 /* version */) || | 321 | 63 | !CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) || | 322 | 63 | !CBB_add_asn1_element(&algorithm, CBS_ASN1_OBJECT, Traits::kOID.data(), | 323 | 63 | Traits::kOID.size()) || | 324 | 63 | !CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) || | 325 | 63 | !CBB_add_asn1_element(&private_key, kSeedTag, priv->seed, | 326 | 63 | sizeof(priv->seed)) || | 327 | 63 | !CBB_flush(out)) { | 328 | 0 | OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR); | 329 | 0 | return 0; | 330 | 0 | } | 331 | 63 | return 1; | 332 | 63 | } |
|
333 | | |
334 | 0 | static bool HasPrivate(const EvpPkey *pk) { |
335 | 0 | return GetKeyData(pk)->AsPrivateKeyData() != nullptr; |
336 | 0 | } Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM768Traits>::HasPrivate(bssl::EvpPkey const*) Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM1024Traits>::HasPrivate(bssl::EvpPkey const*) |
337 | | |
338 | 0 | static int PkeySize(const EvpPkey *pkey) { return Traits::kCiphertextBytes; }Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM768Traits>::PkeySize(bssl::EvpPkey const*) Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM1024Traits>::PkeySize(bssl::EvpPkey const*) |
339 | 0 | static int PkeyBits(const EvpPkey *pkey) { |
340 | 0 | return Traits::kPublicKeyBytes * 8; |
341 | 0 | } Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM768Traits>::PkeyBits(bssl::EvpPkey const*) Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM1024Traits>::PkeyBits(bssl::EvpPkey const*) |
342 | | |
343 | 0 | static int CopyCtx(EvpPkeyCtx *dst, EvpPkeyCtx *src) { return 1; }Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM768Traits>::CopyCtx(bssl::EvpPkeyCtx*, bssl::EvpPkeyCtx*) Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM1024Traits>::CopyCtx(bssl::EvpPkeyCtx*, bssl::EvpPkeyCtx*) |
344 | | |
345 | 0 | static int KeyGen(EvpPkeyCtx *ctx, EvpPkey *pkey) { |
346 | 0 | auto priv = MakeUnique<PrivateKeyData<Traits>>(); |
347 | 0 | if (priv == nullptr) { |
348 | 0 | OPENSSL_PUT_ERROR(EVP, ERR_R_INTERNAL_ERROR); |
349 | 0 | return 0; |
350 | 0 | } |
351 | 0 | uint8_t unused_public[Traits::kPublicKeyBytes]; |
352 | 0 | Traits::GenerateKey(unused_public, priv->seed, &priv->priv); |
353 | 0 | evp_pkey_set0(pkey, &asn1_method, priv.release()); |
354 | 0 | return 1; |
355 | 0 | } Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM768Traits>::KeyGen(bssl::EvpPkeyCtx*, bssl::EvpPkey*) Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM1024Traits>::KeyGen(bssl::EvpPkeyCtx*, bssl::EvpPkey*) |
356 | | |
357 | | static int KemEncap(uint8_t *out_ciphertext, size_t ciphertext_len, |
358 | | uint8_t *out_secret, size_t secret_len, |
359 | 0 | const EVP_PKEY *peer_key) { |
360 | 0 | const auto *peer_pubkey = GetKeyData(FromOpaque(peer_key))->GetPublicKey(); |
361 | 0 | if (ciphertext_len != Traits::kCiphertextBytes) { |
362 | 0 | OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_CIPHERTEXT_LENGTH); |
363 | 0 | return 0; |
364 | 0 | } |
365 | 0 | if (secret_len != MLKEM_SHARED_SECRET_BYTES) { |
366 | 0 | OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_SECRET_LENGTH); |
367 | 0 | return 0; |
368 | 0 | } |
369 | 0 | Traits::Encap(out_ciphertext, out_secret, peer_pubkey); |
370 | 0 | return 1; |
371 | 0 | } Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM768Traits>::KemEncap(unsigned char*, unsigned long, unsigned char*, unsigned long, evp_pkey_st const*) Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM1024Traits>::KemEncap(unsigned char*, unsigned long, unsigned char*, unsigned long, evp_pkey_st const*) |
372 | | |
373 | | static int KemDecap(uint8_t *out_secret, size_t secret_len, |
374 | | const uint8_t *ciphertext, size_t ciphertext_len, |
375 | 0 | const EVP_PKEY *key) { |
376 | 0 | const auto *priv = GetKeyData(FromOpaque(key))->AsPrivateKeyData(); |
377 | 0 | if (priv == nullptr) { |
378 | 0 | OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY); |
379 | 0 | return 0; |
380 | 0 | } |
381 | 0 | if (secret_len != MLKEM_SHARED_SECRET_BYTES) { |
382 | 0 | OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_SECRET_LENGTH); |
383 | 0 | return 0; |
384 | 0 | } |
385 | 0 | return Traits::Decap(out_secret, ciphertext, ciphertext_len, &priv->priv); |
386 | 0 | } Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM768Traits>::KemDecap(unsigned char*, unsigned long, unsigned char const*, unsigned long, evp_pkey_st const*) Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM1024Traits>::KemDecap(unsigned char*, unsigned long, unsigned char const*, unsigned long, evp_pkey_st const*) |
387 | | |
388 | | static constexpr EVP_KEM evp_kem = { |
389 | | /*pkey_id=*/Traits::kType, |
390 | | /*ciphertext_len=*/Traits::kCiphertextBytes, |
391 | | /*secret_len=*/MLKEM_SHARED_SECRET_BYTES, |
392 | | &KemEncap, |
393 | | &KemDecap, |
394 | | }; |
395 | | |
396 | | static constexpr EVP_PKEY_CTX_METHOD pkey_method = { |
397 | | Traits::kType, |
398 | | /*init=*/nullptr, |
399 | | &CopyCtx, |
400 | | /*cleanup=*/nullptr, |
401 | | &KeyGen, |
402 | | /*sign=*/nullptr, |
403 | | /*sign_message=*/nullptr, |
404 | | /*verify=*/nullptr, |
405 | | /*verify_message=*/nullptr, |
406 | | /*verify_recover=*/nullptr, |
407 | | /*encrypt=*/nullptr, |
408 | | /*decrypt=*/nullptr, |
409 | | /*derive=*/nullptr, |
410 | | /*paramgen=*/nullptr, |
411 | | &KemAdapter<evp_kem>::EncapMethod, |
412 | | &KemAdapter<evp_kem>::DecapMethod, |
413 | | /*ctrl=*/nullptr, |
414 | | }; |
415 | | |
416 | 0 | static constexpr EVP_PKEY_ASN1_METHOD BuildASN1Method() { |
417 | 0 | EVP_PKEY_ASN1_METHOD ret = { |
418 | 0 | Traits::kType, |
419 | 0 | // The OID is filled in below. |
420 | 0 | /*oid=*/{}, |
421 | 0 | /*oid_len=*/0, |
422 | 0 |
|
423 | 0 | &pkey_method, |
424 | 0 |
|
425 | 0 | &DecodePublic, |
426 | 0 | &EncodePublic, |
427 | 0 | &EqualPublic, |
428 | 0 | &HasPublic, |
429 | 0 | &CopyPublic, |
430 | 0 | &DecodePrivate, |
431 | 0 | &EncodePrivate, |
432 | 0 | &HasPrivate, |
433 | 0 |
|
434 | 0 | /*set_priv_raw=*/nullptr, |
435 | 0 | &SetPrivateSeed, |
436 | 0 | &SetRawPublic, |
437 | 0 | /*get_priv_raw=*/nullptr, |
438 | 0 | &GetPrivateSeed, |
439 | 0 | &GetRawPublic, |
440 | 0 |
|
441 | 0 | /*set1_tls_encodedpoint=*/nullptr, |
442 | 0 | /*get1_tls_encodedpoint=*/nullptr, |
443 | 0 | /*pkey_opaque=*/nullptr, |
444 | 0 | &PkeySize, |
445 | 0 | &PkeyBits, |
446 | 0 |
|
447 | 0 | /*param_missing=*/nullptr, |
448 | 0 | /*param_copy=*/nullptr, |
449 | 0 | /*param_equal=*/nullptr, |
450 | 0 |
|
451 | 0 | &PkeyFree, |
452 | 0 | }; |
453 | 0 | // TODO(crbug.com/404286922): Use std::copy in C++20, when it's constexpr. |
454 | 0 | // TODO(crbug.com/450823446): Better yet, make this field an InplaceVector |
455 | 0 | // and give it a suitable constructor. |
456 | 0 | constexpr auto oid = Traits::kOID; |
457 | 0 | static_assert(oid.size() <= sizeof(ret.oid)); |
458 | 0 | for (size_t i = 0; i < oid.size(); i++) { |
459 | 0 | ret.oid[i] = oid[i]; |
460 | 0 | } |
461 | 0 | ret.oid_len = oid.size(); |
462 | 0 | return ret; |
463 | 0 | } Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM768Traits>::BuildASN1Method() Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM1024Traits>::BuildASN1Method() |
464 | | |
465 | | static constexpr EVP_PKEY_ASN1_METHOD asn1_method = BuildASN1Method(); |
466 | | static constexpr EVP_PKEY_ALG pkey_alg = {&asn1_method, &pkey_method}; |
467 | | }; |
468 | | |
469 | | } // namespace |
470 | | |
471 | 203k | const EVP_PKEY_ALG *EVP_pkey_ml_kem_768() { |
472 | 203k | return &MLKEMImplementation<MLKEM768Traits>::pkey_alg; |
473 | 203k | } |
474 | | |
475 | 203k | const EVP_PKEY_ALG *EVP_pkey_ml_kem_1024() { |
476 | 203k | return &MLKEMImplementation<MLKEM1024Traits>::pkey_alg; |
477 | 203k | } |
478 | | |
479 | 0 | const EVP_KEM *EVP_kem_ml_kem_768() { |
480 | 0 | return &MLKEMImplementation<MLKEM768Traits>::evp_kem; |
481 | 0 | } |
482 | | |
483 | 0 | const EVP_KEM *EVP_kem_ml_kem_1024() { |
484 | 0 | return &MLKEMImplementation<MLKEM1024Traits>::evp_kem; |
485 | 0 | } |