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 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 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 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 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 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 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 211 static void ssl_dhe_cleanup(SSL_ECDH_CTX *ctx) { 212 DH_free((DH *)ctx->data); 213 } 214 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 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 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 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 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 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 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 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 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 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 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