• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
35 
36 BSSL_NAMESPACE_BEGIN
37 
38 namespace {
39 
40 class ECKeyShare : public SSLKeyShare {
41  public:
ECKeyShare(int nid,uint16_t group_id)42   ECKeyShare(int nid, uint16_t group_id) : nid_(nid), group_id_(group_id) {}
43 
GroupID() const44   uint16_t GroupID() const override { return group_id_; }
45 
Offer(CBB * out)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 
Finish(Array<uint8_t> * out_secret,uint8_t * out_alert,Span<const uint8_t> peer_key)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 
Serialize(CBB * out)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 
Deserialize(CBS * in)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:
X25519KeyShare()162   X25519KeyShare() {}
163 
GroupID() const164   uint16_t GroupID() const override { return SSL_CURVE_X25519; }
165 
Offer(CBB * out)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 
Finish(Array<uint8_t> * out_secret,uint8_t * out_alert,Span<const uint8_t> peer_key)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 
Serialize(CBB * out)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 
Deserialize(CBS * in)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:
CECPQ2KeyShare()214   CECPQ2KeyShare() {}
215 
GroupID() const216   uint16_t GroupID() const override { return SSL_CURVE_CECPQ2; }
217 
Offer(CBB * out)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_entropy[HRSS_GENERATE_KEY_BYTES];
223     HRSS_public_key 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[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 
Accept(CBB * out_public_key,Array<uint8_t> * out_secret,uint8_t * out_alert,Span<const uint8_t> peer_key)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 
Finish(Array<uint8_t> * out_secret,uint8_t * out_alert,Span<const uint8_t> peer_key)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 hrss_private_key_;
301 };
302 
303 CONSTEXPR_ARRAY NamedGroup kNamedGroups[] = {
304     {NID_secp224r1, SSL_CURVE_SECP224R1, "P-224", "secp224r1"},
305     {NID_X9_62_prime256v1, SSL_CURVE_SECP256R1, "P-256", "prime256v1"},
306     {NID_secp384r1, SSL_CURVE_SECP384R1, "P-384", "secp384r1"},
307     {NID_secp521r1, SSL_CURVE_SECP521R1, "P-521", "secp521r1"},
308     {NID_X25519, SSL_CURVE_X25519, "X25519", "x25519"},
309     {NID_CECPQ2, SSL_CURVE_CECPQ2, "CECPQ2", "CECPQ2"},
310 };
311 
312 }  // namespace
313 
NamedGroups()314 Span<const NamedGroup> NamedGroups() {
315   return MakeConstSpan(kNamedGroups, OPENSSL_ARRAY_SIZE(kNamedGroups));
316 }
317 
Create(uint16_t group_id)318 UniquePtr<SSLKeyShare> SSLKeyShare::Create(uint16_t group_id) {
319   switch (group_id) {
320     case SSL_CURVE_SECP224R1:
321       return UniquePtr<SSLKeyShare>(
322           New<ECKeyShare>(NID_secp224r1, SSL_CURVE_SECP224R1));
323     case SSL_CURVE_SECP256R1:
324       return UniquePtr<SSLKeyShare>(
325           New<ECKeyShare>(NID_X9_62_prime256v1, SSL_CURVE_SECP256R1));
326     case SSL_CURVE_SECP384R1:
327       return UniquePtr<SSLKeyShare>(
328           New<ECKeyShare>(NID_secp384r1, SSL_CURVE_SECP384R1));
329     case SSL_CURVE_SECP521R1:
330       return UniquePtr<SSLKeyShare>(
331           New<ECKeyShare>(NID_secp521r1, SSL_CURVE_SECP521R1));
332     case SSL_CURVE_X25519:
333       return UniquePtr<SSLKeyShare>(New<X25519KeyShare>());
334     case SSL_CURVE_CECPQ2:
335       return UniquePtr<SSLKeyShare>(New<CECPQ2KeyShare>());
336     default:
337       return nullptr;
338   }
339 }
340 
Create(CBS * in)341 UniquePtr<SSLKeyShare> SSLKeyShare::Create(CBS *in) {
342   uint64_t group;
343   if (!CBS_get_asn1_uint64(in, &group) || group > 0xffff) {
344     return nullptr;
345   }
346   UniquePtr<SSLKeyShare> key_share = Create(static_cast<uint16_t>(group));
347   if (!key_share || !key_share->Deserialize(in)) {
348     return nullptr;
349   }
350   return key_share;
351 }
352 
353 
Accept(CBB * out_public_key,Array<uint8_t> * out_secret,uint8_t * out_alert,Span<const uint8_t> peer_key)354 bool SSLKeyShare::Accept(CBB *out_public_key, Array<uint8_t> *out_secret,
355                          uint8_t *out_alert, Span<const uint8_t> peer_key) {
356   *out_alert = SSL_AD_INTERNAL_ERROR;
357   return Offer(out_public_key) &&
358          Finish(out_secret, out_alert, peer_key);
359 }
360 
ssl_nid_to_group_id(uint16_t * out_group_id,int nid)361 bool ssl_nid_to_group_id(uint16_t *out_group_id, int nid) {
362   for (const auto &group : kNamedGroups) {
363     if (group.nid == nid) {
364       *out_group_id = group.group_id;
365       return true;
366     }
367   }
368   return false;
369 }
370 
ssl_name_to_group_id(uint16_t * out_group_id,const char * name,size_t len)371 bool ssl_name_to_group_id(uint16_t *out_group_id, const char *name, size_t len) {
372   for (const auto &group : kNamedGroups) {
373     if (len == strlen(group.name) &&
374         !strncmp(group.name, name, len)) {
375       *out_group_id = group.group_id;
376       return true;
377     }
378     if (len == strlen(group.alias) &&
379         !strncmp(group.alias, name, len)) {
380       *out_group_id = group.group_id;
381       return true;
382     }
383   }
384   return false;
385 }
386 
387 BSSL_NAMESPACE_END
388 
389 using namespace bssl;
390 
SSL_get_curve_name(uint16_t group_id)391 const char* SSL_get_curve_name(uint16_t group_id) {
392   for (const auto &group : kNamedGroups) {
393     if (group.group_id == group_id) {
394       return group.name;
395     }
396   }
397   return nullptr;
398 }
399