X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fec%2Fec_key.c;h=7a15e5f159f82457e5655ea20db445028be5ce28;hp=d537fe7de6b975bac1e076315e6b733d5cc80002;hb=8a99cb29d1f0013243a532bccc1dc70ed678eebe;hpb=5454829ae6684c0c9a8640fd940bfd53299ae39b diff --git a/crypto/ec/ec_key.c b/crypto/ec/ec_key.c index d537fe7de6..7a15e5f159 100644 --- a/crypto/ec/ec_key.c +++ b/crypto/ec/ec_key.c @@ -3,7 +3,7 @@ * Written by Nils Larsch for the OpenSSL project. */ /* ==================================================================== - * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved. + * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -61,6 +61,8 @@ * contributed to the OpenSSL project. */ +#define OPENSSL_FIPSAPI + #include #include "ec_lcl.h" #include @@ -73,21 +75,36 @@ EC_KEY *EC_KEY_new(void) ret=(EC_KEY *)OPENSSL_malloc(sizeof(EC_KEY)); if (ret == NULL) { - ECerr(EC_F_EC_NEW, ERR_R_MALLOC_FAILURE); + ECerr(EC_F_EC_KEY_NEW, ERR_R_MALLOC_FAILURE); return(NULL); } ret->version = 1; + ret->flags = 0; ret->group = NULL; ret->pub_key = NULL; ret->priv_key= NULL; ret->enc_flag= 0; + ret->nonce_from_hash_flag = 0; ret->conv_form = POINT_CONVERSION_UNCOMPRESSED; ret->references= 1; - ret->meth_data = NULL; + ret->method_data = NULL; return(ret); } +EC_KEY *EC_KEY_new_by_curve_name(int nid) + { + EC_KEY *ret = EC_KEY_new(); + if (ret == NULL) + return NULL; + ret->group = EC_GROUP_new_by_curve_name(nid); + if (ret->group == NULL) + { + EC_KEY_free(ret); + return NULL; + } + return ret; + } void EC_KEY_free(EC_KEY *r) { @@ -115,16 +132,17 @@ void EC_KEY_free(EC_KEY *r) if (r->priv_key != NULL) BN_clear_free(r->priv_key); - if (r->meth_data && r->meth_data->finish) - r->meth_data->finish(r); + EC_EX_DATA_free_all_data(&r->method_data); - memset((void *)r, 0x0, sizeof(EC_KEY)); + OPENSSL_cleanse((void *)r, sizeof(EC_KEY)); OPENSSL_free(r); } 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); @@ -166,54 +184,39 @@ EC_KEY *EC_KEY_copy(EC_KEY *dest, const EC_KEY *src) 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->nonce_from_hash_flag = src->nonce_from_hash_flag; dest->conv_form = src->conv_form; dest->version = src->version; + dest->flags = src->flags; return dest; } -EC_KEY *EC_KEY_dup(const EC_KEY *eckey) +EC_KEY *EC_KEY_dup(const EC_KEY *ec_key) { - EC_KEY *ret = NULL; - int ok = 1; - - ret = EC_KEY_new(); + EC_KEY *ret = EC_KEY_new(); if (ret == NULL) return NULL; - /* copy the parameters */ - if (eckey->group) - { - ret->group = EC_GROUP_dup(eckey->group); - if (ret->group == NULL) - ok = 0; - } - /* copy the public key */ - if (eckey->pub_key && eckey->group) - { - ret->pub_key = EC_POINT_dup(eckey->pub_key, eckey->group); - if (ret->pub_key == NULL) - ok = 0; - } - /* copy the private key */ - if (eckey->priv_key) - { - ret->priv_key = BN_dup(ret->priv_key); - if (ret->priv_key == NULL) - ok = 0; - } - /* copy the rest */ - ret->enc_flag = eckey->enc_flag; - ret->conv_form = eckey->conv_form; - ret->version = eckey->version; - - if (!ok) + if (EC_KEY_copy(ret, ec_key) == NULL) { EC_KEY_free(ret); - ret = NULL; + return NULL; } - return ret; } @@ -233,6 +236,71 @@ int EC_KEY_up_ref(EC_KEY *r) return ((i > 1) ? 1 : 0); } +#ifdef OPENSSL_FIPS + +#include +#include +#include + +static int fips_check_ec(EC_KEY *key) + { + EVP_PKEY pk; + unsigned char tbs[] = "ECDSA Pairwise Check Data"; + pk.type = EVP_PKEY_EC; + pk.pkey.ec = key; + + if (!fips_pkey_signature_test(FIPS_TEST_PAIRWISE, + &pk, tbs, 0, NULL, 0, NULL, 0, NULL)) + { + FIPSerr(FIPS_F_FIPS_CHECK_EC,FIPS_R_PAIRWISE_TEST_FAILED); + fips_set_selftest_fail(); + return 0; + } + return 1; + } + +int fips_check_ec_prng(EC_KEY *ec) + { + int bits, strength; + if (!FIPS_module_mode()) + return 1; + + if (ec->flags & (EC_FLAG_NON_FIPS_ALLOW|EC_FLAG_FIPS_CHECKED)) + return 1; + + if (!ec->group) + return 1; + + bits = BN_num_bits(&ec->group->order); + + if (bits < 160) + { + FIPSerr(FIPS_F_FIPS_CHECK_EC_PRNG,FIPS_R_KEY_TOO_SHORT); + return 0; + } + /* Comparable algorithm strengths: from SP800-57 table 2 */ + if (bits >= 512) + strength = 256; + else if (bits >= 384) + strength = 192; + else if (bits >= 256) + strength = 128; + else if (bits >= 224) + strength = 112; + else + strength = 80; + + + if (FIPS_rand_strength() >= strength) + return 1; + + FIPSerr(FIPS_F_FIPS_CHECK_EC_PRNG,FIPS_R_PRNG_STRENGTH_TOO_LOW); + return 0; + + } + +#endif + int EC_KEY_generate_key(EC_KEY *eckey) { int ok = 0; @@ -240,6 +308,14 @@ int EC_KEY_generate_key(EC_KEY *eckey) BIGNUM *priv_key = NULL, *order = NULL; EC_POINT *pub_key = NULL; +#ifdef OPENSSL_FIPS + if(FIPS_selftest_failed()) + { + FIPSerr(FIPS_F_EC_KEY_GENERATE_KEY,FIPS_R_FIPS_SELFTEST_FAILED); + return 0; + } +#endif + if (!eckey || !eckey->group) { ECerr(EC_F_EC_KEY_GENERATE_KEY, ERR_R_PASSED_NULL_PARAMETER); @@ -261,6 +337,11 @@ int EC_KEY_generate_key(EC_KEY *eckey) if (!EC_GROUP_get_order(eckey->group, order, ctx)) goto err; +#ifdef OPENSSL_FIPS + if (!fips_check_ec_prng(eckey)) + goto err; +#endif + do if (!BN_rand_range(priv_key, order)) goto err; @@ -281,6 +362,15 @@ int EC_KEY_generate_key(EC_KEY *eckey) eckey->priv_key = priv_key; eckey->pub_key = pub_key; +#ifdef OPENSSL_FIPS + if(!fips_check_ec(eckey)) + { + eckey->priv_key = NULL; + eckey->pub_key = NULL; + goto err; + } +#endif + ok=1; err: @@ -299,7 +389,7 @@ int EC_KEY_check_key(const EC_KEY *eckey) { int ok = 0; BN_CTX *ctx = NULL; - BIGNUM *order = NULL; + const BIGNUM *order = NULL; EC_POINT *point = NULL; if (!eckey || !eckey->group || !eckey->pub_key) @@ -307,10 +397,14 @@ int EC_KEY_check_key(const EC_KEY *eckey) ECerr(EC_F_EC_KEY_CHECK_KEY, ERR_R_PASSED_NULL_PARAMETER); return 0; } - - if ((ctx = BN_CTX_new()) == NULL) + + 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 ((order = BN_new()) == NULL) + } + + if ((ctx = BN_CTX_new()) == NULL) goto err; if ((point = EC_POINT_new(eckey->group)) == NULL) goto err; @@ -322,17 +416,13 @@ int EC_KEY_check_key(const EC_KEY *eckey) goto err; } /* testing whether pub_key * order is the point at infinity */ - if (!EC_GROUP_get_order(eckey->group, order, ctx)) + 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_copy(point, eckey->pub_key)) - { - ECerr(EC_F_EC_KEY_CHECK_KEY, ERR_R_EC_LIB); - goto err; - } - if (!EC_POINT_mul(eckey->group, point, order, NULL, NULL, ctx)) + 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; @@ -369,9 +459,210 @@ int EC_KEY_check_key(const EC_KEY *eckey) err: if (ctx != NULL) BN_CTX_free(ctx); - if (order != NULL) - BN_free(order); if (point != NULL) EC_POINT_free(point); return(ok); } + +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 and are less than + * field order: if not values are out of range. + */ + if (BN_cmp(x, tx) || BN_cmp(y, ty) + || (BN_cmp(x, &key->group->field) >= 0) + || (BN_cmp(y, &key->group->field) >= 0)) + { + 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; + + } + +const EC_GROUP *EC_KEY_get0_group(const EC_KEY *key) + { + return key->group; + } + +int EC_KEY_set_group(EC_KEY *key, const EC_GROUP *group) + { + if (key->group != NULL) + EC_GROUP_free(key->group); + key->group = EC_GROUP_dup(group); + return (key->group == NULL) ? 0 : 1; + } + +const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *key) + { + return key->priv_key; + } + +int EC_KEY_set_private_key(EC_KEY *key, const BIGNUM *priv_key) + { + if (key->priv_key) + BN_clear_free(key->priv_key); + key->priv_key = BN_dup(priv_key); + return (key->priv_key == NULL) ? 0 : 1; + } + +const EC_POINT *EC_KEY_get0_public_key(const EC_KEY *key) + { + return key->pub_key; + } + +int EC_KEY_set_public_key(EC_KEY *key, const EC_POINT *pub_key) + { + if (key->pub_key != NULL) + EC_POINT_free(key->pub_key); + key->pub_key = EC_POINT_dup(pub_key, key->group); + return (key->pub_key == NULL) ? 0 : 1; + } + +unsigned int EC_KEY_get_enc_flags(const EC_KEY *key) + { + return key->enc_flag; + } + +void EC_KEY_set_enc_flags(EC_KEY *key, unsigned int flags) + { + key->enc_flag = flags; + } + +int EC_KEY_get_nonce_from_hash(const EC_KEY *key) + { + return key->nonce_from_hash_flag; + } + +void EC_KEY_set_nonce_from_hash(EC_KEY *key, int on) + { + key->nonce_from_hash_flag = on != 0; + } + +point_conversion_form_t EC_KEY_get_conv_form(const EC_KEY *key) + { + return key->conv_form; + } + +void EC_KEY_set_conv_form(EC_KEY *key, point_conversion_form_t cform) + { + key->conv_form = cform; + if (key->group != NULL) + EC_GROUP_set_point_conversion_form(key->group, cform); + } + +void *EC_KEY_get_key_method_data(EC_KEY *key, + void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *)) + { + void *ret; + + CRYPTO_r_lock(CRYPTO_LOCK_EC); + ret = EC_EX_DATA_get_data(key->method_data, dup_func, free_func, clear_free_func); + CRYPTO_r_unlock(CRYPTO_LOCK_EC); + + return ret; + } + +void *EC_KEY_insert_key_method_data(EC_KEY *key, void *data, + void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *)) + { + EC_EXTRA_DATA *ex_data; + + CRYPTO_w_lock(CRYPTO_LOCK_EC); + ex_data = EC_EX_DATA_get_data(key->method_data, dup_func, free_func, clear_free_func); + if (ex_data == NULL) + EC_EX_DATA_set_data(&key->method_data, data, dup_func, free_func, clear_free_func); + CRYPTO_w_unlock(CRYPTO_LOCK_EC); + + return ex_data; + } + +void EC_KEY_set_asn1_flag(EC_KEY *key, int flag) + { + if (key->group != NULL) + EC_GROUP_set_asn1_flag(key->group, flag); + } + +int EC_KEY_precompute_mult(EC_KEY *key, BN_CTX *ctx) + { + if (key->group == NULL) + return 0; + return EC_GROUP_precompute_mult(key->group, ctx); + } + +int EC_KEY_get_flags(const EC_KEY *key) + { + return key->flags; + } + +void EC_KEY_set_flags(EC_KEY *key, int flags) + { + key->flags |= flags; + } + +void EC_KEY_clear_flags(EC_KEY *key, int flags) + { + key->flags &= ~flags; + }