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 <openssl/bn.h>
21 #include <openssl/bytestring.h>
22 #include <openssl/curve25519.h>
23 #include <openssl/ec.h>
24 #include <openssl/err.h>
25 #include <openssl/mem.h>
26 #include <openssl/nid.h>
27 
28 #include "internal.h"
29 #include "../crypto/internal.h"
30 
31 
32 /* |EC_POINT| implementation. */
33 
ssl_ec_point_cleanup(SSL_ECDH_CTX * ctx)34 static void ssl_ec_point_cleanup(SSL_ECDH_CTX *ctx) {
35   BIGNUM *private_key = (BIGNUM *)ctx->data;
36   BN_clear_free(private_key);
37 }
38 
ssl_ec_point_offer(SSL_ECDH_CTX * ctx,CBB * out)39 static int ssl_ec_point_offer(SSL_ECDH_CTX *ctx, CBB *out) {
40   assert(ctx->data == NULL);
41   BIGNUM *private_key = BN_new();
42   if (private_key == NULL) {
43     return 0;
44   }
45   ctx->data = private_key;
46 
47   /* Set up a shared |BN_CTX| for all operations. */
48   BN_CTX *bn_ctx = BN_CTX_new();
49   if (bn_ctx == NULL) {
50     return 0;
51   }
52   BN_CTX_start(bn_ctx);
53 
54   int ret = 0;
55   EC_POINT *public_key = NULL;
56   EC_GROUP *group = EC_GROUP_new_by_curve_name(ctx->method->nid);
57   if (group == NULL) {
58     goto err;
59   }
60 
61   /* Generate a private key. */
62   if (!BN_rand_range_ex(private_key, 1, EC_GROUP_get0_order(group))) {
63     goto err;
64   }
65 
66   /* Compute the corresponding public key and serialize it. */
67   public_key = EC_POINT_new(group);
68   if (public_key == NULL ||
69       !EC_POINT_mul(group, public_key, private_key, NULL, NULL, bn_ctx) ||
70       !EC_POINT_point2cbb(out, group, public_key, POINT_CONVERSION_UNCOMPRESSED,
71                           bn_ctx)) {
72     goto err;
73   }
74 
75   ret = 1;
76 
77 err:
78   EC_GROUP_free(group);
79   EC_POINT_free(public_key);
80   BN_CTX_end(bn_ctx);
81   BN_CTX_free(bn_ctx);
82   return ret;
83 }
84 
ssl_ec_point_finish(SSL_ECDH_CTX * ctx,uint8_t ** out_secret,size_t * out_secret_len,uint8_t * out_alert,const uint8_t * peer_key,size_t peer_key_len)85 static int ssl_ec_point_finish(SSL_ECDH_CTX *ctx, uint8_t **out_secret,
86                                size_t *out_secret_len, uint8_t *out_alert,
87                                const uint8_t *peer_key, size_t peer_key_len) {
88   BIGNUM *private_key = (BIGNUM *)ctx->data;
89   assert(private_key != NULL);
90   *out_alert = SSL_AD_INTERNAL_ERROR;
91 
92   /* Set up a shared |BN_CTX| for all operations. */
93   BN_CTX *bn_ctx = BN_CTX_new();
94   if (bn_ctx == NULL) {
95     return 0;
96   }
97   BN_CTX_start(bn_ctx);
98 
99   int ret = 0;
100   EC_GROUP *group = EC_GROUP_new_by_curve_name(ctx->method->nid);
101   EC_POINT *peer_point = NULL, *result = NULL;
102   uint8_t *secret = NULL;
103   if (group == NULL) {
104     goto err;
105   }
106 
107   /* Compute the x-coordinate of |peer_key| * |private_key|. */
108   peer_point = EC_POINT_new(group);
109   result = EC_POINT_new(group);
110   if (peer_point == NULL || result == NULL) {
111     goto err;
112   }
113   BIGNUM *x = BN_CTX_get(bn_ctx);
114   if (x == NULL) {
115     goto err;
116   }
117   if (!EC_POINT_oct2point(group, peer_point, peer_key, peer_key_len, bn_ctx)) {
118     *out_alert = SSL_AD_DECODE_ERROR;
119     goto err;
120   }
121   if (!EC_POINT_mul(group, result, NULL, peer_point, private_key, bn_ctx) ||
122       !EC_POINT_get_affine_coordinates_GFp(group, result, x, NULL, bn_ctx)) {
123     goto err;
124   }
125 
126   /* Encode the x-coordinate left-padded with zeros. */
127   size_t secret_len = (EC_GROUP_get_degree(group) + 7) / 8;
128   secret = OPENSSL_malloc(secret_len);
129   if (secret == NULL || !BN_bn2bin_padded(secret, secret_len, x)) {
130     goto err;
131   }
132 
133   *out_secret = secret;
134   *out_secret_len = secret_len;
135   secret = NULL;
136   ret = 1;
137 
138 err:
139   EC_GROUP_free(group);
140   EC_POINT_free(peer_point);
141   EC_POINT_free(result);
142   BN_CTX_end(bn_ctx);
143   BN_CTX_free(bn_ctx);
144   OPENSSL_free(secret);
145   return ret;
146 }
147 
ssl_ec_point_accept(SSL_ECDH_CTX * ctx,CBB * out_public_key,uint8_t ** out_secret,size_t * out_secret_len,uint8_t * out_alert,const uint8_t * peer_key,size_t peer_key_len)148 static int ssl_ec_point_accept(SSL_ECDH_CTX *ctx, CBB *out_public_key,
149                                uint8_t **out_secret, size_t *out_secret_len,
150                                uint8_t *out_alert, const uint8_t *peer_key,
151                                size_t peer_key_len) {
152   *out_alert = SSL_AD_INTERNAL_ERROR;
153   if (!ssl_ec_point_offer(ctx, out_public_key) ||
154       !ssl_ec_point_finish(ctx, out_secret, out_secret_len, out_alert, peer_key,
155                            peer_key_len)) {
156     return 0;
157   }
158   return 1;
159 }
160 
161 /* X25119 implementation. */
162 
ssl_x25519_cleanup(SSL_ECDH_CTX * ctx)163 static void ssl_x25519_cleanup(SSL_ECDH_CTX *ctx) {
164   if (ctx->data == NULL) {
165     return;
166   }
167   OPENSSL_cleanse(ctx->data, 32);
168   OPENSSL_free(ctx->data);
169 }
170 
ssl_x25519_offer(SSL_ECDH_CTX * ctx,CBB * out)171 static int ssl_x25519_offer(SSL_ECDH_CTX *ctx, CBB *out) {
172   assert(ctx->data == NULL);
173 
174   ctx->data = OPENSSL_malloc(32);
175   if (ctx->data == NULL) {
176     OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
177     return 0;
178   }
179   uint8_t public_key[32];
180   X25519_keypair(public_key, (uint8_t *)ctx->data);
181   return CBB_add_bytes(out, public_key, sizeof(public_key));
182 }
183 
ssl_x25519_finish(SSL_ECDH_CTX * ctx,uint8_t ** out_secret,size_t * out_secret_len,uint8_t * out_alert,const uint8_t * peer_key,size_t peer_key_len)184 static int ssl_x25519_finish(SSL_ECDH_CTX *ctx, uint8_t **out_secret,
185                              size_t *out_secret_len, uint8_t *out_alert,
186                              const uint8_t *peer_key, size_t peer_key_len) {
187   assert(ctx->data != NULL);
188   *out_alert = SSL_AD_INTERNAL_ERROR;
189 
190   uint8_t *secret = OPENSSL_malloc(32);
191   if (secret == NULL) {
192     return 0;
193   }
194 
195   if (peer_key_len != 32 ||
196       !X25519(secret, (uint8_t *)ctx->data, peer_key)) {
197     OPENSSL_free(secret);
198     *out_alert = SSL_AD_DECODE_ERROR;
199     OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT);
200     return 0;
201   }
202 
203   *out_secret = secret;
204   *out_secret_len = 32;
205   return 1;
206 }
207 
ssl_x25519_accept(SSL_ECDH_CTX * ctx,CBB * out_public_key,uint8_t ** out_secret,size_t * out_secret_len,uint8_t * out_alert,const uint8_t * peer_key,size_t peer_key_len)208 static int ssl_x25519_accept(SSL_ECDH_CTX *ctx, CBB *out_public_key,
209                              uint8_t **out_secret, size_t *out_secret_len,
210                              uint8_t *out_alert, const uint8_t *peer_key,
211                              size_t peer_key_len) {
212   *out_alert = SSL_AD_INTERNAL_ERROR;
213   if (!ssl_x25519_offer(ctx, out_public_key) ||
214       !ssl_x25519_finish(ctx, out_secret, out_secret_len, out_alert, peer_key,
215                          peer_key_len)) {
216     return 0;
217   }
218   return 1;
219 }
220 
221 
222 /* Legacy DHE-based implementation. */
223 
ssl_dhe_cleanup(SSL_ECDH_CTX * ctx)224 static void ssl_dhe_cleanup(SSL_ECDH_CTX *ctx) {
225   DH_free((DH *)ctx->data);
226 }
227 
ssl_dhe_offer(SSL_ECDH_CTX * ctx,CBB * out)228 static int ssl_dhe_offer(SSL_ECDH_CTX *ctx, CBB *out) {
229   DH *dh = (DH *)ctx->data;
230   /* The group must have been initialized already, but not the key. */
231   assert(dh != NULL);
232   assert(dh->priv_key == NULL);
233 
234   /* Due to a bug in yaSSL, the public key must be zero padded to the size of
235    * the prime. */
236   return DH_generate_key(dh) &&
237          BN_bn2cbb_padded(out, BN_num_bytes(dh->p), dh->pub_key);
238 }
239 
ssl_dhe_finish(SSL_ECDH_CTX * ctx,uint8_t ** out_secret,size_t * out_secret_len,uint8_t * out_alert,const uint8_t * peer_key,size_t peer_key_len)240 static int ssl_dhe_finish(SSL_ECDH_CTX *ctx, uint8_t **out_secret,
241                           size_t *out_secret_len, uint8_t *out_alert,
242                           const uint8_t *peer_key, size_t peer_key_len) {
243   DH *dh = (DH *)ctx->data;
244   assert(dh != NULL);
245   assert(dh->priv_key != NULL);
246   *out_alert = SSL_AD_INTERNAL_ERROR;
247 
248   int secret_len = 0;
249   uint8_t *secret = NULL;
250   BIGNUM *peer_point = BN_bin2bn(peer_key, peer_key_len, NULL);
251   if (peer_point == NULL) {
252     goto err;
253   }
254 
255   secret = OPENSSL_malloc(DH_size(dh));
256   if (secret == NULL) {
257     goto err;
258   }
259   secret_len = DH_compute_key(secret, peer_point, dh);
260   if (secret_len <= 0) {
261     goto err;
262   }
263 
264   *out_secret = secret;
265   *out_secret_len = (size_t)secret_len;
266   BN_free(peer_point);
267   return 1;
268 
269 err:
270   if (secret_len > 0) {
271     OPENSSL_cleanse(secret, (size_t)secret_len);
272   }
273   OPENSSL_free(secret);
274   BN_free(peer_point);
275   return 0;
276 }
277 
ssl_dhe_accept(SSL_ECDH_CTX * ctx,CBB * out_public_key,uint8_t ** out_secret,size_t * out_secret_len,uint8_t * out_alert,const uint8_t * peer_key,size_t peer_key_len)278 static int ssl_dhe_accept(SSL_ECDH_CTX *ctx, CBB *out_public_key,
279                           uint8_t **out_secret, size_t *out_secret_len,
280                           uint8_t *out_alert, const uint8_t *peer_key,
281                           size_t peer_key_len) {
282   *out_alert = SSL_AD_INTERNAL_ERROR;
283   if (!ssl_dhe_offer(ctx, out_public_key) ||
284       !ssl_dhe_finish(ctx, out_secret, out_secret_len, out_alert, peer_key,
285                       peer_key_len)) {
286     return 0;
287   }
288   return 1;
289 }
290 
291 static const SSL_ECDH_METHOD kDHEMethod = {
292     NID_undef, 0, "",
293     ssl_dhe_cleanup,
294     ssl_dhe_offer,
295     ssl_dhe_accept,
296     ssl_dhe_finish,
297     CBS_get_u16_length_prefixed,
298     CBB_add_u16_length_prefixed,
299 };
300 
301 static const SSL_ECDH_METHOD kMethods[] = {
302     {
303         NID_X9_62_prime256v1,
304         SSL_CURVE_SECP256R1,
305         "P-256",
306         ssl_ec_point_cleanup,
307         ssl_ec_point_offer,
308         ssl_ec_point_accept,
309         ssl_ec_point_finish,
310         CBS_get_u8_length_prefixed,
311         CBB_add_u8_length_prefixed,
312     },
313     {
314         NID_secp384r1,
315         SSL_CURVE_SECP384R1,
316         "P-384",
317         ssl_ec_point_cleanup,
318         ssl_ec_point_offer,
319         ssl_ec_point_accept,
320         ssl_ec_point_finish,
321         CBS_get_u8_length_prefixed,
322         CBB_add_u8_length_prefixed,
323     },
324     {
325         NID_secp521r1,
326         SSL_CURVE_SECP521R1,
327         "P-521",
328         ssl_ec_point_cleanup,
329         ssl_ec_point_offer,
330         ssl_ec_point_accept,
331         ssl_ec_point_finish,
332         CBS_get_u8_length_prefixed,
333         CBB_add_u8_length_prefixed,
334     },
335     {
336         NID_X25519,
337         SSL_CURVE_X25519,
338         "X25519",
339         ssl_x25519_cleanup,
340         ssl_x25519_offer,
341         ssl_x25519_accept,
342         ssl_x25519_finish,
343         CBS_get_u8_length_prefixed,
344         CBB_add_u8_length_prefixed,
345     },
346 };
347 
method_from_group_id(uint16_t group_id)348 static const SSL_ECDH_METHOD *method_from_group_id(uint16_t group_id) {
349   for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kMethods); i++) {
350     if (kMethods[i].group_id == group_id) {
351       return &kMethods[i];
352     }
353   }
354   return NULL;
355 }
356 
method_from_nid(int nid)357 static const SSL_ECDH_METHOD *method_from_nid(int nid) {
358   for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kMethods); i++) {
359     if (kMethods[i].nid == nid) {
360       return &kMethods[i];
361     }
362   }
363   return NULL;
364 }
365 
method_from_name(const char * name,size_t len)366 static const SSL_ECDH_METHOD *method_from_name(const char *name, size_t len) {
367   for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kMethods); i++) {
368     if (len == strlen(kMethods[i].name) &&
369         !strncmp(kMethods[i].name, name, len)) {
370       return &kMethods[i];
371     }
372   }
373   return NULL;
374 }
375 
SSL_get_curve_name(uint16_t group_id)376 const char* SSL_get_curve_name(uint16_t group_id) {
377   const SSL_ECDH_METHOD *method = method_from_group_id(group_id);
378   if (method == NULL) {
379     return NULL;
380   }
381   return method->name;
382 }
383 
ssl_nid_to_group_id(uint16_t * out_group_id,int nid)384 int ssl_nid_to_group_id(uint16_t *out_group_id, int nid) {
385   const SSL_ECDH_METHOD *method = method_from_nid(nid);
386   if (method == NULL) {
387     return 0;
388   }
389   *out_group_id = method->group_id;
390   return 1;
391 }
392 
ssl_name_to_group_id(uint16_t * out_group_id,const char * name,size_t len)393 int ssl_name_to_group_id(uint16_t *out_group_id, const char *name, size_t len) {
394   const SSL_ECDH_METHOD *method = method_from_name(name, len);
395   if (method == NULL) {
396     return 0;
397   }
398   *out_group_id = method->group_id;
399   return 1;
400 }
401 
SSL_ECDH_CTX_init(SSL_ECDH_CTX * ctx,uint16_t group_id)402 int SSL_ECDH_CTX_init(SSL_ECDH_CTX *ctx, uint16_t group_id) {
403   SSL_ECDH_CTX_cleanup(ctx);
404 
405   const SSL_ECDH_METHOD *method = method_from_group_id(group_id);
406   if (method == NULL) {
407     OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_ELLIPTIC_CURVE);
408     return 0;
409   }
410   ctx->method = method;
411   return 1;
412 }
413 
SSL_ECDH_CTX_init_for_dhe(SSL_ECDH_CTX * ctx,DH * params)414 void SSL_ECDH_CTX_init_for_dhe(SSL_ECDH_CTX *ctx, DH *params) {
415   SSL_ECDH_CTX_cleanup(ctx);
416 
417   ctx->method = &kDHEMethod;
418   ctx->data = params;
419 }
420 
SSL_ECDH_CTX_cleanup(SSL_ECDH_CTX * ctx)421 void SSL_ECDH_CTX_cleanup(SSL_ECDH_CTX *ctx) {
422   if (ctx->method == NULL) {
423     return;
424   }
425   ctx->method->cleanup(ctx);
426   ctx->method = NULL;
427   ctx->data = NULL;
428 }
429 
SSL_ECDH_CTX_get_id(const SSL_ECDH_CTX * ctx)430 uint16_t SSL_ECDH_CTX_get_id(const SSL_ECDH_CTX *ctx) {
431   return ctx->method->group_id;
432 }
433 
SSL_ECDH_CTX_get_key(SSL_ECDH_CTX * ctx,CBS * cbs,CBS * out)434 int SSL_ECDH_CTX_get_key(SSL_ECDH_CTX *ctx, CBS *cbs, CBS *out) {
435   if (ctx->method == NULL) {
436     return 0;
437   }
438   return ctx->method->get_key(cbs, out);
439 }
440 
SSL_ECDH_CTX_add_key(SSL_ECDH_CTX * ctx,CBB * cbb,CBB * out_contents)441 int SSL_ECDH_CTX_add_key(SSL_ECDH_CTX *ctx, CBB *cbb, CBB *out_contents) {
442   if (ctx->method == NULL) {
443     return 0;
444   }
445   return ctx->method->add_key(cbb, out_contents);
446 }
447 
SSL_ECDH_CTX_offer(SSL_ECDH_CTX * ctx,CBB * out_public_key)448 int SSL_ECDH_CTX_offer(SSL_ECDH_CTX *ctx, CBB *out_public_key) {
449   return ctx->method->offer(ctx, out_public_key);
450 }
451 
SSL_ECDH_CTX_accept(SSL_ECDH_CTX * ctx,CBB * out_public_key,uint8_t ** out_secret,size_t * out_secret_len,uint8_t * out_alert,const uint8_t * peer_key,size_t peer_key_len)452 int SSL_ECDH_CTX_accept(SSL_ECDH_CTX *ctx, CBB *out_public_key,
453                         uint8_t **out_secret, size_t *out_secret_len,
454                         uint8_t *out_alert, const uint8_t *peer_key,
455                         size_t peer_key_len) {
456   return ctx->method->accept(ctx, out_public_key, out_secret, out_secret_len,
457                              out_alert, peer_key, peer_key_len);
458 }
459 
SSL_ECDH_CTX_finish(SSL_ECDH_CTX * ctx,uint8_t ** out_secret,size_t * out_secret_len,uint8_t * out_alert,const uint8_t * peer_key,size_t peer_key_len)460 int SSL_ECDH_CTX_finish(SSL_ECDH_CTX *ctx, uint8_t **out_secret,
461                         size_t *out_secret_len, uint8_t *out_alert,
462                         const uint8_t *peer_key, size_t peer_key_len) {
463   return ctx->method->finish(ctx, out_secret, out_secret_len, out_alert,
464                              peer_key, peer_key_len);
465 }
466