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