/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 | 119 | const PrivateKeyData<Traits> *AsPrivateKeyData() const { |
85 | 119 | return const_cast<KeyData *>(this)->AsPrivateKeyData(); |
86 | 119 | } p_mlkem.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLKEM768Traits>::AsPrivateKeyData() const Line | Count | Source | 84 | 37 | const PrivateKeyData<Traits> *AsPrivateKeyData() const { | 85 | 37 | return const_cast<KeyData *>(this)->AsPrivateKeyData(); | 86 | 37 | } |
p_mlkem.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLKEM1024Traits>::AsPrivateKeyData() const Line | Count | Source | 84 | 82 | const PrivateKeyData<Traits> *AsPrivateKeyData() const { | 85 | 82 | return const_cast<KeyData *>(this)->AsPrivateKeyData(); | 86 | 82 | } |
|
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 | 456 | explicit KeyData(bool is_private) : is_private_(is_private) {}p_mlkem.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLKEM768Traits>::KeyData(bool) Line | Count | Source | 93 | 207 | explicit KeyData(bool is_private) : is_private_(is_private) {} |
p_mlkem.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLKEM1024Traits>::KeyData(bool) Line | Count | Source | 93 | 249 | 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 | 302 | PublicKeyData() : KeyData<Traits>(/*is_private=*/false) {}p_mlkem.cc:(anonymous namespace)::PublicKeyData<(anonymous namespace)::MLKEM768Traits>::PublicKeyData() Line | Count | Source | 102 | 137 | PublicKeyData() : KeyData<Traits>(/*is_private=*/false) {} |
p_mlkem.cc:(anonymous namespace)::PublicKeyData<(anonymous namespace)::MLKEM1024Traits>::PublicKeyData() Line | Count | Source | 102 | 165 | 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 | 154 | PrivateKeyData() : KeyData<Traits>(/*is_private=*/true) {}p_mlkem.cc:(anonymous namespace)::PrivateKeyData<(anonymous namespace)::MLKEM768Traits>::PrivateKeyData() Line | Count | Source | 115 | 70 | PrivateKeyData() : KeyData<Traits>(/*is_private=*/true) {} |
p_mlkem.cc:(anonymous namespace)::PrivateKeyData<(anonymous namespace)::MLKEM1024Traits>::PrivateKeyData() Line | Count | Source | 115 | 84 | 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 | 29 | const typename Traits::PublicKey *KeyData<Traits>::GetPublicKey() const { |
122 | 29 | auto *priv_data = AsPrivateKeyData(); |
123 | 29 | if (priv_data != nullptr) { |
124 | 0 | return Traits::PublicOfPrivate(&priv_data->priv); |
125 | 0 | } |
126 | 29 | return &static_cast<const PublicKeyData<Traits> *>(this)->pub; |
127 | 29 | } Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLKEM768Traits>::GetPublicKey() const p_mlkem.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLKEM1024Traits>::GetPublicKey() const Line | Count | Source | 121 | 29 | const typename Traits::PublicKey *KeyData<Traits>::GetPublicKey() const { | 122 | 29 | auto *priv_data = AsPrivateKeyData(); | 123 | 29 | if (priv_data != nullptr) { | 124 | 0 | return Traits::PublicOfPrivate(&priv_data->priv); | 125 | 0 | } | 126 | 29 | return &static_cast<const PublicKeyData<Traits> *>(this)->pub; | 127 | 29 | } |
|
128 | | |
129 | | template <typename Traits> |
130 | 251 | PrivateKeyData<Traits> *KeyData<Traits>::AsPrivateKeyData() { |
131 | 251 | if (is_private_) { |
132 | 180 | return static_cast<PrivateKeyData<Traits> *>(this); |
133 | 180 | } |
134 | 71 | return nullptr; |
135 | 251 | } p_mlkem.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLKEM768Traits>::AsPrivateKeyData() Line | Count | Source | 130 | 81 | PrivateKeyData<Traits> *KeyData<Traits>::AsPrivateKeyData() { | 131 | 81 | if (is_private_) { | 132 | 74 | return static_cast<PrivateKeyData<Traits> *>(this); | 133 | 74 | } | 134 | 7 | return nullptr; | 135 | 81 | } |
p_mlkem.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLKEM1024Traits>::AsPrivateKeyData() Line | Count | Source | 130 | 170 | PrivateKeyData<Traits> *KeyData<Traits>::AsPrivateKeyData() { | 131 | 170 | if (is_private_) { | 132 | 106 | return static_cast<PrivateKeyData<Traits> *>(this); | 133 | 106 | } | 134 | 64 | return nullptr; | 135 | 170 | } |
|
136 | | |
137 | | template <typename Traits> |
138 | 132 | void KeyData<Traits>::Free(KeyData<Traits> *data) { |
139 | 132 | 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 | 132 | auto *priv_data = data->AsPrivateKeyData(); |
145 | 132 | if (priv_data) { |
146 | 90 | Delete(priv_data); |
147 | 90 | } else { |
148 | 42 | Delete(static_cast<PublicKeyData<Traits> *>(data)); |
149 | 42 | } |
150 | 132 | } p_mlkem.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLKEM768Traits>::Free((anonymous namespace)::KeyData<(anonymous namespace)::MLKEM768Traits>*) Line | Count | Source | 138 | 44 | void KeyData<Traits>::Free(KeyData<Traits> *data) { | 139 | 44 | 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 | 44 | auto *priv_data = data->AsPrivateKeyData(); | 145 | 44 | if (priv_data) { | 146 | 37 | Delete(priv_data); | 147 | 37 | } else { | 148 | 7 | Delete(static_cast<PublicKeyData<Traits> *>(data)); | 149 | 7 | } | 150 | 44 | } |
p_mlkem.cc:(anonymous namespace)::KeyData<(anonymous namespace)::MLKEM1024Traits>::Free((anonymous namespace)::KeyData<(anonymous namespace)::MLKEM1024Traits>*) Line | Count | Source | 138 | 88 | void KeyData<Traits>::Free(KeyData<Traits> *data) { | 139 | 88 | 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 | 88 | auto *priv_data = data->AsPrivateKeyData(); | 145 | 88 | if (priv_data) { | 146 | 53 | Delete(priv_data); | 147 | 53 | } else { | 148 | 35 | Delete(static_cast<PublicKeyData<Traits> *>(data)); | 149 | 35 | } | 150 | 88 | } |
|
151 | | |
152 | | template <typename Traits> |
153 | | struct MLKEMImplementation { |
154 | 251 | static KeyData<Traits> *GetKeyData(EvpPkey *pkey) { |
155 | 251 | assert(pkey->ameth == &asn1_method); |
156 | 251 | return static_cast<KeyData<Traits> *>(pkey->pkey); |
157 | 251 | } p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM768Traits>::GetKeyData(bssl::EvpPkey*) Line | Count | Source | 154 | 81 | static KeyData<Traits> *GetKeyData(EvpPkey *pkey) { | 155 | 81 | assert(pkey->ameth == &asn1_method); | 156 | 81 | return static_cast<KeyData<Traits> *>(pkey->pkey); | 157 | 81 | } |
p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM1024Traits>::GetKeyData(bssl::EvpPkey*) Line | Count | Source | 154 | 170 | static KeyData<Traits> *GetKeyData(EvpPkey *pkey) { | 155 | 170 | assert(pkey->ameth == &asn1_method); | 156 | 170 | return static_cast<KeyData<Traits> *>(pkey->pkey); | 157 | 170 | } |
|
158 | | |
159 | 119 | static const KeyData<Traits> *GetKeyData(const EvpPkey *pkey) { |
160 | 119 | return GetKeyData(const_cast<EvpPkey *>(pkey)); |
161 | 119 | } p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM768Traits>::GetKeyData(bssl::EvpPkey const*) Line | Count | Source | 159 | 37 | static const KeyData<Traits> *GetKeyData(const EvpPkey *pkey) { | 160 | 37 | return GetKeyData(const_cast<EvpPkey *>(pkey)); | 161 | 37 | } |
p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM1024Traits>::GetKeyData(bssl::EvpPkey const*) Line | Count | Source | 159 | 82 | static const KeyData<Traits> *GetKeyData(const EvpPkey *pkey) { | 160 | 82 | return GetKeyData(const_cast<EvpPkey *>(pkey)); | 161 | 82 | } |
|
162 | | |
163 | 132 | static void PkeyFree(EvpPkey *pkey) { |
164 | 132 | KeyData<Traits>::Free(GetKeyData(pkey)); |
165 | 132 | pkey->pkey = nullptr; |
166 | 132 | } p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM768Traits>::PkeyFree(bssl::EvpPkey*) Line | Count | Source | 163 | 44 | static void PkeyFree(EvpPkey *pkey) { | 164 | 44 | KeyData<Traits>::Free(GetKeyData(pkey)); | 165 | 44 | pkey->pkey = nullptr; | 166 | 44 | } |
p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM1024Traits>::PkeyFree(bssl::EvpPkey*) Line | Count | Source | 163 | 88 | static void PkeyFree(EvpPkey *pkey) { | 164 | 88 | KeyData<Traits>::Free(GetKeyData(pkey)); | 165 | 88 | pkey->pkey = nullptr; | 166 | 88 | } |
|
167 | | |
168 | 154 | static int SetPrivateSeed(EvpPkey *pkey, const uint8_t *in, size_t len) { |
169 | 154 | auto priv = MakeUnique<PrivateKeyData<Traits>>(); |
170 | 154 | if (priv == nullptr) { |
171 | 0 | return 0; |
172 | 0 | } |
173 | | |
174 | 154 | if (len != MLKEM_SEED_BYTES || |
175 | 90 | !Traits::PrivateKeyFromSeed(&priv->priv, in, len)) { |
176 | 64 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); |
177 | 64 | return 0; |
178 | 64 | } |
179 | 90 | OPENSSL_memcpy(priv->seed, in, len); |
180 | 90 | evp_pkey_set0(pkey, &asn1_method, priv.release()); |
181 | 90 | return 1; |
182 | 154 | } p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM768Traits>::SetPrivateSeed(bssl::EvpPkey*, unsigned char const*, unsigned long) Line | Count | Source | 168 | 70 | static int SetPrivateSeed(EvpPkey *pkey, const uint8_t *in, size_t len) { | 169 | 70 | auto priv = MakeUnique<PrivateKeyData<Traits>>(); | 170 | 70 | if (priv == nullptr) { | 171 | 0 | return 0; | 172 | 0 | } | 173 | | | 174 | 70 | if (len != MLKEM_SEED_BYTES || | 175 | 37 | !Traits::PrivateKeyFromSeed(&priv->priv, in, len)) { | 176 | 33 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); | 177 | 33 | return 0; | 178 | 33 | } | 179 | 37 | OPENSSL_memcpy(priv->seed, in, len); | 180 | 37 | evp_pkey_set0(pkey, &asn1_method, priv.release()); | 181 | 37 | return 1; | 182 | 70 | } |
p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM1024Traits>::SetPrivateSeed(bssl::EvpPkey*, unsigned char const*, unsigned long) Line | Count | Source | 168 | 84 | static int SetPrivateSeed(EvpPkey *pkey, const uint8_t *in, size_t len) { | 169 | 84 | auto priv = MakeUnique<PrivateKeyData<Traits>>(); | 170 | 84 | if (priv == nullptr) { | 171 | 0 | return 0; | 172 | 0 | } | 173 | | | 174 | 84 | if (len != MLKEM_SEED_BYTES || | 175 | 53 | !Traits::PrivateKeyFromSeed(&priv->priv, in, len)) { | 176 | 31 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); | 177 | 31 | return 0; | 178 | 31 | } | 179 | 53 | OPENSSL_memcpy(priv->seed, in, len); | 180 | 53 | evp_pkey_set0(pkey, &asn1_method, priv.release()); | 181 | 53 | return 1; | 182 | 84 | } |
|
183 | | |
184 | 302 | static int SetRawPublic(EvpPkey *pkey, const uint8_t *in, size_t len) { |
185 | 302 | auto pub = MakeUnique<PublicKeyData<Traits>>(); |
186 | 302 | if (pub == nullptr) { |
187 | 0 | return 0; |
188 | 0 | } |
189 | 302 | CBS cbs; |
190 | 302 | CBS_init(&cbs, in, len); |
191 | 302 | if (!Traits::ParsePublicKey(&pub->pub, &cbs) || CBS_len(&cbs) != 0) { |
192 | 260 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); |
193 | 260 | return 0; |
194 | 260 | } |
195 | 42 | evp_pkey_set0(pkey, &asn1_method, pub.release()); |
196 | 42 | return 1; |
197 | 302 | } p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM768Traits>::SetRawPublic(bssl::EvpPkey*, unsigned char const*, unsigned long) Line | Count | Source | 184 | 137 | static int SetRawPublic(EvpPkey *pkey, const uint8_t *in, size_t len) { | 185 | 137 | auto pub = MakeUnique<PublicKeyData<Traits>>(); | 186 | 137 | if (pub == nullptr) { | 187 | 0 | return 0; | 188 | 0 | } | 189 | 137 | CBS cbs; | 190 | 137 | CBS_init(&cbs, in, len); | 191 | 137 | if (!Traits::ParsePublicKey(&pub->pub, &cbs) || CBS_len(&cbs) != 0) { | 192 | 130 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); | 193 | 130 | return 0; | 194 | 130 | } | 195 | 7 | evp_pkey_set0(pkey, &asn1_method, pub.release()); | 196 | 7 | return 1; | 197 | 137 | } |
p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM1024Traits>::SetRawPublic(bssl::EvpPkey*, unsigned char const*, unsigned long) Line | Count | Source | 184 | 165 | static int SetRawPublic(EvpPkey *pkey, const uint8_t *in, size_t len) { | 185 | 165 | auto pub = MakeUnique<PublicKeyData<Traits>>(); | 186 | 165 | if (pub == nullptr) { | 187 | 0 | return 0; | 188 | 0 | } | 189 | 165 | CBS cbs; | 190 | 165 | CBS_init(&cbs, in, len); | 191 | 165 | if (!Traits::ParsePublicKey(&pub->pub, &cbs) || CBS_len(&cbs) != 0) { | 192 | 130 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); | 193 | 130 | return 0; | 194 | 130 | } | 195 | 35 | evp_pkey_set0(pkey, &asn1_method, pub.release()); | 196 | 35 | return 1; | 197 | 165 | } |
|
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 | 432 | CBS *params, CBS *key) { |
239 | | // Parameters must be absent. See RFC 9935, section 3. |
240 | 432 | if (CBS_len(params) != 0) { |
241 | 130 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); |
242 | 130 | return evp_decode_error; |
243 | 130 | } |
244 | 302 | return SetRawPublic(out, CBS_data(key), CBS_len(key)) ? evp_decode_ok |
245 | 302 | : evp_decode_error; |
246 | 432 | } 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 | 190 | CBS *params, CBS *key) { | 239 | | // Parameters must be absent. See RFC 9935, section 3. | 240 | 190 | if (CBS_len(params) != 0) { | 241 | 53 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); | 242 | 53 | return evp_decode_error; | 243 | 53 | } | 244 | 137 | return SetRawPublic(out, CBS_data(key), CBS_len(key)) ? evp_decode_ok | 245 | 137 | : evp_decode_error; | 246 | 190 | } |
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 | 242 | CBS *params, CBS *key) { | 239 | | // Parameters must be absent. See RFC 9935, section 3. | 240 | 242 | if (CBS_len(params) != 0) { | 241 | 77 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); | 242 | 77 | return evp_decode_error; | 243 | 77 | } | 244 | 165 | return SetRawPublic(out, CBS_data(key), CBS_len(key)) ? evp_decode_ok | 245 | 165 | : evp_decode_error; | 246 | 242 | } |
|
247 | | |
248 | 29 | static int EncodePublic(CBB *out, const EvpPkey *pkey) { |
249 | 29 | const auto *pub = GetKeyData(pkey)->GetPublicKey(); |
250 | | // See RFC 9935, section 4. |
251 | 29 | CBB spki, algorithm, key_bitstring; |
252 | 29 | if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) || |
253 | 29 | !CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) || |
254 | 29 | !CBB_add_asn1_element(&algorithm, CBS_ASN1_OBJECT, Traits::kOID.data(), |
255 | 29 | Traits::kOID.size()) || |
256 | 29 | !CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) || |
257 | 29 | !CBB_add_u8(&key_bitstring, 0 /* no unused bits */) || |
258 | 29 | !Traits::MarshalPublicKey(&key_bitstring, pub) || // |
259 | 29 | !CBB_flush(out)) { |
260 | 0 | OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR); |
261 | 0 | return 0; |
262 | 0 | } |
263 | 29 | return 1; |
264 | 29 | } Unexecuted instantiation: p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM768Traits>::EncodePublic(cbb_st*, bssl::EvpPkey const*) p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM1024Traits>::EncodePublic(cbb_st*, bssl::EvpPkey const*) Line | Count | Source | 248 | 29 | static int EncodePublic(CBB *out, const EvpPkey *pkey) { | 249 | 29 | const auto *pub = GetKeyData(pkey)->GetPublicKey(); | 250 | | // See RFC 9935, section 4. | 251 | 29 | CBB spki, algorithm, key_bitstring; | 252 | 29 | if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) || | 253 | 29 | !CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) || | 254 | 29 | !CBB_add_asn1_element(&algorithm, CBS_ASN1_OBJECT, Traits::kOID.data(), | 255 | 29 | Traits::kOID.size()) || | 256 | 29 | !CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) || | 257 | 29 | !CBB_add_u8(&key_bitstring, 0 /* no unused bits */) || | 258 | 29 | !Traits::MarshalPublicKey(&key_bitstring, pub) || // | 259 | 29 | !CBB_flush(out)) { | 260 | 0 | OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR); | 261 | 0 | return 0; | 262 | 0 | } | 263 | 29 | return 1; | 264 | 29 | } |
|
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 | 230 | CBS *key) { |
287 | | // Parameters must be absent. See RFC 9935, section 3. |
288 | 230 | if (CBS_len(params) != 0) { |
289 | 30 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); |
290 | 30 | return evp_decode_error; |
291 | 30 | } |
292 | | |
293 | | // See RFC 9935, section 6. Three different encodings are specified. We only |
294 | | // implement the "seed" representation. |
295 | 200 | CBS seed; |
296 | 200 | if (!CBS_get_asn1(key, &seed, kSeedTag)) { |
297 | 9 | OPENSSL_PUT_ERROR(EVP, EVP_R_PRIVATE_KEY_WAS_NOT_SEED); |
298 | 9 | return evp_decode_error; |
299 | 9 | } |
300 | 191 | if (CBS_len(key) != 0) { |
301 | 37 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); |
302 | 37 | return evp_decode_error; |
303 | 37 | } |
304 | 154 | return SetPrivateSeed(out, CBS_data(&seed), CBS_len(&seed)) |
305 | 154 | ? evp_decode_ok |
306 | 154 | : evp_decode_error; |
307 | 191 | } 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 | 98 | CBS *key) { | 287 | | // Parameters must be absent. See RFC 9935, section 3. | 288 | 98 | if (CBS_len(params) != 0) { | 289 | 11 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); | 290 | 11 | return evp_decode_error; | 291 | 11 | } | 292 | | | 293 | | // See RFC 9935, section 6. Three different encodings are specified. We only | 294 | | // implement the "seed" representation. | 295 | 87 | CBS seed; | 296 | 87 | 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 | 83 | if (CBS_len(key) != 0) { | 301 | 13 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); | 302 | 13 | return evp_decode_error; | 303 | 13 | } | 304 | 70 | return SetPrivateSeed(out, CBS_data(&seed), CBS_len(&seed)) | 305 | 70 | ? evp_decode_ok | 306 | 70 | : evp_decode_error; | 307 | 83 | } |
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 | 132 | CBS *key) { | 287 | | // Parameters must be absent. See RFC 9935, section 3. | 288 | 132 | if (CBS_len(params) != 0) { | 289 | 19 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); | 290 | 19 | return evp_decode_error; | 291 | 19 | } | 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 | 5 | OPENSSL_PUT_ERROR(EVP, EVP_R_PRIVATE_KEY_WAS_NOT_SEED); | 298 | 5 | return evp_decode_error; | 299 | 5 | } | 300 | 108 | if (CBS_len(key) != 0) { | 301 | 24 | OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); | 302 | 24 | return evp_decode_error; | 303 | 24 | } | 304 | 84 | return SetPrivateSeed(out, CBS_data(&seed), CBS_len(&seed)) | 305 | 84 | ? evp_decode_ok | 306 | 84 | : evp_decode_error; | 307 | 108 | } |
|
308 | | |
309 | 90 | static int EncodePrivate(CBB *out, const EvpPkey *pkey) { |
310 | 90 | const auto *priv = GetKeyData(pkey)->AsPrivateKeyData(); |
311 | 90 | 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 | 90 | CBB pkcs8, algorithm, private_key; |
319 | 90 | if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) || |
320 | 90 | !CBB_add_asn1_uint64(&pkcs8, 0 /* version */) || |
321 | 90 | !CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) || |
322 | 90 | !CBB_add_asn1_element(&algorithm, CBS_ASN1_OBJECT, Traits::kOID.data(), |
323 | 90 | Traits::kOID.size()) || |
324 | 90 | !CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) || |
325 | 90 | !CBB_add_asn1_element(&private_key, kSeedTag, priv->seed, |
326 | 90 | sizeof(priv->seed)) || |
327 | 90 | !CBB_flush(out)) { |
328 | 0 | OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR); |
329 | 0 | return 0; |
330 | 0 | } |
331 | 90 | return 1; |
332 | 90 | } p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM768Traits>::EncodePrivate(cbb_st*, bssl::EvpPkey const*) Line | Count | Source | 309 | 37 | static int EncodePrivate(CBB *out, const EvpPkey *pkey) { | 310 | 37 | const auto *priv = GetKeyData(pkey)->AsPrivateKeyData(); | 311 | 37 | 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 | 37 | CBB pkcs8, algorithm, private_key; | 319 | 37 | if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) || | 320 | 37 | !CBB_add_asn1_uint64(&pkcs8, 0 /* version */) || | 321 | 37 | !CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) || | 322 | 37 | !CBB_add_asn1_element(&algorithm, CBS_ASN1_OBJECT, Traits::kOID.data(), | 323 | 37 | Traits::kOID.size()) || | 324 | 37 | !CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) || | 325 | 37 | !CBB_add_asn1_element(&private_key, kSeedTag, priv->seed, | 326 | 37 | sizeof(priv->seed)) || | 327 | 37 | !CBB_flush(out)) { | 328 | 0 | OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR); | 329 | 0 | return 0; | 330 | 0 | } | 331 | 37 | return 1; | 332 | 37 | } |
p_mlkem.cc:(anonymous namespace)::MLKEMImplementation<(anonymous namespace)::MLKEM1024Traits>::EncodePrivate(cbb_st*, bssl::EvpPkey const*) Line | Count | Source | 309 | 53 | static int EncodePrivate(CBB *out, const EvpPkey *pkey) { | 310 | 53 | const auto *priv = GetKeyData(pkey)->AsPrivateKeyData(); | 311 | 53 | 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 | 53 | CBB pkcs8, algorithm, private_key; | 319 | 53 | if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) || | 320 | 53 | !CBB_add_asn1_uint64(&pkcs8, 0 /* version */) || | 321 | 53 | !CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) || | 322 | 53 | !CBB_add_asn1_element(&algorithm, CBS_ASN1_OBJECT, Traits::kOID.data(), | 323 | 53 | Traits::kOID.size()) || | 324 | 53 | !CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) || | 325 | 53 | !CBB_add_asn1_element(&private_key, kSeedTag, priv->seed, | 326 | 53 | sizeof(priv->seed)) || | 327 | 53 | !CBB_flush(out)) { | 328 | 0 | OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR); | 329 | 0 | return 0; | 330 | 0 | } | 331 | 53 | return 1; | 332 | 53 | } |
|
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 | 209k | const EVP_PKEY_ALG *EVP_pkey_ml_kem_768() { |
472 | 209k | return &MLKEMImplementation<MLKEM768Traits>::pkey_alg; |
473 | 209k | } |
474 | | |
475 | 209k | const EVP_PKEY_ALG *EVP_pkey_ml_kem_1024() { |
476 | 209k | return &MLKEMImplementation<MLKEM1024Traits>::pkey_alg; |
477 | 209k | } |
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 | } |