Coverage Report

Created: 2026-04-30 06:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}