1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/freebl/ecl/ecl.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,396 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "mpi.h" 1.9 +#include "mplogic.h" 1.10 +#include "ecl.h" 1.11 +#include "ecl-priv.h" 1.12 +#include "ec2.h" 1.13 +#include "ecp.h" 1.14 +#include <stdlib.h> 1.15 +#include <string.h> 1.16 + 1.17 +/* Allocate memory for a new ECGroup object. */ 1.18 +ECGroup * 1.19 +ECGroup_new() 1.20 +{ 1.21 + mp_err res = MP_OKAY; 1.22 + ECGroup *group; 1.23 + group = (ECGroup *) malloc(sizeof(ECGroup)); 1.24 + if (group == NULL) 1.25 + return NULL; 1.26 + group->constructed = MP_YES; 1.27 + group->meth = NULL; 1.28 + group->text = NULL; 1.29 + MP_DIGITS(&group->curvea) = 0; 1.30 + MP_DIGITS(&group->curveb) = 0; 1.31 + MP_DIGITS(&group->genx) = 0; 1.32 + MP_DIGITS(&group->geny) = 0; 1.33 + MP_DIGITS(&group->order) = 0; 1.34 + group->base_point_mul = NULL; 1.35 + group->points_mul = NULL; 1.36 + group->validate_point = NULL; 1.37 + group->extra1 = NULL; 1.38 + group->extra2 = NULL; 1.39 + group->extra_free = NULL; 1.40 + MP_CHECKOK(mp_init(&group->curvea)); 1.41 + MP_CHECKOK(mp_init(&group->curveb)); 1.42 + MP_CHECKOK(mp_init(&group->genx)); 1.43 + MP_CHECKOK(mp_init(&group->geny)); 1.44 + MP_CHECKOK(mp_init(&group->order)); 1.45 + 1.46 + CLEANUP: 1.47 + if (res != MP_OKAY) { 1.48 + ECGroup_free(group); 1.49 + return NULL; 1.50 + } 1.51 + return group; 1.52 +} 1.53 + 1.54 +/* Construct a generic ECGroup for elliptic curves over prime fields. */ 1.55 +ECGroup * 1.56 +ECGroup_consGFp(const mp_int *irr, const mp_int *curvea, 1.57 + const mp_int *curveb, const mp_int *genx, 1.58 + const mp_int *geny, const mp_int *order, int cofactor) 1.59 +{ 1.60 + mp_err res = MP_OKAY; 1.61 + ECGroup *group = NULL; 1.62 + 1.63 + group = ECGroup_new(); 1.64 + if (group == NULL) 1.65 + return NULL; 1.66 + 1.67 + group->meth = GFMethod_consGFp(irr); 1.68 + if (group->meth == NULL) { 1.69 + res = MP_MEM; 1.70 + goto CLEANUP; 1.71 + } 1.72 + MP_CHECKOK(mp_copy(curvea, &group->curvea)); 1.73 + MP_CHECKOK(mp_copy(curveb, &group->curveb)); 1.74 + MP_CHECKOK(mp_copy(genx, &group->genx)); 1.75 + MP_CHECKOK(mp_copy(geny, &group->geny)); 1.76 + MP_CHECKOK(mp_copy(order, &group->order)); 1.77 + group->cofactor = cofactor; 1.78 + group->point_add = &ec_GFp_pt_add_aff; 1.79 + group->point_sub = &ec_GFp_pt_sub_aff; 1.80 + group->point_dbl = &ec_GFp_pt_dbl_aff; 1.81 + group->point_mul = &ec_GFp_pt_mul_jm_wNAF; 1.82 + group->base_point_mul = NULL; 1.83 + group->points_mul = &ec_GFp_pts_mul_jac; 1.84 + group->validate_point = &ec_GFp_validate_point; 1.85 + 1.86 + CLEANUP: 1.87 + if (res != MP_OKAY) { 1.88 + ECGroup_free(group); 1.89 + return NULL; 1.90 + } 1.91 + return group; 1.92 +} 1.93 + 1.94 +/* Construct a generic ECGroup for elliptic curves over prime fields with 1.95 + * field arithmetic implemented in Montgomery coordinates. */ 1.96 +ECGroup * 1.97 +ECGroup_consGFp_mont(const mp_int *irr, const mp_int *curvea, 1.98 + const mp_int *curveb, const mp_int *genx, 1.99 + const mp_int *geny, const mp_int *order, int cofactor) 1.100 +{ 1.101 + mp_err res = MP_OKAY; 1.102 + ECGroup *group = NULL; 1.103 + 1.104 + group = ECGroup_new(); 1.105 + if (group == NULL) 1.106 + return NULL; 1.107 + 1.108 + group->meth = GFMethod_consGFp_mont(irr); 1.109 + if (group->meth == NULL) { 1.110 + res = MP_MEM; 1.111 + goto CLEANUP; 1.112 + } 1.113 + MP_CHECKOK(group->meth-> 1.114 + field_enc(curvea, &group->curvea, group->meth)); 1.115 + MP_CHECKOK(group->meth-> 1.116 + field_enc(curveb, &group->curveb, group->meth)); 1.117 + MP_CHECKOK(group->meth->field_enc(genx, &group->genx, group->meth)); 1.118 + MP_CHECKOK(group->meth->field_enc(geny, &group->geny, group->meth)); 1.119 + MP_CHECKOK(mp_copy(order, &group->order)); 1.120 + group->cofactor = cofactor; 1.121 + group->point_add = &ec_GFp_pt_add_aff; 1.122 + group->point_sub = &ec_GFp_pt_sub_aff; 1.123 + group->point_dbl = &ec_GFp_pt_dbl_aff; 1.124 + group->point_mul = &ec_GFp_pt_mul_jm_wNAF; 1.125 + group->base_point_mul = NULL; 1.126 + group->points_mul = &ec_GFp_pts_mul_jac; 1.127 + group->validate_point = &ec_GFp_validate_point; 1.128 + 1.129 + CLEANUP: 1.130 + if (res != MP_OKAY) { 1.131 + ECGroup_free(group); 1.132 + return NULL; 1.133 + } 1.134 + return group; 1.135 +} 1.136 + 1.137 +#ifdef NSS_ECC_MORE_THAN_SUITE_B 1.138 +/* Construct a generic ECGroup for elliptic curves over binary polynomial 1.139 + * fields. */ 1.140 +ECGroup * 1.141 +ECGroup_consGF2m(const mp_int *irr, const unsigned int irr_arr[5], 1.142 + const mp_int *curvea, const mp_int *curveb, 1.143 + const mp_int *genx, const mp_int *geny, 1.144 + const mp_int *order, int cofactor) 1.145 +{ 1.146 + mp_err res = MP_OKAY; 1.147 + ECGroup *group = NULL; 1.148 + 1.149 + group = ECGroup_new(); 1.150 + if (group == NULL) 1.151 + return NULL; 1.152 + 1.153 + group->meth = GFMethod_consGF2m(irr, irr_arr); 1.154 + if (group->meth == NULL) { 1.155 + res = MP_MEM; 1.156 + goto CLEANUP; 1.157 + } 1.158 + MP_CHECKOK(mp_copy(curvea, &group->curvea)); 1.159 + MP_CHECKOK(mp_copy(curveb, &group->curveb)); 1.160 + MP_CHECKOK(mp_copy(genx, &group->genx)); 1.161 + MP_CHECKOK(mp_copy(geny, &group->geny)); 1.162 + MP_CHECKOK(mp_copy(order, &group->order)); 1.163 + group->cofactor = cofactor; 1.164 + group->point_add = &ec_GF2m_pt_add_aff; 1.165 + group->point_sub = &ec_GF2m_pt_sub_aff; 1.166 + group->point_dbl = &ec_GF2m_pt_dbl_aff; 1.167 + group->point_mul = &ec_GF2m_pt_mul_mont; 1.168 + group->base_point_mul = NULL; 1.169 + group->points_mul = &ec_pts_mul_basic; 1.170 + group->validate_point = &ec_GF2m_validate_point; 1.171 + 1.172 + CLEANUP: 1.173 + if (res != MP_OKAY) { 1.174 + ECGroup_free(group); 1.175 + return NULL; 1.176 + } 1.177 + return group; 1.178 +} 1.179 +#endif 1.180 + 1.181 +/* Construct ECGroup from hex parameters and name, if any. Called by 1.182 + * ECGroup_fromHex and ECGroup_fromName. */ 1.183 +ECGroup * 1.184 +ecgroup_fromNameAndHex(const ECCurveName name, 1.185 + const ECCurveParams * params) 1.186 +{ 1.187 + mp_int irr, curvea, curveb, genx, geny, order; 1.188 + int bits; 1.189 + ECGroup *group = NULL; 1.190 + mp_err res = MP_OKAY; 1.191 + 1.192 + /* initialize values */ 1.193 + MP_DIGITS(&irr) = 0; 1.194 + MP_DIGITS(&curvea) = 0; 1.195 + MP_DIGITS(&curveb) = 0; 1.196 + MP_DIGITS(&genx) = 0; 1.197 + MP_DIGITS(&geny) = 0; 1.198 + MP_DIGITS(&order) = 0; 1.199 + MP_CHECKOK(mp_init(&irr)); 1.200 + MP_CHECKOK(mp_init(&curvea)); 1.201 + MP_CHECKOK(mp_init(&curveb)); 1.202 + MP_CHECKOK(mp_init(&genx)); 1.203 + MP_CHECKOK(mp_init(&geny)); 1.204 + MP_CHECKOK(mp_init(&order)); 1.205 + MP_CHECKOK(mp_read_radix(&irr, params->irr, 16)); 1.206 + MP_CHECKOK(mp_read_radix(&curvea, params->curvea, 16)); 1.207 + MP_CHECKOK(mp_read_radix(&curveb, params->curveb, 16)); 1.208 + MP_CHECKOK(mp_read_radix(&genx, params->genx, 16)); 1.209 + MP_CHECKOK(mp_read_radix(&geny, params->geny, 16)); 1.210 + MP_CHECKOK(mp_read_radix(&order, params->order, 16)); 1.211 + 1.212 + /* determine number of bits */ 1.213 + bits = mpl_significant_bits(&irr) - 1; 1.214 + if (bits < MP_OKAY) { 1.215 + res = bits; 1.216 + goto CLEANUP; 1.217 + } 1.218 + 1.219 + /* determine which optimizations (if any) to use */ 1.220 + if (params->field == ECField_GFp) { 1.221 + switch (name) { 1.222 +#ifdef NSS_ECC_MORE_THAN_SUITE_B 1.223 +#ifdef ECL_USE_FP 1.224 + case ECCurve_SECG_PRIME_160R1: 1.225 + group = 1.226 + ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, 1.227 + &order, params->cofactor); 1.228 + if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } 1.229 + MP_CHECKOK(ec_group_set_secp160r1_fp(group)); 1.230 + break; 1.231 +#endif 1.232 + case ECCurve_SECG_PRIME_192R1: 1.233 +#ifdef ECL_USE_FP 1.234 + group = 1.235 + ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, 1.236 + &order, params->cofactor); 1.237 + if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } 1.238 + MP_CHECKOK(ec_group_set_nistp192_fp(group)); 1.239 +#else 1.240 + group = 1.241 + ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, 1.242 + &order, params->cofactor); 1.243 + if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } 1.244 + MP_CHECKOK(ec_group_set_gfp192(group, name)); 1.245 +#endif 1.246 + break; 1.247 + case ECCurve_SECG_PRIME_224R1: 1.248 +#ifdef ECL_USE_FP 1.249 + group = 1.250 + ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, 1.251 + &order, params->cofactor); 1.252 + if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } 1.253 + MP_CHECKOK(ec_group_set_nistp224_fp(group)); 1.254 +#else 1.255 + group = 1.256 + ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, 1.257 + &order, params->cofactor); 1.258 + if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } 1.259 + MP_CHECKOK(ec_group_set_gfp224(group, name)); 1.260 +#endif 1.261 + break; 1.262 +#endif /* NSS_ECC_MORE_THAN_SUITE_B */ 1.263 + case ECCurve_SECG_PRIME_256R1: 1.264 + group = 1.265 + ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, 1.266 + &order, params->cofactor); 1.267 + if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } 1.268 + MP_CHECKOK(ec_group_set_gfp256(group, name)); 1.269 + MP_CHECKOK(ec_group_set_gfp256_32(group, name)); 1.270 + break; 1.271 + case ECCurve_SECG_PRIME_521R1: 1.272 + group = 1.273 + ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, 1.274 + &order, params->cofactor); 1.275 + if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } 1.276 + MP_CHECKOK(ec_group_set_gfp521(group, name)); 1.277 + break; 1.278 + default: 1.279 + /* use generic arithmetic */ 1.280 + group = 1.281 + ECGroup_consGFp_mont(&irr, &curvea, &curveb, &genx, &geny, 1.282 + &order, params->cofactor); 1.283 + if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } 1.284 + } 1.285 +#ifdef NSS_ECC_MORE_THAN_SUITE_B 1.286 + } else if (params->field == ECField_GF2m) { 1.287 + group = ECGroup_consGF2m(&irr, NULL, &curvea, &curveb, &genx, &geny, &order, params->cofactor); 1.288 + if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } 1.289 + if ((name == ECCurve_NIST_K163) || 1.290 + (name == ECCurve_NIST_B163) || 1.291 + (name == ECCurve_SECG_CHAR2_163R1)) { 1.292 + MP_CHECKOK(ec_group_set_gf2m163(group, name)); 1.293 + } else if ((name == ECCurve_SECG_CHAR2_193R1) || 1.294 + (name == ECCurve_SECG_CHAR2_193R2)) { 1.295 + MP_CHECKOK(ec_group_set_gf2m193(group, name)); 1.296 + } else if ((name == ECCurve_NIST_K233) || 1.297 + (name == ECCurve_NIST_B233)) { 1.298 + MP_CHECKOK(ec_group_set_gf2m233(group, name)); 1.299 + } 1.300 +#endif 1.301 + } else { 1.302 + res = MP_UNDEF; 1.303 + goto CLEANUP; 1.304 + } 1.305 + 1.306 + /* set name, if any */ 1.307 + if ((group != NULL) && (params->text != NULL)) { 1.308 + group->text = strdup(params->text); 1.309 + if (group->text == NULL) { 1.310 + res = MP_MEM; 1.311 + } 1.312 + } 1.313 + 1.314 + CLEANUP: 1.315 + mp_clear(&irr); 1.316 + mp_clear(&curvea); 1.317 + mp_clear(&curveb); 1.318 + mp_clear(&genx); 1.319 + mp_clear(&geny); 1.320 + mp_clear(&order); 1.321 + if (res != MP_OKAY) { 1.322 + ECGroup_free(group); 1.323 + return NULL; 1.324 + } 1.325 + return group; 1.326 +} 1.327 + 1.328 +/* Construct ECGroup from hexadecimal representations of parameters. */ 1.329 +ECGroup * 1.330 +ECGroup_fromHex(const ECCurveParams * params) 1.331 +{ 1.332 + return ecgroup_fromNameAndHex(ECCurve_noName, params); 1.333 +} 1.334 + 1.335 +/* Construct ECGroup from named parameters. */ 1.336 +ECGroup * 1.337 +ECGroup_fromName(const ECCurveName name) 1.338 +{ 1.339 + ECGroup *group = NULL; 1.340 + ECCurveParams *params = NULL; 1.341 + mp_err res = MP_OKAY; 1.342 + 1.343 + params = EC_GetNamedCurveParams(name); 1.344 + if (params == NULL) { 1.345 + res = MP_UNDEF; 1.346 + goto CLEANUP; 1.347 + } 1.348 + 1.349 + /* construct actual group */ 1.350 + group = ecgroup_fromNameAndHex(name, params); 1.351 + if (group == NULL) { 1.352 + res = MP_UNDEF; 1.353 + goto CLEANUP; 1.354 + } 1.355 + 1.356 + CLEANUP: 1.357 + EC_FreeCurveParams(params); 1.358 + if (res != MP_OKAY) { 1.359 + ECGroup_free(group); 1.360 + return NULL; 1.361 + } 1.362 + return group; 1.363 +} 1.364 + 1.365 +/* Validates an EC public key as described in Section 5.2.2 of X9.62. */ 1.366 +mp_err ECPoint_validate(const ECGroup *group, const mp_int *px, const 1.367 + mp_int *py) 1.368 +{ 1.369 + /* 1: Verify that publicValue is not the point at infinity */ 1.370 + /* 2: Verify that the coordinates of publicValue are elements 1.371 + * of the field. 1.372 + */ 1.373 + /* 3: Verify that publicValue is on the curve. */ 1.374 + /* 4: Verify that the order of the curve times the publicValue 1.375 + * is the point at infinity. 1.376 + */ 1.377 + return group->validate_point(px, py, group); 1.378 +} 1.379 + 1.380 +/* Free the memory allocated (if any) to an ECGroup object. */ 1.381 +void 1.382 +ECGroup_free(ECGroup *group) 1.383 +{ 1.384 + if (group == NULL) 1.385 + return; 1.386 + GFMethod_free(group->meth); 1.387 + if (group->constructed == MP_NO) 1.388 + return; 1.389 + mp_clear(&group->curvea); 1.390 + mp_clear(&group->curveb); 1.391 + mp_clear(&group->genx); 1.392 + mp_clear(&group->geny); 1.393 + mp_clear(&group->order); 1.394 + if (group->text != NULL) 1.395 + free(group->text); 1.396 + if (group->extra_free != NULL) 1.397 + group->extra_free(group); 1.398 + free(group); 1.399 +}