diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 7dcc98d0e..bcf462f39 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -79,6 +79,7 @@ add_test_suite(aes aes.rest) add_test_suite(aes aes.xts) add_test_suite(arc4) add_test_suite(aria) +add_test_suite(asn1parse) add_test_suite(asn1write) add_test_suite(base64) add_test_suite(blowfish) diff --git a/tests/suites/test_suite_asn1parse.data b/tests/suites/test_suite_asn1parse.data new file mode 100644 index 000000000..83319e3e5 --- /dev/null +++ b/tests/suites/test_suite_asn1parse.data @@ -0,0 +1,438 @@ +Empty length +parse_prefixes:"04":0:MBEDTLS_ERR_ASN1_INVALID_LENGTH + +Prefixes of OCTET STRING, length=0 +parse_prefixes:"04007e":2:0 + +Prefixes of OCTET STRING, length=0 (0 length bytes) +parse_prefixes:"04807e":2:MBEDTLS_ERR_ASN1_INVALID_LENGTH + +Prefixes of OCTET STRING, length=1 +parse_prefixes:"0401417e":3:0 + +Prefixes of OCTET STRING, length=2 +parse_prefixes:"040241427e":4:0 + +Prefixes of BOOLEAN, length=0 +parse_prefixes:"01007e":2:MBEDTLS_ERR_ASN1_INVALID_LENGTH + +Prefixes of BOOLEAN, length=1 +parse_prefixes:"0101007e":3:0 + +Prefixes of BOOLEAN, length=2 +parse_prefixes:"010200007e":4:MBEDTLS_ERR_ASN1_INVALID_LENGTH + +Prefixes of INTEGER, length=1 +parse_prefixes:"0201417e":3:0 + +Prefixes of INTEGER, length=2 +parse_prefixes:"020241427e":4:0 + +Prefixes of INTEGER, length=5 +parse_prefixes:"020541424344457e":7:0 + +Prefixes of empty BIT STRING +parse_prefixes:"03007e":2:MBEDTLS_ERR_ASN1_OUT_OF_DATA + +Prefixes of BIT STRING, unused_bits=0, payload_length=0 +parse_prefixes:"030100":3:0 + +Prefixes of BIT STRING, unused_bits=0, payload_length=1 +parse_prefixes:"0302002a":4:0 + +Prefixes of BIT STRING, unused_bits=1, payload_length=1 +parse_prefixes:"0302012a":4:0 + +Prefixes of empty SEQUENCE +parse_prefixes:"30007e":2:0 + +Prefixes of SEQUENCE of BOOLEAN, INTEGER, INTEGER +parse_prefixes:"300b01010102012a02031234567e":13:0 + +Prefixes of SEQUENCE of (SEQUENCE of INTEGER, INTEGER), INTEGER +parse_prefixes:"300b30060201410201420201617e":13:0 + +length=0 (short form) +get_len:"00":0 + +length=0 (1 length byte) +get_len:"8100":0 + +length=0 (2 length bytes) +get_len:"820000":0 + +length=1 (short form) +get_len:"01":1 + +length=1 (1 length byte) +get_len:"8101":1 + +length=1 (2 length bytes) +get_len:"820001":1 + +length=1 (3 length bytes) +get_len:"83000001":1 + +length=1 (4 length bytes) +get_len:"8400000001":1 + +length=2 (short form) +get_len:"02":2 + +length=2 (1 length byte) +get_len:"8102":2 + +length=2 (2 length bytes) +get_len:"820002":2 + +length=2 (3 length bytes) +get_len:"83000002":2 + +length=2 (4 length bytes) +get_len:"8400000002":2 + +length=127 (short form) +get_len:"7f":127 + +length=128 (1 length byte) +get_len:"8180":128 + +length=128 (2 length bytes) +get_len:"820080":128 + +length=255 (1 length byte) +get_len:"81ff":255 + +length=255 (2 length bytes) +get_len:"8200ff":255 + +length=256 (2 length bytes) +get_len:"820100":256 + +length=256 (3 length bytes) +get_len:"83000100":256 + +length=258 (2 length bytes) +get_len:"820102":258 + +length=258 (3 length bytes) +get_len:"83000102":258 + +length=65535 (2 length bytes) +get_len:"82ffff":65535 + +length=65535 (3 length bytes) +get_len:"8300ffff":65535 + +length=65535 (4 length bytes) +get_len:"840000ffff":65535 + +length=65536 (3 length bytes) +get_len:"83010000":65536 + +length=65536 (4 length bytes) +get_len:"8400010000":65536 + +length=16777215 (3 length bytes) +get_len:"83ffffff":16777215 + +length=16777215 (4 length bytes) +get_len:"8400ffffff":16777215 + +length=16777216 (4 length bytes) +get_len:"8401000000":16777216 + +length=16909060 (4 length bytes) +get_len:"8401020304":16909060 + +BOOLEAN FALSE +get_boolean:"010100":0:0 + +BOOLEAN TRUE (1) +get_boolean:"010101":1:0 + +BOOLEAN TRUE (2) +get_boolean:"010101":1:0 + +BOOLEAN TRUE (128) +get_boolean:"010180":1:0 + +BOOLEAN TRUE (255) +get_boolean:"0101ff":1:0 + +Not BOOLEAN +get_boolean:"020101":0:MBEDTLS_ERR_ASN1_UNEXPECTED_TAG + +Empty INTEGER +depends_on:SUPPORT_NEGATIVE_INTEGERS +get_integer:"0200":"":MBEDTLS_ERR_ASN1_INVALID_LENGTH + +INTEGER 0 +get_integer:"020100":"0":0 + +INTEGER 0, extra leading 0 +get_integer:"02020000":"0":0 + +INTEGER -0 +depends_on:SUPPORT_NEGATIVE_INTEGERS +get_integer:"020180":"0":0 + +INTEGER 1 +get_integer:"020101":"1":0: + +INTEGER 1, extra leading 0 +get_integer:"02020001":"1":0: + +INTEGER -1 +depends_on:SUPPORT_NEGATIVE_INTEGERS +get_integer:"020181":"-1":0 + +INTEGER 0x7f +get_integer:"02017f":"7f":0 + +INTEGER -0x7f +depends_on:SUPPORT_NEGATIVE_INTEGERS +get_integer:"0201ff":"-7f":0 + +INTEGER 0x80 +get_integer:"02020080":"80":0 + +INTEGER 0x80, extra leading 0 +get_integer:"0203000080":"80":0 + +INTEGER 0xff +get_integer:"020200ff":"ff":0 + +INTEGER 0x7fff +get_integer:"02027fff":"7fff":0 + +INTEGER 0x12345678 +get_integer:"020412345678":"12345678":0 + +INTEGER 0x12345678, extra leading 0 +get_integer:"02050012345678":"12345678":0 + +INTEGER 0x123456789abcdef0 +get_integer:"0208123456789abcdef0":"123456789abcdef0":0 + +INTEGER with 127 value octets +get_integer:"027f0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd":"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd":0 + +INTEGER with 127 value octets (long length encoding) +get_integer:"02817f0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd":"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd":0 + +INTEGER with 128 value octets +get_integer:"0281800123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef":"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef":0 + +INTEGER with 128 value octets (leading 0 in length) +get_integer:"028200800123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef":"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef":0 + +Not INTEGER +get_integer:"010101":"":MBEDTLS_ERR_ASN1_UNEXPECTED_TAG + +INTEGER too large for mpi +get_mpi_too_large: + +BIT STRING: empty +get_bitstring:"0300":0:0:MBEDTLS_ERR_ASN1_OUT_OF_DATA:MBEDTLS_ERR_ASN1_INVALID_DATA + +BIT STRING: octets=0, unused_bits=0 +get_bitstring:"030100":0:0:0:0 + +BIT STRING: octets=0, unused_bits=7 +get_bitstring:"030107":0:7:0:MBEDTLS_ERR_ASN1_INVALID_DATA + +BIT STRING: octets=0, unused_bits=8 +get_bitstring:"030108":0:0:MBEDTLS_ERR_ASN1_INVALID_LENGTH:MBEDTLS_ERR_ASN1_INVALID_DATA + +BIT STRING: octets=1, unused_bits=0 +get_bitstring:"03020041":1:0:0:0 + +BIT STRING: octets=1, unused_bits=7 +get_bitstring:"03020741":1:7:0:MBEDTLS_ERR_ASN1_INVALID_DATA + +BIT STRING: octets=1, unused_bits=8 +get_bitstring:"03020841":1:8:MBEDTLS_ERR_ASN1_INVALID_LENGTH:MBEDTLS_ERR_ASN1_INVALID_DATA + +BIT STRING: octets=2, unused_bits=0 +get_bitstring:"0303004142":2:0:0:0 + +BIT STRING: octets=2, unused_bits=7 +get_bitstring:"0303074142":2:7:0:MBEDTLS_ERR_ASN1_INVALID_DATA + +BIT STRING: octets=2, unused_bits=8 +get_bitstring:"0303084142":2:8:MBEDTLS_ERR_ASN1_INVALID_LENGTH:MBEDTLS_ERR_ASN1_INVALID_DATA + +BIT STRING with trailing garbage, unused_bits=0 +get_bitstring:"030200417e":1:0:MBEDTLS_ERR_ASN1_LENGTH_MISMATCH:0 + +BIT STRING with trailing garbage, unused_bits=7 +get_bitstring:"030207417e":1:7:MBEDTLS_ERR_ASN1_LENGTH_MISMATCH:MBEDTLS_ERR_ASN1_INVALID_DATA + +BIT STRING with trailing garbage, unused_bits=8 +get_bitstring:"030208417e":1:8:MBEDTLS_ERR_ASN1_INVALID_LENGTH:MBEDTLS_ERR_ASN1_INVALID_DATA + +Not BIT STRING +get_bitstring:"04020100":0:0:MBEDTLS_ERR_ASN1_UNEXPECTED_TAG:MBEDTLS_ERR_ASN1_UNEXPECTED_TAG + +SEQUENCE OF 0 OCTET STRING +get_sequence_of:"3000":0x04:"":0 + +SEQUENCE OF 0 OCTET STRING plus trailing garbage +get_sequence_of:"30007e":0x04:"":MBEDTLS_ERR_ASN1_LENGTH_MISMATCH + +SEQUENCE of 1 OCTET STRING truncated after tag +get_sequence_of:"300104":0x04:"":MBEDTLS_ERR_ASN1_OUT_OF_DATA + +SEQUENCE of 1 OCTET STRING truncated in length #1 +get_sequence_of:"30020481":0x04:"":MBEDTLS_ERR_ASN1_OUT_OF_DATA + +SEQUENCE of 1 OCTET STRING truncated in length #2 +get_sequence_of:"3003048201":0x04:"":MBEDTLS_ERR_ASN1_OUT_OF_DATA + +SEQUENCE of 1 OCTET STRING truncated in content #1 +get_sequence_of:"30020401":0x04:"":MBEDTLS_ERR_ASN1_OUT_OF_DATA + +SEQUENCE of 1 OCTET STRING truncated in content #2 +get_sequence_of:"3003040241":0x04:"":MBEDTLS_ERR_ASN1_OUT_OF_DATA + +SEQUENCE of 1 OCTET STRING truncated in content #3 +get_sequence_of:"300404034142":0x04:"":MBEDTLS_ERR_ASN1_OUT_OF_DATA + +SEQUENCE of 1 OCTET STRING (0) +get_sequence_of:"30020400":0x04:"4,0":0 + +SEQUENCE of 1 OCTET STRING (1) +get_sequence_of:"3003040141":0x04:"4,1":0 + +SEQUENCE of 1 OCTET STRING (126) +get_sequence_of:"308180047e414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141":0x04:"5,126":0 + +SEQUENCE of 2 OCTET STRINGs, second truncated after tag +get_sequence_of:"30050402414104":0x04:"":MBEDTLS_ERR_ASN1_OUT_OF_DATA + +SEQUENCE of 2 OCTET STRINGs, second truncated in length #1 +get_sequence_of:"3006040241410481":0x04:"":MBEDTLS_ERR_ASN1_OUT_OF_DATA + +SEQUENCE of 2 OCTET STRINGs, second truncated in length #2 +get_sequence_of:"300704024141048201":0x04:"":MBEDTLS_ERR_ASN1_OUT_OF_DATA + +SEQUENCE of 2 OCTET STRINGs, second truncated in content #1 +get_sequence_of:"3006040241410401":0x04:"":MBEDTLS_ERR_ASN1_OUT_OF_DATA + +SEQUENCE of 2 OCTET STRINGs, second truncated in content #2 +get_sequence_of:"300704024141040241":0x04:"":MBEDTLS_ERR_ASN1_OUT_OF_DATA + +SEQUENCE of 2 OCTET STRINGs, second truncated in content #3 +get_sequence_of:"30080402414104034142":0x04:"":MBEDTLS_ERR_ASN1_OUT_OF_DATA + +SEQUENCE of 2 OCTET STRINGs (2, 0) +get_sequence_of:"3006040241410400":0x04:"4,2,8,0":0 + +SEQUENCE of 2 OCTET STRINGs (2, 1) +get_sequence_of:"300704024141040142":0x04:"4,2,8,1":0 + +SEQUENCE of 2 OCTET STRINGs (0, 2) +get_sequence_of:"3006040004024141":0x04:"4,0,6,2":0 + +SEQUENCE of 2 OCTET STRINGs (1, 2) +get_sequence_of:"300704014104024242":0x04:"4,1,7,2":0 + +Not a SEQUENCE (not CONSTRUCTED) +get_sequence_of:"1000":0x04:"":MBEDTLS_ERR_ASN1_UNEXPECTED_TAG + +Not a SEQUENCE (not SEQUENCE) +get_sequence_of:"3100":0x04:"":MBEDTLS_ERR_ASN1_UNEXPECTED_TAG + +AlgorithmIdentifier, no params +get_alg:"300506034f4944":4:3:0:0:0:7:0 + +AlgorithmIdentifier, no params, trailing garbage +get_alg:"300506034f49447e":4:3:0:0:0:7:0 + +AlgorithmIdentifier, null params +get_alg:"300706034f49440500":4:3:0x05:9:0:9:0 + +AlgorithmIdentifier, null params, trailing garbage +get_alg:"300706034f494405007e":4:3:0x05:9:0:9:0 + +AlgorithmIdentifier, OCTET STRING params +get_alg:"300c06034f494404056162636465":4:3:0x04:9:5:14:0 + +AlgorithmIdentifier, truncated before OID +get_alg:"3000":4:3:0:0:0:2:MBEDTLS_ERR_ASN1_OUT_OF_DATA + +AlgorithmIdentifier, truncated in OID after tag +get_alg:"300106":0:0:0:0:0:3:MBEDTLS_ERR_ASN1_OUT_OF_DATA + +AlgorithmIdentifier, truncated in OID after length +get_alg:"30020603":4:3:0:0:0:4:MBEDTLS_ERR_ASN1_OUT_OF_DATA + +AlgorithmIdentifier, truncated inside OID content +get_alg:"300406034f49":4:3:0:0:0:6:MBEDTLS_ERR_ASN1_OUT_OF_DATA + +AlgorithmIdentifier, truncated in params after tag +get_alg:"300606034f494404":4:3:0x04:0:0:8:MBEDTLS_ERR_ASN1_OUT_OF_DATA + +AlgorithmIdentifier, truncated in params after length +get_alg:"300706034f49440405":4:3:0x04:9:0:9:MBEDTLS_ERR_ASN1_OUT_OF_DATA + +AlgorithmIdentifier, truncated inside params content +get_alg:"300806034f4944040561":4:3:0x04:9:5:10:MBEDTLS_ERR_ASN1_OUT_OF_DATA + +Not an AlgorithmIdentifier (not a SEQUENCE) +get_alg:"310506034f4944":0:0:0:0:0:0:MBEDTLS_ERR_ASN1_UNEXPECTED_TAG + +Not an AlgorithmIdentifier (empty SEQUENCE) +get_alg:"3000":0:0:0:0:0:0:MBEDTLS_ERR_ASN1_OUT_OF_DATA + +Not an AlgorithmIdentifier (not an OID) +get_alg:"3006050006034f4944":0:0:0:0:0:0:MBEDTLS_ERR_ASN1_UNEXPECTED_TAG + +Not an AlgorithmIdentifier (too many elements) +get_alg:"300f06034f494406034f494406034f4944":0:0:0:0:0:0:MBEDTLS_ERR_ASN1_LENGTH_MISMATCH + +Find named data: not found +find_named_data:"414141":"424242":"434343":"444444":"7f7f7f":0:4 + +Find named data: empty haystack +find_named_data:"414141":"424242":"434343":"444444":"7f7f7f":4:4 + +Find named data: first +find_named_data:"414141":"424242":"434343":"444444":"414141":0:0 + +Find named data: last +find_named_data:"414141":"424242":"434343":"444444":"444444":0:3 + +Find named data: skip suffix +find_named_data:"41414141":"414141":"434343":"444444":"414141":0:1 + +Find named data: skip prefix +find_named_data:"4141":"414141":"434343":"444444":"414141":0:1 + +Find named data: first match +find_named_data:"414141":"414141":"434343":"444444":"414141":0:0 + +Free named data: null pointer +free_named_data_null: + +Free named data: all null +free_named_data:0:0:0 + +Free named data: with oid +free_named_data:1:0:0 + +Free named data: with val +free_named_data:0:1:0 + +Free named data: with next +free_named_data:0:0:1 + +Free named data list (empty) +free_named_data_list:0 + +Free named data list (1) +free_named_data_list:0 + +Free named data list (2) +free_named_data_list:0 diff --git a/tests/suites/test_suite_asn1parse.function b/tests/suites/test_suite_asn1parse.function new file mode 100644 index 000000000..9e9f50949 --- /dev/null +++ b/tests/suites/test_suite_asn1parse.function @@ -0,0 +1,568 @@ +/* BEGIN_HEADER */ +#include +#include +#include + +#include "mbedtls/bignum.h" +#include "mbedtls/asn1.h" +#if defined(MBEDTLS_ASN1_WRITE_C) +#include "mbedtls/asn1write.h" +#endif + +#define ERR_PARSE_INCONSISTENCY INT_MAX + +static int nested_parse( unsigned char **const p, + const unsigned char *const end ) +{ + int ret; + size_t len = 0; + size_t len2 = 0; + unsigned char *const start = *p; + unsigned char *content_start; + unsigned char tag; + + /* First get the length, skipping over the tag. */ + content_start = start + 1; + ret = mbedtls_asn1_get_len( &content_start, end, &len ); + TEST_ASSERT( content_start <= end ); + if( ret != 0 ) + return( ret ); + + /* Since we have a valid element start (tag and length), retrieve and + * check the tag. */ + tag = start[0]; + TEST_EQUAL( mbedtls_asn1_get_tag( p, end, &len2, tag ^ 1 ), + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + *p = start; + TEST_EQUAL( mbedtls_asn1_get_tag( p, end, &len2, tag ), 0 ); + TEST_EQUAL( len, len2 ); + TEST_ASSERT( *p == content_start ); + *p = content_start; + + switch( tag & 0x1f ) + { + case MBEDTLS_ASN1_BOOLEAN: + { + int val = -257; + *p = start; + ret = mbedtls_asn1_get_bool( p, end, &val ); + if( ret == 0 ) + TEST_ASSERT( val == 0 || val == 1 ); + break; + } + + case MBEDTLS_ASN1_INTEGER: + { +#if defined(MBEDTLS_BIGNUM_C) + mbedtls_mpi mpi; + mbedtls_mpi_init( &mpi ); + *p = start; + ret = mbedtls_asn1_get_mpi( p, end, &mpi ); + mbedtls_mpi_free( &mpi ); +#endif + /* If we're sure that the number fits in an int, also + * call mbedtls_asn1_get_int(). */ + if( ret == 0 && len < sizeof( int ) ) + { + int val = -257; + unsigned char *q = start; + ret = mbedtls_asn1_get_int( &q, end, &val ); + TEST_ASSERT( *p == q ); + } + break; + } + + case MBEDTLS_ASN1_BIT_STRING: + { + mbedtls_asn1_bitstring bs; + *p = start; + ret = mbedtls_asn1_get_bitstring( p, end, &bs ); + break; + } + + case MBEDTLS_ASN1_SEQUENCE: + { + while( *p <= end && *p < content_start + len && ret == 0 ) + ret = nested_parse( p, content_start + len ); + break; + } + + case MBEDTLS_ASN1_OCTET_STRING: + case MBEDTLS_ASN1_NULL: + case MBEDTLS_ASN1_OID: + case MBEDTLS_ASN1_UTF8_STRING: + case MBEDTLS_ASN1_SET: + case MBEDTLS_ASN1_PRINTABLE_STRING: + case MBEDTLS_ASN1_T61_STRING: + case MBEDTLS_ASN1_IA5_STRING: + case MBEDTLS_ASN1_UTC_TIME: + case MBEDTLS_ASN1_GENERALIZED_TIME: + case MBEDTLS_ASN1_UNIVERSAL_STRING: + case MBEDTLS_ASN1_BMP_STRING: + default: + /* No further testing implemented for this tag. */ + *p += len; + return( 0 ); + } + + TEST_ASSERT( *p <= end ); + return( ret ); + +exit: + return( ERR_PARSE_INCONSISTENCY ); +} + +int get_len_step( const data_t *input, size_t buffer_size, + size_t actual_length ) +{ + unsigned char *buf = NULL; + unsigned char *p = NULL; + size_t parsed_length; + int ret; + + test_set_step( buffer_size ); + /* Allocate a new buffer of exactly the length to parse each time. + * This gives memory sanitizers a chance to catch buffer overreads. */ + if( buffer_size == 0 ) + { + ASSERT_ALLOC( buf, 1 ); + p = buf + 1; + } + else + { + ASSERT_ALLOC( buf, buffer_size ); + if( buffer_size > input->len ) + { + memcpy( buf, input->x, input->len ); + memset( buf + input->len, 'A', buffer_size - input->len ); + } + else + { + memcpy( buf, input->x, buffer_size ); + } + p = buf; + } + + ret = mbedtls_asn1_get_len( &p, buf + buffer_size, &parsed_length ); + + if( buffer_size >= input->len + actual_length ) + { + TEST_EQUAL( ret, 0 ); + TEST_ASSERT( p == buf + input->len ); + TEST_EQUAL( parsed_length, actual_length ); + } + else + { + TEST_EQUAL( ret, MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + } + mbedtls_free( buf ); + return( 1 ); + +exit: + /* It may be impossible to allocate large lengths on embedded platforms. + * Pass in this case (though it would be better to mark the test + * as skipped). */ + if( buf == NULL ) + return( 1 ); + + mbedtls_free( buf ); + return( 0 ); +} + +/* END_HEADER */ + +/* BEGIN_DEPENDENCIES + * depends_on:MBEDTLS_ASN1_PARSE_C + * END_DEPENDENCIES + */ + +/* BEGIN_CASE */ +void parse_prefixes( const data_t *input, + int actual_length_arg, + int last_result ) +{ + size_t actual_length = actual_length_arg; + unsigned char *buf = NULL; + unsigned char *p = NULL; + size_t buffer_size; + int ret; + + for( buffer_size = 1; buffer_size <= input->len; buffer_size++ ) + { + test_set_step( buffer_size ); + /* Allocate a new buffer of exactly the length to parse each time. + * This gives memory sanitizers a chance to catch buffer overreads. */ + ASSERT_ALLOC( buf, buffer_size ); + memcpy( buf, input->x, buffer_size ); + p = buf; + ret = nested_parse( &p, buf + buffer_size ); + if( ret == ERR_PARSE_INCONSISTENCY ) + goto exit; + if( actual_length > 0 && buffer_size >= actual_length ) + { + TEST_EQUAL( ret, last_result ); + if( ret == 0 ) + TEST_ASSERT( p == buf + actual_length ); + } + else + { + TEST_EQUAL( ret, MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + } + mbedtls_free( buf ); + buf = NULL; + } + +exit: + mbedtls_free( buf ); +} +/* END_CASE */ + +/* BEGIN_CASE */ +void get_len( const data_t *input, int actual_length_arg ) +{ + size_t actual_length = actual_length_arg; + size_t buffer_size; + + for( buffer_size = 1; buffer_size <= input->len + 1; buffer_size++ ) + { + if( ! get_len_step( input, buffer_size, actual_length ) ) + goto exit; + } + if( ! get_len_step( input, input->len + actual_length - 1, actual_length ) ) + goto exit; + if( ! get_len_step( input, input->len + actual_length, actual_length ) ) + goto exit; +} +/* END_CASE */ + +/* BEGIN_CASE */ +void get_boolean( const data_t *input, + int expected_value, int expected_result ) +{ + unsigned char *p = input->x; + int val; + int ret; + ret = mbedtls_asn1_get_bool( &p, input->x + input->len, &val ); + TEST_EQUAL( ret, expected_result ); + if( expected_result == 0 ) + { + TEST_EQUAL( val, expected_value ); + TEST_ASSERT( p == input->x + input->len ); + } +} +/* END_CASE */ + +/* BEGIN_CASE */ +void get_integer( const data_t *input, + const char *expected_hex, int expected_result ) +{ + unsigned char *p; +#if defined(MBEDTLS_BIGNUM_C) + mbedtls_mpi expected_mpi; + mbedtls_mpi actual_mpi; +#endif + long expected_value; + int expected_result_for_int = expected_result; + int expected_result_for_mpi = expected_result; + int val; + int ret; + +#if defined(MBEDTLS_BIGNUM_C) + mbedtls_mpi_init( &expected_mpi ); + mbedtls_mpi_init( &actual_mpi ); +#endif + + errno = 0; + expected_value = strtol( expected_hex, NULL, 16 ); + if( expected_result == 0 && + ( errno == ERANGE +#if LONG_MAX > INT_MAX + || expected_value > INT_MAX || expected_value < INT_MIN +#endif + ) ) + { + expected_result_for_int = MBEDTLS_ERR_ASN1_INVALID_LENGTH; + } + + p = input->x; + ret = mbedtls_asn1_get_int( &p, input->x + input->len, &val ); + TEST_EQUAL( ret, expected_result_for_int ); + if( ret == 0 ) + { + TEST_EQUAL( val, expected_value ); + TEST_ASSERT( p == input->x + input->len ); + } + +#if defined(MBEDTLS_BIGNUM_C) + ret = mbedtls_mpi_read_string( &expected_mpi, 16, expected_hex ); + TEST_ASSERT( ret == 0 || ret == MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + if( ret == MBEDTLS_ERR_MPI_BAD_INPUT_DATA ) + { + /* The data overflows the maximum MPI size. */ + expected_result_for_mpi = MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + p = input->x; + ret = mbedtls_asn1_get_mpi( &p, input->x + input->len, &actual_mpi ); + TEST_EQUAL( ret, expected_result_for_mpi ); + if( ret == 0 ) + { + TEST_ASSERT( mbedtls_mpi_cmp_mpi( &actual_mpi , &expected_mpi ) == 0 ); + TEST_ASSERT( p == input->x + input->len ); + } +#endif + +exit: +#if defined(MBEDTLS_BIGNUM_C) + mbedtls_mpi_free( &expected_mpi ); + mbedtls_mpi_free( &actual_mpi ); +#endif +} +/* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_BIGNUM_C */ +void get_mpi_too_large( ) +{ + unsigned char *buf = NULL; + unsigned char *p; + mbedtls_mpi actual_mpi; + size_t too_many_octets = + MBEDTLS_MPI_MAX_LIMBS * sizeof(mbedtls_mpi_uint) + 1; + size_t size = too_many_octets + 6; + + mbedtls_mpi_init( &actual_mpi ); + + ASSERT_ALLOC( buf, size ); + buf[0] = 0x02; /* tag: INTEGER */ + buf[1] = 0x84; /* 4-octet length */ + buf[2] = ( too_many_octets >> 24 ) & 0xff; + buf[3] = ( too_many_octets >> 16 ) & 0xff; + buf[4] = ( too_many_octets >> 8 ) & 0xff; + buf[5] = too_many_octets & 0xff; + buf[6] = 0x01; /* most significant octet */ + + p = buf; + TEST_EQUAL( mbedtls_asn1_get_mpi( &p, buf + size, &actual_mpi ), + MBEDTLS_ERR_MPI_ALLOC_FAILED ); + +exit: + mbedtls_mpi_free( &actual_mpi ); + mbedtls_free( buf ); +} +/* END_CASE */ + +/* BEGIN_CASE */ +void get_bitstring( const data_t *input, + int expected_length, int expected_unused_bits, + int expected_result, int expected_result_null ) +{ + mbedtls_asn1_bitstring bs = { 0xdead, 0x21, NULL }; + unsigned char *p = input->x; + + TEST_EQUAL( mbedtls_asn1_get_bitstring( &p, input->x + input->len, &bs ), + expected_result ); + if( expected_result == 0 ) + { + TEST_EQUAL( bs.len, (size_t) expected_length ); + TEST_EQUAL( bs.unused_bits, expected_unused_bits ); + TEST_ASSERT( bs.p != NULL ); + TEST_EQUAL( bs.p - input->x + bs.len, input->len ); + TEST_ASSERT( p == input->x + input->len ); + } + + p = input->x; + TEST_EQUAL( mbedtls_asn1_get_bitstring_null( &p, input->x + input->len, + &bs.len ), + expected_result_null ); + if( expected_result_null == 0 ) + { + TEST_EQUAL( bs.len, (size_t) expected_length ); + if( expected_result == 0 ) + TEST_ASSERT( p == input->x + input->len - bs.len ); + } +} +/* END_CASE */ + +/* BEGIN_CASE */ +void get_sequence_of( const data_t *input, int tag, + const char *description, + int expected_result ) +{ + mbedtls_asn1_sequence head = { { 0, 0, NULL }, NULL }; + mbedtls_asn1_sequence *cur, *next; + unsigned char *p = input->x; + const char *rest = description; + unsigned long n; + + TEST_EQUAL( mbedtls_asn1_get_sequence_of( &p, input->x + input->len, + &head, tag ), + expected_result ); + if( expected_result == 0 ) + { + TEST_ASSERT( p == input->x + input->len ); + + if( ! *rest ) + { + TEST_EQUAL( head.buf.tag, 0 ); + TEST_ASSERT( head.buf.p == NULL ); + TEST_EQUAL( head.buf.len, 0 ); + TEST_ASSERT( head.next == NULL ); + } + else + { + cur = &head; + while( *rest ) + { + ++test_info.step; + TEST_ASSERT( cur != NULL ); + TEST_EQUAL( cur->buf.tag, tag ); + n = strtoul( rest, (char **) &rest, 0 ); + TEST_EQUAL( n, (size_t)( cur->buf.p - input->x ) ); + ++rest; + n = strtoul( rest, (char **) &rest, 0 ); + TEST_EQUAL( n, cur->buf.len ); + if( *rest ) + ++rest; + cur = cur->next; + } + TEST_ASSERT( cur == NULL ); + } + } + +exit: + cur = head.next; + while( cur != NULL ) + { + next = cur->next; + mbedtls_free( cur ); + cur = next; + } +} +/* END_CASE */ + +/* BEGIN_CASE */ +void get_alg( const data_t *input, + int oid_offset, int oid_length, + int params_tag, int params_offset, int params_length, + int total_length, + int expected_result ) +{ + mbedtls_asn1_buf oid = { -1, 0, NULL }; + mbedtls_asn1_buf params = { -1, 0, NULL }; + unsigned char *p = input->x; + int ret; + + TEST_EQUAL( mbedtls_asn1_get_alg( &p, input->x + input->len, + &oid, ¶ms ), + expected_result ); + if( expected_result == 0 ) + { + TEST_EQUAL( oid.tag, MBEDTLS_ASN1_OID ); + TEST_EQUAL( oid.p - input->x, oid_offset ); + TEST_EQUAL( oid.len, (size_t) oid_length ); + TEST_EQUAL( params.tag, params_tag ); + if( params_offset != 0 ) + TEST_EQUAL( params.p - input->x, params_offset ); + else + TEST_ASSERT( params.p == NULL ); + TEST_EQUAL( params.len, (size_t) params_length ); + TEST_EQUAL( p - input->x, total_length ); + } + + ret = mbedtls_asn1_get_alg_null( &p, input->x + input->len, &oid ); + if( expected_result == 0 && params_offset == 0 ) + { + TEST_EQUAL( oid.tag, MBEDTLS_ASN1_OID ); + TEST_EQUAL( oid.p - input->x, oid_offset ); + TEST_EQUAL( oid.len, (size_t) oid_length ); + TEST_EQUAL( p - input->x, total_length ); + } + else + TEST_ASSERT( ret != 0 ); +} +/* END_CASE */ + +/* BEGIN_CASE */ +void find_named_data( data_t *oid0, data_t *oid1, data_t *oid2, data_t *oid3, + data_t *needle, int from, int position ) +{ + mbedtls_asn1_named_data nd[] ={ + { {0x06, oid0->len, oid0->x}, {0, 0, NULL}, NULL, 0 }, + { {0x06, oid1->len, oid1->x}, {0, 0, NULL}, NULL, 0 }, + { {0x06, oid2->len, oid2->x}, {0, 0, NULL}, NULL, 0 }, + { {0x06, oid3->len, oid3->x}, {0, 0, NULL}, NULL, 0 }, + }; + mbedtls_asn1_named_data *pointers[ARRAY_LENGTH( nd ) + 1]; + size_t i; + mbedtls_asn1_named_data *found; + + for( i = 0; i < ARRAY_LENGTH( nd ); i++ ) + pointers[i] = &nd[i]; + pointers[ARRAY_LENGTH( nd )] = NULL; + for( i = 0; i < ARRAY_LENGTH( nd ); i++ ) + nd[i].next = pointers[i+1]; + + found = mbedtls_asn1_find_named_data( pointers[from], + (const char *) needle->x, + needle->len ); + TEST_ASSERT( found == pointers[position] ); +} +/* END_CASE */ + +/* BEGIN_CASE */ +void free_named_data_null( ) +{ + mbedtls_asn1_free_named_data( NULL ); + goto exit; /* Silence unused label warning */ +} +/* END_CASE */ + +/* BEGIN_CASE */ +void free_named_data( int with_oid, int with_val, int with_next ) +{ + mbedtls_asn1_named_data next = + { {0x06, 0, NULL}, {0, 0xcafe, NULL}, NULL, 0 }; + mbedtls_asn1_named_data head = + { {0x06, 0, NULL}, {0, 0, NULL}, NULL, 0 }; + + if( with_oid ) + ASSERT_ALLOC( head.oid.p, 1 ); + if( with_val ) + ASSERT_ALLOC( head.val.p, 1 ); + if( with_next ) + head.next = &next; + + mbedtls_asn1_free_named_data( &head ); + TEST_ASSERT( head.oid.p == NULL ); + TEST_ASSERT( head.val.p == NULL ); + TEST_ASSERT( head.next == NULL ); + TEST_ASSERT( next.val.len == 0xcafe ); + +exit: + mbedtls_free( head.oid.p ); + mbedtls_free( head.val.p ); +} +/* END_CASE */ + +/* BEGIN_CASE */ +void free_named_data_list( int length ) +{ + mbedtls_asn1_named_data *head = NULL; + int i; + + for( i = 0; i < length; i++ ) + { + mbedtls_asn1_named_data *new = NULL; + ASSERT_ALLOC( new, sizeof( mbedtls_asn1_named_data ) ); + head->next = new; + head = new; + } + + mbedtls_asn1_free_named_data_list( &head ); + TEST_ASSERT( head == NULL ); + /* Most of the point of the test is that it doesn't leak memory. + * So this test is only really useful under a memory leak detection + * framework. */ +exit: + mbedtls_asn1_free_named_data_list( &head ); +} +/* END_CASE */