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
ssl_ec_point_cleanup(SSL_ECDH_CTX * ctx)33 static void ssl_ec_point_cleanup(SSL_ECDH_CTX *ctx) {
34 BIGNUM *private_key = (BIGNUM *)ctx->data;
35 BN_clear_free(private_key);
36 }
37
ssl_ec_point_generate_keypair(SSL_ECDH_CTX * ctx,CBB * out)38 static 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
88 err:
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
ssl_ec_point_compute_secret(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)96 int 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
149 err:
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
ssl_x25519_cleanup(SSL_ECDH_CTX * ctx)162 static 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
ssl_x25519_generate_keypair(SSL_ECDH_CTX * ctx,CBB * out)170 static 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
ssl_x25519_compute_secret(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)183 static 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
ssl_dhe_cleanup(SSL_ECDH_CTX * ctx)211 static void ssl_dhe_cleanup(SSL_ECDH_CTX *ctx) {
212 DH_free((DH *)ctx->data);
213 }
214
ssl_dhe_generate_keypair(SSL_ECDH_CTX * ctx,CBB * out)215 static 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
ssl_dhe_compute_secret(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)227 static 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
257 err:
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
266 static 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
274 static 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
method_from_curve_id(uint16_t curve_id)309 static 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
method_from_nid(int nid)319 static 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
SSL_get_curve_name(uint16_t curve_id)329 const 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
ssl_nid_to_curve_id(uint16_t * out_curve_id,int nid)337 int 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
SSL_ECDH_CTX_init(SSL_ECDH_CTX * ctx,uint16_t curve_id)346 int 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
SSL_ECDH_CTX_init_for_dhe(SSL_ECDH_CTX * ctx,DH * params)358 void 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
SSL_ECDH_CTX_cleanup(SSL_ECDH_CTX * ctx)365 void 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
SSL_ECDH_CTX_generate_keypair(SSL_ECDH_CTX * ctx,CBB * out_public_key)374 int 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
SSL_ECDH_CTX_compute_secret(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)378 int 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