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.h>
     69 
     70 #include <openssl/bn.h>
     71 #include <openssl/bytestring.h>
     72 #include <openssl/err.h>
     73 
     74 #include "internal.h"
     75 
     76 
     77 static size_t ec_GFp_simple_point2oct(const EC_GROUP *group,
     78                                       const EC_POINT *point,
     79                                       point_conversion_form_t form,
     80                                       uint8_t *buf, size_t len, BN_CTX *ctx) {
     81   size_t ret;
     82   BN_CTX *new_ctx = NULL;
     83   int used_ctx = 0;
     84   BIGNUM *x, *y;
     85   size_t field_len, i;
     86 
     87   if ((form != POINT_CONVERSION_COMPRESSED) &&
     88       (form != POINT_CONVERSION_UNCOMPRESSED)) {
     89     OPENSSL_PUT_ERROR(EC, EC_R_INVALID_FORM);
     90     goto err;
     91   }
     92 
     93   if (EC_POINT_is_at_infinity(group, point)) {
     94     OPENSSL_PUT_ERROR(EC, EC_R_POINT_AT_INFINITY);
     95     goto err;
     96   }
     97 
     98   /* ret := required output buffer length */
     99   field_len = BN_num_bytes(&group->field);
    100   ret =
    101       (form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2 * field_len;
    102 
    103   /* if 'buf' is NULL, just return required length */
    104   if (buf != NULL) {
    105     if (len < ret) {
    106       OPENSSL_PUT_ERROR(EC, EC_R_BUFFER_TOO_SMALL);
    107       goto err;
    108     }
    109 
    110     if (ctx == NULL) {
    111       ctx = new_ctx = BN_CTX_new();
    112       if (ctx == NULL) {
    113         goto err;
    114       }
    115     }
    116 
    117     BN_CTX_start(ctx);
    118     used_ctx = 1;
    119     x = BN_CTX_get(ctx);
    120     y = BN_CTX_get(ctx);
    121     if (y == NULL) {
    122       goto err;
    123     }
    124 
    125     if (!EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx)) {
    126       goto err;
    127     }
    128 
    129     if ((form == POINT_CONVERSION_COMPRESSED) &&
    130         BN_is_odd(y)) {
    131       buf[0] = form + 1;
    132     } else {
    133       buf[0] = form;
    134     }
    135     i = 1;
    136 
    137     if (!BN_bn2bin_padded(buf + i, field_len, x)) {
    138       OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
    139       goto err;
    140     }
    141     i += field_len;
    142 
    143     if (form == POINT_CONVERSION_UNCOMPRESSED) {
    144       if (!BN_bn2bin_padded(buf + i, field_len, y)) {
    145         OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
    146         goto err;
    147       }
    148       i += field_len;
    149     }
    150 
    151     if (i != ret) {
    152       OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
    153       goto err;
    154     }
    155   }
    156 
    157   if (used_ctx) {
    158     BN_CTX_end(ctx);
    159   }
    160   BN_CTX_free(new_ctx);
    161   return ret;
    162 
    163 err:
    164   if (used_ctx) {
    165     BN_CTX_end(ctx);
    166   }
    167   BN_CTX_free(new_ctx);
    168   return 0;
    169 }
    170 
    171 
    172 static int ec_GFp_simple_oct2point(const EC_GROUP *group, EC_POINT *point,
    173                                    const uint8_t *buf, size_t len,
    174                                    BN_CTX *ctx) {
    175   point_conversion_form_t form;
    176   int y_bit;
    177   BN_CTX *new_ctx = NULL;
    178   BIGNUM *x, *y;
    179   size_t field_len, enc_len;
    180   int ret = 0;
    181 
    182   if (len == 0) {
    183     OPENSSL_PUT_ERROR(EC, EC_R_BUFFER_TOO_SMALL);
    184     return 0;
    185   }
    186   form = buf[0];
    187   y_bit = form & 1;
    188   form = form & ~1U;
    189   if ((form != POINT_CONVERSION_COMPRESSED &&
    190        form != POINT_CONVERSION_UNCOMPRESSED) ||
    191       (form == POINT_CONVERSION_UNCOMPRESSED && y_bit)) {
    192     OPENSSL_PUT_ERROR(EC, EC_R_INVALID_ENCODING);
    193     return 0;
    194   }
    195 
    196   field_len = BN_num_bytes(&group->field);
    197   enc_len =
    198       (form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2 * field_len;
    199 
    200   if (len != enc_len) {
    201     OPENSSL_PUT_ERROR(EC, EC_R_INVALID_ENCODING);
    202     return 0;
    203   }
    204 
    205   if (ctx == NULL) {
    206     ctx = new_ctx = BN_CTX_new();
    207     if (ctx == NULL) {
    208       return 0;
    209     }
    210   }
    211 
    212   BN_CTX_start(ctx);
    213   x = BN_CTX_get(ctx);
    214   y = BN_CTX_get(ctx);
    215   if (x == NULL || y == NULL) {
    216     goto err;
    217   }
    218 
    219   if (!BN_bin2bn(buf + 1, field_len, x)) {
    220     goto err;
    221   }
    222   if (BN_ucmp(x, &group->field) >= 0) {
    223     OPENSSL_PUT_ERROR(EC, EC_R_INVALID_ENCODING);
    224     goto err;
    225   }
    226 
    227   if (form == POINT_CONVERSION_COMPRESSED) {
    228     if (!EC_POINT_set_compressed_coordinates_GFp(group, point, x, y_bit, ctx)) {
    229       goto err;
    230     }
    231   } else {
    232     if (!BN_bin2bn(buf + 1 + field_len, field_len, y)) {
    233       goto err;
    234     }
    235     if (BN_ucmp(y, &group->field) >= 0) {
    236       OPENSSL_PUT_ERROR(EC, EC_R_INVALID_ENCODING);
    237       goto err;
    238     }
    239 
    240     if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) {
    241       goto err;
    242     }
    243   }
    244 
    245   ret = 1;
    246 
    247 err:
    248   BN_CTX_end(ctx);
    249   BN_CTX_free(new_ctx);
    250   return ret;
    251 }
    252 
    253 int EC_POINT_oct2point(const EC_GROUP *group, EC_POINT *point,
    254                        const uint8_t *buf, size_t len, BN_CTX *ctx) {
    255   if (group->meth != point->meth) {
    256     OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
    257     return 0;
    258   }
    259   return ec_GFp_simple_oct2point(group, point, buf, len, ctx);
    260 }
    261 
    262 size_t EC_POINT_point2oct(const EC_GROUP *group, const EC_POINT *point,
    263                           point_conversion_form_t form, uint8_t *buf,
    264                           size_t len, BN_CTX *ctx) {
    265   if (group->meth != point->meth) {
    266     OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
    267     return 0;
    268   }
    269   return ec_GFp_simple_point2oct(group, point, form, buf, len, ctx);
    270 }
    271 
    272 int EC_POINT_point2cbb(CBB *out, const EC_GROUP *group, const EC_POINT *point,
    273                        point_conversion_form_t form, BN_CTX *ctx) {
    274   size_t len = EC_POINT_point2oct(group, point, form, NULL, 0, ctx);
    275   if (len == 0) {
    276     return 0;
    277   }
    278   uint8_t *p;
    279   return CBB_add_space(out, &p, len) &&
    280          EC_POINT_point2oct(group, point, form, p, len, ctx) == len;
    281 }
    282 
    283 int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group,
    284                                              EC_POINT *point, const BIGNUM *x,
    285                                              int y_bit, BN_CTX *ctx) {
    286   if (BN_is_negative(x) || BN_cmp(x, &group->field) >= 0) {
    287     OPENSSL_PUT_ERROR(EC, EC_R_INVALID_COMPRESSED_POINT);
    288     return 0;
    289   }
    290 
    291   BN_CTX *new_ctx = NULL;
    292   BIGNUM *tmp1, *tmp2, *y;
    293   int ret = 0;
    294 
    295   ERR_clear_error();
    296 
    297   if (ctx == NULL) {
    298     ctx = new_ctx = BN_CTX_new();
    299     if (ctx == NULL) {
    300       return 0;
    301     }
    302   }
    303 
    304   y_bit = (y_bit != 0);
    305 
    306   BN_CTX_start(ctx);
    307   tmp1 = BN_CTX_get(ctx);
    308   tmp2 = BN_CTX_get(ctx);
    309   y = BN_CTX_get(ctx);
    310   if (y == NULL) {
    311     goto err;
    312   }
    313 
    314   /* Recover y.  We have a Weierstrass equation
    315    *     y^2 = x^3 + a*x + b,
    316    * so  y  is one of the square roots of  x^3 + a*x + b. */
    317 
    318   /* tmp1 := x^3 */
    319   if (group->meth->field_decode == 0) {
    320     /* field_{sqr,mul} work on standard representation */
    321     if (!group->meth->field_sqr(group, tmp2, x, ctx) ||
    322         !group->meth->field_mul(group, tmp1, tmp2, x, ctx)) {
    323       goto err;
    324     }
    325   } else {
    326     if (!BN_mod_sqr(tmp2, x, &group->field, ctx) ||
    327         !BN_mod_mul(tmp1, tmp2, x, &group->field, ctx)) {
    328       goto err;
    329     }
    330   }
    331 
    332   /* tmp1 := tmp1 + a*x */
    333   if (group->a_is_minus3) {
    334     if (!BN_mod_lshift1_quick(tmp2, x, &group->field) ||
    335         !BN_mod_add_quick(tmp2, tmp2, x, &group->field) ||
    336         !BN_mod_sub_quick(tmp1, tmp1, tmp2, &group->field)) {
    337       goto err;
    338     }
    339   } else {
    340     if (group->meth->field_decode) {
    341       if (!group->meth->field_decode(group, tmp2, &group->a, ctx) ||
    342           !BN_mod_mul(tmp2, tmp2, x, &group->field, ctx)) {
    343         goto err;
    344       }
    345     } else {
    346       /* field_mul works on standard representation */
    347       if (!group->meth->field_mul(group, tmp2, &group->a, x, ctx)) {
    348         goto err;
    349       }
    350     }
    351 
    352     if (!BN_mod_add_quick(tmp1, tmp1, tmp2, &group->field)) {
    353       goto err;
    354     }
    355   }
    356 
    357   /* tmp1 := tmp1 + b */
    358   if (group->meth->field_decode) {
    359     if (!group->meth->field_decode(group, tmp2, &group->b, ctx) ||
    360         !BN_mod_add_quick(tmp1, tmp1, tmp2, &group->field)) {
    361       goto err;
    362     }
    363   } else {
    364     if (!BN_mod_add_quick(tmp1, tmp1, &group->b, &group->field)) {
    365       goto err;
    366     }
    367   }
    368 
    369   if (!BN_mod_sqrt(y, tmp1, &group->field, ctx)) {
    370     unsigned long err = ERR_peek_last_error();
    371 
    372     if (ERR_GET_LIB(err) == ERR_LIB_BN &&
    373         ERR_GET_REASON(err) == BN_R_NOT_A_SQUARE) {
    374       ERR_clear_error();
    375       OPENSSL_PUT_ERROR(EC, EC_R_INVALID_COMPRESSED_POINT);
    376     } else {
    377       OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
    378     }
    379     goto err;
    380   }
    381 
    382   if (y_bit != BN_is_odd(y)) {
    383     if (BN_is_zero(y)) {
    384       OPENSSL_PUT_ERROR(EC, EC_R_INVALID_COMPRESSION_BIT);
    385       goto err;
    386     }
    387     if (!BN_usub(y, &group->field, y)) {
    388       goto err;
    389     }
    390   }
    391   if (y_bit != BN_is_odd(y)) {
    392     OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
    393     goto err;
    394   }
    395 
    396   if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) {
    397     goto err;
    398   }
    399 
    400   ret = 1;
    401 
    402 err:
    403   BN_CTX_end(ctx);
    404   BN_CTX_free(new_ctx);
    405   return ret;
    406 }
    407 
    408 int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *group,
    409                                             EC_POINT *point, const BIGNUM *x,
    410                                             int y_bit, BN_CTX *ctx) {
    411   if (group->meth != point->meth) {
    412     OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
    413     return 0;
    414   }
    415   return ec_GFp_simple_set_compressed_coordinates(group, point, x, y_bit, ctx);
    416 }
    417