Home | History | Annotate | Download | only in ssl
      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