1 /* *********************************************************************
   2  *
   3  * Sun elects to have this file available under and governed by the
   4  * Mozilla Public License Version 1.1 ("MPL") (see
   5  * http://www.mozilla.org/MPL/ for full license text). For the avoidance
   6  * of doubt and subject to the following, Sun also elects to allow
   7  * licensees to use this file under the MPL, the GNU General Public
   8  * License version 2 only or the Lesser General Public License version
   9  * 2.1 only. Any references to the "GNU General Public License version 2
  10  * or later" or "GPL" in the following shall be construed to mean the
  11  * GNU General Public License version 2 only. Any references to the "GNU
  12  * Lesser General Public License version 2.1 or later" or "LGPL" in the
  13  * following shall be construed to mean the GNU Lesser General Public
  14  * License version 2.1 only. However, the following notice accompanied
  15  * the original version of this file:
  16  *
  17  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  18  *
  19  * The contents of this file are subject to the Mozilla Public License Version
  20  * 1.1 (the "License"); you may not use this file except in compliance with
  21  * the License. You may obtain a copy of the License at
  22  * http://www.mozilla.org/MPL/
  23  *
  24  * Software distributed under the License is distributed on an "AS IS" basis,
  25  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  26  * for the specific language governing rights and limitations under the
  27  * License.
  28  *
  29  * The Original Code is the elliptic curve math library.
  30  *
  31  * The Initial Developer of the Original Code is
  32  * Sun Microsystems, Inc.
  33  * Portions created by the Initial Developer are Copyright (C) 2003
  34  * the Initial Developer. All Rights Reserved.
  35  *
  36  * Contributor(s):
  37  *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
  38  *
  39  * Alternatively, the contents of this file may be used under the terms of
  40  * either the GNU General Public License Version 2 or later (the "GPL"), or
  41  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  42  * in which case the provisions of the GPL or the LGPL are applicable instead
  43  * of those above. If you wish to allow use of your version of this file only
  44  * under the terms of either the GPL or the LGPL, and not to allow others to
  45  * use your version of this file under the terms of the MPL, indicate your
  46  * decision by deleting the provisions above and replace them with the notice
  47  * and other provisions required by the GPL or the LGPL. If you do not delete
  48  * the provisions above, a recipient may use your version of this file under
  49  * the terms of any one of the MPL, the GPL or the LGPL.
  50  *
  51  *********************************************************************** */
  52 /*
  53  * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
  54  * Use is subject to license terms.
  55  */
  56 
  57 #include "mpi.h"
  58 #include "mplogic.h"
  59 #include "ecl.h"
  60 #include "ecl-priv.h"
  61 #include "ec2.h"
  62 #include "ecp.h"
  63 #ifndef _KERNEL
  64 #include <stdlib.h>
  65 #include <string.h>
  66 #endif
  67 
  68 /* Allocate memory for a new ECGroup object. */
  69 ECGroup *
  70 ECGroup_new(int kmflag)
  71 {
  72         mp_err res = MP_OKAY;
  73         ECGroup *group;
  74 #ifdef _KERNEL
  75         group = (ECGroup *) kmem_alloc(sizeof(ECGroup), kmflag);
  76 #else
  77         group = (ECGroup *) malloc(sizeof(ECGroup));
  78 #endif
  79         if (group == NULL)
  80                 return NULL;
  81         group->constructed = MP_YES;
  82         group->meth = NULL;
  83         group->text = NULL;
  84         MP_DIGITS(&group->curvea) = 0;
  85         MP_DIGITS(&group->curveb) = 0;
  86         MP_DIGITS(&group->genx) = 0;
  87         MP_DIGITS(&group->geny) = 0;
  88         MP_DIGITS(&group->order) = 0;
  89         group->base_point_mul = NULL;
  90         group->points_mul = NULL;
  91         group->validate_point = NULL;
  92         group->extra1 = NULL;
  93         group->extra2 = NULL;
  94         group->extra_free = NULL;
  95         MP_CHECKOK(mp_init(&group->curvea, kmflag));
  96         MP_CHECKOK(mp_init(&group->curveb, kmflag));
  97         MP_CHECKOK(mp_init(&group->genx, kmflag));
  98         MP_CHECKOK(mp_init(&group->geny, kmflag));
  99         MP_CHECKOK(mp_init(&group->order, kmflag));
 100 
 101   CLEANUP:
 102         if (res != MP_OKAY) {
 103                 ECGroup_free(group);
 104                 return NULL;
 105         }
 106         return group;
 107 }
 108 
 109 /* Construct a generic ECGroup for elliptic curves over prime fields. */
 110 ECGroup *
 111 ECGroup_consGFp(const mp_int *irr, const mp_int *curvea,
 112                                 const mp_int *curveb, const mp_int *genx,
 113                                 const mp_int *geny, const mp_int *order, int cofactor)
 114 {
 115         mp_err res = MP_OKAY;
 116         ECGroup *group = NULL;
 117 
 118         group = ECGroup_new(FLAG(irr));
 119         if (group == NULL)
 120                 return NULL;
 121 
 122         group->meth = GFMethod_consGFp(irr);
 123         if (group->meth == NULL) {
 124                 res = MP_MEM;
 125                 goto CLEANUP;
 126         }
 127         MP_CHECKOK(mp_copy(curvea, &group->curvea));
 128         MP_CHECKOK(mp_copy(curveb, &group->curveb));
 129         MP_CHECKOK(mp_copy(genx, &group->genx));
 130         MP_CHECKOK(mp_copy(geny, &group->geny));
 131         MP_CHECKOK(mp_copy(order, &group->order));
 132         group->cofactor = cofactor;
 133         group->point_add = &ec_GFp_pt_add_aff;
 134         group->point_sub = &ec_GFp_pt_sub_aff;
 135         group->point_dbl = &ec_GFp_pt_dbl_aff;
 136         group->point_mul = &ec_GFp_pt_mul_jm_wNAF;
 137         group->base_point_mul = NULL;
 138         group->points_mul = &ec_GFp_pts_mul_jac;
 139         group->validate_point = &ec_GFp_validate_point;
 140 
 141   CLEANUP:
 142         if (res != MP_OKAY) {
 143                 ECGroup_free(group);
 144                 return NULL;
 145         }
 146         return group;
 147 }
 148 
 149 /* Construct a generic ECGroup for elliptic curves over prime fields with
 150  * field arithmetic implemented in Montgomery coordinates. */
 151 ECGroup *
 152 ECGroup_consGFp_mont(const mp_int *irr, const mp_int *curvea,
 153                                          const mp_int *curveb, const mp_int *genx,
 154                                          const mp_int *geny, const mp_int *order, int cofactor)
 155 {
 156         mp_err res = MP_OKAY;
 157         ECGroup *group = NULL;
 158 
 159         group = ECGroup_new(FLAG(irr));
 160         if (group == NULL)
 161                 return NULL;
 162 
 163         group->meth = GFMethod_consGFp_mont(irr);
 164         if (group->meth == NULL) {
 165                 res = MP_MEM;
 166                 goto CLEANUP;
 167         }
 168         MP_CHECKOK(group->meth->
 169                            field_enc(curvea, &group->curvea, group->meth));
 170         MP_CHECKOK(group->meth->
 171                            field_enc(curveb, &group->curveb, group->meth));
 172         MP_CHECKOK(group->meth->field_enc(genx, &group->genx, group->meth));
 173         MP_CHECKOK(group->meth->field_enc(geny, &group->geny, group->meth));
 174         MP_CHECKOK(mp_copy(order, &group->order));
 175         group->cofactor = cofactor;
 176         group->point_add = &ec_GFp_pt_add_aff;
 177         group->point_sub = &ec_GFp_pt_sub_aff;
 178         group->point_dbl = &ec_GFp_pt_dbl_aff;
 179         group->point_mul = &ec_GFp_pt_mul_jm_wNAF;
 180         group->base_point_mul = NULL;
 181         group->points_mul = &ec_GFp_pts_mul_jac;
 182         group->validate_point = &ec_GFp_validate_point;
 183 
 184   CLEANUP:
 185         if (res != MP_OKAY) {
 186                 ECGroup_free(group);
 187                 return NULL;
 188         }
 189         return group;
 190 }
 191 
 192 #ifdef NSS_ECC_MORE_THAN_SUITE_B
 193 /* Construct a generic ECGroup for elliptic curves over binary polynomial
 194  * fields. */
 195 ECGroup *
 196 ECGroup_consGF2m(const mp_int *irr, const unsigned int irr_arr[5],
 197                                  const mp_int *curvea, const mp_int *curveb,
 198                                  const mp_int *genx, const mp_int *geny,
 199                                  const mp_int *order, int cofactor)
 200 {
 201         mp_err res = MP_OKAY;
 202         ECGroup *group = NULL;
 203 
 204         group = ECGroup_new(FLAG(irr));
 205         if (group == NULL)
 206                 return NULL;
 207 
 208         group->meth = GFMethod_consGF2m(irr, irr_arr);
 209         if (group->meth == NULL) {
 210                 res = MP_MEM;
 211                 goto CLEANUP;
 212         }
 213         MP_CHECKOK(mp_copy(curvea, &group->curvea));
 214         MP_CHECKOK(mp_copy(curveb, &group->curveb));
 215         MP_CHECKOK(mp_copy(genx, &group->genx));
 216         MP_CHECKOK(mp_copy(geny, &group->geny));
 217         MP_CHECKOK(mp_copy(order, &group->order));
 218         group->cofactor = cofactor;
 219         group->point_add = &ec_GF2m_pt_add_aff;
 220         group->point_sub = &ec_GF2m_pt_sub_aff;
 221         group->point_dbl = &ec_GF2m_pt_dbl_aff;
 222         group->point_mul = &ec_GF2m_pt_mul_mont;
 223         group->base_point_mul = NULL;
 224         group->points_mul = &ec_pts_mul_basic;
 225         group->validate_point = &ec_GF2m_validate_point;
 226 
 227   CLEANUP:
 228         if (res != MP_OKAY) {
 229                 ECGroup_free(group);
 230                 return NULL;
 231         }
 232         return group;
 233 }
 234 #endif
 235 
 236 /* Construct ECGroup from hex parameters and name, if any. Called by
 237  * ECGroup_fromHex and ECGroup_fromName. */
 238 ECGroup *
 239 ecgroup_fromNameAndHex(const ECCurveName name,
 240                                    const ECCurveParams * params, int kmflag)
 241 {
 242         mp_int irr, curvea, curveb, genx, geny, order;
 243         int bits;
 244         ECGroup *group = NULL;
 245         mp_err res = MP_OKAY;
 246 
 247         /* initialize values */
 248         MP_DIGITS(&irr) = 0;
 249         MP_DIGITS(&curvea) = 0;
 250         MP_DIGITS(&curveb) = 0;
 251         MP_DIGITS(&genx) = 0;
 252         MP_DIGITS(&geny) = 0;
 253         MP_DIGITS(&order) = 0;
 254         MP_CHECKOK(mp_init(&irr, kmflag));
 255         MP_CHECKOK(mp_init(&curvea, kmflag));
 256         MP_CHECKOK(mp_init(&curveb, kmflag));
 257         MP_CHECKOK(mp_init(&genx, kmflag));
 258         MP_CHECKOK(mp_init(&geny, kmflag));
 259         MP_CHECKOK(mp_init(&order, kmflag));
 260         MP_CHECKOK(mp_read_radix(&irr, params->irr, 16));
 261         MP_CHECKOK(mp_read_radix(&curvea, params->curvea, 16));
 262         MP_CHECKOK(mp_read_radix(&curveb, params->curveb, 16));
 263         MP_CHECKOK(mp_read_radix(&genx, params->genx, 16));
 264         MP_CHECKOK(mp_read_radix(&geny, params->geny, 16));
 265         MP_CHECKOK(mp_read_radix(&order, params->order, 16));
 266 
 267         /* determine number of bits */
 268         bits = mpl_significant_bits(&irr) - 1;
 269         if (bits < MP_OKAY) {
 270                 res = bits;
 271                 goto CLEANUP;
 272         }
 273 
 274         /* determine which optimizations (if any) to use */
 275         if (params->field == ECField_GFp) {
 276 #ifdef NSS_ECC_MORE_THAN_SUITE_B
 277             switch (name) {
 278 #ifdef ECL_USE_FP
 279                 case ECCurve_SECG_PRIME_160R1:
 280                         group =
 281                                 ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny,
 282                                                                 &order, params->cofactor);
 283                         if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
 284                         MP_CHECKOK(ec_group_set_secp160r1_fp(group));
 285                         break;
 286 #endif
 287                 case ECCurve_SECG_PRIME_192R1:
 288 #ifdef ECL_USE_FP
 289                         group =
 290                                 ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny,
 291                                                                 &order, params->cofactor);
 292                         if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
 293                         MP_CHECKOK(ec_group_set_nistp192_fp(group));
 294 #else
 295                         group =
 296                                 ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny,
 297                                                                 &order, params->cofactor);
 298                         if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
 299                         MP_CHECKOK(ec_group_set_gfp192(group, name));
 300 #endif
 301                         break;
 302                 case ECCurve_SECG_PRIME_224R1:
 303 #ifdef ECL_USE_FP
 304                         group =
 305                                 ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny,
 306                                                                 &order, params->cofactor);
 307                         if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
 308                         MP_CHECKOK(ec_group_set_nistp224_fp(group));
 309 #else
 310                         group =
 311                                 ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny,
 312                                                                 &order, params->cofactor);
 313                         if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
 314                         MP_CHECKOK(ec_group_set_gfp224(group, name));
 315 #endif
 316                         break;
 317                 case ECCurve_SECG_PRIME_256R1:
 318                         group =
 319                                 ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny,
 320                                                                 &order, params->cofactor);
 321                         if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
 322                         MP_CHECKOK(ec_group_set_gfp256(group, name));
 323                         break;
 324                 case ECCurve_SECG_PRIME_521R1:
 325                         group =
 326                                 ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny,
 327                                                                 &order, params->cofactor);
 328                         if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
 329                         MP_CHECKOK(ec_group_set_gfp521(group, name));
 330                         break;
 331                 default:
 332                         /* use generic arithmetic */
 333 #endif
 334                         group =
 335                                 ECGroup_consGFp_mont(&irr, &curvea, &curveb, &genx, &geny,
 336                                                                          &order, params->cofactor);
 337                         if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
 338 #ifdef NSS_ECC_MORE_THAN_SUITE_B
 339                 }
 340         } else if (params->field == ECField_GF2m) {
 341                 group = ECGroup_consGF2m(&irr, NULL, &curvea, &curveb, &genx, &geny, &order, params->cofactor);
 342                 if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
 343                 if ((name == ECCurve_NIST_K163) ||
 344                     (name == ECCurve_NIST_B163) ||
 345                     (name == ECCurve_SECG_CHAR2_163R1)) {
 346                         MP_CHECKOK(ec_group_set_gf2m163(group, name));
 347                 } else if ((name == ECCurve_SECG_CHAR2_193R1) ||
 348                            (name == ECCurve_SECG_CHAR2_193R2)) {
 349                         MP_CHECKOK(ec_group_set_gf2m193(group, name));
 350                 } else if ((name == ECCurve_NIST_K233) ||
 351                            (name == ECCurve_NIST_B233)) {
 352                         MP_CHECKOK(ec_group_set_gf2m233(group, name));
 353                 }
 354 #endif
 355         } else {
 356                 res = MP_UNDEF;
 357                 goto CLEANUP;
 358         }
 359 
 360         /* set name, if any */
 361         if ((group != NULL) && (params->text != NULL)) {
 362 #ifdef _KERNEL
 363                 int n = strlen(params->text) + 1;
 364 
 365                 group->text = kmem_alloc(n, kmflag);
 366                 if (group->text == NULL) {
 367                         res = MP_MEM;
 368                         goto CLEANUP;
 369                 }
 370                 bcopy(params->text, group->text, n);
 371                 group->text_len = n;
 372 #else
 373                 group->text = strdup(params->text);
 374                 if (group->text == NULL) {
 375                         res = MP_MEM;
 376                 }
 377 #endif
 378         }
 379 
 380   CLEANUP:
 381         mp_clear(&irr);
 382         mp_clear(&curvea);
 383         mp_clear(&curveb);
 384         mp_clear(&genx);
 385         mp_clear(&geny);
 386         mp_clear(&order);
 387         if (res != MP_OKAY) {
 388                 ECGroup_free(group);
 389                 return NULL;
 390         }
 391         return group;
 392 }
 393 
 394 /* Construct ECGroup from hexadecimal representations of parameters. */
 395 ECGroup *
 396 ECGroup_fromHex(const ECCurveParams * params, int kmflag)
 397 {
 398         return ecgroup_fromNameAndHex(ECCurve_noName, params, kmflag);
 399 }
 400 
 401 /* Construct ECGroup from named parameters. */
 402 ECGroup *
 403 ECGroup_fromName(const ECCurveName name, int kmflag)
 404 {
 405         ECGroup *group = NULL;
 406         ECCurveParams *params = NULL;
 407         mp_err res = MP_OKAY;
 408 
 409         params = EC_GetNamedCurveParams(name, kmflag);
 410         if (params == NULL) {
 411                 res = MP_UNDEF;
 412                 goto CLEANUP;
 413         }
 414 
 415         /* construct actual group */
 416         group = ecgroup_fromNameAndHex(name, params, kmflag);
 417         if (group == NULL) {
 418                 res = MP_UNDEF;
 419                 goto CLEANUP;
 420         }
 421 
 422   CLEANUP:
 423         EC_FreeCurveParams(params);
 424         if (res != MP_OKAY) {
 425                 ECGroup_free(group);
 426                 return NULL;
 427         }
 428         return group;
 429 }
 430 
 431 /* Validates an EC public key as described in Section 5.2.2 of X9.62. */
 432 mp_err ECPoint_validate(const ECGroup *group, const mp_int *px, const
 433                                         mp_int *py)
 434 {
 435     /* 1: Verify that publicValue is not the point at infinity */
 436     /* 2: Verify that the coordinates of publicValue are elements
 437      *    of the field.
 438      */
 439     /* 3: Verify that publicValue is on the curve. */
 440     /* 4: Verify that the order of the curve times the publicValue
 441      *    is the point at infinity.
 442      */
 443         return group->validate_point(px, py, group);
 444 }
 445 
 446 /* Free the memory allocated (if any) to an ECGroup object. */
 447 void
 448 ECGroup_free(ECGroup *group)
 449 {
 450         if (group == NULL)
 451                 return;
 452         GFMethod_free(group->meth);
 453         if (group->constructed == MP_NO)
 454                 return;
 455         mp_clear(&group->curvea);
 456         mp_clear(&group->curveb);
 457         mp_clear(&group->genx);
 458         mp_clear(&group->geny);
 459         mp_clear(&group->order);
 460         if (group->text != NULL)
 461 #ifdef _KERNEL
 462                 kmem_free(group->text, group->text_len);
 463 #else
 464                 free(group->text);
 465 #endif
 466         if (group->extra_free != NULL)
 467                 group->extra_free(group);
 468 #ifdef _KERNEL
 469         kmem_free(group, sizeof (ECGroup));
 470 #else
 471         free(group);
 472 #endif
 473 }