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/obj.h>
27
28#include "internal.h"
29
30
31/* |EC_POINT| implementation. */
32
33static void ssl_ec_point_cleanup(SSL_ECDH_CTX *ctx) {
34  BIGNUM *private_key = (BIGNUM *)ctx->data;
35  BN_clear_free(private_key);
36}
37
38static int ssl_ec_point_generate_keypair(SSL_ECDH_CTX *ctx, CBB *out) {
39  assert(ctx->data == NULL);
40  BIGNUM *private_key = BN_new();
41  if (private_key == NULL) {
42    return 0;
43  }
44  ctx->data = private_key;
45
46  /* Set up a shared |BN_CTX| for all operations. */
47  BN_CTX *bn_ctx = BN_CTX_new();
48  if (bn_ctx == NULL) {
49    return 0;
50  }
51  BN_CTX_start(bn_ctx);
52
53  int ret = 0;
54  EC_POINT *public_key = NULL;
55  EC_GROUP *group = EC_GROUP_new_by_curve_name(ctx->method->nid);
56  if (group == NULL) {
57    goto err;
58  }
59
60  /* Generate a private key. */
61  const BIGNUM *order = EC_GROUP_get0_order(group);
62  do {
63    if (!BN_rand_range(private_key, order)) {
64      goto err;
65    }
66  } while (BN_is_zero(private_key));
67
68  /* Compute the corresponding public key. */
69  public_key = EC_POINT_new(group);
70  if (public_key == NULL ||
71      !EC_POINT_mul(group, public_key, private_key, NULL, NULL, bn_ctx)) {
72    goto err;
73  }
74
75  /* Serialize the public key. */
76  size_t len = EC_POINT_point2oct(
77      group, public_key, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, bn_ctx);
78  uint8_t *ptr;
79  if (len == 0 ||
80      !CBB_add_space(out, &ptr, len) ||
81      EC_POINT_point2oct(group, public_key, POINT_CONVERSION_UNCOMPRESSED, ptr,
82                         len, bn_ctx) != len) {
83    goto err;
84  }
85
86  ret = 1;
87
88err:
89  EC_GROUP_free(group);
90  EC_POINT_free(public_key);
91  BN_CTX_end(bn_ctx);
92  BN_CTX_free(bn_ctx);
93  return ret;
94}
95
96int ssl_ec_point_compute_secret(SSL_ECDH_CTX *ctx, uint8_t **out_secret,
97                                size_t *out_secret_len, uint8_t *out_alert,
98                                const uint8_t *peer_key, size_t peer_key_len) {
99  BIGNUM *private_key = (BIGNUM *)ctx->data;
100  assert(private_key != NULL);
101  *out_alert = SSL_AD_INTERNAL_ERROR;
102
103  /* Set up a shared |BN_CTX| for all operations. */
104  BN_CTX *bn_ctx = BN_CTX_new();
105  if (bn_ctx == NULL) {
106    return 0;
107  }
108  BN_CTX_start(bn_ctx);
109
110  int ret = 0;
111  EC_GROUP *group = EC_GROUP_new_by_curve_name(ctx->method->nid);
112  EC_POINT *peer_point = NULL, *result = NULL;
113  uint8_t *secret = NULL;
114  if (group == NULL) {
115    goto err;
116  }
117
118  /* Compute the x-coordinate of |peer_key| * |private_key|. */
119  peer_point = EC_POINT_new(group);
120  result = EC_POINT_new(group);
121  if (peer_point == NULL || result == NULL) {
122    goto err;
123  }
124  BIGNUM *x = BN_CTX_get(bn_ctx);
125  if (x == NULL) {
126    goto err;
127  }
128  if (!EC_POINT_oct2point(group, peer_point, peer_key, peer_key_len, bn_ctx)) {
129    *out_alert = SSL_AD_DECODE_ERROR;
130    goto err;
131  }
132  if (!EC_POINT_mul(group, result, NULL, peer_point, private_key, bn_ctx) ||
133      !EC_POINT_get_affine_coordinates_GFp(group, result, x, NULL, bn_ctx)) {
134    goto err;
135  }
136
137  /* Encode the x-coordinate left-padded with zeros. */
138  size_t secret_len = (EC_GROUP_get_degree(group) + 7) / 8;
139  secret = OPENSSL_malloc(secret_len);
140  if (secret == NULL || !BN_bn2bin_padded(secret, secret_len, x)) {
141    goto err;
142  }
143
144  *out_secret = secret;
145  *out_secret_len = secret_len;
146  secret = NULL;
147  ret = 1;
148
149err:
150  EC_GROUP_free(group);
151  EC_POINT_free(peer_point);
152  EC_POINT_free(result);
153  BN_CTX_end(bn_ctx);
154  BN_CTX_free(bn_ctx);
155  OPENSSL_free(secret);
156  return ret;
157}
158
159
160/* X25119 implementation. */
161
162static void ssl_x25519_cleanup(SSL_ECDH_CTX *ctx) {
163  if (ctx->data == NULL) {
164    return;
165  }
166  OPENSSL_cleanse(ctx->data, 32);
167  OPENSSL_free(ctx->data);
168}
169
170static int ssl_x25519_generate_keypair(SSL_ECDH_CTX *ctx, CBB *out) {
171  assert(ctx->data == NULL);
172
173  ctx->data = OPENSSL_malloc(32);
174  if (ctx->data == NULL) {
175    OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
176    return 0;
177  }
178  uint8_t public_key[32];
179  X25519_keypair(public_key, (uint8_t *)ctx->data);
180  return CBB_add_bytes(out, public_key, sizeof(public_key));
181}
182
183static int ssl_x25519_compute_secret(SSL_ECDH_CTX *ctx, uint8_t **out_secret,
184                                     size_t *out_secret_len, uint8_t *out_alert,
185                                     const uint8_t *peer_key,
186                                     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
208
209/* Legacy DHE-based implementation. */
210
211static void ssl_dhe_cleanup(SSL_ECDH_CTX *ctx) {
212  DH_free((DH *)ctx->data);
213}
214
215static int ssl_dhe_generate_keypair(SSL_ECDH_CTX *ctx, CBB *out) {
216  DH *dh = (DH *)ctx->data;
217  /* The group must have been initialized already, but not the key. */
218  assert(dh != NULL);
219  assert(dh->priv_key == NULL);
220
221  /* Due to a bug in yaSSL, the public key must be zero padded to the size of
222   * the prime. */
223  return DH_generate_key(dh) &&
224         BN_bn2cbb_padded(out, BN_num_bytes(dh->p), dh->pub_key);
225}
226
227static int ssl_dhe_compute_secret(SSL_ECDH_CTX *ctx, uint8_t **out_secret,
228                                  size_t *out_secret_len, uint8_t *out_alert,
229                                  const uint8_t *peer_key,
230                                  size_t peer_key_len) {
231  DH *dh = (DH *)ctx->data;
232  assert(dh != NULL);
233  assert(dh->priv_key != NULL);
234  *out_alert = SSL_AD_INTERNAL_ERROR;
235
236  int secret_len = 0;
237  uint8_t *secret = NULL;
238  BIGNUM *peer_point = BN_bin2bn(peer_key, peer_key_len, NULL);
239  if (peer_point == NULL) {
240    goto err;
241  }
242
243  secret = OPENSSL_malloc(DH_size(dh));
244  if (secret == NULL) {
245    goto err;
246  }
247  secret_len = DH_compute_key(secret, peer_point, dh);
248  if (secret_len <= 0) {
249    goto err;
250  }
251
252  *out_secret = secret;
253  *out_secret_len = (size_t)secret_len;
254  BN_free(peer_point);
255  return 1;
256
257err:
258  if (secret_len > 0) {
259    OPENSSL_cleanse(secret, (size_t)secret_len);
260  }
261  OPENSSL_free(secret);
262  BN_free(peer_point);
263  return 0;
264}
265
266static const SSL_ECDH_METHOD kDHEMethod = {
267    NID_undef, 0, "",
268    ssl_dhe_cleanup,
269    ssl_dhe_generate_keypair,
270    ssl_dhe_compute_secret,
271};
272
273
274static const SSL_ECDH_METHOD kMethods[] = {
275    {
276        NID_X9_62_prime256v1,
277        SSL_CURVE_SECP256R1,
278        "P-256",
279        ssl_ec_point_cleanup,
280        ssl_ec_point_generate_keypair,
281        ssl_ec_point_compute_secret,
282    },
283    {
284        NID_secp384r1,
285        SSL_CURVE_SECP384R1,
286        "P-384",
287        ssl_ec_point_cleanup,
288        ssl_ec_point_generate_keypair,
289        ssl_ec_point_compute_secret,
290    },
291    {
292        NID_secp521r1,
293        SSL_CURVE_SECP521R1,
294        "P-521",
295        ssl_ec_point_cleanup,
296        ssl_ec_point_generate_keypair,
297        ssl_ec_point_compute_secret,
298    },
299    {
300        NID_x25519,
301        SSL_CURVE_ECDH_X25519,
302        "X25519",
303        ssl_x25519_cleanup,
304        ssl_x25519_generate_keypair,
305        ssl_x25519_compute_secret,
306    },
307};
308
309static const SSL_ECDH_METHOD *method_from_curve_id(uint16_t curve_id) {
310  size_t i;
311  for (i = 0; i < sizeof(kMethods) / sizeof(kMethods[0]); i++) {
312    if (kMethods[i].curve_id == curve_id) {
313      return &kMethods[i];
314    }
315  }
316  return NULL;
317}
318
319static const SSL_ECDH_METHOD *method_from_nid(int nid) {
320  size_t i;
321  for (i = 0; i < sizeof(kMethods) / sizeof(kMethods[0]); i++) {
322    if (kMethods[i].nid == nid) {
323      return &kMethods[i];
324    }
325  }
326  return NULL;
327}
328
329const char* SSL_get_curve_name(uint16_t curve_id) {
330  const SSL_ECDH_METHOD *method = method_from_curve_id(curve_id);
331  if (method == NULL) {
332    return NULL;
333  }
334  return method->name;
335}
336
337int ssl_nid_to_curve_id(uint16_t *out_curve_id, int nid) {
338  const SSL_ECDH_METHOD *method = method_from_nid(nid);
339  if (method == NULL) {
340    return 0;
341  }
342  *out_curve_id = method->curve_id;
343  return 1;
344}
345
346int SSL_ECDH_CTX_init(SSL_ECDH_CTX *ctx, uint16_t curve_id) {
347  SSL_ECDH_CTX_cleanup(ctx);
348
349  const SSL_ECDH_METHOD *method = method_from_curve_id(curve_id);
350  if (method == NULL) {
351    OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_ELLIPTIC_CURVE);
352    return 0;
353  }
354  ctx->method = method;
355  return 1;
356}
357
358void SSL_ECDH_CTX_init_for_dhe(SSL_ECDH_CTX *ctx, DH *params) {
359  SSL_ECDH_CTX_cleanup(ctx);
360
361  ctx->method = &kDHEMethod;
362  ctx->data = params;
363}
364
365void SSL_ECDH_CTX_cleanup(SSL_ECDH_CTX *ctx) {
366  if (ctx->method == NULL) {
367    return;
368  }
369  ctx->method->cleanup(ctx);
370  ctx->method = NULL;
371  ctx->data = NULL;
372}
373
374int SSL_ECDH_CTX_generate_keypair(SSL_ECDH_CTX *ctx, CBB *out_public_key) {
375  return ctx->method->generate_keypair(ctx, out_public_key);
376}
377
378int SSL_ECDH_CTX_compute_secret(SSL_ECDH_CTX *ctx, uint8_t **out_secret,
379                                size_t *out_secret_len, uint8_t *out_alert,
380                                const uint8_t *peer_key, size_t peer_key_len) {
381  return ctx->method->compute_secret(ctx, out_secret, out_secret_len, out_alert,
382                                     peer_key, peer_key_len);
383}
384