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 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 39 static int ssl_ec_point_offer(SSL_ECDH_CTX *ctx, CBB *out) { 40 /* Set up a shared |BN_CTX| for all operations. */ 41 bssl::UniquePtr<BN_CTX> bn_ctx(BN_CTX_new()); 42 if (!bn_ctx) { 43 return 0; 44 } 45 bssl::BN_CTXScope scope(bn_ctx.get()); 46 47 /* Generate a private key. */ 48 bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(ctx->method->nid)); 49 bssl::UniquePtr<BIGNUM> private_key(BN_new()); 50 if (!group || !private_key || 51 !BN_rand_range_ex(private_key.get(), 1, 52 EC_GROUP_get0_order(group.get()))) { 53 return 0; 54 } 55 56 /* Compute the corresponding public key and serialize it. */ 57 bssl::UniquePtr<EC_POINT> public_key(EC_POINT_new(group.get())); 58 if (!public_key || 59 !EC_POINT_mul(group.get(), public_key.get(), private_key.get(), NULL, 60 NULL, bn_ctx.get()) || 61 !EC_POINT_point2cbb(out, group.get(), public_key.get(), 62 POINT_CONVERSION_UNCOMPRESSED, bn_ctx.get())) { 63 return 0; 64 } 65 66 assert(ctx->data == NULL); 67 ctx->data = private_key.release(); 68 return 1; 69 } 70 71 static int ssl_ec_point_finish(SSL_ECDH_CTX *ctx, uint8_t **out_secret, 72 size_t *out_secret_len, uint8_t *out_alert, 73 const uint8_t *peer_key, size_t peer_key_len) { 74 BIGNUM *private_key = (BIGNUM *)ctx->data; 75 assert(private_key != NULL); 76 *out_alert = SSL_AD_INTERNAL_ERROR; 77 78 /* Set up a shared |BN_CTX| for all operations. */ 79 bssl::UniquePtr<BN_CTX> bn_ctx(BN_CTX_new()); 80 if (!bn_ctx) { 81 return 0; 82 } 83 bssl::BN_CTXScope scope(bn_ctx.get()); 84 85 bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(ctx->method->nid)); 86 if (!group) { 87 return 0; 88 } 89 90 bssl::UniquePtr<EC_POINT> peer_point(EC_POINT_new(group.get())); 91 bssl::UniquePtr<EC_POINT> result(EC_POINT_new(group.get())); 92 BIGNUM *x = BN_CTX_get(bn_ctx.get()); 93 if (!peer_point || !result || !x) { 94 return 0; 95 } 96 97 if (!EC_POINT_oct2point(group.get(), peer_point.get(), peer_key, peer_key_len, 98 bn_ctx.get())) { 99 *out_alert = SSL_AD_DECODE_ERROR; 100 return 0; 101 } 102 103 /* Compute the x-coordinate of |peer_key| * |private_key|. */ 104 if (!EC_POINT_mul(group.get(), result.get(), NULL, peer_point.get(), 105 private_key, bn_ctx.get()) || 106 !EC_POINT_get_affine_coordinates_GFp(group.get(), result.get(), x, NULL, 107 bn_ctx.get())) { 108 return 0; 109 } 110 111 /* Encode the x-coordinate left-padded with zeros. */ 112 size_t secret_len = (EC_GROUP_get_degree(group.get()) + 7) / 8; 113 bssl::UniquePtr<uint8_t> secret((uint8_t *)OPENSSL_malloc(secret_len)); 114 if (!secret || !BN_bn2bin_padded(secret.get(), secret_len, x)) { 115 return 0; 116 } 117 118 *out_secret = secret.release(); 119 *out_secret_len = secret_len; 120 return 1; 121 } 122 123 static int ssl_ec_point_accept(SSL_ECDH_CTX *ctx, CBB *out_public_key, 124 uint8_t **out_secret, size_t *out_secret_len, 125 uint8_t *out_alert, const uint8_t *peer_key, 126 size_t peer_key_len) { 127 *out_alert = SSL_AD_INTERNAL_ERROR; 128 if (!ssl_ec_point_offer(ctx, out_public_key) || 129 !ssl_ec_point_finish(ctx, out_secret, out_secret_len, out_alert, peer_key, 130 peer_key_len)) { 131 return 0; 132 } 133 return 1; 134 } 135 136 /* X25119 implementation. */ 137 138 static void ssl_x25519_cleanup(SSL_ECDH_CTX *ctx) { 139 if (ctx->data == NULL) { 140 return; 141 } 142 OPENSSL_cleanse(ctx->data, 32); 143 OPENSSL_free(ctx->data); 144 } 145 146 static int ssl_x25519_offer(SSL_ECDH_CTX *ctx, CBB *out) { 147 assert(ctx->data == NULL); 148 149 ctx->data = OPENSSL_malloc(32); 150 if (ctx->data == NULL) { 151 OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); 152 return 0; 153 } 154 uint8_t public_key[32]; 155 X25519_keypair(public_key, (uint8_t *)ctx->data); 156 return CBB_add_bytes(out, public_key, sizeof(public_key)); 157 } 158 159 static int ssl_x25519_finish(SSL_ECDH_CTX *ctx, uint8_t **out_secret, 160 size_t *out_secret_len, uint8_t *out_alert, 161 const uint8_t *peer_key, size_t peer_key_len) { 162 assert(ctx->data != NULL); 163 *out_alert = SSL_AD_INTERNAL_ERROR; 164 165 uint8_t *secret = (uint8_t *)OPENSSL_malloc(32); 166 if (secret == NULL) { 167 OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); 168 return 0; 169 } 170 171 if (peer_key_len != 32 || 172 !X25519(secret, (uint8_t *)ctx->data, peer_key)) { 173 OPENSSL_free(secret); 174 *out_alert = SSL_AD_DECODE_ERROR; 175 OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); 176 return 0; 177 } 178 179 *out_secret = secret; 180 *out_secret_len = 32; 181 return 1; 182 } 183 184 static int ssl_x25519_accept(SSL_ECDH_CTX *ctx, CBB *out_public_key, 185 uint8_t **out_secret, size_t *out_secret_len, 186 uint8_t *out_alert, const uint8_t *peer_key, 187 size_t peer_key_len) { 188 *out_alert = SSL_AD_INTERNAL_ERROR; 189 if (!ssl_x25519_offer(ctx, out_public_key) || 190 !ssl_x25519_finish(ctx, out_secret, out_secret_len, out_alert, peer_key, 191 peer_key_len)) { 192 return 0; 193 } 194 return 1; 195 } 196 197 198 static const SSL_ECDH_METHOD kMethods[] = { 199 { 200 NID_secp224r1, 201 SSL_CURVE_SECP224R1, 202 "P-224", 203 ssl_ec_point_cleanup, 204 ssl_ec_point_offer, 205 ssl_ec_point_accept, 206 ssl_ec_point_finish, 207 }, 208 { 209 NID_X9_62_prime256v1, 210 SSL_CURVE_SECP256R1, 211 "P-256", 212 ssl_ec_point_cleanup, 213 ssl_ec_point_offer, 214 ssl_ec_point_accept, 215 ssl_ec_point_finish, 216 }, 217 { 218 NID_secp384r1, 219 SSL_CURVE_SECP384R1, 220 "P-384", 221 ssl_ec_point_cleanup, 222 ssl_ec_point_offer, 223 ssl_ec_point_accept, 224 ssl_ec_point_finish, 225 }, 226 { 227 NID_secp521r1, 228 SSL_CURVE_SECP521R1, 229 "P-521", 230 ssl_ec_point_cleanup, 231 ssl_ec_point_offer, 232 ssl_ec_point_accept, 233 ssl_ec_point_finish, 234 }, 235 { 236 NID_X25519, 237 SSL_CURVE_X25519, 238 "X25519", 239 ssl_x25519_cleanup, 240 ssl_x25519_offer, 241 ssl_x25519_accept, 242 ssl_x25519_finish, 243 }, 244 }; 245 246 static const SSL_ECDH_METHOD *method_from_group_id(uint16_t group_id) { 247 for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kMethods); i++) { 248 if (kMethods[i].group_id == group_id) { 249 return &kMethods[i]; 250 } 251 } 252 return NULL; 253 } 254 255 static const SSL_ECDH_METHOD *method_from_nid(int nid) { 256 for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kMethods); i++) { 257 if (kMethods[i].nid == nid) { 258 return &kMethods[i]; 259 } 260 } 261 return NULL; 262 } 263 264 static const SSL_ECDH_METHOD *method_from_name(const char *name, size_t len) { 265 for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kMethods); i++) { 266 if (len == strlen(kMethods[i].name) && 267 !strncmp(kMethods[i].name, name, len)) { 268 return &kMethods[i]; 269 } 270 } 271 return NULL; 272 } 273 274 const char* SSL_get_curve_name(uint16_t group_id) { 275 const SSL_ECDH_METHOD *method = method_from_group_id(group_id); 276 if (method == NULL) { 277 return NULL; 278 } 279 return method->name; 280 } 281 282 int ssl_nid_to_group_id(uint16_t *out_group_id, int nid) { 283 const SSL_ECDH_METHOD *method = method_from_nid(nid); 284 if (method == NULL) { 285 return 0; 286 } 287 *out_group_id = method->group_id; 288 return 1; 289 } 290 291 int ssl_name_to_group_id(uint16_t *out_group_id, const char *name, size_t len) { 292 const SSL_ECDH_METHOD *method = method_from_name(name, len); 293 if (method == NULL) { 294 return 0; 295 } 296 *out_group_id = method->group_id; 297 return 1; 298 } 299 300 int SSL_ECDH_CTX_init(SSL_ECDH_CTX *ctx, uint16_t group_id) { 301 SSL_ECDH_CTX_cleanup(ctx); 302 303 const SSL_ECDH_METHOD *method = method_from_group_id(group_id); 304 if (method == NULL) { 305 OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_ELLIPTIC_CURVE); 306 return 0; 307 } 308 ctx->method = method; 309 return 1; 310 } 311 312 void SSL_ECDH_CTX_cleanup(SSL_ECDH_CTX *ctx) { 313 if (ctx->method == NULL) { 314 return; 315 } 316 ctx->method->cleanup(ctx); 317 ctx->method = NULL; 318 ctx->data = NULL; 319 } 320 321 uint16_t SSL_ECDH_CTX_get_id(const SSL_ECDH_CTX *ctx) { 322 return ctx->method->group_id; 323 } 324 325 int SSL_ECDH_CTX_offer(SSL_ECDH_CTX *ctx, CBB *out_public_key) { 326 return ctx->method->offer(ctx, out_public_key); 327 } 328 329 int SSL_ECDH_CTX_accept(SSL_ECDH_CTX *ctx, CBB *out_public_key, 330 uint8_t **out_secret, size_t *out_secret_len, 331 uint8_t *out_alert, const uint8_t *peer_key, 332 size_t peer_key_len) { 333 return ctx->method->accept(ctx, out_public_key, out_secret, out_secret_len, 334 out_alert, peer_key, peer_key_len); 335 } 336 337 int SSL_ECDH_CTX_finish(SSL_ECDH_CTX *ctx, uint8_t **out_secret, 338 size_t *out_secret_len, uint8_t *out_alert, 339 const uint8_t *peer_key, size_t peer_key_len) { 340 return ctx->method->finish(ctx, out_secret, out_secret_len, out_alert, 341 peer_key, peer_key_len); 342 } 343