123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376 |
- /**
- * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
- * SPDX-License-Identifier: Apache-2.0.
- */
- #include <aws/cal/private/ecc.h>
- #include <aws/cal/cal.h>
- #include <aws/cal/private/der.h>
- #include <openssl/bn.h>
- #include <openssl/ec.h>
- #include <openssl/ecdsa.h>
- #include <openssl/obj_mac.h>
- struct libcrypto_ecc_key {
- struct aws_ecc_key_pair key_pair;
- EC_KEY *ec_key;
- };
- static int s_curve_name_to_nid(enum aws_ecc_curve_name curve_name) {
- switch (curve_name) {
- case AWS_CAL_ECDSA_P256:
- return NID_X9_62_prime256v1;
- case AWS_CAL_ECDSA_P384:
- return NID_secp384r1;
- }
- AWS_FATAL_ASSERT(!"Unsupported elliptic curve name");
- return -1;
- }
- static void s_key_pair_destroy(struct aws_ecc_key_pair *key_pair) {
- if (key_pair) {
- aws_byte_buf_clean_up(&key_pair->pub_x);
- aws_byte_buf_clean_up(&key_pair->pub_y);
- aws_byte_buf_clean_up_secure(&key_pair->priv_d);
- struct libcrypto_ecc_key *key_impl = key_pair->impl;
- if (key_impl->ec_key) {
- EC_KEY_free(key_impl->ec_key);
- }
- aws_mem_release(key_pair->allocator, key_pair);
- }
- }
- static int s_sign_payload(
- const struct aws_ecc_key_pair *key_pair,
- const struct aws_byte_cursor *hash,
- struct aws_byte_buf *signature_output) {
- struct libcrypto_ecc_key *libcrypto_key_pair = key_pair->impl;
- unsigned int signature_size = signature_output->capacity - signature_output->len;
- int ret_val = ECDSA_sign(
- 0,
- hash->ptr,
- hash->len,
- signature_output->buffer + signature_output->len,
- &signature_size,
- libcrypto_key_pair->ec_key);
- signature_output->len += signature_size;
- return ret_val == 1 ? AWS_OP_SUCCESS : aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
- }
- static int s_verify_payload(
- const struct aws_ecc_key_pair *key_pair,
- const struct aws_byte_cursor *hash,
- const struct aws_byte_cursor *signature) {
- struct libcrypto_ecc_key *libcrypto_key_pair = key_pair->impl;
- return ECDSA_verify(0, hash->ptr, hash->len, signature->ptr, signature->len, libcrypto_key_pair->ec_key) == 1
- ? AWS_OP_SUCCESS
- : aws_raise_error(AWS_ERROR_CAL_SIGNATURE_VALIDATION_FAILED);
- }
- static size_t s_signature_length(const struct aws_ecc_key_pair *key_pair) {
- struct libcrypto_ecc_key *libcrypto_key_pair = key_pair->impl;
- return ECDSA_size(libcrypto_key_pair->ec_key);
- }
- static int s_fill_in_public_key_info(
- struct libcrypto_ecc_key *libcrypto_key_pair,
- const EC_GROUP *group,
- const EC_POINT *pub_key_point) {
- BIGNUM *big_num_x = BN_new();
- BIGNUM *big_num_y = BN_new();
- int ret_val = AWS_OP_ERR;
- if (EC_POINT_get_affine_coordinates_GFp(group, pub_key_point, big_num_x, big_num_y, NULL) != 1) {
- aws_raise_error(AWS_ERROR_INVALID_STATE);
- goto clean_up;
- }
- size_t x_coor_size = BN_num_bytes(big_num_x);
- size_t y_coor_size = BN_num_bytes(big_num_y);
- if (aws_byte_buf_init(&libcrypto_key_pair->key_pair.pub_x, libcrypto_key_pair->key_pair.allocator, x_coor_size)) {
- goto clean_up;
- }
- if (aws_byte_buf_init(&libcrypto_key_pair->key_pair.pub_y, libcrypto_key_pair->key_pair.allocator, y_coor_size)) {
- goto clean_up;
- }
- BN_bn2bin(big_num_x, libcrypto_key_pair->key_pair.pub_x.buffer);
- BN_bn2bin(big_num_y, libcrypto_key_pair->key_pair.pub_y.buffer);
- libcrypto_key_pair->key_pair.pub_x.len = x_coor_size;
- libcrypto_key_pair->key_pair.pub_y.len = y_coor_size;
- ret_val = AWS_OP_SUCCESS;
- clean_up:
- BN_free(big_num_x);
- BN_free(big_num_y);
- return ret_val;
- }
- static int s_derive_public_key(struct aws_ecc_key_pair *key_pair) {
- struct libcrypto_ecc_key *libcrypto_key_pair = key_pair->impl;
- if (!libcrypto_key_pair->key_pair.priv_d.buffer) {
- return aws_raise_error(AWS_ERROR_INVALID_STATE);
- }
- /* we already have a public key. */
- if (libcrypto_key_pair->key_pair.pub_x.len) {
- return AWS_OP_SUCCESS;
- }
- BIGNUM *priv_key_num =
- BN_bin2bn(libcrypto_key_pair->key_pair.priv_d.buffer, libcrypto_key_pair->key_pair.priv_d.len, NULL);
- const EC_GROUP *group = EC_KEY_get0_group(libcrypto_key_pair->ec_key);
- EC_POINT *point = EC_POINT_new(group);
- EC_POINT_mul(group, point, priv_key_num, NULL, NULL, NULL);
- BN_free(priv_key_num);
- EC_KEY_set_public_key(libcrypto_key_pair->ec_key, point);
- int ret_val = s_fill_in_public_key_info(libcrypto_key_pair, group, point);
- EC_POINT_free(point);
- return ret_val;
- }
- static struct aws_ecc_key_pair_vtable vtable = {
- .sign_message = s_sign_payload,
- .verify_signature = s_verify_payload,
- .derive_pub_key = s_derive_public_key,
- .signature_length = s_signature_length,
- .destroy = s_key_pair_destroy,
- };
- struct aws_ecc_key_pair *aws_ecc_key_pair_new_from_private_key_impl(
- struct aws_allocator *allocator,
- enum aws_ecc_curve_name curve_name,
- const struct aws_byte_cursor *priv_key) {
- size_t key_length = aws_ecc_key_coordinate_byte_size_from_curve_name(curve_name);
- if (priv_key->len != key_length) {
- AWS_LOGF_ERROR(AWS_LS_CAL_ECC, "Private key length does not match curve's expected length");
- aws_raise_error(AWS_ERROR_CAL_INVALID_KEY_LENGTH_FOR_ALGORITHM);
- return NULL;
- }
- struct libcrypto_ecc_key *key_impl = aws_mem_calloc(allocator, 1, sizeof(struct libcrypto_ecc_key));
- key_impl->ec_key = EC_KEY_new_by_curve_name(s_curve_name_to_nid(curve_name));
- key_impl->key_pair.curve_name = curve_name;
- key_impl->key_pair.allocator = allocator;
- key_impl->key_pair.vtable = &vtable;
- key_impl->key_pair.impl = key_impl;
- aws_atomic_init_int(&key_impl->key_pair.ref_count, 1);
- aws_byte_buf_init_copy_from_cursor(&key_impl->key_pair.priv_d, allocator, *priv_key);
- BIGNUM *priv_key_num = BN_bin2bn(key_impl->key_pair.priv_d.buffer, key_impl->key_pair.priv_d.len, NULL);
- if (!EC_KEY_set_private_key(key_impl->ec_key, priv_key_num)) {
- AWS_LOGF_ERROR(AWS_LS_CAL_ECC, "Failed to set openssl private key");
- aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
- BN_free(priv_key_num);
- s_key_pair_destroy(&key_impl->key_pair);
- return NULL;
- }
- BN_free(priv_key_num);
- return &key_impl->key_pair;
- }
- struct aws_ecc_key_pair *aws_ecc_key_pair_new_generate_random(
- struct aws_allocator *allocator,
- enum aws_ecc_curve_name curve_name) {
- struct libcrypto_ecc_key *key_impl = aws_mem_calloc(allocator, 1, sizeof(struct libcrypto_ecc_key));
- key_impl->ec_key = EC_KEY_new_by_curve_name(s_curve_name_to_nid(curve_name));
- key_impl->key_pair.curve_name = curve_name;
- key_impl->key_pair.allocator = allocator;
- key_impl->key_pair.vtable = &vtable;
- key_impl->key_pair.impl = key_impl;
- aws_atomic_init_int(&key_impl->key_pair.ref_count, 1);
- if (EC_KEY_generate_key(key_impl->ec_key) != 1) {
- goto error;
- }
- const EC_POINT *pub_key_point = EC_KEY_get0_public_key(key_impl->ec_key);
- const EC_GROUP *group = EC_KEY_get0_group(key_impl->ec_key);
- const BIGNUM *private_key_num = EC_KEY_get0_private_key(key_impl->ec_key);
- size_t priv_key_size = BN_num_bytes(private_key_num);
- if (aws_byte_buf_init(&key_impl->key_pair.priv_d, allocator, priv_key_size)) {
- goto error;
- }
- BN_bn2bin(private_key_num, key_impl->key_pair.priv_d.buffer);
- key_impl->key_pair.priv_d.len = priv_key_size;
- if (!s_fill_in_public_key_info(key_impl, group, pub_key_point)) {
- return &key_impl->key_pair;
- }
- error:
- s_key_pair_destroy(&key_impl->key_pair);
- return NULL;
- }
- struct aws_ecc_key_pair *aws_ecc_key_pair_new_from_public_key_impl(
- struct aws_allocator *allocator,
- enum aws_ecc_curve_name curve_name,
- const struct aws_byte_cursor *public_key_x,
- const struct aws_byte_cursor *public_key_y) {
- struct libcrypto_ecc_key *key_impl = aws_mem_calloc(allocator, 1, sizeof(struct libcrypto_ecc_key));
- BIGNUM *pub_x_num = NULL;
- BIGNUM *pub_y_num = NULL;
- EC_POINT *point = NULL;
- if (!key_impl) {
- return NULL;
- }
- key_impl->ec_key = EC_KEY_new_by_curve_name(s_curve_name_to_nid(curve_name));
- key_impl->key_pair.curve_name = curve_name;
- key_impl->key_pair.allocator = allocator;
- key_impl->key_pair.vtable = &vtable;
- key_impl->key_pair.impl = key_impl;
- aws_atomic_init_int(&key_impl->key_pair.ref_count, 1);
- if (aws_byte_buf_init_copy_from_cursor(&key_impl->key_pair.pub_x, allocator, *public_key_x)) {
- s_key_pair_destroy(&key_impl->key_pair);
- return NULL;
- }
- if (aws_byte_buf_init_copy_from_cursor(&key_impl->key_pair.pub_y, allocator, *public_key_y)) {
- s_key_pair_destroy(&key_impl->key_pair);
- return NULL;
- }
- pub_x_num = BN_bin2bn(public_key_x->ptr, public_key_x->len, NULL);
- pub_y_num = BN_bin2bn(public_key_y->ptr, public_key_y->len, NULL);
- const EC_GROUP *group = EC_KEY_get0_group(key_impl->ec_key);
- point = EC_POINT_new(group);
- if (EC_POINT_set_affine_coordinates_GFp(group, point, pub_x_num, pub_y_num, NULL) != 1) {
- goto error;
- }
- if (EC_KEY_set_public_key(key_impl->ec_key, point) != 1) {
- goto error;
- }
- EC_POINT_free(point);
- BN_free(pub_x_num);
- BN_free(pub_y_num);
- return &key_impl->key_pair;
- error:
- if (point) {
- EC_POINT_free(point);
- }
- if (pub_x_num) {
- BN_free(pub_x_num);
- }
- if (pub_y_num) {
- BN_free(pub_y_num);
- }
- s_key_pair_destroy(&key_impl->key_pair);
- return NULL;
- }
- struct aws_ecc_key_pair *aws_ecc_key_pair_new_from_asn1(
- struct aws_allocator *allocator,
- const struct aws_byte_cursor *encoded_keys) {
- struct aws_ecc_key_pair *key = NULL;
- struct aws_der_decoder *decoder = aws_der_decoder_new(allocator, *encoded_keys);
- if (!decoder) {
- return NULL;
- }
- struct aws_byte_cursor pub_x;
- struct aws_byte_cursor pub_y;
- struct aws_byte_cursor priv_d;
- enum aws_ecc_curve_name curve_name;
- if (aws_der_decoder_load_ecc_key_pair(decoder, &pub_x, &pub_y, &priv_d, &curve_name)) {
- goto error;
- }
- if (priv_d.ptr) {
- struct libcrypto_ecc_key *key_impl = aws_mem_calloc(allocator, 1, sizeof(struct libcrypto_ecc_key));
- key_impl->key_pair.curve_name = curve_name;
- /* as awkward as it seems, there's not a great way to manually set the public key, so let openssl just parse
- * the der document manually now that we know what parts are what. */
- if (!d2i_ECPrivateKey(&key_impl->ec_key, (const unsigned char **)&encoded_keys->ptr, encoded_keys->len)) {
- aws_mem_release(allocator, key_impl);
- aws_raise_error(AWS_ERROR_CAL_MISSING_REQUIRED_KEY_COMPONENT);
- goto error;
- }
- key_impl->key_pair.allocator = allocator;
- key_impl->key_pair.vtable = &vtable;
- key_impl->key_pair.impl = key_impl;
- aws_atomic_init_int(&key_impl->key_pair.ref_count, 1);
- key = &key_impl->key_pair;
- struct aws_byte_buf temp_buf;
- AWS_ZERO_STRUCT(temp_buf);
- if (pub_x.ptr) {
- temp_buf = aws_byte_buf_from_array(pub_x.ptr, pub_x.len);
- if (aws_byte_buf_init_copy(&key->pub_x, allocator, &temp_buf)) {
- goto error;
- }
- }
- if (pub_y.ptr) {
- temp_buf = aws_byte_buf_from_array(pub_y.ptr, pub_y.len);
- if (aws_byte_buf_init_copy(&key->pub_y, allocator, &temp_buf)) {
- goto error;
- }
- }
- if (priv_d.ptr) {
- temp_buf = aws_byte_buf_from_array(priv_d.ptr, priv_d.len);
- if (aws_byte_buf_init_copy(&key->priv_d, allocator, &temp_buf)) {
- goto error;
- }
- }
- } else {
- key = aws_ecc_key_pair_new_from_public_key(allocator, curve_name, &pub_x, &pub_y);
- if (!key) {
- goto error;
- }
- }
- aws_der_decoder_destroy(decoder);
- return key;
- error:
- aws_der_decoder_destroy(decoder);
- s_key_pair_destroy(key);
- return NULL;
- }
|