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 | #include <openssl/hrss.h> |
28 | #include <openssl/mem.h> |
29 | #include <openssl/nid.h> |
30 | #include <openssl/rand.h> |
31 | |
32 | #include "internal.h" |
33 | #include "../crypto/internal.h" |
34 | #include "../third_party/sike/sike.h" |
35 | |
36 | BSSL_NAMESPACE_BEGIN |
37 | |
38 | namespace { |
39 | |
40 | class ECKeyShare : public SSLKeyShare { |
41 | public: |
42 | ECKeyShare(int nid, uint16_t group_id) : nid_(nid), group_id_(group_id) {} |
43 | |
44 | uint16_t GroupID() const override { return group_id_; } |
45 | |
46 | bool Offer(CBB *out) override { |
47 | assert(!private_key_); |
48 | // Set up a shared |BN_CTX| for all operations. |
49 | UniquePtr<BN_CTX> bn_ctx(BN_CTX_new()); |
50 | if (!bn_ctx) { |
51 | return false; |
52 | } |
53 | BN_CTXScope scope(bn_ctx.get()); |
54 | |
55 | // Generate a private key. |
56 | UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(nid_)); |
57 | private_key_.reset(BN_new()); |
58 | if (!group || !private_key_ || |
59 | !BN_rand_range_ex(private_key_.get(), 1, |
60 | EC_GROUP_get0_order(group.get()))) { |
61 | return false; |
62 | } |
63 | |
64 | // Compute the corresponding public key and serialize it. |
65 | UniquePtr<EC_POINT> public_key(EC_POINT_new(group.get())); |
66 | if (!public_key || |
67 | !EC_POINT_mul(group.get(), public_key.get(), private_key_.get(), NULL, |
68 | NULL, bn_ctx.get()) || |
69 | !EC_POINT_point2cbb(out, group.get(), public_key.get(), |
70 | POINT_CONVERSION_UNCOMPRESSED, bn_ctx.get())) { |
71 | return false; |
72 | } |
73 | |
74 | return true; |
75 | } |
76 | |
77 | bool Finish(Array<uint8_t> *out_secret, uint8_t *out_alert, |
78 | Span<const uint8_t> peer_key) override { |
79 | assert(private_key_); |
80 | *out_alert = SSL_AD_INTERNAL_ERROR; |
81 | |
82 | // Set up a shared |BN_CTX| for all operations. |
83 | UniquePtr<BN_CTX> bn_ctx(BN_CTX_new()); |
84 | if (!bn_ctx) { |
85 | return false; |
86 | } |
87 | BN_CTXScope scope(bn_ctx.get()); |
88 | |
89 | UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(nid_)); |
90 | if (!group) { |
91 | return false; |
92 | } |
93 | |
94 | UniquePtr<EC_POINT> peer_point(EC_POINT_new(group.get())); |
95 | UniquePtr<EC_POINT> result(EC_POINT_new(group.get())); |
96 | BIGNUM *x = BN_CTX_get(bn_ctx.get()); |
97 | if (!peer_point || !result || !x) { |
98 | return false; |
99 | } |
100 | |
101 | if (peer_key.empty() || peer_key[0] != POINT_CONVERSION_UNCOMPRESSED || |
102 | !EC_POINT_oct2point(group.get(), peer_point.get(), peer_key.data(), |
103 | peer_key.size(), bn_ctx.get())) { |
104 | OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); |
105 | *out_alert = SSL_AD_DECODE_ERROR; |
106 | return false; |
107 | } |
108 | |
109 | // Compute the x-coordinate of |peer_key| * |private_key_|. |
110 | if (!EC_POINT_mul(group.get(), result.get(), NULL, peer_point.get(), |
111 | private_key_.get(), bn_ctx.get()) || |
112 | !EC_POINT_get_affine_coordinates_GFp(group.get(), result.get(), x, NULL, |
113 | bn_ctx.get())) { |
114 | return false; |
115 | } |
116 | |
117 | // Encode the x-coordinate left-padded with zeros. |
118 | Array<uint8_t> secret; |
119 | if (!secret.Init((EC_GROUP_get_degree(group.get()) + 7) / 8) || |
120 | !BN_bn2bin_padded(secret.data(), secret.size(), x)) { |
121 | return false; |
122 | } |
123 | |
124 | *out_secret = std::move(secret); |
125 | return true; |
126 | } |
127 | |
128 | bool Serialize(CBB *out) override { |
129 | assert(private_key_); |
130 | CBB cbb; |
131 | UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(nid_)); |
132 | // Padding is added to avoid leaking the length. |
133 | size_t len = BN_num_bytes(EC_GROUP_get0_order(group.get())); |
134 | if (!CBB_add_asn1_uint64(out, group_id_) || |
135 | !CBB_add_asn1(out, &cbb, CBS_ASN1_OCTETSTRING) || |
136 | !BN_bn2cbb_padded(&cbb, len, private_key_.get()) || |
137 | !CBB_flush(out)) { |
138 | return false; |
139 | } |
140 | return true; |
141 | } |
142 | |
143 | bool Deserialize(CBS *in) override { |
144 | assert(!private_key_); |
145 | CBS private_key; |
146 | if (!CBS_get_asn1(in, &private_key, CBS_ASN1_OCTETSTRING)) { |
147 | return false; |
148 | } |
149 | private_key_.reset(BN_bin2bn(CBS_data(&private_key), |
150 | CBS_len(&private_key), nullptr)); |
151 | return private_key_ != nullptr; |
152 | } |
153 | |
154 | private: |
155 | UniquePtr<BIGNUM> private_key_; |
156 | int nid_; |
157 | uint16_t group_id_; |
158 | }; |
159 | |
160 | class X25519KeyShare : public SSLKeyShare { |
161 | public: |
162 | X25519KeyShare() {} |
163 | |
164 | uint16_t GroupID() const override { return SSL_CURVE_X25519; } |
165 | |
166 | bool Offer(CBB *out) override { |
167 | uint8_t public_key[32]; |
168 | X25519_keypair(public_key, private_key_); |
169 | return !!CBB_add_bytes(out, public_key, sizeof(public_key)); |
170 | } |
171 | |
172 | bool Finish(Array<uint8_t> *out_secret, uint8_t *out_alert, |
173 | Span<const uint8_t> peer_key) override { |
174 | *out_alert = SSL_AD_INTERNAL_ERROR; |
175 | |
176 | Array<uint8_t> secret; |
177 | if (!secret.Init(32)) { |
178 | OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); |
179 | return false; |
180 | } |
181 | |
182 | if (peer_key.size() != 32 || |
183 | !X25519(secret.data(), private_key_, peer_key.data())) { |
184 | *out_alert = SSL_AD_DECODE_ERROR; |
185 | OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); |
186 | return false; |
187 | } |
188 | |
189 | *out_secret = std::move(secret); |
190 | return true; |
191 | } |
192 | |
193 | bool Serialize(CBB *out) override { |
194 | return (CBB_add_asn1_uint64(out, GroupID()) && |
195 | CBB_add_asn1_octet_string(out, private_key_, sizeof(private_key_))); |
196 | } |
197 | |
198 | bool Deserialize(CBS *in) override { |
199 | CBS key; |
200 | if (!CBS_get_asn1(in, &key, CBS_ASN1_OCTETSTRING) || |
201 | CBS_len(&key) != sizeof(private_key_) || |
202 | !CBS_copy_bytes(&key, private_key_, sizeof(private_key_))) { |
203 | return false; |
204 | } |
205 | return true; |
206 | } |
207 | |
208 | private: |
209 | uint8_t private_key_[32]; |
210 | }; |
211 | |
212 | class CECPQ2KeyShare : public SSLKeyShare { |
213 | public: |
214 | CECPQ2KeyShare() {} |
215 | |
216 | uint16_t GroupID() const override { return SSL_CURVE_CECPQ2; } |
217 | |
218 | bool Offer(CBB *out) override { |
219 | uint8_t x25519_public_key[32]; |
220 | X25519_keypair(x25519_public_key, x25519_private_key_); |
221 | |
222 | uint8_t [HRSS_GENERATE_KEY_BYTES]; |
223 | HRSS_public_key ; |
224 | RAND_bytes(hrss_entropy, sizeof(hrss_entropy)); |
225 | HRSS_generate_key(&hrss_public_key, &hrss_private_key_, hrss_entropy); |
226 | |
227 | uint8_t [HRSS_PUBLIC_KEY_BYTES]; |
228 | HRSS_marshal_public_key(hrss_public_key_bytes, &hrss_public_key); |
229 | |
230 | if (!CBB_add_bytes(out, x25519_public_key, sizeof(x25519_public_key)) || |
231 | !CBB_add_bytes(out, hrss_public_key_bytes, |
232 | sizeof(hrss_public_key_bytes))) { |
233 | return false; |
234 | } |
235 | |
236 | return true; |
237 | } |
238 | |
239 | bool Accept(CBB *out_public_key, Array<uint8_t> *out_secret, |
240 | uint8_t *out_alert, Span<const uint8_t> peer_key) override { |
241 | Array<uint8_t> secret; |
242 | if (!secret.Init(32 + HRSS_KEY_BYTES)) { |
243 | OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); |
244 | return false; |
245 | } |
246 | |
247 | uint8_t x25519_public_key[32]; |
248 | X25519_keypair(x25519_public_key, x25519_private_key_); |
249 | |
250 | HRSS_public_key peer_public_key; |
251 | if (peer_key.size() != 32 + HRSS_PUBLIC_KEY_BYTES || |
252 | !HRSS_parse_public_key(&peer_public_key, peer_key.data() + 32) || |
253 | !X25519(secret.data(), x25519_private_key_, peer_key.data())) { |
254 | *out_alert = SSL_AD_DECODE_ERROR; |
255 | OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); |
256 | return false; |
257 | } |
258 | |
259 | uint8_t ciphertext[HRSS_CIPHERTEXT_BYTES]; |
260 | uint8_t entropy[HRSS_ENCAP_BYTES]; |
261 | RAND_bytes(entropy, sizeof(entropy)); |
262 | HRSS_encap(ciphertext, secret.data() + 32, &peer_public_key, entropy); |
263 | |
264 | if (!CBB_add_bytes(out_public_key, x25519_public_key, |
265 | sizeof(x25519_public_key)) || |
266 | !CBB_add_bytes(out_public_key, ciphertext, sizeof(ciphertext))) { |
267 | return false; |
268 | } |
269 | |
270 | *out_secret = std::move(secret); |
271 | return true; |
272 | } |
273 | |
274 | bool Finish(Array<uint8_t> *out_secret, uint8_t *out_alert, |
275 | Span<const uint8_t> peer_key) override { |
276 | *out_alert = SSL_AD_INTERNAL_ERROR; |
277 | |
278 | Array<uint8_t> secret; |
279 | if (!secret.Init(32 + HRSS_KEY_BYTES)) { |
280 | OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); |
281 | return false; |
282 | } |
283 | |
284 | if (peer_key.size() != 32 + HRSS_CIPHERTEXT_BYTES || |
285 | !X25519(secret.data(), x25519_private_key_, peer_key.data())) { |
286 | *out_alert = SSL_AD_DECODE_ERROR; |
287 | OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); |
288 | return false; |
289 | } |
290 | |
291 | HRSS_decap(secret.data() + 32, &hrss_private_key_, peer_key.data() + 32, |
292 | peer_key.size() - 32); |
293 | |
294 | *out_secret = std::move(secret); |
295 | return true; |
296 | } |
297 | |
298 | private: |
299 | uint8_t x25519_private_key_[32]; |
300 | HRSS_private_key ; |
301 | }; |
302 | |
303 | class CECPQ2bKeyShare : public SSLKeyShare { |
304 | public: |
305 | uint16_t GroupID() const override { return SSL_CURVE_CECPQ2b; } |
306 | |
307 | bool Offer(CBB *out) override { |
308 | uint8_t public_x25519[32] = {0}; |
309 | X25519_keypair(public_x25519, private_x25519_); |
310 | if (!SIKE_keypair(private_sike_, public_sike_)) { |
311 | return false; |
312 | } |
313 | |
314 | return CBB_add_bytes(out, public_x25519, sizeof(public_x25519)) && |
315 | CBB_add_bytes(out, public_sike_, sizeof(public_sike_)); |
316 | } |
317 | |
318 | bool Accept(CBB *out_public_key, Array<uint8_t> *out_secret, |
319 | uint8_t *out_alert, Span<const uint8_t> peer_key) override { |
320 | uint8_t public_x25519[32]; |
321 | uint8_t private_x25519[32]; |
322 | uint8_t sike_ciphertext[SIKE_CT_BYTESZ] = {0}; |
323 | |
324 | *out_alert = SSL_AD_INTERNAL_ERROR; |
325 | |
326 | if (peer_key.size() != sizeof(public_x25519) + SIKE_PUB_BYTESZ) { |
327 | *out_alert = SSL_AD_DECODE_ERROR; |
328 | OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); |
329 | return false; |
330 | } |
331 | |
332 | Array<uint8_t> secret; |
333 | if (!secret.Init(sizeof(private_x25519_) + SIKE_SS_BYTESZ)) { |
334 | OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); |
335 | return false; |
336 | } |
337 | |
338 | X25519_keypair(public_x25519, private_x25519); |
339 | if (!X25519(secret.data(), private_x25519, peer_key.data())) { |
340 | *out_alert = SSL_AD_DECODE_ERROR; |
341 | OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); |
342 | return false; |
343 | } |
344 | |
345 | SIKE_encaps(secret.data() + sizeof(private_x25519_), sike_ciphertext, |
346 | peer_key.data() + sizeof(public_x25519)); |
347 | *out_secret = std::move(secret); |
348 | |
349 | return CBB_add_bytes(out_public_key, public_x25519, |
350 | sizeof(public_x25519)) && |
351 | CBB_add_bytes(out_public_key, sike_ciphertext, |
352 | sizeof(sike_ciphertext)); |
353 | } |
354 | |
355 | bool Finish(Array<uint8_t> *out_secret, uint8_t *out_alert, |
356 | Span<const uint8_t> peer_key) override { |
357 | *out_alert = SSL_AD_INTERNAL_ERROR; |
358 | |
359 | Array<uint8_t> secret; |
360 | if (!secret.Init(sizeof(private_x25519_) + SIKE_SS_BYTESZ)) { |
361 | OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); |
362 | return false; |
363 | } |
364 | |
365 | if (peer_key.size() != 32 + SIKE_CT_BYTESZ || |
366 | !X25519(secret.data(), private_x25519_, peer_key.data())) { |
367 | *out_alert = SSL_AD_DECODE_ERROR; |
368 | OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); |
369 | return false; |
370 | } |
371 | |
372 | SIKE_decaps(secret.data() + sizeof(private_x25519_), peer_key.data() + 32, |
373 | public_sike_, private_sike_); |
374 | *out_secret = std::move(secret); |
375 | return true; |
376 | } |
377 | |
378 | private: |
379 | uint8_t private_x25519_[32]; |
380 | uint8_t private_sike_[SIKE_PRV_BYTESZ]; |
381 | uint8_t public_sike_[SIKE_PUB_BYTESZ]; |
382 | }; |
383 | |
384 | CONSTEXPR_ARRAY NamedGroup kNamedGroups[] = { |
385 | {NID_secp224r1, SSL_CURVE_SECP224R1, "P-224" , "secp224r1" }, |
386 | {NID_X9_62_prime256v1, SSL_CURVE_SECP256R1, "P-256" , "prime256v1" }, |
387 | {NID_secp384r1, SSL_CURVE_SECP384R1, "P-384" , "secp384r1" }, |
388 | {NID_secp521r1, SSL_CURVE_SECP521R1, "P-521" , "secp521r1" }, |
389 | {NID_X25519, SSL_CURVE_X25519, "X25519" , "x25519" }, |
390 | {NID_CECPQ2, SSL_CURVE_CECPQ2, "CECPQ2" , "CECPQ2" }, |
391 | {NID_CECPQ2b, SSL_CURVE_CECPQ2b, "CECPQ2b" , "CECPQ2b" }, |
392 | }; |
393 | |
394 | } // namespace |
395 | |
396 | Span<const NamedGroup> NamedGroups() { |
397 | return MakeConstSpan(kNamedGroups, OPENSSL_ARRAY_SIZE(kNamedGroups)); |
398 | } |
399 | |
400 | UniquePtr<SSLKeyShare> SSLKeyShare::Create(uint16_t group_id) { |
401 | switch (group_id) { |
402 | case SSL_CURVE_SECP224R1: |
403 | return UniquePtr<SSLKeyShare>( |
404 | New<ECKeyShare>(NID_secp224r1, SSL_CURVE_SECP224R1)); |
405 | case SSL_CURVE_SECP256R1: |
406 | return UniquePtr<SSLKeyShare>( |
407 | New<ECKeyShare>(NID_X9_62_prime256v1, SSL_CURVE_SECP256R1)); |
408 | case SSL_CURVE_SECP384R1: |
409 | return UniquePtr<SSLKeyShare>( |
410 | New<ECKeyShare>(NID_secp384r1, SSL_CURVE_SECP384R1)); |
411 | case SSL_CURVE_SECP521R1: |
412 | return UniquePtr<SSLKeyShare>( |
413 | New<ECKeyShare>(NID_secp521r1, SSL_CURVE_SECP521R1)); |
414 | case SSL_CURVE_X25519: |
415 | return UniquePtr<SSLKeyShare>(New<X25519KeyShare>()); |
416 | case SSL_CURVE_CECPQ2: |
417 | return UniquePtr<SSLKeyShare>(New<CECPQ2KeyShare>()); |
418 | case SSL_CURVE_CECPQ2b: |
419 | return UniquePtr<SSLKeyShare>(New<CECPQ2bKeyShare>()); |
420 | default: |
421 | return nullptr; |
422 | } |
423 | } |
424 | |
425 | UniquePtr<SSLKeyShare> SSLKeyShare::Create(CBS *in) { |
426 | uint64_t group; |
427 | if (!CBS_get_asn1_uint64(in, &group) || group > 0xffff) { |
428 | return nullptr; |
429 | } |
430 | UniquePtr<SSLKeyShare> key_share = Create(static_cast<uint16_t>(group)); |
431 | if (!key_share || !key_share->Deserialize(in)) { |
432 | return nullptr; |
433 | } |
434 | return key_share; |
435 | } |
436 | |
437 | |
438 | bool SSLKeyShare::Accept(CBB *out_public_key, Array<uint8_t> *out_secret, |
439 | uint8_t *out_alert, Span<const uint8_t> peer_key) { |
440 | *out_alert = SSL_AD_INTERNAL_ERROR; |
441 | return Offer(out_public_key) && |
442 | Finish(out_secret, out_alert, peer_key); |
443 | } |
444 | |
445 | bool ssl_nid_to_group_id(uint16_t *out_group_id, int nid) { |
446 | for (const auto &group : kNamedGroups) { |
447 | if (group.nid == nid) { |
448 | *out_group_id = group.group_id; |
449 | return true; |
450 | } |
451 | } |
452 | return false; |
453 | } |
454 | |
455 | bool ssl_name_to_group_id(uint16_t *out_group_id, const char *name, size_t len) { |
456 | for (const auto &group : kNamedGroups) { |
457 | if (len == strlen(group.name) && |
458 | !strncmp(group.name, name, len)) { |
459 | *out_group_id = group.group_id; |
460 | return true; |
461 | } |
462 | if (len == strlen(group.alias) && |
463 | !strncmp(group.alias, name, len)) { |
464 | *out_group_id = group.group_id; |
465 | return true; |
466 | } |
467 | } |
468 | return false; |
469 | } |
470 | |
471 | BSSL_NAMESPACE_END |
472 | |
473 | using namespace bssl; |
474 | |
475 | const char* SSL_get_curve_name(uint16_t group_id) { |
476 | for (const auto &group : kNamedGroups) { |
477 | if (group.group_id == group_id) { |
478 | return group.name; |
479 | } |
480 | } |
481 | return nullptr; |
482 | } |
483 | |