1 /* Copyright (c) 2015, Google Inc.
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14
15 #include <openssl/ssl.h>
16
17 #include <assert.h>
18 #include <string.h>
19
20 #include <utility>
21
22 #include <openssl/bn.h>
23 #include <openssl/bytestring.h>
24 #include <openssl/curve25519.h>
25 #include <openssl/ec.h>
26 #include <openssl/err.h>
27 #define OPENSSL_UNSTABLE_EXPERIMENTAL_KYBER
28 #include <openssl/experimental/kyber.h>
29 #include <openssl/hrss.h>
30 #include <openssl/mem.h>
31 #include <openssl/nid.h>
32 #include <openssl/rand.h>
33 #include <openssl/span.h>
34
35 #include "internal.h"
36 #include "../crypto/internal.h"
37
38 BSSL_NAMESPACE_BEGIN
39
40 namespace {
41
42 class ECKeyShare : public SSLKeyShare {
43 public:
ECKeyShare(const EC_GROUP * group,uint16_t group_id)44 ECKeyShare(const EC_GROUP *group, uint16_t group_id)
45 : group_(group), group_id_(group_id) {}
46
GroupID() const47 uint16_t GroupID() const override { return group_id_; }
48
Generate(CBB * out)49 bool Generate(CBB *out) override {
50 assert(!private_key_);
51 // Generate a private key.
52 private_key_.reset(BN_new());
53 if (!private_key_ ||
54 !BN_rand_range_ex(private_key_.get(), 1, EC_GROUP_get0_order(group_))) {
55 return false;
56 }
57
58 // Compute the corresponding public key and serialize it.
59 UniquePtr<EC_POINT> public_key(EC_POINT_new(group_));
60 if (!public_key ||
61 !EC_POINT_mul(group_, public_key.get(), private_key_.get(), nullptr,
62 nullptr, /*ctx=*/nullptr) ||
63 !EC_POINT_point2cbb(out, group_, public_key.get(),
64 POINT_CONVERSION_UNCOMPRESSED, /*ctx=*/nullptr)) {
65 return false;
66 }
67
68 return true;
69 }
70
Encap(CBB * out_ciphertext,Array<uint8_t> * out_secret,uint8_t * out_alert,Span<const uint8_t> peer_key)71 bool Encap(CBB *out_ciphertext, Array<uint8_t> *out_secret,
72 uint8_t *out_alert, Span<const uint8_t> peer_key) override {
73 // ECDH may be fit into a KEM-like abstraction by using a second keypair's
74 // public key as the ciphertext.
75 *out_alert = SSL_AD_INTERNAL_ERROR;
76 return Generate(out_ciphertext) && Decap(out_secret, out_alert, peer_key);
77 }
78
Decap(Array<uint8_t> * out_secret,uint8_t * out_alert,Span<const uint8_t> ciphertext)79 bool Decap(Array<uint8_t> *out_secret, uint8_t *out_alert,
80 Span<const uint8_t> ciphertext) override {
81 assert(group_);
82 assert(private_key_);
83 *out_alert = SSL_AD_INTERNAL_ERROR;
84
85 UniquePtr<EC_POINT> peer_point(EC_POINT_new(group_));
86 UniquePtr<EC_POINT> result(EC_POINT_new(group_));
87 UniquePtr<BIGNUM> x(BN_new());
88 if (!peer_point || !result || !x) {
89 return false;
90 }
91
92 if (ciphertext.empty() || ciphertext[0] != POINT_CONVERSION_UNCOMPRESSED ||
93 !EC_POINT_oct2point(group_, peer_point.get(), ciphertext.data(),
94 ciphertext.size(), /*ctx=*/nullptr)) {
95 OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT);
96 *out_alert = SSL_AD_DECODE_ERROR;
97 return false;
98 }
99
100 // Compute the x-coordinate of |peer_key| * |private_key_|.
101 if (!EC_POINT_mul(group_, result.get(), nullptr, peer_point.get(),
102 private_key_.get(), /*ctx=*/nullptr) ||
103 !EC_POINT_get_affine_coordinates_GFp(group_, result.get(), x.get(),
104 nullptr, /*ctx=*/nullptr)) {
105 return false;
106 }
107
108 // Encode the x-coordinate left-padded with zeros.
109 Array<uint8_t> secret;
110 if (!secret.Init((EC_GROUP_get_degree(group_) + 7) / 8) ||
111 !BN_bn2bin_padded(secret.data(), secret.size(), x.get())) {
112 return false;
113 }
114
115 *out_secret = std::move(secret);
116 return true;
117 }
118
SerializePrivateKey(CBB * out)119 bool SerializePrivateKey(CBB *out) override {
120 assert(group_);
121 assert(private_key_);
122 // Padding is added to avoid leaking the length.
123 size_t len = BN_num_bytes(EC_GROUP_get0_order(group_));
124 return BN_bn2cbb_padded(out, len, private_key_.get());
125 }
126
DeserializePrivateKey(CBS * in)127 bool DeserializePrivateKey(CBS *in) override {
128 assert(!private_key_);
129 private_key_.reset(BN_bin2bn(CBS_data(in), CBS_len(in), nullptr));
130 return private_key_ != nullptr;
131 }
132
133 private:
134 UniquePtr<BIGNUM> private_key_;
135 const EC_GROUP *const group_ = nullptr;
136 uint16_t group_id_;
137 };
138
139 class X25519KeyShare : public SSLKeyShare {
140 public:
X25519KeyShare()141 X25519KeyShare() {}
142
GroupID() const143 uint16_t GroupID() const override { return SSL_GROUP_X25519; }
144
Generate(CBB * out)145 bool Generate(CBB *out) override {
146 uint8_t public_key[32];
147 X25519_keypair(public_key, private_key_);
148 return !!CBB_add_bytes(out, public_key, sizeof(public_key));
149 }
150
Encap(CBB * out_ciphertext,Array<uint8_t> * out_secret,uint8_t * out_alert,Span<const uint8_t> peer_key)151 bool Encap(CBB *out_ciphertext, Array<uint8_t> *out_secret,
152 uint8_t *out_alert, Span<const uint8_t> peer_key) override {
153 // X25519 may be fit into a KEM-like abstraction by using a second keypair's
154 // public key as the ciphertext.
155 *out_alert = SSL_AD_INTERNAL_ERROR;
156 return Generate(out_ciphertext) && Decap(out_secret, out_alert, peer_key);
157 }
158
Decap(Array<uint8_t> * out_secret,uint8_t * out_alert,Span<const uint8_t> ciphertext)159 bool Decap(Array<uint8_t> *out_secret, uint8_t *out_alert,
160 Span<const uint8_t> ciphertext) override {
161 *out_alert = SSL_AD_INTERNAL_ERROR;
162
163 Array<uint8_t> secret;
164 if (!secret.Init(32)) {
165 return false;
166 }
167
168 if (ciphertext.size() != 32 || //
169 !X25519(secret.data(), private_key_, ciphertext.data())) {
170 *out_alert = SSL_AD_DECODE_ERROR;
171 OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT);
172 return false;
173 }
174
175 *out_secret = std::move(secret);
176 return true;
177 }
178
SerializePrivateKey(CBB * out)179 bool SerializePrivateKey(CBB *out) override {
180 return CBB_add_bytes(out, private_key_, sizeof(private_key_));
181 }
182
DeserializePrivateKey(CBS * in)183 bool DeserializePrivateKey(CBS *in) override {
184 if (CBS_len(in) != sizeof(private_key_) ||
185 !CBS_copy_bytes(in, private_key_, sizeof(private_key_))) {
186 return false;
187 }
188 return true;
189 }
190
191 private:
192 uint8_t private_key_[32];
193 };
194
195 class X25519Kyber768KeyShare : public SSLKeyShare {
196 public:
X25519Kyber768KeyShare()197 X25519Kyber768KeyShare() {}
198
GroupID() const199 uint16_t GroupID() const override {
200 return SSL_GROUP_X25519_KYBER768_DRAFT00;
201 }
202
Generate(CBB * out)203 bool Generate(CBB *out) override {
204 uint8_t x25519_public_key[32];
205 X25519_keypair(x25519_public_key, x25519_private_key_);
206
207 uint8_t kyber_public_key[KYBER_PUBLIC_KEY_BYTES];
208 KYBER_generate_key(kyber_public_key, &kyber_private_key_);
209
210 if (!CBB_add_bytes(out, x25519_public_key, sizeof(x25519_public_key)) ||
211 !CBB_add_bytes(out, kyber_public_key, sizeof(kyber_public_key))) {
212 return false;
213 }
214
215 return true;
216 }
217
Encap(CBB * out_ciphertext,Array<uint8_t> * out_secret,uint8_t * out_alert,Span<const uint8_t> peer_key)218 bool Encap(CBB *out_ciphertext, Array<uint8_t> *out_secret,
219 uint8_t *out_alert, Span<const uint8_t> peer_key) override {
220 Array<uint8_t> secret;
221 if (!secret.Init(32 + KYBER_SHARED_SECRET_BYTES)) {
222 return false;
223 }
224
225 uint8_t x25519_public_key[32];
226 X25519_keypair(x25519_public_key, x25519_private_key_);
227 KYBER_public_key peer_kyber_pub;
228 CBS peer_key_cbs;
229 CBS peer_x25519_cbs;
230 CBS peer_kyber_cbs;
231 CBS_init(&peer_key_cbs, peer_key.data(), peer_key.size());
232 if (!CBS_get_bytes(&peer_key_cbs, &peer_x25519_cbs, 32) ||
233 !CBS_get_bytes(&peer_key_cbs, &peer_kyber_cbs,
234 KYBER_PUBLIC_KEY_BYTES) ||
235 CBS_len(&peer_key_cbs) != 0 ||
236 !X25519(secret.data(), x25519_private_key_,
237 CBS_data(&peer_x25519_cbs)) ||
238 !KYBER_parse_public_key(&peer_kyber_pub, &peer_kyber_cbs)) {
239 *out_alert = SSL_AD_DECODE_ERROR;
240 OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT);
241 return false;
242 }
243
244 uint8_t kyber_ciphertext[KYBER_CIPHERTEXT_BYTES];
245 KYBER_encap(kyber_ciphertext, secret.data() + 32, &peer_kyber_pub);
246
247 if (!CBB_add_bytes(out_ciphertext, x25519_public_key,
248 sizeof(x25519_public_key)) ||
249 !CBB_add_bytes(out_ciphertext, kyber_ciphertext,
250 sizeof(kyber_ciphertext))) {
251 return false;
252 }
253
254 *out_secret = std::move(secret);
255 return true;
256 }
257
Decap(Array<uint8_t> * out_secret,uint8_t * out_alert,Span<const uint8_t> ciphertext)258 bool Decap(Array<uint8_t> *out_secret, uint8_t *out_alert,
259 Span<const uint8_t> ciphertext) override {
260 *out_alert = SSL_AD_INTERNAL_ERROR;
261
262 Array<uint8_t> secret;
263 if (!secret.Init(32 + KYBER_SHARED_SECRET_BYTES)) {
264 return false;
265 }
266
267 if (ciphertext.size() != 32 + KYBER_CIPHERTEXT_BYTES ||
268 !X25519(secret.data(), x25519_private_key_, ciphertext.data())) {
269 *out_alert = SSL_AD_DECODE_ERROR;
270 OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT);
271 return false;
272 }
273
274 KYBER_decap(secret.data() + 32, ciphertext.data() + 32,
275 &kyber_private_key_);
276 *out_secret = std::move(secret);
277 return true;
278 }
279
280 private:
281 uint8_t x25519_private_key_[32];
282 KYBER_private_key kyber_private_key_;
283 };
284
285 constexpr NamedGroup kNamedGroups[] = {
286 {NID_secp224r1, SSL_GROUP_SECP224R1, "P-224", "secp224r1"},
287 {NID_X9_62_prime256v1, SSL_GROUP_SECP256R1, "P-256", "prime256v1"},
288 {NID_secp384r1, SSL_GROUP_SECP384R1, "P-384", "secp384r1"},
289 {NID_secp521r1, SSL_GROUP_SECP521R1, "P-521", "secp521r1"},
290 {NID_X25519, SSL_GROUP_X25519, "X25519", "x25519"},
291 {NID_X25519Kyber768Draft00, SSL_GROUP_X25519_KYBER768_DRAFT00,
292 "X25519Kyber768Draft00", ""},
293 };
294
295 } // namespace
296
NamedGroups()297 Span<const NamedGroup> NamedGroups() {
298 return MakeConstSpan(kNamedGroups, OPENSSL_ARRAY_SIZE(kNamedGroups));
299 }
300
Create(uint16_t group_id)301 UniquePtr<SSLKeyShare> SSLKeyShare::Create(uint16_t group_id) {
302 switch (group_id) {
303 case SSL_GROUP_SECP224R1:
304 return MakeUnique<ECKeyShare>(EC_group_p224(), SSL_GROUP_SECP224R1);
305 case SSL_GROUP_SECP256R1:
306 return MakeUnique<ECKeyShare>(EC_group_p256(), SSL_GROUP_SECP256R1);
307 case SSL_GROUP_SECP384R1:
308 return MakeUnique<ECKeyShare>(EC_group_p384(), SSL_GROUP_SECP384R1);
309 case SSL_GROUP_SECP521R1:
310 return MakeUnique<ECKeyShare>(EC_group_p521(), SSL_GROUP_SECP521R1);
311 case SSL_GROUP_X25519:
312 return MakeUnique<X25519KeyShare>();
313 case SSL_GROUP_X25519_KYBER768_DRAFT00:
314 return MakeUnique<X25519Kyber768KeyShare>();
315 default:
316 return nullptr;
317 }
318 }
319
ssl_nid_to_group_id(uint16_t * out_group_id,int nid)320 bool ssl_nid_to_group_id(uint16_t *out_group_id, int nid) {
321 for (const auto &group : kNamedGroups) {
322 if (group.nid == nid) {
323 *out_group_id = group.group_id;
324 return true;
325 }
326 }
327 return false;
328 }
329
ssl_name_to_group_id(uint16_t * out_group_id,const char * name,size_t len)330 bool ssl_name_to_group_id(uint16_t *out_group_id, const char *name, size_t len) {
331 for (const auto &group : kNamedGroups) {
332 if (len == strlen(group.name) &&
333 !strncmp(group.name, name, len)) {
334 *out_group_id = group.group_id;
335 return true;
336 }
337 if (strlen(group.alias) > 0 && len == strlen(group.alias) &&
338 !strncmp(group.alias, name, len)) {
339 *out_group_id = group.group_id;
340 return true;
341 }
342 }
343 return false;
344 }
345
ssl_group_id_to_nid(uint16_t group_id)346 int ssl_group_id_to_nid(uint16_t group_id) {
347 for (const auto &group : kNamedGroups) {
348 if (group.group_id == group_id) {
349 return group.nid;
350 }
351 }
352 return NID_undef;
353 }
354
355 BSSL_NAMESPACE_END
356
357 using namespace bssl;
358
SSL_get_group_name(uint16_t group_id)359 const char* SSL_get_group_name(uint16_t group_id) {
360 for (const auto &group : kNamedGroups) {
361 if (group.group_id == group_id) {
362 return group.name;
363 }
364 }
365 return nullptr;
366 }
367
SSL_get_all_group_names(const char ** out,size_t max_out)368 size_t SSL_get_all_group_names(const char **out, size_t max_out) {
369 return GetAllNames(out, max_out, Span<const char *>(), &NamedGroup::name,
370 MakeConstSpan(kNamedGroups));
371 }
372