static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp, const unsigned char *dgst, int dlen) { BN_CTX *ctx = NULL; BIGNUM *k = NULL, *r = NULL, *X = NULL; const BIGNUM *order; EC_POINT *tmp_point = NULL; const EC_GROUP *group; int ret = 0; int order_bits; if (eckey == NULL || (group = EC_KEY_get0_group(eckey)) == NULL) { ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_PASSED_NULL_PARAMETER); return 0; } if (!EC_KEY_can_sign(eckey)) { ECerr(EC_F_ECDSA_SIGN_SETUP, EC_R_CURVE_DOES_NOT_SUPPORT_SIGNING); return 0; } if (ctx_in == NULL) { if ((ctx = BN_CTX_new()) == NULL) { ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_MALLOC_FAILURE); return 0; } } else ctx = ctx_in; k = BN_new(); /* this value is later returned in *kinvp */ r = BN_new(); /* this value is later returned in *rp */ X = BN_new(); if (k == NULL || r == NULL || X == NULL) { ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_MALLOC_FAILURE); goto err; } if ((tmp_point = EC_POINT_new(group)) == NULL) { ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB); goto err; } order = EC_GROUP_get0_order(group); if (order == NULL) { ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB); goto err; } /* Preallocate space */ order_bits = BN_num_bits(order); if (!BN_set_bit(k, order_bits) || !BN_set_bit(r, order_bits) || !BN_set_bit(X, order_bits)) goto err; do { /* get random k */ do if (dgst != NULL) { if (!BN_generate_dsa_nonce (k, order, EC_KEY_get0_private_key(eckey), dgst, dlen, ctx)) { ECerr(EC_F_ECDSA_SIGN_SETUP, EC_R_RANDOM_NUMBER_GENERATION_FAILED); goto err; } } else { if (!BN_priv_rand_range(k, order)) { ECerr(EC_F_ECDSA_SIGN_SETUP, EC_R_RANDOM_NUMBER_GENERATION_FAILED); goto err; } } while (BN_is_zero(k)); /* compute r the x-coordinate of generator * k */ if (!EC_POINT_mul(group, tmp_point, k, NULL, NULL, ctx)) { ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB); goto err; } if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) == NID_X9_62_prime_field) { if (!EC_POINT_get_affine_coordinates_GFp (group, tmp_point, X, NULL, ctx)) { ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB); goto err; } } #ifndef OPENSSL_NO_EC2M else { /* NID_X9_62_characteristic_two_field */ if (!EC_POINT_get_affine_coordinates_GF2m(group, tmp_point, X, NULL, ctx)) { ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_EC_LIB); goto err; } } #endif if (!BN_nnmod(r, X, order, ctx)) { ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB); goto err; } } while (BN_is_zero(r)); /* Check if optimized inverse is implemented */ if (EC_GROUP_do_inverse_ord(group, k, k, ctx) == 0) { /* compute the inverse of k */ if (group->mont_data != NULL) { /* * We want inverse in constant time, therefore we utilize the fact * order must be prime and use Fermats Little Theorem instead. */ if (!BN_set_word(X, 2)) { ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB); goto err; } if (!BN_mod_sub(X, order, X, order, ctx)) { ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB); goto err; } BN_set_flags(X, BN_FLG_CONSTTIME); if (!BN_mod_exp_mont_consttime(k, k, X, order, ctx, group->mont_data)) { ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB); goto err; } } else { if (!BN_mod_inverse(k, k, order, ctx)) { ECerr(EC_F_ECDSA_SIGN_SETUP, ERR_R_BN_LIB); goto err; } } } /* clear old values if necessary */ BN_clear_free(*rp); BN_clear_free(*kinvp); /* save the pre-computed values */ *rp = r; *kinvp = k; ret = 1; err: if (!ret) { BN_clear_free(k); BN_clear_free(r); } if (ctx != ctx_in) BN_CTX_free(ctx); EC_POINT_free(tmp_point); BN_clear_free(X); return ret; }
EC_KEY *EC_KEY_copy(EC_KEY *dest, const EC_KEY *src) { EC_EXTRA_DATA *d; if (dest == NULL || src == NULL) { ECerr(EC_F_EC_KEY_COPY, ERR_R_PASSED_NULL_PARAMETER); return NULL; } /* copy the parameters */ if (src->group) { const EC_METHOD *meth = EC_GROUP_method_of(src->group); /* clear the old group */ if (dest->group) EC_GROUP_free(dest->group); dest->group = EC_GROUP_new(meth); if (dest->group == NULL) return NULL; if (!EC_GROUP_copy(dest->group, src->group)) return NULL; } /* copy the public key */ if (src->pub_key && src->group) { if (dest->pub_key) EC_POINT_free(dest->pub_key); dest->pub_key = EC_POINT_new(src->group); if (dest->pub_key == NULL) return NULL; if (!EC_POINT_copy(dest->pub_key, src->pub_key)) return NULL; } /* copy the private key */ if (src->priv_key) { if (dest->priv_key == NULL) { dest->priv_key = BN_new(); if (dest->priv_key == NULL) return NULL; } if (!BN_copy(dest->priv_key, src->priv_key)) return NULL; } /* copy method/extra data */ EC_EX_DATA_free_all_data(&dest->method_data); for (d = src->method_data; d != NULL; d = d->next) { void *t = d->dup_func(d->data); if (t == NULL) return 0; if (!EC_EX_DATA_set_data(&dest->method_data, t, d->dup_func, d->free_func, d->clear_free_func)) return 0; } /* copy the rest */ dest->enc_flag = src->enc_flag; dest->conv_form = src->conv_form; dest->version = src->version; dest->flags = src->flags; return dest; }
int EC_KEY_check_key(const EC_KEY *eckey) { int ok = 0; BN_CTX *ctx = NULL; const BIGNUM *order = NULL; EC_POINT *point = NULL; if (!eckey || !eckey->group || !eckey->pub_key) { ECerr(EC_F_EC_KEY_CHECK_KEY, ERR_R_PASSED_NULL_PARAMETER); return 0; } if (EC_POINT_is_at_infinity(eckey->group, eckey->pub_key)) { ECerr(EC_F_EC_KEY_CHECK_KEY, EC_R_POINT_AT_INFINITY); goto err; } if ((ctx = BN_CTX_new()) == NULL) goto err; if ((point = EC_POINT_new(eckey->group)) == NULL) goto err; /* testing whether the pub_key is on the elliptic curve */ if (EC_POINT_is_on_curve(eckey->group, eckey->pub_key, ctx) <= 0) { ECerr(EC_F_EC_KEY_CHECK_KEY, EC_R_POINT_IS_NOT_ON_CURVE); goto err; } /* testing whether pub_key * order is the point at infinity */ order = &eckey->group->order; if (BN_is_zero(order)) { ECerr(EC_F_EC_KEY_CHECK_KEY, EC_R_INVALID_GROUP_ORDER); goto err; } if (!EC_POINT_mul(eckey->group, point, NULL, eckey->pub_key, order, ctx)) { ECerr(EC_F_EC_KEY_CHECK_KEY, ERR_R_EC_LIB); goto err; } if (!EC_POINT_is_at_infinity(eckey->group, point)) { ECerr(EC_F_EC_KEY_CHECK_KEY, EC_R_WRONG_ORDER); goto err; } /* in case the priv_key is present : * check if generator * priv_key == pub_key */ if (eckey->priv_key) { if (BN_cmp(eckey->priv_key, order) >= 0) { ECerr(EC_F_EC_KEY_CHECK_KEY, EC_R_WRONG_ORDER); goto err; } if (!EC_POINT_mul(eckey->group, point, eckey->priv_key, NULL, NULL, ctx)) { ECerr(EC_F_EC_KEY_CHECK_KEY, ERR_R_EC_LIB); goto err; } if (EC_POINT_cmp(eckey->group, point, eckey->pub_key, ctx) != 0) { ECerr(EC_F_EC_KEY_CHECK_KEY, EC_R_INVALID_PRIVATE_KEY); goto err; } } ok = 1; err: if (ctx != NULL) BN_CTX_free(ctx); if (point != NULL) EC_POINT_free(point); return(ok); }
/* * Converts an EC_POINT to an octet string. If buf is NULL, the encoded * length will be returned. If the length len of buf is smaller than required * an error will be returned. */ size_t ec_GF2m_simple_point2oct(const EC_GROUP *group, const EC_POINT *point, point_conversion_form_t form, unsigned char *buf, size_t len, BN_CTX *ctx) { size_t ret; BN_CTX *new_ctx = NULL; int used_ctx = 0; BIGNUM *x, *y, *yxi; size_t field_len, i, skip; if ((form != POINT_CONVERSION_COMPRESSED) && (form != POINT_CONVERSION_UNCOMPRESSED) && (form != POINT_CONVERSION_HYBRID)) { ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, EC_R_INVALID_FORM); goto err; } if (EC_POINT_is_at_infinity(group, point)) { /* encodes to a single 0 octet */ if (buf != NULL) { if (len < 1) { ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, EC_R_BUFFER_TOO_SMALL); return 0; } buf[0] = 0; } return 1; } /* ret := required output buffer length */ field_len = (EC_GROUP_get_degree(group) + 7) / 8; ret = (form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2 * field_len; /* if 'buf' is NULL, just return required length */ if (buf != NULL) { if (len < ret) { ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, EC_R_BUFFER_TOO_SMALL); goto err; } if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); if (ctx == NULL) return 0; } BN_CTX_start(ctx); used_ctx = 1; x = BN_CTX_get(ctx); y = BN_CTX_get(ctx); yxi = BN_CTX_get(ctx); if (yxi == NULL) goto err; if (!EC_POINT_get_affine_coordinates_GF2m(group, point, x, y, ctx)) goto err; buf[0] = form; if ((form != POINT_CONVERSION_UNCOMPRESSED) && !BN_is_zero(x)) { if (!group->meth->field_div(group, yxi, y, x, ctx)) goto err; if (BN_is_odd(yxi)) buf[0]++; } i = 1; skip = field_len - BN_num_bytes(x); if (skip > field_len) { ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR); goto err; } while (skip > 0) { buf[i++] = 0; skip--; } skip = BN_bn2bin(x, buf + i); i += skip; if (i != 1 + field_len) { ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR); goto err; } if (form == POINT_CONVERSION_UNCOMPRESSED || form == POINT_CONVERSION_HYBRID) { skip = field_len - BN_num_bytes(y); if (skip > field_len) { ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR); goto err; } while (skip > 0) { buf[i++] = 0; skip--; } skip = BN_bn2bin(y, buf + i); i += skip; } if (i != ret) { ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR); goto err; } } if (used_ctx) BN_CTX_end(ctx); BN_CTX_free(new_ctx); return ret; err: if (used_ctx) BN_CTX_end(ctx); BN_CTX_free(new_ctx); return 0; }
/*- * Calculates and sets the affine coordinates of an EC_POINT from the given * compressed coordinates. Uses algorithm 2.3.4 of SEC 1. * Note that the simple implementation only uses affine coordinates. * * The method is from the following publication: * * Harper, Menezes, Vanstone: * "Public-Key Cryptosystems with Very Small Key Lengths", * EUROCRYPT '92, Springer-Verlag LNCS 658, * published February 1993 * * US Patents 6,141,420 and 6,618,483 (Vanstone, Mullin, Agnew) describe * the same method, but claim no priority date earlier than July 29, 1994 * (and additionally fail to cite the EUROCRYPT '92 publication as prior art). */ int ec_GF2m_simple_set_compressed_coordinates(const EC_GROUP *group, EC_POINT *point, const BIGNUM *x_, int y_bit, BN_CTX *ctx) { BN_CTX *new_ctx = NULL; BIGNUM *tmp, *x, *y, *z; int ret = 0, z0; /* clear error queue */ ERR_clear_error(); if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); if (ctx == NULL) return 0; } y_bit = (y_bit != 0) ? 1 : 0; BN_CTX_start(ctx); tmp = BN_CTX_get(ctx); x = BN_CTX_get(ctx); y = BN_CTX_get(ctx); z = BN_CTX_get(ctx); if (z == NULL) goto err; if (!BN_GF2m_mod_arr(x, x_, group->poly)) goto err; if (BN_is_zero(x)) { if (!BN_GF2m_mod_sqrt_arr(y, group->b, group->poly, ctx)) goto err; } else { if (!group->meth->field_sqr(group, tmp, x, ctx)) goto err; if (!group->meth->field_div(group, tmp, group->b, tmp, ctx)) goto err; if (!BN_GF2m_add(tmp, group->a, tmp)) goto err; if (!BN_GF2m_add(tmp, x, tmp)) goto err; if (!BN_GF2m_mod_solve_quad_arr(z, tmp, group->poly, ctx)) { unsigned long err = ERR_peek_last_error(); if (ERR_GET_LIB(err) == ERR_LIB_BN && ERR_GET_REASON(err) == BN_R_NO_SOLUTION) { ERR_clear_error(); ECerr(EC_F_EC_GF2M_SIMPLE_SET_COMPRESSED_COORDINATES, EC_R_INVALID_COMPRESSED_POINT); } else ECerr(EC_F_EC_GF2M_SIMPLE_SET_COMPRESSED_COORDINATES, ERR_R_BN_LIB); goto err; } z0 = (BN_is_odd(z)) ? 1 : 0; if (!group->meth->field_mul(group, y, x, z, ctx)) goto err; if (z0 != y_bit) { if (!BN_GF2m_add(y, y, x)) goto err; } } if (!EC_POINT_set_affine_coordinates_GF2m(group, point, x, y, ctx)) goto err; ret = 1; err: BN_CTX_end(ctx); BN_CTX_free(new_ctx); return ret; }
int ECPKParameters_print(BIO *bp, const EC_GROUP *x, int off) { unsigned char *buffer=NULL; size_t buf_len=0, i; int ret=0, reason=ERR_R_BIO_LIB; BN_CTX *ctx=NULL; const EC_POINT *point=NULL; BIGNUM *p=NULL, *a=NULL, *b=NULL, *gen=NULL, *order=NULL, *cofactor=NULL; const unsigned char *seed; size_t seed_len=0; static const char *gen_compressed = "Generator (compressed):"; static const char *gen_uncompressed = "Generator (uncompressed):"; static const char *gen_hybrid = "Generator (hybrid):"; if (!x) { reason = ERR_R_PASSED_NULL_PARAMETER; goto err; } if (EC_GROUP_get_asn1_flag(x)) { /* the curve parameter are given by an asn1 OID */ int nid; if (!BIO_indent(bp, off, 128)) goto err; nid = EC_GROUP_get_curve_name(x); if (nid == 0) goto err; if (BIO_printf(bp, "ASN1 OID: %s", OBJ_nid2sn(nid)) <= 0) goto err; if (BIO_printf(bp, "\n") <= 0) goto err; } else { /* explicit parameters */ int is_char_two = 0; point_conversion_form_t form; int tmp_nid = EC_METHOD_get_field_type(EC_GROUP_method_of(x)); if (tmp_nid == NID_X9_62_characteristic_two_field) is_char_two = 1; if ((p = BN_new()) == NULL || (a = BN_new()) == NULL || (b = BN_new()) == NULL || (order = BN_new()) == NULL || (cofactor = BN_new()) == NULL) { reason = ERR_R_MALLOC_FAILURE; goto err; } if (is_char_two) { if (!EC_GROUP_get_curve_GF2m(x, p, a, b, ctx)) { reason = ERR_R_EC_LIB; goto err; } } else /* prime field */ { if (!EC_GROUP_get_curve_GFp(x, p, a, b, ctx)) { reason = ERR_R_EC_LIB; goto err; } } if ((point = EC_GROUP_get0_generator(x)) == NULL) { reason = ERR_R_EC_LIB; goto err; } if (!EC_GROUP_get_order(x, order, NULL) || !EC_GROUP_get_cofactor(x, cofactor, NULL)) { reason = ERR_R_EC_LIB; goto err; } form = EC_GROUP_get_point_conversion_form(x); if ((gen = EC_POINT_point2bn(x, point, form, NULL, ctx)) == NULL) { reason = ERR_R_EC_LIB; goto err; } buf_len = (size_t)BN_num_bytes(p); if (buf_len < (i = (size_t)BN_num_bytes(a))) buf_len = i; if (buf_len < (i = (size_t)BN_num_bytes(b))) buf_len = i; if (buf_len < (i = (size_t)BN_num_bytes(gen))) buf_len = i; if (buf_len < (i = (size_t)BN_num_bytes(order))) buf_len = i; if (buf_len < (i = (size_t)BN_num_bytes(cofactor))) buf_len = i; if ((seed = EC_GROUP_get0_seed(x)) != NULL) seed_len = EC_GROUP_get_seed_len(x); buf_len += 10; if ((buffer = OPENSSL_malloc(buf_len)) == NULL) { reason = ERR_R_MALLOC_FAILURE; goto err; } if (!BIO_indent(bp, off, 128)) goto err; /* print the 'short name' of the field type */ if (BIO_printf(bp, "Field Type: %s\n", OBJ_nid2sn(tmp_nid)) <= 0) goto err; if (is_char_two) { /* print the 'short name' of the base type OID */ int basis_type = EC_GROUP_get_basis_type(x); if (basis_type == 0) goto err; if (!BIO_indent(bp, off, 128)) goto err; if (BIO_printf(bp, "Basis Type: %s\n", OBJ_nid2sn(basis_type)) <= 0) goto err; /* print the polynomial */ if ((p != NULL) && !print(bp, "Polynomial:", p, buffer, off)) goto err; } else { if ((p != NULL) && !print(bp, "Prime:", p, buffer,off)) goto err; } if ((a != NULL) && !print(bp, "A: ", a, buffer, off)) goto err; if ((b != NULL) && !print(bp, "B: ", b, buffer, off)) goto err; if (form == POINT_CONVERSION_COMPRESSED) { if ((gen != NULL) && !print(bp, gen_compressed, gen, buffer, off)) goto err; } else if (form == POINT_CONVERSION_UNCOMPRESSED) { if ((gen != NULL) && !print(bp, gen_uncompressed, gen, buffer, off)) goto err; } else /* form == POINT_CONVERSION_HYBRID */ { if ((gen != NULL) && !print(bp, gen_hybrid, gen, buffer, off)) goto err; } if ((order != NULL) && !print(bp, "Order: ", order, buffer, off)) goto err; if ((cofactor != NULL) && !print(bp, "Cofactor: ", cofactor, buffer, off)) goto err; if (seed && !print_bin(bp, "Seed:", seed, seed_len, off)) goto err; } ret=1; err: if (!ret) ECerr(EC_F_ECPKPARAMETERS_PRINT, reason); if (p) BN_free(p); if (a) BN_free(a); if (b) BN_free(b); if (gen) BN_free(gen); if (order) BN_free(order); if (cofactor) BN_free(cofactor); if (ctx) BN_CTX_free(ctx); if (buffer != NULL) OPENSSL_free(buffer); return(ret); }
int EC_GROUP_copy(EC_GROUP *dest, const EC_GROUP *src) { EC_EXTRA_DATA *d; if (dest->meth->group_copy == 0) { ECerr(EC_F_EC_GROUP_COPY, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); return 0; } if (dest->meth != src->meth) { ECerr(EC_F_EC_GROUP_COPY, EC_R_INCOMPATIBLE_OBJECTS); return 0; } if (dest == src) return 1; EC_EX_DATA_free_all_data(&dest->extra_data); for (d = src->extra_data; d != NULL; d = d->next) { void *t = d->dup_func(d->data); if (t == NULL) return 0; if (!EC_EX_DATA_set_data(&dest->extra_data, t, d->dup_func, d->free_func, d->clear_free_func)) return 0; } if (src->generator != NULL) { if (dest->generator == NULL) { dest->generator = EC_POINT_new(dest); if (dest->generator == NULL) return 0; } if (!EC_POINT_copy(dest->generator, src->generator)) return 0; } else { /* src->generator == NULL */ if (dest->generator != NULL) { EC_POINT_clear_free(dest->generator); dest->generator = NULL; } } if (!BN_copy(&dest->order, &src->order)) return 0; if (!BN_copy(&dest->cofactor, &src->cofactor)) return 0; dest->curve_name = src->curve_name; dest->asn1_flag = src->asn1_flag; dest->asn1_form = src->asn1_form; if (src->seed) { if (dest->seed) OPENSSL_free(dest->seed); dest->seed = clBnAlloc( "EC_GROUP_copy",src->seed_len); /* pcg */ if (dest->seed == NULL) return 0; if (!memcpy(dest->seed, src->seed, src->seed_len)) return 0; dest->seed_len = src->seed_len; } else { if (dest->seed) OPENSSL_free(dest->seed); dest->seed = NULL; dest->seed_len = 0; } return dest->meth->group_copy(dest, src); }
/* Determine the modified width-(w+1) Non-Adjacent Form (wNAF) of 'scalar'. * This is an array r[] of values that are either zero or odd with an * absolute value less than 2^w satisfying * scalar = \sum_j r[j]*2^j * where at most one of any w+1 consecutive digits is non-zero * with the exception that the most significant digit may be only * w-1 zeros away from that next non-zero digit. */ static signed char * compute_wNAF(const BIGNUM * scalar, int w, size_t * ret_len) { int window_val; int ok = 0; signed char *r = NULL; int sign = 1; int bit, next_bit, mask; size_t len = 0, j; if (BN_is_zero(scalar)) { r = malloc(1); if (!r) { ECerr(EC_F_COMPUTE_WNAF, ERR_R_MALLOC_FAILURE); goto err; } r[0] = 0; *ret_len = 1; return r; } if (w <= 0 || w > 7) { /* 'signed char' can represent integers with * absolute values less than 2^7 */ ECerr(EC_F_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR); goto err; } bit = 1 << w; /* at most 128 */ next_bit = bit << 1; /* at most 256 */ mask = next_bit - 1; /* at most 255 */ if (BN_is_negative(scalar)) { sign = -1; } if (scalar->d == NULL || scalar->top == 0) { ECerr(EC_F_COMPUTE_WNAF, ERR_R_INTERNAL_ERROR); goto err; } len = BN_num_bits(scalar); r = malloc(len + 1); /* modified wNAF may be one digit longer than * binary representation (*ret_len will be * set to the actual length, i.e. at most * BN_num_bits(scalar) + 1) */ if (r == NULL) { ECerr(EC_F_COMPUTE_WNAF, ERR_R_MALLOC_FAILURE); goto err; } window_val = scalar->d[0] & mask; j = 0; while ((window_val != 0) || (j + w + 1 < len)) { /* if j+w+1 >= len, window_val will not increase */ int digit = 0; /* 0 <= window_val <= 2^(w+1) */ if (window_val & 1) { /* 0 < window_val < 2^(w+1) */ if (window_val & bit) { digit = window_val - next_bit; /* -2^w < digit < 0 */ #if 1 /* modified wNAF */ if (j + w + 1 >= len) { /* * special case for generating * modified wNAFs: no new bits will * be added into window_val, so using * a positive digit here will * decrease the total length of the * representation */ digit = window_val & (mask >> 1); /* 0 < digit < 2^w */ } #endif } else {
static EC_GROUP *ec_group_new_from_data(const ec_list_element curve) { EC_GROUP *group = NULL; EC_POINT *P = NULL; BN_CTX *ctx = NULL; BIGNUM *p = NULL, *a = NULL, *b = NULL, *x = NULL, *y = NULL, *order = NULL; int ok = 0; int seed_len, param_len; const EC_METHOD *meth; const EC_CURVE_DATA *data; const unsigned char *params; /* If no curve data curve method must handle everything */ if (curve.data == NULL) return EC_GROUP_new(curve.meth != NULL ? curve.meth() : NULL); if ((ctx = BN_CTX_new()) == NULL) { ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_MALLOC_FAILURE); goto err; } data = curve.data; seed_len = data->seed_len; param_len = data->param_len; params = (const unsigned char *)(data + 1); /* skip header */ params += seed_len; /* skip seed */ if ((p = BN_bin2bn(params + 0 * param_len, param_len, NULL)) == NULL || (a = BN_bin2bn(params + 1 * param_len, param_len, NULL)) == NULL || (b = BN_bin2bn(params + 2 * param_len, param_len, NULL)) == NULL) { ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_BN_LIB); goto err; } if (curve.meth != 0) { meth = curve.meth(); if (((group = EC_GROUP_new(meth)) == NULL) || (!(group->meth->group_set_curve(group, p, a, b, ctx)))) { ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_EC_LIB); goto err; } } else if (data->field_type == NID_X9_62_prime_field) { if ((group = EC_GROUP_new_curve_GFp(p, a, b, ctx)) == NULL) { ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_EC_LIB); goto err; } } #ifndef OPENSSL_NO_EC2M else { /* field_type == * NID_X9_62_characteristic_two_field */ if ((group = EC_GROUP_new_curve_GF2m(p, a, b, ctx)) == NULL) { ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_EC_LIB); goto err; } } #endif if ((P = EC_POINT_new(group)) == NULL) { ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_EC_LIB); goto err; } if ((x = BN_bin2bn(params + 3 * param_len, param_len, NULL)) == NULL || (y = BN_bin2bn(params + 4 * param_len, param_len, NULL)) == NULL) { ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_BN_LIB); goto err; } if (!EC_POINT_set_affine_coordinates_GFp(group, P, x, y, ctx)) { ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_EC_LIB); goto err; } if ((order = BN_bin2bn(params + 5 * param_len, param_len, NULL)) == NULL || !BN_set_word(x, (BN_ULONG)data->cofactor)) { ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_BN_LIB); goto err; } if (!EC_GROUP_set_generator(group, P, order, x)) { ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_EC_LIB); goto err; } if (seed_len) { if (!EC_GROUP_set_seed(group, params - seed_len, seed_len)) { ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_EC_LIB); goto err; } } ok = 1; err: if (!ok) { EC_GROUP_free(group); group = NULL; } EC_POINT_free(P); BN_CTX_free(ctx); BN_free(p); BN_free(a); BN_free(b); BN_free(order); BN_free(x); BN_free(y); return group; }
static int pkey_ec_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) { EC_PKEY_CTX *dctx = ctx->data; EC_GROUP *group; switch (type) { case EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID: group = EC_GROUP_new_by_curve_name(p1); if (group == NULL) { ECerr(EC_F_PKEY_EC_CTRL, EC_R_INVALID_CURVE); return 0; } EC_GROUP_free(dctx->gen_group); dctx->gen_group = group; return 1; case EVP_PKEY_CTRL_EC_PARAM_ENC: if (!dctx->gen_group) { ECerr(EC_F_PKEY_EC_CTRL, EC_R_NO_PARAMETERS_SET); return 0; } EC_GROUP_set_asn1_flag(dctx->gen_group, p1); return 1; #ifndef OPENSSL_NO_EC case EVP_PKEY_CTRL_EC_ECDH_COFACTOR: if (p1 == -2) { if (dctx->cofactor_mode != -1) return dctx->cofactor_mode; else { EC_KEY *ec_key = ctx->pkey->pkey.ec; return EC_KEY_get_flags(ec_key) & EC_FLAG_COFACTOR_ECDH ? 1 : 0; } } else if (p1 < -1 || p1 > 1) return -2; dctx->cofactor_mode = p1; if (p1 != -1) { EC_KEY *ec_key = ctx->pkey->pkey.ec; if (!ec_key->group) return -2; /* If cofactor is 1 cofactor mode does nothing */ if (BN_is_one(ec_key->group->cofactor)) return 1; if (!dctx->co_key) { dctx->co_key = EC_KEY_dup(ec_key); if (!dctx->co_key) return 0; } if (p1) EC_KEY_set_flags(dctx->co_key, EC_FLAG_COFACTOR_ECDH); else EC_KEY_clear_flags(dctx->co_key, EC_FLAG_COFACTOR_ECDH); } else { EC_KEY_free(dctx->co_key); dctx->co_key = NULL; } return 1; #endif case EVP_PKEY_CTRL_EC_KDF_TYPE: if (p1 == -2) return dctx->kdf_type; if (p1 != EVP_PKEY_ECDH_KDF_NONE && p1 != EVP_PKEY_ECDH_KDF_X9_62) return -2; dctx->kdf_type = p1; return 1; #ifndef OPENSSL_NO_SM2 case EVP_PKEY_CTRL_EC_SCHEME: if (p1 == -2) { return dctx->ec_scheme; } if (p1 != NID_secg_scheme && p1 != NID_sm_scheme) { ECerr(EC_F_PKEY_EC_CTRL, EC_R_INVALID_EC_SCHEME); return 0; } dctx->ec_scheme = p1; return 1; case EVP_PKEY_CTRL_SIGNER_ID: if (!p2 || !strlen((char *)p2) || strlen((char *)p2) > SM2_MAX_ID_LENGTH) { ECerr(EC_F_PKEY_EC_CTRL, EC_R_INVALID_SIGNER_ID); return 0; } else { char *id = NULL; if (!(id = OPENSSL_strdup((char *)p2))) { ECerr(EC_F_PKEY_EC_CTRL, ERR_R_MALLOC_FAILURE); return 0; } if (dctx->signer_id) OPENSSL_free(dctx->signer_id); dctx->signer_id = id; if (dctx->ec_scheme == NID_sm_scheme) { EC_KEY *ec_key = ctx->pkey->pkey.ec; unsigned char zid[SM3_DIGEST_LENGTH]; size_t zidlen = SM3_DIGEST_LENGTH; if (!SM2_compute_id_digest(EVP_sm3(), dctx->signer_id, strlen(dctx->signer_id), zid, &zidlen, ec_key)) { ECerr(EC_F_PKEY_EC_CTRL, ERR_R_SM2_LIB); return 0; } if (!dctx->signer_zid) { if (!(dctx->signer_zid = OPENSSL_malloc(zidlen))) { ECerr(EC_F_PKEY_EC_CTRL, ERR_R_MALLOC_FAILURE); return 0; } } memcpy(dctx->signer_zid, zid, zidlen); } } return 1; case EVP_PKEY_CTRL_GET_SIGNER_ID: *(const char **)p2 = dctx->signer_id; return 1; case EVP_PKEY_CTRL_GET_SIGNER_ZID: if (dctx->ec_scheme != NID_sm_scheme) { *(const unsigned char **)p2 = NULL; return -2; } if (!dctx->signer_zid) { EC_KEY *ec_key = ctx->pkey->pkey.ec; unsigned char *zid; size_t zidlen = SM3_DIGEST_LENGTH; if (!(zid = OPENSSL_malloc(zidlen))) { ECerr(EC_F_PKEY_EC_CTRL, ERR_R_MALLOC_FAILURE); return 0; } if (!SM2_compute_id_digest(EVP_sm3(), SM2_DEFAULT_ID, SM2_DEFAULT_ID_LENGTH, zid, &zidlen, ec_key)) { ECerr(EC_F_PKEY_EC_CTRL, ERR_R_SM2_LIB); OPENSSL_free(zid); return 0; } dctx->signer_zid = zid; } *(const unsigned char **)p2 = dctx->signer_zid; return 1; case EVP_PKEY_CTRL_EC_ENCRYPT_PARAM: if (p1 == -2) { return dctx->ec_encrypt_param; } dctx->ec_encrypt_param = p1; return 1; #endif case EVP_PKEY_CTRL_EC_KDF_MD: dctx->kdf_md = p2; return 1; case EVP_PKEY_CTRL_GET_EC_KDF_MD: *(const EVP_MD **)p2 = dctx->kdf_md; return 1; case EVP_PKEY_CTRL_EC_KDF_OUTLEN: if (p1 <= 0) return -2; dctx->kdf_outlen = (size_t)p1; return 1; case EVP_PKEY_CTRL_GET_EC_KDF_OUTLEN: *(int *)p2 = dctx->kdf_outlen; return 1; case EVP_PKEY_CTRL_EC_KDF_UKM: OPENSSL_free(dctx->kdf_ukm); dctx->kdf_ukm = p2; if (p2) dctx->kdf_ukmlen = p1; else dctx->kdf_ukmlen = 0; return 1; case EVP_PKEY_CTRL_GET_EC_KDF_UKM: *(unsigned char **)p2 = dctx->kdf_ukm; return dctx->kdf_ukmlen; case EVP_PKEY_CTRL_MD: if (EVP_MD_type((const EVP_MD *)p2) != NID_sha1 && #ifndef OPENSSL_NO_SM3 EVP_MD_type((const EVP_MD *)p2) != NID_sm3 && #endif EVP_MD_type((const EVP_MD *)p2) != NID_ecdsa_with_SHA1 && EVP_MD_type((const EVP_MD *)p2) != NID_sha224 && EVP_MD_type((const EVP_MD *)p2) != NID_sha256 && EVP_MD_type((const EVP_MD *)p2) != NID_sha384 && EVP_MD_type((const EVP_MD *)p2) != NID_sha512) { ECerr(EC_F_PKEY_EC_CTRL, EC_R_INVALID_DIGEST_TYPE); return 0; } dctx->md = p2; return 1; case EVP_PKEY_CTRL_GET_MD: *(const EVP_MD **)p2 = dctx->md; return 1; case EVP_PKEY_CTRL_PEER_KEY: /* Default behaviour is OK */ case EVP_PKEY_CTRL_DIGESTINIT: case EVP_PKEY_CTRL_PKCS7_SIGN: case EVP_PKEY_CTRL_CMS_SIGN: return 1; default: return -2; } }
/* Setup EVP_PKEY using public, private or generation */ static int ecx_key_op(EVP_PKEY *pkey, int id, const X509_ALGOR *palg, const unsigned char *p, int plen, ecx_key_op_t op) { ECX_KEY *key = NULL; unsigned char *privkey, *pubkey; if (op != KEY_OP_KEYGEN) { if (palg != NULL) { int ptype; /* Algorithm parameters must be absent */ X509_ALGOR_get0(NULL, &ptype, NULL, palg); if (ptype != V_ASN1_UNDEF) { ECerr(EC_F_ECX_KEY_OP, EC_R_INVALID_ENCODING); return 0; } } if (p == NULL || plen != KEYLENID(id)) { ECerr(EC_F_ECX_KEY_OP, EC_R_INVALID_ENCODING); return 0; } } key = OPENSSL_zalloc(sizeof(*key)); if (key == NULL) { ECerr(EC_F_ECX_KEY_OP, ERR_R_MALLOC_FAILURE); return 0; } pubkey = key->pubkey; if (op == KEY_OP_PUBLIC) { memcpy(pubkey, p, plen); } else { privkey = key->privkey = OPENSSL_secure_malloc(KEYLENID(id)); if (privkey == NULL) { ECerr(EC_F_ECX_KEY_OP, ERR_R_MALLOC_FAILURE); goto err; } if (op == KEY_OP_KEYGEN) { if (RAND_priv_bytes(privkey, KEYLENID(id)) <= 0) { OPENSSL_secure_free(privkey); key->privkey = NULL; goto err; } if (id == EVP_PKEY_X25519) { privkey[0] &= 248; privkey[X25519_KEYLEN - 1] &= 127; privkey[X25519_KEYLEN - 1] |= 64; } else if (id == EVP_PKEY_X448) { privkey[0] &= 252; privkey[X448_KEYLEN - 1] |= 128; } } else { memcpy(privkey, p, KEYLENID(id)); } switch (id) { case EVP_PKEY_X25519: X25519_public_from_private(pubkey, privkey); break; case EVP_PKEY_ED25519: ED25519_public_from_private(pubkey, privkey); break; case EVP_PKEY_X448: X448_public_from_private(pubkey, privkey); break; case EVP_PKEY_ED448: ED448_public_from_private(pubkey, privkey); break; } } EVP_PKEY_assign(pkey, id, key); return 1; err: OPENSSL_free(key); return 0; }
static int do_EC_KEY_print(BIO *bp, const EC_KEY *x, int off, ec_print_t ktype) { const char *ecstr; unsigned char *priv = NULL, *pub = NULL; size_t privlen = 0, publen = 0; int ret = 0; const EC_GROUP *group; if (x == NULL || (group = EC_KEY_get0_group(x)) == NULL) { ECerr(EC_F_DO_EC_KEY_PRINT, ERR_R_PASSED_NULL_PARAMETER); return 0; } if (ktype != EC_KEY_PRINT_PARAM && EC_KEY_get0_public_key(x) != NULL) { publen = EC_KEY_key2buf(x, EC_KEY_get_conv_form(x), &pub, NULL); if (publen == 0) goto err; } if (ktype == EC_KEY_PRINT_PRIVATE && EC_KEY_get0_private_key(x) != NULL) { privlen = EC_KEY_priv2buf(x, &priv); if (privlen == 0) goto err; } if (ktype == EC_KEY_PRINT_PRIVATE) ecstr = "Private-Key"; else if (ktype == EC_KEY_PRINT_PUBLIC) ecstr = "Public-Key"; else ecstr = "ECDSA-Parameters"; if (!BIO_indent(bp, off, 128)) goto err; if (BIO_printf(bp, "%s: (%d bit)\n", ecstr, EC_GROUP_order_bits(group)) <= 0) goto err; if (privlen != 0) { if (BIO_printf(bp, "%*spriv:\n", off, "") <= 0) goto err; if (ASN1_buf_print(bp, priv, privlen, off + 4) == 0) goto err; } if (publen != 0) { if (BIO_printf(bp, "%*spub:\n", off, "") <= 0) goto err; if (ASN1_buf_print(bp, pub, publen, off + 4) == 0) goto err; } if (!ECPKParameters_print(bp, group, off)) goto err; ret = 1; err: if (!ret) ECerr(EC_F_DO_EC_KEY_PRINT, ERR_R_EC_LIB); OPENSSL_clear_free(priv, privlen); OPENSSL_free(pub); return ret; }
/*- * This implementation is based on the following primitives in the IEEE 1363 standard: * - ECKAS-DH1 * - ECSVDP-DH * Finally an optional KDF is applied. */ int ossl_ecdh_compute_key(void *out, size_t outlen, const EC_POINT *pub_key, const EC_KEY *ecdh, void *(*KDF) (const void *in, size_t inlen, void *out, size_t *outlen)) { BN_CTX *ctx; EC_POINT *tmp = NULL; BIGNUM *x = NULL, *y = NULL; const BIGNUM *priv_key; const EC_GROUP *group; int ret = -1; size_t buflen, len; unsigned char *buf = NULL; if (outlen > INT_MAX) { ECerr(EC_F_OSSL_ECDH_COMPUTE_KEY, ERR_R_MALLOC_FAILURE); /* sort of, * anyway */ return -1; } if (ecdh->group->meth->ecdh_compute_key != 0) return ecdh->group->meth->ecdh_compute_key(out, outlen, pub_key, ecdh, KDF); if ((ctx = BN_CTX_new()) == NULL) goto err; BN_CTX_start(ctx); x = BN_CTX_get(ctx); y = BN_CTX_get(ctx); priv_key = EC_KEY_get0_private_key(ecdh); if (priv_key == NULL) { ECerr(EC_F_OSSL_ECDH_COMPUTE_KEY, EC_R_NO_PRIVATE_VALUE); goto err; } group = EC_KEY_get0_group(ecdh); if (EC_KEY_get_flags(ecdh) & EC_FLAG_COFACTOR_ECDH) { if (!EC_GROUP_get_cofactor(group, x, NULL) || !BN_mul(x, x, priv_key, ctx)) { ECerr(EC_F_OSSL_ECDH_COMPUTE_KEY, ERR_R_MALLOC_FAILURE); goto err; } priv_key = x; } if ((tmp = EC_POINT_new(group)) == NULL) { ECerr(EC_F_OSSL_ECDH_COMPUTE_KEY, ERR_R_MALLOC_FAILURE); goto err; } if (!EC_POINT_mul(group, tmp, NULL, pub_key, priv_key, ctx)) { ECerr(EC_F_OSSL_ECDH_COMPUTE_KEY, EC_R_POINT_ARITHMETIC_FAILURE); goto err; } if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) == NID_X9_62_prime_field) { if (!EC_POINT_get_affine_coordinates_GFp(group, tmp, x, y, ctx)) { ECerr(EC_F_OSSL_ECDH_COMPUTE_KEY, EC_R_POINT_ARITHMETIC_FAILURE); goto err; } } #ifndef OPENSSL_NO_EC2M else { if (!EC_POINT_get_affine_coordinates_GF2m(group, tmp, x, y, ctx)) { ECerr(EC_F_OSSL_ECDH_COMPUTE_KEY, EC_R_POINT_ARITHMETIC_FAILURE); goto err; } } #endif buflen = (EC_GROUP_get_degree(group) + 7) / 8; len = BN_num_bytes(x); if (len > buflen) { ECerr(EC_F_OSSL_ECDH_COMPUTE_KEY, ERR_R_INTERNAL_ERROR); goto err; } if ((buf = OPENSSL_malloc(buflen)) == NULL) { ECerr(EC_F_OSSL_ECDH_COMPUTE_KEY, ERR_R_MALLOC_FAILURE); goto err; } memset(buf, 0, buflen - len); if (len != (size_t)BN_bn2bin(x, buf + buflen - len)) { ECerr(EC_F_OSSL_ECDH_COMPUTE_KEY, ERR_R_BN_LIB); goto err; } if (KDF != 0) { if (KDF(buf, buflen, out, &outlen) == NULL) { ECerr(EC_F_OSSL_ECDH_COMPUTE_KEY, EC_R_KDF_FAILED); goto err; } ret = outlen; } else { /* no KDF, just copy as much as we can */ if (outlen > buflen) outlen = buflen; memcpy(out, buf, outlen); ret = outlen; } err: EC_POINT_free(tmp); if (ctx) BN_CTX_end(ctx); BN_CTX_free(ctx); OPENSSL_free(buf); return (ret); }
int ossl_ecdsa_verify_sig(const unsigned char *dgst, int dgst_len, const ECDSA_SIG *sig, EC_KEY *eckey) { int ret = -1, i; BN_CTX *ctx; const BIGNUM *order; BIGNUM *u1, *u2, *m, *X; EC_POINT *point = NULL; const EC_GROUP *group; const EC_POINT *pub_key; /* check input values */ if (eckey == NULL || (group = EC_KEY_get0_group(eckey)) == NULL || (pub_key = EC_KEY_get0_public_key(eckey)) == NULL || sig == NULL) { ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, EC_R_MISSING_PARAMETERS); return -1; } if (!EC_KEY_can_sign(eckey)) { ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, EC_R_CURVE_DOES_NOT_SUPPORT_SIGNING); return -1; } ctx = BN_CTX_new(); if (ctx == NULL) { ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, ERR_R_MALLOC_FAILURE); return -1; } BN_CTX_start(ctx); u1 = BN_CTX_get(ctx); u2 = BN_CTX_get(ctx); m = BN_CTX_get(ctx); X = BN_CTX_get(ctx); if (X == NULL) { ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, ERR_R_BN_LIB); goto err; } order = EC_GROUP_get0_order(group); if (order == NULL) { ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, ERR_R_EC_LIB); goto err; } if (BN_is_zero(sig->r) || BN_is_negative(sig->r) || BN_ucmp(sig->r, order) >= 0 || BN_is_zero(sig->s) || BN_is_negative(sig->s) || BN_ucmp(sig->s, order) >= 0) { ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, EC_R_BAD_SIGNATURE); ret = 0; /* signature is invalid */ goto err; } /* calculate tmp1 = inv(S) mod order */ /* Check if optimized inverse is implemented */ if (EC_GROUP_do_inverse_ord(group, u2, sig->s, ctx) == 0) { if (!BN_mod_inverse(u2, sig->s, order, ctx)) { ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, ERR_R_BN_LIB); goto err; } } /* digest -> m */ i = BN_num_bits(order); /* * Need to truncate digest if it is too long: first truncate whole bytes. */ if (8 * dgst_len > i) dgst_len = (i + 7) / 8; if (!BN_bin2bn(dgst, dgst_len, m)) { ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, ERR_R_BN_LIB); goto err; } /* If still too long truncate remaining bits with a shift */ if ((8 * dgst_len > i) && !BN_rshift(m, m, 8 - (i & 0x7))) { ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, ERR_R_BN_LIB); goto err; } /* u1 = m * tmp mod order */ if (!BN_mod_mul(u1, m, u2, order, ctx)) { ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, ERR_R_BN_LIB); goto err; } /* u2 = r * w mod q */ if (!BN_mod_mul(u2, sig->r, u2, order, ctx)) { ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, ERR_R_BN_LIB); goto err; } if ((point = EC_POINT_new(group)) == NULL) { ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, ERR_R_MALLOC_FAILURE); goto err; } if (!EC_POINT_mul(group, point, u1, pub_key, u2, ctx)) { ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, ERR_R_EC_LIB); goto err; } if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) == NID_X9_62_prime_field) { if (!EC_POINT_get_affine_coordinates_GFp(group, point, X, NULL, ctx)) { ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, ERR_R_EC_LIB); goto err; } } #ifndef OPENSSL_NO_EC2M else { /* NID_X9_62_characteristic_two_field */ if (!EC_POINT_get_affine_coordinates_GF2m(group, point, X, NULL, ctx)) { ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, ERR_R_EC_LIB); goto err; } } #endif if (!BN_nnmod(u1, X, order, ctx)) { ECerr(EC_F_OSSL_ECDSA_VERIFY_SIG, ERR_R_BN_LIB); goto err; } /* if the signature is correct u1 is equal to sig->r */ ret = (BN_ucmp(u1, sig->r) == 0); err: BN_CTX_end(ctx); BN_CTX_free(ctx); EC_POINT_free(point); return ret; }
static int eckey_priv_decode(EVP_PKEY * pkey, PKCS8_PRIV_KEY_INFO * p8) { const unsigned char *p = NULL; void *pval; int ptype, pklen; EC_KEY *eckey = NULL; X509_ALGOR *palg; if (!PKCS8_pkey_get0(NULL, &p, &pklen, &palg, p8)) return 0; X509_ALGOR_get0(NULL, &ptype, &pval, palg); eckey = eckey_type2param(ptype, pval); if (!eckey) goto ecliberr; /* We have parameters now set private key */ if (!d2i_ECPrivateKey(&eckey, &p, pklen)) { ECerr(EC_F_ECKEY_PRIV_DECODE, EC_R_DECODE_ERROR); goto ecerr; } /* calculate public key (if necessary) */ if (EC_KEY_get0_public_key(eckey) == NULL) { const BIGNUM *priv_key; const EC_GROUP *group; EC_POINT *pub_key; /* * the public key was not included in the SEC1 private key => * calculate the public key */ group = EC_KEY_get0_group(eckey); pub_key = EC_POINT_new(group); if (pub_key == NULL) { ECerr(EC_F_ECKEY_PRIV_DECODE, ERR_R_EC_LIB); goto ecliberr; } if (!EC_POINT_copy(pub_key, EC_GROUP_get0_generator(group))) { EC_POINT_free(pub_key); ECerr(EC_F_ECKEY_PRIV_DECODE, ERR_R_EC_LIB); goto ecliberr; } priv_key = EC_KEY_get0_private_key(eckey); if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, NULL)) { EC_POINT_free(pub_key); ECerr(EC_F_ECKEY_PRIV_DECODE, ERR_R_EC_LIB); goto ecliberr; } if (EC_KEY_set_public_key(eckey, pub_key) == 0) { EC_POINT_free(pub_key); ECerr(EC_F_ECKEY_PRIV_DECODE, ERR_R_EC_LIB); goto ecliberr; } EC_POINT_free(pub_key); } EVP_PKEY_assign_EC_KEY(pkey, eckey); return 1; ecliberr: ECerr(EC_F_ECKEY_PRIV_DECODE, ERR_R_EC_LIB); ecerr: if (eckey) EC_KEY_free(eckey); return 0; }
EC_KEY *EC_KEY_copy(EC_KEY *dest, const EC_KEY *src) { if (dest == NULL || src == NULL) { ECerr(EC_F_EC_KEY_COPY, ERR_R_PASSED_NULL_PARAMETER); return NULL; } if (src->meth != dest->meth) { if (dest->meth->finish != NULL) dest->meth->finish(dest); if (dest->group && dest->group->meth->keyfinish) dest->group->meth->keyfinish(dest); #ifndef OPENSSL_NO_ENGINE if (ENGINE_finish(dest->engine) == 0) return 0; dest->engine = NULL; #endif } /* copy the parameters */ if (src->group != NULL) { const EC_METHOD *meth = EC_GROUP_method_of(src->group); /* clear the old group */ EC_GROUP_free(dest->group); dest->group = EC_GROUP_new(meth); if (dest->group == NULL) return NULL; if (!EC_GROUP_copy(dest->group, src->group)) return NULL; /* copy the public key */ if (src->pub_key != NULL) { EC_POINT_free(dest->pub_key); dest->pub_key = EC_POINT_new(src->group); if (dest->pub_key == NULL) return NULL; if (!EC_POINT_copy(dest->pub_key, src->pub_key)) return NULL; } /* copy the private key */ if (src->priv_key != NULL) { if (dest->priv_key == NULL) { dest->priv_key = BN_new(); if (dest->priv_key == NULL) return NULL; } if (!BN_copy(dest->priv_key, src->priv_key)) return NULL; if (src->group->meth->keycopy && src->group->meth->keycopy(dest, src) == 0) return NULL; } } /* copy the rest */ dest->enc_flag = src->enc_flag; dest->conv_form = src->conv_form; dest->version = src->version; dest->flags = src->flags; if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_EC_KEY, &dest->ex_data, &src->ex_data)) return NULL; if (src->meth != dest->meth) { #ifndef OPENSSL_NO_ENGINE if (src->engine != NULL && ENGINE_init(src->engine) == 0) return NULL; dest->engine = src->engine; #endif dest->meth = src->meth; } if (src->meth->copy != NULL && src->meth->copy(dest, src) == 0) return NULL; return dest; }
static int do_EC_KEY_print(BIO * bp, const EC_KEY * x, int off, int ktype) { unsigned char *buffer = NULL; const char *ecstr; size_t buf_len = 0, i; int ret = 0, reason = ERR_R_BIO_LIB; BIGNUM *pub_key = NULL, *order = NULL; BN_CTX *ctx = NULL; const EC_GROUP *group; const EC_POINT *public_key; const BIGNUM *priv_key; if (x == NULL || (group = EC_KEY_get0_group(x)) == NULL) { reason = ERR_R_PASSED_NULL_PARAMETER; goto err; } ctx = BN_CTX_new(); if (ctx == NULL) { reason = ERR_R_MALLOC_FAILURE; goto err; } if (ktype > 0) { public_key = EC_KEY_get0_public_key(x); if ((pub_key = EC_POINT_point2bn(group, public_key, EC_KEY_get_conv_form(x), NULL, ctx)) == NULL) { reason = ERR_R_EC_LIB; goto err; } if (pub_key) buf_len = (size_t) BN_num_bytes(pub_key); } if (ktype == 2) { priv_key = EC_KEY_get0_private_key(x); if (priv_key && (i = (size_t) BN_num_bytes(priv_key)) > buf_len) buf_len = i; } else priv_key = NULL; if (ktype > 0) { buf_len += 10; if ((buffer = malloc(buf_len)) == NULL) { reason = ERR_R_MALLOC_FAILURE; goto err; } } if (ktype == 2) ecstr = "Private-Key"; else if (ktype == 1) ecstr = "Public-Key"; else ecstr = "ECDSA-Parameters"; if (!BIO_indent(bp, off, 128)) goto err; if ((order = BN_new()) == NULL) goto err; if (!EC_GROUP_get_order(group, order, NULL)) goto err; if (BIO_printf(bp, "%s: (%d bit)\n", ecstr, BN_num_bits(order)) <= 0) goto err; if ((priv_key != NULL) && !ASN1_bn_print(bp, "priv:", priv_key, buffer, off)) goto err; if ((pub_key != NULL) && !ASN1_bn_print(bp, "pub: ", pub_key, buffer, off)) goto err; if (!ECPKParameters_print(bp, group, off)) goto err; ret = 1; err: if (!ret) ECerr(EC_F_DO_EC_KEY_PRINT, reason); BN_free(pub_key); BN_free(order); BN_CTX_free(ctx); free(buffer); return (ret); }
int ec_GFp_simple_points_make_affine(const EC_GROUP *group, size_t num, EC_POINT *points[], BN_CTX *ctx) { BN_CTX *new_ctx = NULL; BIGNUM *tmp0, *tmp1; size_t pow2 = 0; BIGNUM **heap = NULL; size_t i; int ret = 0; if (num == 0) return 1; if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); if (ctx == NULL) return 0; } BN_CTX_start(ctx); tmp0 = BN_CTX_get(ctx); tmp1 = BN_CTX_get(ctx); if (tmp0 == NULL || tmp1 == NULL) goto err; /* Before converting the individual points, compute inverses of all Z values. * Modular inversion is rather slow, but luckily we can do with a single * explicit inversion, plus about 3 multiplications per input value. */ pow2 = 1; while (num > pow2) pow2 <<= 1; /* Now pow2 is the smallest power of 2 satifsying pow2 >= num. * We need twice that. */ pow2 <<= 1; heap = OPENSSL_malloc(pow2 * sizeof heap[0]); if (heap == NULL) goto err; /* The array is used as a binary tree, exactly as in heapsort: * * heap[1] * heap[2] heap[3] * heap[4] heap[5] heap[6] heap[7] * heap[8]heap[9] heap[10]heap[11] heap[12]heap[13] heap[14] heap[15] * * We put the Z's in the last line; * then we set each other node to the product of its two child-nodes (where * empty or 0 entries are treated as ones); * then we invert heap[1]; * then we invert each other node by replacing it by the product of its * parent (after inversion) and its sibling (before inversion). */ heap[0] = NULL; for (i = pow2/2 - 1; i > 0; i--) heap[i] = NULL; for (i = 0; i < num; i++) heap[pow2/2 + i] = &points[i]->Z; for (i = pow2/2 + num; i < pow2; i++) heap[i] = NULL; /* set each node to the product of its children */ for (i = pow2/2 - 1; i > 0; i--) { heap[i] = BN_new(); if (heap[i] == NULL) goto err; if (heap[2*i] != NULL) { if ((heap[2*i + 1] == NULL) || BN_is_zero(heap[2*i + 1])) { if (!BN_copy(heap[i], heap[2*i])) goto err; } else { if (BN_is_zero(heap[2*i])) { if (!BN_copy(heap[i], heap[2*i + 1])) goto err; } else { if (!group->meth->field_mul(group, heap[i], heap[2*i], heap[2*i + 1], ctx)) goto err; } } } } /* invert heap[1] */ if (!BN_is_zero(heap[1])) { if (!BN_mod_inverse(heap[1], heap[1], &group->field, ctx)) { ECerr(EC_F_EC_GFP_SIMPLE_POINTS_MAKE_AFFINE, ERR_R_BN_LIB); goto err; } } if (group->meth->field_encode != 0) { /* in the Montgomery case, we just turned R*H (representing H) * into 1/(R*H), but we need R*(1/H) (representing 1/H); * i.e. we have need to multiply by the Montgomery factor twice */ if (!group->meth->field_encode(group, heap[1], heap[1], ctx)) goto err; if (!group->meth->field_encode(group, heap[1], heap[1], ctx)) goto err; } /* set other heap[i]'s to their inverses */ for (i = 2; i < pow2/2 + num; i += 2) { /* i is even */ if ((heap[i + 1] != NULL) && !BN_is_zero(heap[i + 1])) { if (!group->meth->field_mul(group, tmp0, heap[i/2], heap[i + 1], ctx)) goto err; if (!group->meth->field_mul(group, tmp1, heap[i/2], heap[i], ctx)) goto err; if (!BN_copy(heap[i], tmp0)) goto err; if (!BN_copy(heap[i + 1], tmp1)) goto err; } else { if (!BN_copy(heap[i], heap[i/2])) goto err; } } /* we have replaced all non-zero Z's by their inverses, now fix up all the points */ for (i = 0; i < num; i++) { EC_POINT *p = points[i]; if (!BN_is_zero(&p->Z)) { /* turn (X, Y, 1/Z) into (X/Z^2, Y/Z^3, 1) */ if (!group->meth->field_sqr(group, tmp1, &p->Z, ctx)) goto err; if (!group->meth->field_mul(group, &p->X, &p->X, tmp1, ctx)) goto err; if (!group->meth->field_mul(group, tmp1, tmp1, &p->Z, ctx)) goto err; if (!group->meth->field_mul(group, &p->Y, &p->Y, tmp1, ctx)) goto err; if (group->meth->field_set_to_one != 0) { if (!group->meth->field_set_to_one(group, &p->Z, ctx)) goto err; } else { if (!BN_one(&p->Z)) goto err; } p->Z_is_one = 1; } } ret = 1; err: BN_CTX_end(ctx); if (new_ctx != NULL) BN_CTX_free(new_ctx); if (heap != NULL) { /* heap[pow2/2] .. heap[pow2-1] have not been allocated locally! */ for (i = pow2/2 - 1; i > 0; i--) { if (heap[i] != NULL) BN_clear_free(heap[i]); } OPENSSL_free(heap); } return ret; }
int EC_KEY_print(BIO *bp, const EC_KEY *x, int off) { unsigned char *buffer=NULL; size_t buf_len=0, i; int ret=0, reason=ERR_R_BIO_LIB; BIGNUM *pub_key=NULL, *order=NULL; BN_CTX *ctx=NULL; const EC_GROUP *group; const EC_POINT *public_key; const BIGNUM *priv_key; if (x == NULL || (group = EC_KEY_get0_group(x)) == NULL) { reason = ERR_R_PASSED_NULL_PARAMETER; goto err; } public_key = EC_KEY_get0_public_key(x); if ((pub_key = EC_POINT_point2bn(group, public_key, EC_KEY_get_conv_form(x), NULL, ctx)) == NULL) { reason = ERR_R_EC_LIB; goto err; } buf_len = (size_t)BN_num_bytes(pub_key); priv_key = EC_KEY_get0_private_key(x); if (priv_key != NULL) { if ((i = (size_t)BN_num_bytes(priv_key)) > buf_len) buf_len = i; } buf_len += 10; if ((buffer = OPENSSL_malloc(buf_len)) == NULL) { reason = ERR_R_MALLOC_FAILURE; goto err; } if (priv_key != NULL) { if (!BIO_indent(bp, off, 128)) goto err; if ((order = BN_new()) == NULL) goto err; if (!EC_GROUP_get_order(group, order, NULL)) goto err; if (BIO_printf(bp, "Private-Key: (%d bit)\n", BN_num_bits(order)) <= 0) goto err; } if ((priv_key != NULL) && !print(bp, "priv:", priv_key, buffer, off)) goto err; if ((pub_key != NULL) && !print(bp, "pub: ", pub_key, buffer, off)) goto err; if (!ECPKParameters_print(bp, group, off)) goto err; ret=1; err: if (!ret) ECerr(EC_F_EC_KEY_PRINT, reason); if (pub_key) BN_free(pub_key); if (order) BN_free(order); if (ctx) BN_CTX_free(ctx); if (buffer != NULL) OPENSSL_free(buffer); return(ret); }
int ec_GFp_simple_points_make_affine(const EC_GROUP *group, size_t num, EC_POINT *points[], BN_CTX *ctx) { BN_CTX *new_ctx = NULL; BIGNUM *tmp, *tmp_Z; BIGNUM **prod_Z = NULL; size_t i; int ret = 0; if (num == 0) return 1; if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); if (ctx == NULL) return 0; } BN_CTX_start(ctx); tmp = BN_CTX_get(ctx); tmp_Z = BN_CTX_get(ctx); if (tmp == NULL || tmp_Z == NULL) goto err; prod_Z = OPENSSL_malloc(num * sizeof prod_Z[0]); if (prod_Z == NULL) goto err; for (i = 0; i < num; i++) { prod_Z[i] = BN_new(); if (prod_Z[i] == NULL) goto err; } /* * Set each prod_Z[i] to the product of points[0]->Z .. points[i]->Z, * skipping any zero-valued inputs (pretend that they're 1). */ if (!BN_is_zero(&points[0]->Z)) { if (!BN_copy(prod_Z[0], &points[0]->Z)) goto err; } else { if (group->meth->field_set_to_one != 0) { if (!group->meth->field_set_to_one(group, prod_Z[0], ctx)) goto err; } else { if (!BN_one(prod_Z[0])) goto err; } } for (i = 1; i < num; i++) { if (!BN_is_zero(&points[i]->Z)) { if (!group->meth->field_mul(group, prod_Z[i], prod_Z[i - 1], &points[i]->Z, ctx)) goto err; } else { if (!BN_copy(prod_Z[i], prod_Z[i - 1])) goto err; } } /* * Now use a single explicit inversion to replace every non-zero * points[i]->Z by its inverse. */ if (!BN_mod_inverse(tmp, prod_Z[num - 1], &group->field, ctx)) { ECerr(EC_F_EC_GFP_SIMPLE_POINTS_MAKE_AFFINE, ERR_R_BN_LIB); goto err; } if (group->meth->field_encode != 0) { /* * In the Montgomery case, we just turned R*H (representing H) into * 1/(R*H), but we need R*(1/H) (representing 1/H); i.e. we need to * multiply by the Montgomery factor twice. */ if (!group->meth->field_encode(group, tmp, tmp, ctx)) goto err; if (!group->meth->field_encode(group, tmp, tmp, ctx)) goto err; } for (i = num - 1; i > 0; --i) { /* * Loop invariant: tmp is the product of the inverses of points[0]->Z * .. points[i]->Z (zero-valued inputs skipped). */ if (!BN_is_zero(&points[i]->Z)) { /* * Set tmp_Z to the inverse of points[i]->Z (as product of Z * inverses 0 .. i, Z values 0 .. i - 1). */ if (!group-> meth->field_mul(group, tmp_Z, prod_Z[i - 1], tmp, ctx)) goto err; /* * Update tmp to satisfy the loop invariant for i - 1. */ if (!group->meth->field_mul(group, tmp, tmp, &points[i]->Z, ctx)) goto err; /* Replace points[i]->Z by its inverse. */ if (!BN_copy(&points[i]->Z, tmp_Z)) goto err; } } if (!BN_is_zero(&points[0]->Z)) { /* Replace points[0]->Z by its inverse. */ if (!BN_copy(&points[0]->Z, tmp)) goto err; } /* Finally, fix up the X and Y coordinates for all points. */ for (i = 0; i < num; i++) { EC_POINT *p = points[i]; if (!BN_is_zero(&p->Z)) { /* turn (X, Y, 1/Z) into (X/Z^2, Y/Z^3, 1) */ if (!group->meth->field_sqr(group, tmp, &p->Z, ctx)) goto err; if (!group->meth->field_mul(group, &p->X, &p->X, tmp, ctx)) goto err; if (!group->meth->field_mul(group, tmp, tmp, &p->Z, ctx)) goto err; if (!group->meth->field_mul(group, &p->Y, &p->Y, tmp, ctx)) goto err; if (group->meth->field_set_to_one != 0) { if (!group->meth->field_set_to_one(group, &p->Z, ctx)) goto err; } else { if (!BN_one(&p->Z)) goto err; } p->Z_is_one = 1; } } ret = 1; err: BN_CTX_end(ctx); if (new_ctx != NULL) BN_CTX_free(new_ctx); if (prod_Z != NULL) { for (i = 0; i < num; i++) { if (prod_Z[i] == NULL) break; BN_clear_free(prod_Z[i]); } OPENSSL_free(prod_Z); } return ret; }
/* Computes scalar*point and stores the result in r. * point can not equal r. * Uses a modified algorithm 2P of * Lopez, J. and Dahab, R. "Fast multiplication on elliptic curves over * GF(2^m) without precomputation" (CHES '99, LNCS 1717). * * To protect against side-channel attack the function uses constant time swap, * avoiding conditional branches. */ static int ec_GF2m_montgomery_point_multiply(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, const EC_POINT *point, BN_CTX *ctx) { BIGNUM *x1, *x2, *z1, *z2; int ret = 0, i; BN_ULONG mask,word; if (r == point) { ECerr(EC_F_EC_GF2M_MONTGOMERY_POINT_MULTIPLY, EC_R_INVALID_ARGUMENT); return 0; } /* if result should be point at infinity */ if ((scalar == NULL) || BN_is_zero(scalar) || (point == NULL) || EC_POINT_is_at_infinity(group, point)) { return EC_POINT_set_to_infinity(group, r); } /* only support affine coordinates */ if (!point->Z_is_one) return 0; /* Since point_multiply is static we can guarantee that ctx != NULL. */ BN_CTX_start(ctx); x1 = BN_CTX_get(ctx); z1 = BN_CTX_get(ctx); if (z1 == NULL) goto err; x2 = &r->X; z2 = &r->Y; bn_wexpand(x1, group->field.top); bn_wexpand(z1, group->field.top); bn_wexpand(x2, group->field.top); bn_wexpand(z2, group->field.top); if (!BN_GF2m_mod_arr(x1, &point->X, group->poly)) goto err; /* x1 = x */ if (!BN_one(z1)) goto err; /* z1 = 1 */ if (!group->meth->field_sqr(group, z2, x1, ctx)) goto err; /* z2 = x1^2 = x^2 */ if (!group->meth->field_sqr(group, x2, z2, ctx)) goto err; if (!BN_GF2m_add(x2, x2, &group->b)) goto err; /* x2 = x^4 + b */ /* find top most bit and go one past it */ i = scalar->top - 1; mask = BN_TBIT; word = scalar->d[i]; while (!(word & mask)) mask >>= 1; mask >>= 1; /* if top most bit was at word break, go to next word */ if (!mask) { i--; mask = BN_TBIT; } for (; i >= 0; i--) { word = scalar->d[i]; while (mask) { BN_consttime_swap(word & mask, x1, x2, group->field.top); BN_consttime_swap(word & mask, z1, z2, group->field.top); if (!gf2m_Madd(group, &point->X, x2, z2, x1, z1, ctx)) goto err; if (!gf2m_Mdouble(group, x1, z1, ctx)) goto err; BN_consttime_swap(word & mask, x1, x2, group->field.top); BN_consttime_swap(word & mask, z1, z2, group->field.top); mask >>= 1; } mask = BN_TBIT; } /* convert out of "projective" coordinates */ i = gf2m_Mxy(group, &point->X, &point->Y, x1, z1, x2, z2, ctx); if (i == 0) goto err; else if (i == 1) { if (!EC_POINT_set_to_infinity(group, r)) goto err; } else { if (!BN_one(&r->Z)) goto err; r->Z_is_one = 1; } /* GF(2^m) field elements should always have BIGNUM::neg = 0 */ BN_set_negative(&r->X, 0); BN_set_negative(&r->Y, 0); ret = 1; err: BN_CTX_end(ctx); return ret; }
int ec_GFp_simple_group_check_discriminant(const EC_GROUP *group, BN_CTX *ctx) { int ret = 0; BIGNUM *a, *b, *order, *tmp_1, *tmp_2; const BIGNUM *p = &group->field; BN_CTX *new_ctx = NULL; if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); if (ctx == NULL) { ECerr(EC_F_EC_GFP_SIMPLE_GROUP_CHECK_DISCRIMINANT, ERR_R_MALLOC_FAILURE); goto err; } } BN_CTX_start(ctx); a = BN_CTX_get(ctx); b = BN_CTX_get(ctx); tmp_1 = BN_CTX_get(ctx); tmp_2 = BN_CTX_get(ctx); order = BN_CTX_get(ctx); if (order == NULL) goto err; if (group->meth->field_decode) { if (!group->meth->field_decode(group, a, &group->a, ctx)) goto err; if (!group->meth->field_decode(group, b, &group->b, ctx)) goto err; } else { if (!BN_copy(a, &group->a)) goto err; if (!BN_copy(b, &group->b)) goto err; } /*- * check the discriminant: * y^2 = x^3 + a*x + b is an elliptic curve <=> 4*a^3 + 27*b^2 != 0 (mod p) * 0 =< a, b < p */ if (BN_is_zero(a)) { if (BN_is_zero(b)) goto err; } else if (!BN_is_zero(b)) { if (!BN_mod_sqr(tmp_1, a, p, ctx)) goto err; if (!BN_mod_mul(tmp_2, tmp_1, a, p, ctx)) goto err; if (!BN_lshift(tmp_1, tmp_2, 2)) goto err; /* tmp_1 = 4*a^3 */ if (!BN_mod_sqr(tmp_2, b, p, ctx)) goto err; if (!BN_mul_word(tmp_2, 27)) goto err; /* tmp_2 = 27*b^2 */ if (!BN_mod_add(a, tmp_1, tmp_2, p, ctx)) goto err; if (BN_is_zero(a)) goto err; } ret = 1; err: if (ctx != NULL) BN_CTX_end(ctx); if (new_ctx != NULL) BN_CTX_free(new_ctx); return ret; }
/* * Converts an octet string representation to an EC_POINT. Note that the * simple implementation only uses affine coordinates. */ int ec_GF2m_simple_oct2point(const EC_GROUP *group, EC_POINT *point, const unsigned char *buf, size_t len, BN_CTX *ctx) { point_conversion_form_t form; int y_bit; BN_CTX *new_ctx = NULL; BIGNUM *x, *y, *yxi; size_t field_len, enc_len; int ret = 0; if (len == 0) { ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_BUFFER_TOO_SMALL); return 0; } form = buf[0]; y_bit = form & 1; form = form & ~1U; if ((form != 0) && (form != POINT_CONVERSION_COMPRESSED) && (form != POINT_CONVERSION_UNCOMPRESSED) && (form != POINT_CONVERSION_HYBRID)) { ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING); return 0; } if ((form == 0 || form == POINT_CONVERSION_UNCOMPRESSED) && y_bit) { ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING); return 0; } if (form == 0) { if (len != 1) { ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING); return 0; } return EC_POINT_set_to_infinity(group, point); } field_len = (EC_GROUP_get_degree(group) + 7) / 8; enc_len = (form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2 * field_len; if (len != enc_len) { ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING); return 0; } if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); if (ctx == NULL) return 0; } BN_CTX_start(ctx); x = BN_CTX_get(ctx); y = BN_CTX_get(ctx); yxi = BN_CTX_get(ctx); if (yxi == NULL) goto err; if (!BN_bin2bn(buf + 1, field_len, x)) goto err; if (BN_ucmp(x, group->field) >= 0) { ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING); goto err; } if (form == POINT_CONVERSION_COMPRESSED) { if (!EC_POINT_set_compressed_coordinates_GF2m (group, point, x, y_bit, ctx)) goto err; } else { if (!BN_bin2bn(buf + 1 + field_len, field_len, y)) goto err; if (BN_ucmp(y, group->field) >= 0) { ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING); goto err; } if (form == POINT_CONVERSION_HYBRID) { if (!group->meth->field_div(group, yxi, y, x, ctx)) goto err; if (y_bit != BN_is_odd(yxi)) { ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING); goto err; } } if (!EC_POINT_set_affine_coordinates_GF2m(group, point, x, y, ctx)) goto err; } /* test required by X9.62 */ if (EC_POINT_is_on_curve(group, point, ctx) <= 0) { ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_POINT_IS_NOT_ON_CURVE); goto err; } ret = 1; err: BN_CTX_end(ctx); BN_CTX_free(new_ctx); return ret; }
int ec_GFp_simple_point_get_affine_coordinates(const EC_GROUP *group, const EC_POINT *point, BIGNUM *x, BIGNUM *y, BN_CTX *ctx) { BN_CTX *new_ctx = NULL; BIGNUM *Z, *Z_1, *Z_2, *Z_3; const BIGNUM *Z_; int ret = 0; if (EC_POINT_is_at_infinity(group, point)) { ECerr(EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES, EC_R_POINT_AT_INFINITY); return 0; } if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); if (ctx == NULL) return 0; } BN_CTX_start(ctx); Z = BN_CTX_get(ctx); Z_1 = BN_CTX_get(ctx); Z_2 = BN_CTX_get(ctx); Z_3 = BN_CTX_get(ctx); if (Z_3 == NULL) goto err; /* transform (X, Y, Z) into (x, y) := (X/Z^2, Y/Z^3) */ if (group->meth->field_decode) { if (!group->meth->field_decode(group, Z, &point->Z, ctx)) goto err; Z_ = Z; } else { Z_ = &point->Z; } if (BN_is_one(Z_)) { if (group->meth->field_decode) { if (x != NULL) { if (!group->meth->field_decode(group, x, &point->X, ctx)) goto err; } if (y != NULL) { if (!group->meth->field_decode(group, y, &point->Y, ctx)) goto err; } } else { if (x != NULL) { if (!BN_copy(x, &point->X)) goto err; } if (y != NULL) { if (!BN_copy(y, &point->Y)) goto err; } } } else { if (!BN_mod_inverse(Z_1, Z_, &group->field, ctx)) { ECerr(EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES, ERR_R_BN_LIB); goto err; } if (group->meth->field_encode == 0) { /* field_sqr works on standard representation */ if (!group->meth->field_sqr(group, Z_2, Z_1, ctx)) goto err; } else { if (!BN_mod_sqr(Z_2, Z_1, &group->field, ctx)) goto err; } if (x != NULL) { /* * in the Montgomery case, field_mul will cancel out Montgomery * factor in X: */ if (!group->meth->field_mul(group, x, &point->X, Z_2, ctx)) goto err; } if (y != NULL) { if (group->meth->field_encode == 0) { /* * field_mul works on standard representation */ if (!group->meth->field_mul(group, Z_3, Z_2, Z_1, ctx)) goto err; } else { if (!BN_mod_mul(Z_3, Z_2, Z_1, &group->field, ctx)) goto err; } /* * in the Montgomery case, field_mul will cancel out Montgomery * factor in Y: */ if (!group->meth->field_mul(group, y, &point->Y, Z_3, ctx)) goto err; } } ret = 1; err: BN_CTX_end(ctx); if (new_ctx != NULL) BN_CTX_free(new_ctx); return ret; }
int EC_GROUP_copy(EC_GROUP *dest, const EC_GROUP *src) { if (dest->meth->group_copy == 0) { ECerr(EC_F_EC_GROUP_COPY, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); return 0; } if (dest->meth != src->meth) { ECerr(EC_F_EC_GROUP_COPY, EC_R_INCOMPATIBLE_OBJECTS); return 0; } if (dest == src) return 1; dest->curve_name = src->curve_name; /* Copy precomputed */ dest->pre_comp_type = src->pre_comp_type; switch (src->pre_comp_type) { case PCT_none: dest->pre_comp.ec = NULL; break; case PCT_nistz256: #ifdef ECP_NISTZ256_ASM dest->pre_comp.nistz256 = EC_nistz256_pre_comp_dup(src->pre_comp.nistz256); #endif break; #ifndef OPENSSL_NO_EC_NISTP_64_GCC_128 case PCT_nistp224: dest->pre_comp.nistp224 = EC_nistp224_pre_comp_dup(src->pre_comp.nistp224); break; case PCT_nistp256: dest->pre_comp.nistp256 = EC_nistp256_pre_comp_dup(src->pre_comp.nistp256); break; case PCT_nistp521: dest->pre_comp.nistp521 = EC_nistp521_pre_comp_dup(src->pre_comp.nistp521); break; #else case PCT_nistp224: case PCT_nistp256: case PCT_nistp521: break; #endif case PCT_ec: dest->pre_comp.ec = EC_ec_pre_comp_dup(src->pre_comp.ec); break; } if (src->mont_data != NULL) { if (dest->mont_data == NULL) { dest->mont_data = BN_MONT_CTX_new(); if (dest->mont_data == NULL) return 0; } if (!BN_MONT_CTX_copy(dest->mont_data, src->mont_data)) return 0; } else { /* src->generator == NULL */ BN_MONT_CTX_free(dest->mont_data); dest->mont_data = NULL; } if (src->generator != NULL) { if (dest->generator == NULL) { dest->generator = EC_POINT_new(dest); if (dest->generator == NULL) return 0; } if (!EC_POINT_copy(dest->generator, src->generator)) return 0; } else { /* src->generator == NULL */ EC_POINT_clear_free(dest->generator); dest->generator = NULL; } if ((src->meth->flags & EC_FLAGS_CUSTOM_CURVE) == 0) { if (!BN_copy(dest->order, src->order)) return 0; if (!BN_copy(dest->cofactor, src->cofactor)) return 0; } dest->asn1_flag = src->asn1_flag; dest->asn1_form = src->asn1_form; if (src->seed) { OPENSSL_free(dest->seed); if ((dest->seed = OPENSSL_malloc(src->seed_len)) == NULL) { ECerr(EC_F_EC_GROUP_COPY, ERR_R_MALLOC_FAILURE); return 0; } if (!memcpy(dest->seed, src->seed, src->seed_len)) return 0; dest->seed_len = src->seed_len; } else { OPENSSL_free(dest->seed); dest->seed = NULL; dest->seed_len = 0; } return dest->meth->group_copy(dest, src); }
int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group, EC_POINT *point, const BIGNUM *x_, int y_bit, BN_CTX *ctx) { BN_CTX *new_ctx = NULL; BIGNUM *tmp1, *tmp2, *x, *y; int ret = 0; /* clear error queue */ ERR_clear_error(); if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); if (ctx == NULL) return 0; } y_bit = (y_bit != 0); BN_CTX_start(ctx); tmp1 = BN_CTX_get(ctx); tmp2 = BN_CTX_get(ctx); x = BN_CTX_get(ctx); y = BN_CTX_get(ctx); if (y == NULL) goto err; /*- * Recover y. We have a Weierstrass equation * y^2 = x^3 + a*x + b, * so y is one of the square roots of x^3 + a*x + b. */ /* tmp1 := x^3 */ if (!BN_nnmod(x, x_, &group->field, ctx)) goto err; if (group->meth->field_decode == 0) { /* field_{sqr,mul} work on standard representation */ if (!group->meth->field_sqr(group, tmp2, x_, ctx)) goto err; if (!group->meth->field_mul(group, tmp1, tmp2, x_, ctx)) goto err; } else { if (!BN_mod_sqr(tmp2, x_, &group->field, ctx)) goto err; if (!BN_mod_mul(tmp1, tmp2, x_, &group->field, ctx)) goto err; } /* tmp1 := tmp1 + a*x */ if (group->a_is_minus3) { if (!BN_mod_lshift1_quick(tmp2, x, &group->field)) goto err; if (!BN_mod_add_quick(tmp2, tmp2, x, &group->field)) goto err; if (!BN_mod_sub_quick(tmp1, tmp1, tmp2, &group->field)) goto err; } else { if (group->meth->field_decode) { if (!group->meth->field_decode(group, tmp2, &group->a, ctx)) goto err; if (!BN_mod_mul(tmp2, tmp2, x, &group->field, ctx)) goto err; } else { /* field_mul works on standard representation */ if (!group->meth->field_mul(group, tmp2, &group->a, x, ctx)) goto err; } if (!BN_mod_add_quick(tmp1, tmp1, tmp2, &group->field)) goto err; } /* tmp1 := tmp1 + b */ if (group->meth->field_decode) { if (!group->meth->field_decode(group, tmp2, &group->b, ctx)) goto err; if (!BN_mod_add_quick(tmp1, tmp1, tmp2, &group->field)) goto err; } else { if (!BN_mod_add_quick(tmp1, tmp1, &group->b, &group->field)) goto err; } if (!BN_mod_sqrt(y, tmp1, &group->field, ctx)) { unsigned long err = ERR_peek_last_error(); if (ERR_GET_LIB(err) == ERR_LIB_BN && ERR_GET_REASON(err) == BN_R_NOT_A_SQUARE) { ERR_clear_error(); ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES, EC_R_INVALID_COMPRESSED_POINT); } else ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES, ERR_R_BN_LIB); goto err; } if (y_bit != BN_is_odd(y)) { if (BN_is_zero(y)) { int kron; kron = BN_kronecker(x, &group->field, ctx); if (kron == -2) goto err; if (kron == 1) ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES, EC_R_INVALID_COMPRESSION_BIT); else /* * BN_mod_sqrt() should have cought this error (not a square) */ ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES, EC_R_INVALID_COMPRESSED_POINT); goto err; } if (!BN_usub(y, &group->field, y)) goto err; } if (y_bit != BN_is_odd(y)) { ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES, ERR_R_INTERNAL_ERROR); goto err; } if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) goto err; ret = 1; err: BN_CTX_end(ctx); if (new_ctx != NULL) BN_CTX_free(new_ctx); return ret; }
int EC_KEY_generate_key(EC_KEY *eckey) { int ok = 0; BN_CTX *ctx = NULL; BIGNUM *priv_key = NULL, *order = NULL; EC_POINT *pub_key = NULL; #ifdef OPENSSL_FIPS if (FIPS_mode()) return FIPS_ec_key_generate_key(eckey); #endif if (!eckey || !eckey->group) { ECerr(EC_F_EC_KEY_GENERATE_KEY, ERR_R_PASSED_NULL_PARAMETER); return 0; } if ((order = BN_new()) == NULL) goto err; if ((ctx = BN_CTX_new()) == NULL) goto err; if (eckey->priv_key == NULL) { priv_key = BN_new(); if (priv_key == NULL) goto err; } else priv_key = eckey->priv_key; if (!EC_GROUP_get_order(eckey->group, order, ctx)) goto err; do if (!BN_rand_range(priv_key, order)) goto err; while (BN_is_zero(priv_key)); if (eckey->pub_key == NULL) { pub_key = EC_POINT_new(eckey->group); if (pub_key == NULL) goto err; } else pub_key = eckey->pub_key; if (!EC_POINT_mul(eckey->group, pub_key, priv_key, NULL, NULL, ctx)) goto err; eckey->priv_key = priv_key; eckey->pub_key = pub_key; ok=1; err: if (order) BN_free(order); if (pub_key != NULL && eckey->pub_key == NULL) EC_POINT_free(pub_key); if (priv_key != NULL && eckey->priv_key == NULL) BN_free(priv_key); if (ctx != NULL) BN_CTX_free(ctx); return(ok); }
static int ecdh_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri) { int rv = 0; X509_ALGOR *alg, *kekalg = NULL; ASN1_OCTET_STRING *ukm; const unsigned char *p; unsigned char *der = NULL; int plen, keylen; const EVP_CIPHER *kekcipher; EVP_CIPHER_CTX *kekctx; if (!CMS_RecipientInfo_kari_get0_alg(ri, &alg, &ukm)) return 0; if (!ecdh_cms_set_kdf_param(pctx, OBJ_obj2nid(alg->algorithm))) { ECerr(EC_F_ECDH_CMS_SET_SHARED_INFO, EC_R_KDF_PARAMETER_ERROR); return 0; } if (alg->parameter->type != V_ASN1_SEQUENCE) return 0; p = alg->parameter->value.sequence->data; plen = alg->parameter->value.sequence->length; kekalg = d2i_X509_ALGOR(NULL, &p, plen); if (!kekalg) goto err; kekctx = CMS_RecipientInfo_kari_get0_ctx(ri); if (!kekctx) goto err; kekcipher = EVP_get_cipherbyobj(kekalg->algorithm); if (!kekcipher || EVP_CIPHER_mode(kekcipher) != EVP_CIPH_WRAP_MODE) goto err; if (!EVP_EncryptInit_ex(kekctx, kekcipher, NULL, NULL, NULL)) goto err; if (EVP_CIPHER_asn1_to_param(kekctx, kekalg->parameter) <= 0) goto err; keylen = EVP_CIPHER_CTX_key_length(kekctx); if (EVP_PKEY_CTX_set_ecdh_kdf_outlen(pctx, keylen) <= 0) goto err; plen = CMS_SharedInfo_encode(&der, kekalg, ukm, keylen); if (!plen) goto err; if (EVP_PKEY_CTX_set0_ecdh_kdf_ukm(pctx, der, plen) <= 0) goto err; der = NULL; rv = 1; err: if (kekalg) X509_ALGOR_free(kekalg); if (der) OPENSSL_free(der); return rv; }
int EC_KEY_set_public_key_affine_coordinates(EC_KEY *key, BIGNUM *x, BIGNUM *y) { BN_CTX *ctx = NULL; BIGNUM *tx, *ty; EC_POINT *point = NULL; int ok = 0, tmp_nid, is_char_two = 0; if (!key || !key->group || !x || !y) { ECerr(EC_F_EC_KEY_SET_PUBLIC_KEY_AFFINE_COORDINATES, ERR_R_PASSED_NULL_PARAMETER); return 0; } ctx = BN_CTX_new(); if (!ctx) goto err; point = EC_POINT_new(key->group); if (!point) goto err; tmp_nid = EC_METHOD_get_field_type(EC_GROUP_method_of(key->group)); if (tmp_nid == NID_X9_62_characteristic_two_field) is_char_two = 1; tx = BN_CTX_get(ctx); ty = BN_CTX_get(ctx); #ifndef OPENSSL_NO_EC2M if (is_char_two) { if (!EC_POINT_set_affine_coordinates_GF2m(key->group, point, x, y, ctx)) goto err; if (!EC_POINT_get_affine_coordinates_GF2m(key->group, point, tx, ty, ctx)) goto err; } else #endif { if (!EC_POINT_set_affine_coordinates_GFp(key->group, point, x, y, ctx)) goto err; if (!EC_POINT_get_affine_coordinates_GFp(key->group, point, tx, ty, ctx)) goto err; } /* Check if retrieved coordinates match originals: if not values * are out of range. */ if (BN_cmp(x, tx) || BN_cmp(y, ty)) { ECerr(EC_F_EC_KEY_SET_PUBLIC_KEY_AFFINE_COORDINATES, EC_R_COORDINATES_OUT_OF_RANGE); goto err; } if (!EC_KEY_set_public_key(key, point)) goto err; if (EC_KEY_check_key(key) == 0) goto err; ok = 1; err: if (ctx) BN_CTX_free(ctx); if (point) EC_POINT_free(point); return ok; }
ECDSA_SIG *ossl_ecdsa_sign_sig(const unsigned char *dgst, int dgst_len, const BIGNUM *in_kinv, const BIGNUM *in_r, EC_KEY *eckey) { int ok = 0, i; BIGNUM *kinv = NULL, *s, *m = NULL, *tmp = NULL; const BIGNUM *order, *ckinv; BN_CTX *ctx = NULL; const EC_GROUP *group; ECDSA_SIG *ret; const BIGNUM *priv_key; group = EC_KEY_get0_group(eckey); priv_key = EC_KEY_get0_private_key(eckey); if (group == NULL || priv_key == NULL) { ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_PASSED_NULL_PARAMETER); return NULL; } if (!EC_KEY_can_sign(eckey)) { ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, EC_R_CURVE_DOES_NOT_SUPPORT_SIGNING); return NULL; } ret = ECDSA_SIG_new(); if (ret == NULL) { ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_MALLOC_FAILURE); return NULL; } ret->r = BN_new(); ret->s = BN_new(); if (ret->r == NULL || ret->s == NULL) { ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_MALLOC_FAILURE); goto err; } s = ret->s; if ((ctx = BN_CTX_new()) == NULL || (tmp = BN_new()) == NULL || (m = BN_new()) == NULL) { ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_MALLOC_FAILURE); goto err; } order = EC_GROUP_get0_order(group); if (order == NULL) { ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_EC_LIB); goto err; } i = BN_num_bits(order); /* * Need to truncate digest if it is too long: first truncate whole bytes. */ if (8 * dgst_len > i) dgst_len = (i + 7) / 8; if (!BN_bin2bn(dgst, dgst_len, m)) { ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_BN_LIB); goto err; } /* If still too long truncate remaining bits with a shift */ if ((8 * dgst_len > i) && !BN_rshift(m, m, 8 - (i & 0x7))) { ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_BN_LIB); goto err; } do { if (in_kinv == NULL || in_r == NULL) { if (!ecdsa_sign_setup(eckey, ctx, &kinv, &ret->r, dgst, dgst_len)) { ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_ECDSA_LIB); goto err; } ckinv = kinv; } else { ckinv = in_kinv; if (BN_copy(ret->r, in_r) == NULL) { ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_MALLOC_FAILURE); goto err; } } if (!BN_mod_mul(tmp, priv_key, ret->r, order, ctx)) { ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_BN_LIB); goto err; } if (!BN_mod_add_quick(s, tmp, m, order)) { ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_BN_LIB); goto err; } if (!BN_mod_mul(s, s, ckinv, order, ctx)) { ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, ERR_R_BN_LIB); goto err; } if (BN_is_zero(s)) { /* * if kinv and r have been supplied by the caller, don't * generate new kinv and r values */ if (in_kinv != NULL && in_r != NULL) { ECerr(EC_F_OSSL_ECDSA_SIGN_SIG, EC_R_NEED_NEW_SETUP_VALUES); goto err; } } else /* s != 0 => we have a valid signature */ break; } while (1); ok = 1; err: if (!ok) { ECDSA_SIG_free(ret); ret = NULL; } BN_CTX_free(ctx); BN_clear_free(m); BN_clear_free(tmp); BN_clear_free(kinv); return ret; }