Home | History | Annotate | Download | only in ec
      1 /* Originally written by Bodo Moeller for the OpenSSL project.
      2  * ====================================================================
      3  * Copyright (c) 1998-2005 The OpenSSL Project.  All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  *
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in
     14  *    the documentation and/or other materials provided with the
     15  *    distribution.
     16  *
     17  * 3. All advertising materials mentioning features or use of this
     18  *    software must display the following acknowledgment:
     19  *    "This product includes software developed by the OpenSSL Project
     20  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
     21  *
     22  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
     23  *    endorse or promote products derived from this software without
     24  *    prior written permission. For written permission, please contact
     25  *    openssl-core (at) openssl.org.
     26  *
     27  * 5. Products derived from this software may not be called "OpenSSL"
     28  *    nor may "OpenSSL" appear in their names without prior written
     29  *    permission of the OpenSSL Project.
     30  *
     31  * 6. Redistributions of any form whatsoever must retain the following
     32  *    acknowledgment:
     33  *    "This product includes software developed by the OpenSSL Project
     34  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
     35  *
     36  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
     37  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     38  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     39  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
     40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     42  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     43  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     44  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     45  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     46  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
     47  * OF THE POSSIBILITY OF SUCH DAMAGE.
     48  * ====================================================================
     49  *
     50  * This product includes cryptographic software written by Eric Young
     51  * (eay (at) cryptsoft.com).  This product includes software written by Tim
     52  * Hudson (tjh (at) cryptsoft.com).
     53  *
     54  */
     55 /* ====================================================================
     56  * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
     57  *
     58  * Portions of the attached software ("Contribution") are developed by
     59  * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
     60  *
     61  * The Contribution is licensed pursuant to the OpenSSL open source
     62  * license provided above.
     63  *
     64  * The elliptic curve binary polynomial software is originally written by
     65  * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems
     66  * Laboratories. */
     67 
     68 #include <openssl/ec_key.h>
     69 
     70 #include <string.h>
     71 
     72 #include <openssl/ec.h>
     73 #include <openssl/engine.h>
     74 #include <openssl/err.h>
     75 #include <openssl/ex_data.h>
     76 #include <openssl/mem.h>
     77 #include <openssl/thread.h>
     78 
     79 #include "internal.h"
     80 #include "../internal.h"
     81 
     82 
     83 static CRYPTO_EX_DATA_CLASS g_ex_data_class = CRYPTO_EX_DATA_CLASS_INIT;
     84 
     85 EC_KEY *EC_KEY_new(void) { return EC_KEY_new_method(NULL); }
     86 
     87 EC_KEY *EC_KEY_new_method(const ENGINE *engine) {
     88   EC_KEY *ret = (EC_KEY *)OPENSSL_malloc(sizeof(EC_KEY));
     89   if (ret == NULL) {
     90     OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
     91     return NULL;
     92   }
     93 
     94   memset(ret, 0, sizeof(EC_KEY));
     95 
     96   if (engine) {
     97     ret->ecdsa_meth = ENGINE_get_ECDSA_method(engine);
     98   }
     99   if (ret->ecdsa_meth) {
    100     METHOD_ref(ret->ecdsa_meth);
    101   }
    102 
    103   ret->version = 1;
    104   ret->conv_form = POINT_CONVERSION_UNCOMPRESSED;
    105   ret->references = 1;
    106 
    107   CRYPTO_new_ex_data(&ret->ex_data);
    108 
    109   if (ret->ecdsa_meth && ret->ecdsa_meth->init && !ret->ecdsa_meth->init(ret)) {
    110     CRYPTO_free_ex_data(&g_ex_data_class, ret, &ret->ex_data);
    111     if (ret->ecdsa_meth) {
    112       METHOD_unref(ret->ecdsa_meth);
    113     }
    114     OPENSSL_free(ret);
    115     return NULL;
    116   }
    117 
    118   return ret;
    119 }
    120 
    121 EC_KEY *EC_KEY_new_by_curve_name(int nid) {
    122   EC_KEY *ret = EC_KEY_new();
    123   if (ret == NULL) {
    124     OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
    125     return NULL;
    126   }
    127   ret->group = EC_GROUP_new_by_curve_name(nid);
    128   if (ret->group == NULL) {
    129     EC_KEY_free(ret);
    130     return NULL;
    131   }
    132   return ret;
    133 }
    134 
    135 void EC_KEY_free(EC_KEY *r) {
    136   if (r == NULL) {
    137     return;
    138   }
    139 
    140   if (!CRYPTO_refcount_dec_and_test_zero(&r->references)) {
    141     return;
    142   }
    143 
    144   if (r->ecdsa_meth) {
    145     if (r->ecdsa_meth->finish) {
    146       r->ecdsa_meth->finish(r);
    147     }
    148     METHOD_unref(r->ecdsa_meth);
    149   }
    150 
    151   EC_GROUP_free(r->group);
    152   EC_POINT_free(r->pub_key);
    153   BN_clear_free(r->priv_key);
    154 
    155   CRYPTO_free_ex_data(&g_ex_data_class, r, &r->ex_data);
    156 
    157   OPENSSL_cleanse((void *)r, sizeof(EC_KEY));
    158   OPENSSL_free(r);
    159 }
    160 
    161 EC_KEY *EC_KEY_copy(EC_KEY *dest, const EC_KEY *src) {
    162   if (dest == NULL || src == NULL) {
    163     OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
    164     return NULL;
    165   }
    166   /* Copy the parameters. */
    167   if (src->group) {
    168     /* TODO(fork): duplicating the group seems wasteful. */
    169     EC_GROUP_free(dest->group);
    170     dest->group = EC_GROUP_dup(src->group);
    171     if (dest->group == NULL) {
    172       return NULL;
    173     }
    174   }
    175 
    176   /* Copy the public key. */
    177   if (src->pub_key && src->group) {
    178     EC_POINT_free(dest->pub_key);
    179     dest->pub_key = EC_POINT_dup(src->pub_key, src->group);
    180     if (dest->pub_key == NULL) {
    181       return NULL;
    182     }
    183   }
    184 
    185   /* copy the private key */
    186   if (src->priv_key) {
    187     if (dest->priv_key == NULL) {
    188       dest->priv_key = BN_new();
    189       if (dest->priv_key == NULL) {
    190         return NULL;
    191       }
    192     }
    193     if (!BN_copy(dest->priv_key, src->priv_key)) {
    194       return NULL;
    195     }
    196   }
    197   /* copy method/extra data */
    198   if (src->ecdsa_meth) {
    199       METHOD_unref(dest->ecdsa_meth);
    200       dest->ecdsa_meth = src->ecdsa_meth;
    201       METHOD_ref(dest->ecdsa_meth);
    202   }
    203   CRYPTO_free_ex_data(&g_ex_data_class, dest, &dest->ex_data);
    204   if (!CRYPTO_dup_ex_data(&g_ex_data_class, &dest->ex_data,
    205                           &src->ex_data)) {
    206     return NULL;
    207   }
    208 
    209   /* copy the rest */
    210   dest->enc_flag = src->enc_flag;
    211   dest->conv_form = src->conv_form;
    212   dest->version = src->version;
    213   dest->flags = src->flags;
    214 
    215   return dest;
    216 }
    217 
    218 EC_KEY *EC_KEY_dup(const EC_KEY *ec_key) {
    219   EC_KEY *ret = EC_KEY_new();
    220   if (ret == NULL) {
    221     return NULL;
    222   }
    223   if (EC_KEY_copy(ret, ec_key) == NULL) {
    224     EC_KEY_free(ret);
    225     return NULL;
    226   }
    227   return ret;
    228 }
    229 
    230 int EC_KEY_up_ref(EC_KEY *r) {
    231   CRYPTO_refcount_inc(&r->references);
    232   return 1;
    233 }
    234 
    235 int EC_KEY_is_opaque(const EC_KEY *key) {
    236   return key->ecdsa_meth && (key->ecdsa_meth->flags & ECDSA_FLAG_OPAQUE);
    237 }
    238 
    239 const EC_GROUP *EC_KEY_get0_group(const EC_KEY *key) { return key->group; }
    240 
    241 int EC_KEY_set_group(EC_KEY *key, const EC_GROUP *group) {
    242   EC_GROUP_free(key->group);
    243   /* TODO(fork): duplicating the group seems wasteful but see
    244    * |EC_KEY_set_conv_form|. */
    245   key->group = EC_GROUP_dup(group);
    246   if (key->group == NULL) {
    247     return 0;
    248   }
    249   /* XXX: |BN_cmp| is not constant time. */
    250   if (key->priv_key != NULL &&
    251       BN_cmp(key->priv_key, EC_GROUP_get0_order(group)) >= 0) {
    252     return 0;
    253   }
    254   return 1;
    255 }
    256 
    257 const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *key) {
    258   return key->priv_key;
    259 }
    260 
    261 int EC_KEY_set_private_key(EC_KEY *key, const BIGNUM *priv_key) {
    262   /* XXX: |BN_cmp| is not constant time. */
    263   if (key->group != NULL &&
    264       BN_cmp(priv_key, EC_GROUP_get0_order(key->group)) >= 0) {
    265     OPENSSL_PUT_ERROR(EC, EC_R_WRONG_ORDER);
    266     return 0;
    267   }
    268   BN_clear_free(key->priv_key);
    269   key->priv_key = BN_dup(priv_key);
    270   return (key->priv_key == NULL) ? 0 : 1;
    271 }
    272 
    273 const EC_POINT *EC_KEY_get0_public_key(const EC_KEY *key) {
    274   return key->pub_key;
    275 }
    276 
    277 int EC_KEY_set_public_key(EC_KEY *key, const EC_POINT *pub_key) {
    278   EC_POINT_free(key->pub_key);
    279   key->pub_key = EC_POINT_dup(pub_key, key->group);
    280   return (key->pub_key == NULL) ? 0 : 1;
    281 }
    282 
    283 unsigned int EC_KEY_get_enc_flags(const EC_KEY *key) { return key->enc_flag; }
    284 
    285 void EC_KEY_set_enc_flags(EC_KEY *key, unsigned int flags) {
    286   key->enc_flag = flags;
    287 }
    288 
    289 point_conversion_form_t EC_KEY_get_conv_form(const EC_KEY *key) {
    290   return key->conv_form;
    291 }
    292 
    293 void EC_KEY_set_conv_form(EC_KEY *key, point_conversion_form_t cform) {
    294   key->conv_form = cform;
    295 }
    296 
    297 int EC_KEY_check_key(const EC_KEY *eckey) {
    298   int ok = 0;
    299   BN_CTX *ctx = NULL;
    300   EC_POINT *point = NULL;
    301 
    302   if (!eckey || !eckey->group || !eckey->pub_key) {
    303     OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
    304     return 0;
    305   }
    306 
    307   if (EC_POINT_is_at_infinity(eckey->group, eckey->pub_key)) {
    308     OPENSSL_PUT_ERROR(EC, EC_R_POINT_AT_INFINITY);
    309     goto err;
    310   }
    311 
    312   ctx = BN_CTX_new();
    313 
    314   if (ctx == NULL) {
    315     goto err;
    316   }
    317 
    318   /* testing whether the pub_key is on the elliptic curve */
    319   if (!EC_POINT_is_on_curve(eckey->group, eckey->pub_key, ctx)) {
    320     OPENSSL_PUT_ERROR(EC, EC_R_POINT_IS_NOT_ON_CURVE);
    321     goto err;
    322   }
    323   /* TODO(fork): can this be skipped if the cofactor is one or if we're about
    324    * to check the private key, below? */
    325   if (eckey->group->meth->check_pub_key_order != NULL &&
    326       !eckey->group->meth->check_pub_key_order(eckey->group, eckey->pub_key,
    327                                                ctx)) {
    328     OPENSSL_PUT_ERROR(EC, EC_R_WRONG_ORDER);
    329     goto err;
    330   }
    331   /* in case the priv_key is present :
    332    * check if generator * priv_key == pub_key
    333    */
    334   if (eckey->priv_key) {
    335     /* XXX: |BN_cmp| is not constant time. */
    336     if (BN_cmp(eckey->priv_key, EC_GROUP_get0_order(eckey->group)) >= 0) {
    337       OPENSSL_PUT_ERROR(EC, EC_R_WRONG_ORDER);
    338       goto err;
    339     }
    340     point = EC_POINT_new(eckey->group);
    341     if (point == NULL ||
    342         !EC_POINT_mul(eckey->group, point, eckey->priv_key, NULL, NULL, ctx)) {
    343       OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB);
    344       goto err;
    345     }
    346     if (EC_POINT_cmp(eckey->group, point, eckey->pub_key, ctx) != 0) {
    347       OPENSSL_PUT_ERROR(EC, EC_R_INVALID_PRIVATE_KEY);
    348       goto err;
    349     }
    350   }
    351   ok = 1;
    352 
    353 err:
    354   BN_CTX_free(ctx);
    355   EC_POINT_free(point);
    356   return ok;
    357 }
    358 
    359 int EC_KEY_set_public_key_affine_coordinates(EC_KEY *key, BIGNUM *x,
    360                                              BIGNUM *y) {
    361   BN_CTX *ctx = NULL;
    362   BIGNUM *tx, *ty;
    363   EC_POINT *point = NULL;
    364   int ok = 0;
    365 
    366   if (!key || !key->group || !x || !y) {
    367     OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
    368     return 0;
    369   }
    370   ctx = BN_CTX_new();
    371   point = EC_POINT_new(key->group);
    372 
    373   if (ctx == NULL ||
    374       point == NULL) {
    375     goto err;
    376   }
    377 
    378   tx = BN_CTX_get(ctx);
    379   ty = BN_CTX_get(ctx);
    380 
    381   if (!EC_POINT_set_affine_coordinates_GFp(key->group, point, x, y, ctx) ||
    382       !EC_POINT_get_affine_coordinates_GFp(key->group, point, tx, ty, ctx)) {
    383     goto err;
    384   }
    385 
    386   /* Check if retrieved coordinates match originals: if not values
    387    * are out of range. */
    388   if (BN_cmp(x, tx) || BN_cmp(y, ty)) {
    389     OPENSSL_PUT_ERROR(EC, EC_R_COORDINATES_OUT_OF_RANGE);
    390     goto err;
    391   }
    392 
    393   if (!EC_KEY_set_public_key(key, point)) {
    394     goto err;
    395   }
    396 
    397   if (EC_KEY_check_key(key) == 0) {
    398     goto err;
    399   }
    400 
    401   ok = 1;
    402 
    403 err:
    404   BN_CTX_free(ctx);
    405   EC_POINT_free(point);
    406   return ok;
    407 }
    408 
    409 int EC_KEY_generate_key(EC_KEY *eckey) {
    410   int ok = 0;
    411   BIGNUM *priv_key = NULL;
    412   EC_POINT *pub_key = NULL;
    413 
    414   if (!eckey || !eckey->group) {
    415     OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
    416     return 0;
    417   }
    418 
    419   if (eckey->priv_key == NULL) {
    420     priv_key = BN_new();
    421     if (priv_key == NULL) {
    422       goto err;
    423     }
    424   } else {
    425     priv_key = eckey->priv_key;
    426   }
    427 
    428   const BIGNUM *order = EC_GROUP_get0_order(eckey->group);
    429   do {
    430     if (!BN_rand_range(priv_key, order)) {
    431       goto err;
    432     }
    433   } while (BN_is_zero(priv_key));
    434 
    435   if (eckey->pub_key == NULL) {
    436     pub_key = EC_POINT_new(eckey->group);
    437     if (pub_key == NULL) {
    438       goto err;
    439     }
    440   } else {
    441     pub_key = eckey->pub_key;
    442   }
    443 
    444   if (!EC_POINT_mul(eckey->group, pub_key, priv_key, NULL, NULL, NULL)) {
    445     goto err;
    446   }
    447 
    448   eckey->priv_key = priv_key;
    449   eckey->pub_key = pub_key;
    450 
    451   ok = 1;
    452 
    453 err:
    454   if (eckey->pub_key == NULL) {
    455     EC_POINT_free(pub_key);
    456   }
    457   if (eckey->priv_key == NULL) {
    458     BN_free(priv_key);
    459   }
    460   return ok;
    461 }
    462 
    463 int EC_KEY_get_ex_new_index(long argl, void *argp, CRYPTO_EX_unused *unused,
    464                             CRYPTO_EX_dup *dup_func,
    465                             CRYPTO_EX_free *free_func) {
    466   int index;
    467   if (!CRYPTO_get_ex_new_index(&g_ex_data_class, &index, argl, argp, dup_func,
    468                                free_func)) {
    469     return -1;
    470   }
    471   return index;
    472 }
    473 
    474 int EC_KEY_set_ex_data(EC_KEY *d, int idx, void *arg) {
    475   return CRYPTO_set_ex_data(&d->ex_data, idx, arg);
    476 }
    477 
    478 void *EC_KEY_get_ex_data(const EC_KEY *d, int idx) {
    479   return CRYPTO_get_ex_data(&d->ex_data, idx);
    480 }
    481 
    482 void EC_KEY_set_asn1_flag(EC_KEY *key, int flag) {}
    483