Skip to content

Commit

Permalink
Use fake pub key to get around issue creating SecKey with private key…
Browse files Browse the repository at this point in the history
… on MacOS 14+ (#163)

Use fake pub key to get around the issue about create SecKey with private key only on MacOS 14+
  • Loading branch information
TingDaoK authored Oct 12, 2023
1 parent 16597f5 commit 0f943e8
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 3 deletions.
63 changes: 60 additions & 3 deletions source/darwin/securityframework_ecc.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,29 @@ static uint8_t s_preamble = 0x04;

static size_t s_der_overhead = 8;

/* The hard-coded "valid" public keys. Copy/pated from one of our unit test. */
const static uint8_t s_fake_x_ecdsa_p256[] = {
0xd0, 0x72, 0x0d, 0xc6, 0x91, 0xaa, 0x80, 0x09, 0x6b, 0xa3, 0x2f, 0xed, 0x1c, 0xb9, 0x7c, 0x2b,
0x62, 0x06, 0x90, 0xd0, 0x6d, 0xe0, 0x31, 0x7b, 0x86, 0x18, 0xd5, 0xce, 0x65, 0xeb, 0x72, 0x8f,
};

const static uint8_t s_fake_y_ecdsa_p256[] = {
0x96, 0x81, 0xb5, 0x17, 0xb1, 0xcd, 0xa1, 0x7d, 0x0d, 0x83, 0xd3, 0x35, 0xd9, 0xc4, 0xa8, 0xa9,
0xa9, 0xb0, 0xb1, 0xb3, 0xc7, 0x10, 0x6d, 0x8f, 0x3c, 0x72, 0xbc, 0x50, 0x93, 0xdc, 0x27, 0x5f,
};

const static uint8_t s_fake_x_ecdsa_p384[] = {
0xfd, 0x3c, 0x84, 0xe5, 0x68, 0x9b, 0xed, 0x27, 0x0e, 0x60, 0x1b, 0x3d, 0x80, 0xf9, 0x0d, 0x67,
0xa9, 0xae, 0x45, 0x1c, 0xce, 0x89, 0x0f, 0x53, 0xe5, 0x83, 0x22, 0x9a, 0xd0, 0xe2, 0xee, 0x64,
0x56, 0x11, 0xfa, 0x99, 0x36, 0xdf, 0xa4, 0x53, 0x06, 0xec, 0x18, 0x06, 0x67, 0x74, 0xaa, 0x24,
};

const static uint8_t s_fake_y_ecdsa_p384[] = {
0xb8, 0x3c, 0xa4, 0x12, 0x6c, 0xfc, 0x4c, 0x4d, 0x1d, 0x18, 0xa4, 0xb6, 0xc2, 0x1c, 0x7f, 0x69,
0x9d, 0x51, 0x23, 0xdd, 0x9c, 0x24, 0xf6, 0x6f, 0x83, 0x38, 0x46, 0xee, 0xb5, 0x82, 0x96, 0x19,
0x6b, 0x42, 0xec, 0x06, 0x42, 0x5d, 0xb5, 0xb7, 0x0a, 0x4b, 0x81, 0xb7, 0xfc, 0xf7, 0x05, 0xa0,
};

static int s_sign_message(
const struct aws_ecc_key_pair *key_pair,
const struct aws_byte_cursor *message,
Expand Down Expand Up @@ -207,10 +230,40 @@ struct aws_ecc_key_pair *aws_ecc_key_pair_new_from_private_key_impl(
enum aws_ecc_curve_name curve_name,
const struct aws_byte_cursor *priv_key) {

struct aws_byte_cursor empty_cur;
AWS_ZERO_STRUCT(empty_cur);
/**
* We use SecCreateKeyWithData to create ECC key. Expected format for the key passed to that api is a byte buffer
* consisting of "0x04 | x | y | p", where x,y is public pair and p is private key.
*
* In this case we only have private key and we need to construct SecKey from that.
*
* We used to just pass 0,0 point for x,y, i.e. "0x04 | 0 | 0 | p".
*
* This used to work on Macs before 14, but in 14+ SecCreateKeyWithData returns error,
* which is reasonable since 0,0 is not a valid public point.
*
* To get around the issue, we use a fake public key, which is a valid public point, but not matching the private
* key as a quick workaround.
*/
struct aws_byte_cursor fake_pub_x;
AWS_ZERO_STRUCT(fake_pub_x);
struct aws_byte_cursor fake_pub_y;
AWS_ZERO_STRUCT(fake_pub_y);
switch (curve_name) {
case AWS_CAL_ECDSA_P256:
fake_pub_x = aws_byte_cursor_from_array(s_fake_x_ecdsa_p256, AWS_ARRAY_SIZE(s_fake_x_ecdsa_p256));
fake_pub_y = aws_byte_cursor_from_array(s_fake_y_ecdsa_p256, AWS_ARRAY_SIZE(s_fake_y_ecdsa_p256));
break;
case AWS_CAL_ECDSA_P384:
fake_pub_x = aws_byte_cursor_from_array(s_fake_x_ecdsa_p384, AWS_ARRAY_SIZE(s_fake_x_ecdsa_p384));
fake_pub_y = aws_byte_cursor_from_array(s_fake_y_ecdsa_p384, AWS_ARRAY_SIZE(s_fake_y_ecdsa_p384));
break;
default:
aws_raise_error(AWS_ERROR_CAL_UNSUPPORTED_ALGORITHM);
return NULL;
}

struct commoncrypto_ecc_key_pair *cc_key_pair =
s_alloc_pair_and_init_buffers(allocator, curve_name, empty_cur, empty_cur, *priv_key);
s_alloc_pair_and_init_buffers(allocator, curve_name, fake_pub_x, fake_pub_y, *priv_key);

if (!cc_key_pair) {
return NULL;
Expand Down Expand Up @@ -248,6 +301,10 @@ struct aws_ecc_key_pair *aws_ecc_key_pair_new_from_private_key_impl(
goto error;
}

/* Zero out the fake public keys in the key pair */
aws_byte_buf_secure_zero(&cc_key_pair->key_pair.pub_x);
aws_byte_buf_secure_zero(&cc_key_pair->key_pair.pub_y);

CFRelease(key_attributes);
CFRelease(private_key_data);

Expand Down
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -144,5 +144,6 @@ add_test_case(ecc_key_pair_random_ref_count_test)
add_test_case(ecc_key_pair_public_ref_count_test)
add_test_case(ecc_key_pair_asn1_ref_count_test)
add_test_case(ecc_key_pair_private_ref_count_test)
add_test_case(ecc_key_gen_from_private_fuzz_test)

generate_test_driver(${PROJECT_NAME}-tests)
82 changes: 82 additions & 0 deletions tests/ecc_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -929,3 +929,85 @@ static int s_ecdsa_p256_test_small_coordinate_verification(struct aws_allocator
return AWS_OP_SUCCESS;
}
AWS_TEST_CASE(ecdsa_p256_test_small_coordinate_verification, s_ecdsa_p256_test_small_coordinate_verification);

#ifdef AWS_OS_APPLE

static int s_test_key_gen_from_private_fuzz(
struct aws_allocator *allocator,
enum aws_ecc_curve_name curve_name,
size_t number_loop) {

uint8_t message[] = {
0x59, 0x05, 0x23, 0x88, 0x77, 0xc7, 0x74, 0x21, 0xf7, 0x3e, 0x43, 0xee, 0x3d, 0xa6, 0xf2, 0xd9,
0xe2, 0xcc, 0xad, 0x5f, 0xc9, 0x42, 0xdc, 0xec, 0x0c, 0xbd, 0x25, 0x48, 0x29, 0x35, 0xfa, 0xaf,
0x41, 0x69, 0x83, 0xfe, 0x16, 0x5b, 0x1a, 0x04, 0x5e, 0xe2, 0xbc, 0xd2, 0xe6, 0xdc, 0xa3, 0xbd,
0xf4, 0x6c, 0x43, 0x10, 0xa7, 0x46, 0x1f, 0x9a, 0x37, 0x96, 0x0c, 0xa6, 0x72, 0xd3, 0xfe, 0xb5,
0x47, 0x3e, 0x25, 0x36, 0x05, 0xfb, 0x1d, 0xdf, 0xd2, 0x80, 0x65, 0xb5, 0x3c, 0xb5, 0x85, 0x8a,
0x8a, 0xd2, 0x81, 0x75, 0xbf, 0x9b, 0xd3, 0x86, 0xa5, 0xe4, 0x71, 0xea, 0x7a, 0x65, 0xc1, 0x7c,
0xc9, 0x34, 0xa9, 0xd7, 0x91, 0xe9, 0x14, 0x91, 0xeb, 0x37, 0x54, 0xd0, 0x37, 0x99, 0x79, 0x0f,
0xe2, 0xd3, 0x08, 0xd1, 0x61, 0x46, 0xd5, 0xc9, 0xb0, 0xd0, 0xde, 0xbd, 0x97, 0xd7, 0x9c, 0xe8,
};
struct aws_byte_cursor message_input = aws_byte_cursor_from_array(message, sizeof(message));
uint8_t hash[AWS_SHA256_LEN];
AWS_ZERO_ARRAY(hash);
struct aws_byte_buf hash_value = aws_byte_buf_from_empty_array(hash, sizeof(hash));
struct aws_byte_cursor hash_cur = aws_byte_cursor_from_buf(&hash_value);
aws_sha256_compute(allocator, &message_input, &hash_value, 0);

for (size_t i = 0; i < number_loop; i++) {
struct aws_ecc_key_pair *key_pair = aws_ecc_key_pair_new_generate_random(allocator, curve_name);
struct aws_byte_cursor priv_d;
aws_ecc_key_pair_get_private_key(key_pair, &priv_d);
ASSERT_TRUE(priv_d.len > 0);

struct aws_ecc_key_pair *key_pair_private =
aws_ecc_key_pair_new_from_private_key(allocator, curve_name, &priv_d);
ASSERT_NOT_NULL(key_pair_private);
struct aws_byte_cursor pub_x;
struct aws_byte_cursor pub_y;
aws_ecc_key_pair_get_public_key(key_pair_private, &pub_x, &pub_y);
ASSERT_UINT_EQUALS(0, pub_x.len);
ASSERT_UINT_EQUALS(0, pub_y.len);

size_t signature_size = aws_ecc_key_pair_signature_length(key_pair_private);

struct aws_byte_buf signature_buf;
AWS_ZERO_STRUCT(signature_buf);
aws_byte_buf_init(&signature_buf, allocator, signature_size);

/* Use key from private to sign */
ASSERT_SUCCESS(aws_ecc_key_pair_sign_message(key_pair_private, &hash_cur, &signature_buf));
struct aws_byte_cursor signature_cur = aws_byte_cursor_from_buf(&signature_buf);
ASSERT_SUCCESS(aws_ecc_key_pair_verify_signature(key_pair, &hash_cur, &signature_cur));

aws_ecc_key_pair_release(key_pair);
aws_ecc_key_pair_release(key_pair_private);
aws_byte_buf_clean_up(&signature_buf);
}
aws_byte_buf_clean_up(&hash_value);

return AWS_OP_SUCCESS;
}

static int s_ecc_key_gen_from_private_fuzz_test(struct aws_allocator *allocator, void *ctx) {
(void)ctx;

aws_cal_library_init(allocator);
ASSERT_SUCCESS(s_test_key_gen_from_private_fuzz(allocator, AWS_CAL_ECDSA_P256, 1000));
ASSERT_SUCCESS(s_test_key_gen_from_private_fuzz(allocator, AWS_CAL_ECDSA_P384, 1000));
aws_cal_library_clean_up();
return AWS_OP_SUCCESS;
}

AWS_TEST_CASE(ecc_key_gen_from_private_fuzz_test, s_ecc_key_gen_from_private_fuzz_test)

#else

static int s_ecc_key_gen_from_private_fuzz_test(struct aws_allocator *allocator, void *ctx) {
(void)ctx;
(void)allocator;
return AWS_OP_SUCCESS;
}

AWS_TEST_CASE(ecc_key_gen_from_private_fuzz_test, s_ecc_key_gen_from_private_fuzz_test)
#endif

0 comments on commit 0f943e8

Please sign in to comment.