X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fec%2Fecp_nistp521.c;h=4e6c0f98fbc7943ef9a4a27a9f119f544d060951;hp=dd5b19b5813af1ac4944959be25762b9d50ee924;hb=3f5abab94104574c32991243668ac633a8d8e525;hpb=90945fa31a42dcf3beb90540c618e4d627c595ea diff --git a/crypto/ec/ecp_nistp521.c b/crypto/ec/ecp_nistp521.c index dd5b19b581..4e6c0f98fb 100644 --- a/crypto/ec/ecp_nistp521.c +++ b/crypto/ec/ecp_nistp521.c @@ -1,7 +1,12 @@ -/* crypto/ec/ecp_nistp521.c */ /* - * Written by Adam Langley (Google) for the OpenSSL project + * Copyright 2011-2018 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html */ + /* Copyright 2011 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,30 +31,25 @@ * work which got its smarts from Daniel J. Bernstein's work on the same. */ -#include -#ifndef OPENSSL_NO_EC_NISTP_64_GCC_128 - -# ifndef OPENSSL_SYS_VMS -# include -# else -# include -# endif +#include +#ifdef OPENSSL_NO_EC_NISTP_64_GCC_128 +NON_EMPTY_TRANSLATION_UNIT +#else # include # include # include "ec_lcl.h" -# if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +# if defined(__SIZEOF_INT128__) && __SIZEOF_INT128__==16 /* even with gcc, the typedef won't work for 32-bit platforms */ typedef __uint128_t uint128_t; /* nonstandard; implemented by gcc on 64-bit * platforms */ # else -# error "Need GCC 3.1 or later to define type uint128_t" +# error "Your compiler doesn't appear to support 128-bit integer types" # endif typedef uint8_t u8; typedef uint64_t u64; -typedef int64_t s64; /* * The underlying field. P521 operates over GF(2^521-1). We can serialise an @@ -187,7 +187,7 @@ static int BN_to_felem(felem out, const BIGNUM *bn) /* BN_bn2bin eats leading zeroes */ memset(b_out, 0, sizeof(b_out)); num_bytes = BN_num_bytes(bn); - if (num_bytes > sizeof b_out) { + if (num_bytes > sizeof(b_out)) { ECerr(EC_F_BN_TO_FELEM, EC_R_BIGNUM_OUT_OF_RANGE); return 0; } @@ -206,8 +206,8 @@ static BIGNUM *felem_to_BN(BIGNUM *out, const felem in) { felem_bytearray b_in, b_out; felem_to_bin66(b_in, in); - flip_endian(b_out, b_in, sizeof b_out); - return BN_bin2bn(b_out, sizeof b_out, out); + flip_endian(b_out, b_in, sizeof(b_out)); + return BN_bin2bn(b_out, sizeof(b_out), out); } /*- @@ -866,7 +866,7 @@ static limb felem_is_zero(const felem in) * We know that ftmp[i] < 2^63, therefore the only way that the top bit * can be set is if is_zero was 0 before the decrement. */ - is_zero = ((s64) is_zero) >> 63; + is_zero = 0 - (is_zero >> 63); is_p = ftmp[0] ^ kPrime[0]; is_p |= ftmp[1] ^ kPrime[1]; @@ -879,13 +879,13 @@ static limb felem_is_zero(const felem in) is_p |= ftmp[8] ^ kPrime[8]; is_p--; - is_p = ((s64) is_p) >> 63; + is_p = 0 - (is_p >> 63); is_zero |= is_p; return is_zero; } -static int felem_is_zero_int(const felem in) +static int felem_is_zero_int(const void *in) { return (int)(felem_is_zero(in) & ((limb) 1)); } @@ -950,7 +950,7 @@ static void felem_contract(felem out, const felem in) is_p &= is_p << 4; is_p &= is_p << 2; is_p &= is_p << 1; - is_p = ((s64) is_p) >> 63; + is_p = 0 - (is_p >> 63); is_p = ~is_p; /* is_p is 0 iff |out| == 2^521-1 and all ones otherwise */ @@ -976,7 +976,7 @@ static void felem_contract(felem out, const felem in) is_greater |= is_greater << 4; is_greater |= is_greater << 2; is_greater |= is_greater << 1; - is_greater = ((s64) is_greater) >> 63; + is_greater = 0 - (is_greater >> 63); out[0] -= kPrime[0] & is_greater; out[1] -= kPrime[1] & is_greater; @@ -1033,7 +1033,7 @@ static void felem_contract(felem out, const felem in) * coordinates */ /*- - * point_double calcuates 2*(x_in, y_in, z_in) + * point_double calculates 2*(x_in, y_in, z_in) * * The method is taken from: * http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b @@ -1149,16 +1149,16 @@ static void copy_conditional(felem out, const felem in, limb mask) } /*- - * point_add calcuates (x1, y1, z1) + (x2, y2, z2) + * point_add calculates (x1, y1, z1) + (x2, y2, z2) * * The method is taken from * http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl, * adapted for mixed addition (z2 = 1, or z2 = 0 for the point at infinity). * * This function includes a branch for checking whether the two input points - * are equal (while not equal to the point at infinity). This case never - * happens during single point multiplication, so there is no timing leak for - * ECDH or ECDSA signing. */ + * are equal (while not equal to the point at infinity). See comment below + * on constant-time. + */ static void point_add(felem x3, felem y3, felem z3, const felem x1, const felem y1, const felem z1, const int mixed, const felem x2, const felem y2, @@ -1252,6 +1252,22 @@ static void point_add(felem x3, felem y3, felem z3, /* ftmp5[i] < 2^61 */ if (x_equal && y_equal && !z1_is_zero && !z2_is_zero) { + /* + * This is obviously not constant-time but it will almost-never happen + * for ECDH / ECDSA. The case where it can happen is during scalar-mult + * where the intermediate value gets very close to the group order. + * Since |ec_GFp_nistp_recode_scalar_bits| produces signed digits for + * the scalar, it's possible for the intermediate value to be a small + * negative multiple of the base point, and for the final signed digit + * to be the same value. We believe that this only occurs for the scalar + * 1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + * ffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb + * 71e913863f7, in that case the penultimate intermediate is -9G and + * the final digit is also -9G. Since this only happens for a single + * scalar, the timing leak is irrelevent. (Any attacker who wanted to + * check whether a secret scalar was that exact value, can already do + * so.) + */ point_double(x3, y3, z3, x1, y1, z1); return; } @@ -1585,10 +1601,11 @@ static void batch_mul(felem x_out, felem y_out, felem z_out, } /* Precomputation for the group generator. */ -typedef struct { +struct nistp521_pre_comp_st { felem g_pre_comp[16][3]; - int references; -} NISTP521_PRE_COMP; + CRYPTO_REF_COUNT references; + CRYPTO_RWLOCK *lock; +}; const EC_METHOD *EC_GFp_nistp521_method(void) { @@ -1602,6 +1619,7 @@ const EC_METHOD *EC_GFp_nistp521_method(void) ec_GFp_nistp521_group_set_curve, ec_GFp_simple_group_get_curve, ec_GFp_simple_group_get_degree, + ec_group_simple_order_bits, ec_GFp_simple_group_check_discriminant, ec_GFp_simple_point_init, ec_GFp_simple_point_finish, @@ -1631,7 +1649,18 @@ const EC_METHOD *EC_GFp_nistp521_method(void) 0 /* field_div */ , 0 /* field_encode */ , 0 /* field_decode */ , - 0 /* field_set_to_one */ + 0, /* field_set_to_one */ + ec_key_simple_priv2oct, + ec_key_simple_oct2priv, + 0, /* set private */ + ec_key_simple_generate_key, + ec_key_simple_check_key, + ec_key_simple_generate_public_key, + 0, /* keycopy */ + 0, /* keyfinish */ + ecdh_simple_compute_key, + 0, /* field_inverse_mod_ord */ + 0 /* blind_coordinates */ }; return &ret; @@ -1642,7 +1671,7 @@ const EC_METHOD *EC_GFp_nistp521_method(void) * FUNCTIONS TO MANAGE PRECOMPUTATION */ -static NISTP521_PRE_COMP *nistp521_pre_comp_new() +static NISTP521_PRE_COMP *nistp521_pre_comp_new(void) { NISTP521_PRE_COMP *ret = OPENSSL_zalloc(sizeof(*ret)); @@ -1650,48 +1679,41 @@ static NISTP521_PRE_COMP *nistp521_pre_comp_new() ECerr(EC_F_NISTP521_PRE_COMP_NEW, ERR_R_MALLOC_FAILURE); return ret; } - ret->references = 1; - return ret; -} - -static void *nistp521_pre_comp_dup(void *src_) -{ - NISTP521_PRE_COMP *src = src_; - /* no need to actually copy, these objects never change! */ - CRYPTO_add(&src->references, 1, CRYPTO_LOCK_EC_PRE_COMP); + ret->references = 1; - return src_; + ret->lock = CRYPTO_THREAD_lock_new(); + if (ret->lock == NULL) { + ECerr(EC_F_NISTP521_PRE_COMP_NEW, ERR_R_MALLOC_FAILURE); + OPENSSL_free(ret); + return NULL; + } + return ret; } -static void nistp521_pre_comp_free(void *pre_) +NISTP521_PRE_COMP *EC_nistp521_pre_comp_dup(NISTP521_PRE_COMP *p) { int i; - NISTP521_PRE_COMP *pre = pre_; - - if (!pre) - return; - - i = CRYPTO_add(&pre->references, -1, CRYPTO_LOCK_EC_PRE_COMP); - if (i > 0) - return; - - OPENSSL_free(pre); + if (p != NULL) + CRYPTO_UP_REF(&p->references, &i, p->lock); + return p; } -static void nistp521_pre_comp_clear_free(void *pre_) +void EC_nistp521_pre_comp_free(NISTP521_PRE_COMP *p) { int i; - NISTP521_PRE_COMP *pre = pre_; - if (!pre) + if (p == NULL) return; - i = CRYPTO_add(&pre->references, -1, CRYPTO_LOCK_EC_PRE_COMP); + CRYPTO_DOWN_REF(&p->references, &i, p->lock); + REF_PRINT_COUNT("EC_nistp521", x); if (i > 0) return; + REF_ASSERT_ISNT(i < 0); - OPENSSL_clear_free(pre, sizeof(*pre)); + CRYPTO_THREAD_lock_free(p->lock); + OPENSSL_free(p); } /******************************************************************************/ @@ -1719,9 +1741,10 @@ int ec_GFp_nistp521_group_set_curve(EC_GROUP *group, const BIGNUM *p, if ((ctx = new_ctx = BN_CTX_new()) == NULL) return 0; BN_CTX_start(ctx); - if (((curve_p = BN_CTX_get(ctx)) == NULL) || - ((curve_a = BN_CTX_get(ctx)) == NULL) || - ((curve_b = BN_CTX_get(ctx)) == NULL)) + curve_p = BN_CTX_get(ctx); + curve_a = BN_CTX_get(ctx); + curve_b = BN_CTX_get(ctx); + if (curve_b == NULL) goto err; BN_bin2bn(nistp521_curve_params[0], sizeof(felem_bytearray), curve_p); BN_bin2bn(nistp521_curve_params[1], sizeof(felem_bytearray), curve_a); @@ -1800,7 +1823,6 @@ static void make_points_affine(size_t num, felem points[][3], sizeof(felem), tmp_felems, (void (*)(void *))felem_one, - (int (*)(const void *)) felem_is_zero_int, (void (*)(void *, const void *)) felem_assign, @@ -1851,17 +1873,15 @@ int ec_GFp_nistp521_points_mul(const EC_GROUP *group, EC_POINT *r, if ((ctx = new_ctx = BN_CTX_new()) == NULL) return 0; BN_CTX_start(ctx); - if (((x = BN_CTX_get(ctx)) == NULL) || - ((y = BN_CTX_get(ctx)) == NULL) || - ((z = BN_CTX_get(ctx)) == NULL) || - ((tmp_scalar = BN_CTX_get(ctx)) == NULL)) + x = BN_CTX_get(ctx); + y = BN_CTX_get(ctx); + z = BN_CTX_get(ctx); + tmp_scalar = BN_CTX_get(ctx); + if (tmp_scalar == NULL) goto err; if (scalar != NULL) { - pre = EC_EX_DATA_get_data(group->extra_data, - nistp521_pre_comp_dup, - nistp521_pre_comp_free, - nistp521_pre_comp_clear_free); + pre = group->pre_comp.nistp521; if (pre) /* we have precomputation, try to use it */ g_pre_comp = &pre->g_pre_comp[0]; @@ -2036,14 +2056,14 @@ int ec_GFp_nistp521_precompute_mult(EC_GROUP *group, BN_CTX *ctx) felem tmp_felems[16]; /* throw away old precomputation */ - EC_EX_DATA_free_data(&group->extra_data, nistp521_pre_comp_dup, - nistp521_pre_comp_free, - nistp521_pre_comp_clear_free); + EC_pre_comp_free(group); if (ctx == NULL) if ((ctx = new_ctx = BN_CTX_new()) == NULL) return 0; BN_CTX_start(ctx); - if (((x = BN_CTX_get(ctx)) == NULL) || ((y = BN_CTX_get(ctx)) == NULL)) + x = BN_CTX_get(ctx); + y = BN_CTX_get(ctx); + if (y == NULL) goto err; /* get the generator */ if (group->generator == NULL) @@ -2062,8 +2082,7 @@ int ec_GFp_nistp521_precompute_mult(EC_GROUP *group, BN_CTX *ctx) */ if (0 == EC_POINT_cmp(group, generator, group->generator, ctx)) { memcpy(pre->g_pre_comp, gmul, sizeof(pre->g_pre_comp)); - ret = 1; - goto err; + goto done; } if ((!BN_to_felem(pre->g_pre_comp[1][0], group->generator->X)) || (!BN_to_felem(pre->g_pre_comp[1][1], group->generator->Y)) || @@ -2121,31 +2140,21 @@ int ec_GFp_nistp521_precompute_mult(EC_GROUP *group, BN_CTX *ctx) } make_points_affine(15, &(pre->g_pre_comp[1]), tmp_felems); - if (!EC_EX_DATA_set_data(&group->extra_data, pre, nistp521_pre_comp_dup, - nistp521_pre_comp_free, - nistp521_pre_comp_clear_free)) - goto err; + done: + SETPRECOMP(group, nistp521, pre); ret = 1; pre = NULL; err: BN_CTX_end(ctx); EC_POINT_free(generator); BN_CTX_free(new_ctx); - nistp521_pre_comp_free(pre); + EC_nistp521_pre_comp_free(pre); return ret; } int ec_GFp_nistp521_have_precompute_mult(const EC_GROUP *group) { - if (EC_EX_DATA_get_data(group->extra_data, nistp521_pre_comp_dup, - nistp521_pre_comp_free, - nistp521_pre_comp_clear_free) - != NULL) - return 1; - else - return 0; + return HAVEPRECOMP(group, nistp521); } -#else -static void *dummy = &dummy; #endif