Skip to content

Commit 8703b3e

Browse files
authored
[FIX] heap use after free on aws_ecc_key_pair_new_from_asn1 (#219)
1 parent 938d0fe commit 8703b3e

File tree

2 files changed

+29
-11
lines changed

2 files changed

+29
-11
lines changed

source/der.c

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ struct aws_der_decoder {
2626
int tlv_idx; /* index to elements after parsing */
2727
struct aws_byte_cursor input; /* input buffer */
2828
uint32_t depth; /* recursion depth when expanding containers */
29-
struct der_tlv *container; /* currently expanding container */
29+
uint64_t container_index; /* currently expanding container index in the list `tlvs` */
3030
};
3131

3232
struct der_tlv {
@@ -377,7 +377,7 @@ struct aws_der_decoder *aws_der_decoder_new(struct aws_allocator *allocator, str
377377
decoder->input = input;
378378
decoder->tlv_idx = -1;
379379
decoder->depth = 0;
380-
decoder->container = NULL;
380+
decoder->container_index = UINT64_MAX; /* no container is being expanded */
381381
if (aws_array_list_init_dynamic(&decoder->tlvs, decoder->allocator, 16, sizeof(struct der_tlv))) {
382382
goto error;
383383
}
@@ -421,15 +421,20 @@ int s_parse_cursor(struct aws_der_decoder *decoder, struct aws_byte_cursor cur)
421421
if (aws_array_list_push_back(&decoder->tlvs, &tlv)) {
422422
return aws_raise_error(AWS_ERROR_INVALID_STATE);
423423
}
424-
if (decoder->container) {
425-
decoder->container->count++;
424+
if (decoder->container_index != UINT64_MAX) {
425+
struct der_tlv *container = NULL;
426+
aws_array_list_get_at_ptr(&decoder->tlvs, (void **)&container, (size_t)decoder->container_index);
427+
if (!container) {
428+
return aws_raise_error(AWS_ERROR_INVALID_STATE);
429+
}
430+
container->count++;
426431
}
427432
/* if the last element was a container, expand it recursively to maintain order */
428433
if (tlv.tag & AWS_DER_FORM_CONSTRUCTED) {
429-
struct der_tlv *outer_container = decoder->container;
434+
uint64_t outer_container_index = decoder->container_index;
430435
struct der_tlv *container = NULL;
431436
aws_array_list_get_at_ptr(&decoder->tlvs, (void **)&container, decoder->tlvs.length - 1);
432-
decoder->container = container;
437+
decoder->container_index = decoder->tlvs.length - 1;
433438

434439
if (!container) {
435440
return aws_raise_error(AWS_ERROR_INVALID_STATE);
@@ -439,7 +444,7 @@ int s_parse_cursor(struct aws_der_decoder *decoder, struct aws_byte_cursor cur)
439444
if (s_parse_cursor(decoder, container_cur)) {
440445
return aws_raise_error(AWS_ERROR_CAL_MALFORMED_ASN1_ENCOUNTERED);
441446
}
442-
decoder->container = outer_container; /* restore the container stack */
447+
decoder->container_index = outer_container_index; /* restore the container stack */
443448
}
444449
}
445450

tests/ecc_test.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,7 @@ static int s_ecdsa_test_import_asn1_key_pair_invalid_fails_fn(struct aws_allocat
614614
aws_cal_library_test_init(allocator);
615615

616616
/* I changed the OID to nonsense */
617-
uint8_t bad_asn1_encoded_full_key_raw[] = {
617+
uint8_t bad_asn1_encoded_full_key_raw_1[] = {
618618
0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0x99, 0x16, 0x2a, 0x5b, 0x4e, 0x63, 0x86, 0x4c, 0x5f, 0x8e, 0x37,
619619
0xf7, 0x2b, 0xbd, 0x97, 0x1d, 0x5c, 0x68, 0x80, 0x18, 0xc3, 0x91, 0x0f, 0xb3, 0xc3, 0xf9, 0x3a, 0xc9, 0x7a,
620620
0x4b, 0xa3, 0xf6, 0xa0, 0x0a, 0x06, 0x08, 0x2a, 0x8a, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0xa1, 0x44, 0x03,
@@ -623,14 +623,27 @@ static int s_ecdsa_test_import_asn1_key_pair_invalid_fails_fn(struct aws_allocat
623623
0xf6, 0xac, 0xa4, 0xc6, 0x16, 0x7e, 0x3e, 0xe0, 0xff, 0x7b, 0x43, 0xe8, 0xa1, 0x36, 0x50, 0x92, 0x83, 0x06,
624624
0x94, 0xb3, 0xd4, 0x93, 0x06, 0xde, 0x63, 0x8a, 0xa1, 0x1c, 0x3f, 0xb2, 0x57, 0x0a,
625625
};
626+
/* Once upon a time, we store the pointer of container in the aws_der_decoder, which points to the address in an
627+
* array list. However, since the array list will be dynamically expanded, when it happens, the point is freed and
628+
* becomes invalid. This blob serves as a regression test. */
629+
uint8_t bad_asn1_encoded_full_key_raw_2[] = {
630+
0x2b, 0x20, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
631+
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x0,
632+
};
626633

627-
struct aws_byte_cursor bad_full_key_asn1 =
628-
aws_byte_cursor_from_array(bad_asn1_encoded_full_key_raw, sizeof(bad_asn1_encoded_full_key_raw));
634+
struct aws_byte_cursor bad_full_key_asn1_1 =
635+
aws_byte_cursor_from_array(bad_asn1_encoded_full_key_raw_1, sizeof(bad_asn1_encoded_full_key_raw_1));
629636

630-
struct aws_ecc_key_pair *signing_key = aws_ecc_key_pair_new_from_asn1(allocator, &bad_full_key_asn1);
637+
struct aws_ecc_key_pair *signing_key = aws_ecc_key_pair_new_from_asn1(allocator, &bad_full_key_asn1_1);
631638
ASSERT_NULL(signing_key);
632639
ASSERT_INT_EQUALS(AWS_ERROR_CAL_UNKNOWN_OBJECT_IDENTIFIER, aws_last_error());
633640

641+
struct aws_byte_cursor bad_full_key_asn1_2 =
642+
aws_byte_cursor_from_array(bad_asn1_encoded_full_key_raw_2, sizeof(bad_asn1_encoded_full_key_raw_2));
643+
644+
signing_key = aws_ecc_key_pair_new_from_asn1(allocator, &bad_full_key_asn1_2);
645+
ASSERT_NULL(signing_key);
646+
ASSERT_INT_EQUALS(AWS_ERROR_CAL_UNKNOWN_OBJECT_IDENTIFIER, aws_last_error());
634647
aws_cal_library_clean_up();
635648

636649
return AWS_OP_SUCCESS;

0 commit comments

Comments
 (0)