Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 22 additions & 4 deletions include/mbedtls/asn1.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
#define MBEDTLS_ASN1_OCTET_STRING 0x04
#define MBEDTLS_ASN1_NULL 0x05
#define MBEDTLS_ASN1_OID 0x06
#define MBEDTLS_ASN1_ENUMERATED 0x0A
#define MBEDTLS_ASN1_UTF8_STRING 0x0C
#define MBEDTLS_ASN1_SEQUENCE 0x10
#define MBEDTLS_ASN1_SET 0x11
Expand Down Expand Up @@ -254,13 +255,32 @@ int mbedtls_asn1_get_bool( unsigned char **p,
* a valid ASN.1 INTEGER.
* \return #MBEDTLS_ERR_ASN1_INVALID_LENGTH if the parsed value does
* not fit in an \c int.
* \return An ASN.1 error code if the input does not start with
* a valid ASN.1 INTEGER.
*/
int mbedtls_asn1_get_int( unsigned char **p,
const unsigned char *end,
int *val );

/**
* \brief Retrieve an enumerated ASN.1 tag and its value.
* Updates the pointer to immediately behind the full tag.
*
* \param p On entry, \c *p points to the start of the ASN.1 element.
* On successful completion, \c *p points to the first byte
* beyond the ASN.1 element.
* On error, the value of \c *p is undefined.
* \param end End of data.
* \param val On success, the parsed value.
*
* \return 0 if successful.
* \return An ASN.1 error code if the input does not start with
* a valid ASN.1 ENUMERATED.
* \return #MBEDTLS_ERR_ASN1_INVALID_LENGTH if the parsed value does
* not fit in an \c int.
*/
int mbedtls_asn1_get_enum( unsigned char **p,
const unsigned char *end,
int *val );

/**
* \brief Retrieve a bitstring ASN.1 tag and its value.
* Updates the pointer to immediately behind the full tag.
Expand Down Expand Up @@ -367,8 +387,6 @@ int mbedtls_asn1_get_sequence_of( unsigned char **p,
* \return #MBEDTLS_ERR_ASN1_INVALID_LENGTH if the parsed value does
* not fit in an \c int.
* \return An MPI error code if the parsed value is too large.
* \return An ASN.1 error code if the input does not start with
* a valid ASN.1 INTEGER.
*/
int mbedtls_asn1_get_mpi( unsigned char **p,
const unsigned char *end,
Expand Down
15 changes: 15 additions & 0 deletions include/mbedtls/asn1write.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,21 @@ int mbedtls_asn1_write_bool( unsigned char **p, unsigned char *start,
*/
int mbedtls_asn1_write_int( unsigned char **p, unsigned char *start, int val );

/**
* \brief Write an enum tag (#MBEDTLS_ASN1_ENUMERATED) and value
* in ASN.1 format.
*
* \note This function works backwards in data buffer.
*
* \param p The reference to the current position pointer.
* \param start The start of the buffer, for bounds-checking.
* \param val The integer value to write.
*
* \return The number of bytes written to \p p on success.
* \return A negative \c MBEDTLS_ERR_ASN1_XXX error code on failure.
*/
int mbedtls_asn1_write_enum( unsigned char **p, unsigned char *start, int val );

/**
* \brief Write a string in ASN.1 format using a specific
* string encoding tag.
Expand Down
27 changes: 22 additions & 5 deletions library/asn1parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,17 +139,20 @@ int mbedtls_asn1_get_bool( unsigned char **p,
return( 0 );
}

int mbedtls_asn1_get_int( unsigned char **p,
const unsigned char *end,
int *val )
static int asn1_get_tagged_int( unsigned char **p,
const unsigned char *end,
int tag, int *val )
{
int ret;
size_t len;

if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_INTEGER ) ) != 0 )
if( ( ret = mbedtls_asn1_get_tag( p, end, &len, tag ) ) != 0 )
return( ret );

/* len==0 is malformed (0 must be represented as 020100). */
/*
* len==0 is malformed (0 must be represented as 020100 for INTEGER,
* or 0A0100 for ENUMERATED tags
*/
if( len == 0 )
return( MBEDTLS_ERR_ASN1_INVALID_LENGTH );
/* This is a cryptography library. Reject negative integers. */
Expand Down Expand Up @@ -180,6 +183,20 @@ int mbedtls_asn1_get_int( unsigned char **p,
return( 0 );
}

int mbedtls_asn1_get_int( unsigned char **p,
const unsigned char *end,
int *val )
{
return( asn1_get_tagged_int( p, end, MBEDTLS_ASN1_INTEGER, val) );
}

int mbedtls_asn1_get_enum( unsigned char **p,
const unsigned char *end,
int *val )
{
return( asn1_get_tagged_int( p, end, MBEDTLS_ASN1_ENUMERATED, val) );
}

#if defined(MBEDTLS_BIGNUM_C)
int mbedtls_asn1_get_mpi( unsigned char **p,
const unsigned char *end,
Expand Down
14 changes: 12 additions & 2 deletions library/asn1write.c
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ int mbedtls_asn1_write_bool( unsigned char **p, unsigned char *start, int boolea
return( (int) len );
}

int mbedtls_asn1_write_int( unsigned char **p, unsigned char *start, int val )
static int asn1_write_tagged_int( unsigned char **p, unsigned char *start, int val, int tag )
{
int ret;
size_t len = 0;
Expand All @@ -255,11 +255,21 @@ int mbedtls_asn1_write_int( unsigned char **p, unsigned char *start, int val )
}

MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_INTEGER ) );
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, tag ) );

return( (int) len );
}

int mbedtls_asn1_write_int( unsigned char **p, unsigned char *start, int val )
{
return( asn1_write_tagged_int( p, start, val, MBEDTLS_ASN1_INTEGER ) );
}

int mbedtls_asn1_write_enum( unsigned char **p, unsigned char *start, int val )
{
return( asn1_write_tagged_int( p, start, val, MBEDTLS_ASN1_ENUMERATED ) );
}

int mbedtls_asn1_write_tagged_string( unsigned char **p, unsigned char *start, int tag,
const char *text, size_t text_len )
{
Expand Down
84 changes: 84 additions & 0 deletions tests/suites/test_suite_asn1parse.data
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,90 @@ get_integer:"010101":"":MBEDTLS_ERR_ASN1_UNEXPECTED_TAG
INTEGER too large for mpi
get_mpi_too_large:

ENUMERATED 0
get_enum:"0A0100":"0":0

ENUMERATED 0, extra leading 0
get_enum:"0A020000":"0":0

ENUMERATED 1
get_enum:"0A0101":"1":0

ENUMERATED 1, extra leading 0
get_enum:"0A020001":"1":0

ENUMERATED 0x7f
get_enum:"0A017f":"7f":0

ENUMERATED 0x80
get_enum:"0A020080":"80":0

ENUMERATED 0x80, extra leading 0
get_enum:"0A03000080":"80":0

ENUMERATED 0xff
get_enum:"0A0200ff":"ff":0

ENUMERATED 0x7fff
get_enum:"0A027fff":"7fff":0

ENUMERATED 0x12345678
get_enum:"0A0412345678":"12345678":0

ENUMERATED 0x12345678, extra leading 0
get_enum:"0A050012345678":"12345678":0

ENUMERATED 0x7fffffff
get_enum:"0A047fffffff":"7fffffff":0

ENUMERATED 0x7fffffff, extra leading 0
get_enum:"0A05007fffffff":"7fffffff":0

ENUMERATED 0x80000000
get_enum:"0A050080000000":"80000000":0

ENUMERATED 0xffffffff
get_enum:"0A0500ffffffff":"ffffffff":0

ENUMERATED 0x100000000
get_enum:"0A050100000000":"0100000000":0

ENUMERATED -1
get_enum:"0A01ff":"-1":0

ENUMERATED -1, extra leading ff
get_enum:"0A02ffff":"-1":0

ENUMERATED -0x7f
get_enum:"0A0181":"-7f":0

ENUMERATED -0x80
get_enum:"0A0180":"-80":0

ENUMERATED -0x81
get_enum:"0A02ff7f":"-81":0

ENUMERATED -0xff
get_enum:"0A02ff01":"-ff":0

ENUMERATED -0x100
get_enum:"0A02ff00":"-100":0

ENUMERATED -0x7fffffff
get_enum:"0A0480000001":"-7fffffff":0

ENUMERATED -0x80000000
get_enum:"0A0480000000":"-80000000":0

ENUMERATED -0x80000001
get_enum:"0A05ff7fffffff":"-80000001":0

ENUMERATED -0xffffffff
get_enum:"0A05ff00000001":"-ffffffff":0

ENUMERATED -0x100000000
get_enum:"0A05ff00000000":"-100000000":0

BIT STRING: empty
get_bitstring:"0300":0:0:MBEDTLS_ERR_ASN1_OUT_OF_DATA:MBEDTLS_ERR_ASN1_INVALID_DATA

Expand Down
43 changes: 43 additions & 0 deletions tests/suites/test_suite_asn1parse.function
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,49 @@ exit:
}
/* END_CASE */

/* BEGIN_CASE */
void get_enum( const data_t *input,
const char *expected_hex, int expected_result )
{
unsigned char *p;
long expected_value;
int expected_result_for_enum = expected_result;
int val;
int ret;

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
) )
{
/* The library returns the dubious error code INVALID_LENGTH
* for integers that are out of range. */
expected_result_for_enum = MBEDTLS_ERR_ASN1_INVALID_LENGTH;
}
if( expected_result == 0 && expected_value < 0 )
{
/* The library does not support negative INTEGERs and
* returns the dubious error code INVALID_LENGTH.
* Test that we preserve the historical behavior. If we
* decide to change the behavior, we'll also change this test. */
expected_result_for_enum = MBEDTLS_ERR_ASN1_INVALID_LENGTH;
}

p = input->x;
ret = mbedtls_asn1_get_enum( &p, input->x + input->len, &val );
TEST_EQUAL( ret, expected_result_for_enum );
if( ret == 0 )
{
TEST_EQUAL( val, expected_value );
TEST_ASSERT( p == input->x + input->len );
}
}
/* END_CASE */

/* BEGIN_CASE depends_on:MBEDTLS_BIGNUM_C */
void get_mpi_too_large( )
{
Expand Down
42 changes: 42 additions & 0 deletions tests/suites/test_suite_asn1write.data
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,48 @@ mbedtls_asn1_write_int:0x12345678:"020412345678"
ASN.1 Write int 2147483647
mbedtls_asn1_write_int:0x7fffffff:"02047fffffff"

ASN.1 Write enum 0
mbedtls_asn1_write_enum:0:"0A0100"

ASN.1 Write enum 1
mbedtls_asn1_write_enum:1:"0A0101"

ASN.1 Write enum 127
mbedtls_asn1_write_enum:0x7f:"0A017f"

ASN.1 Write enum 128
mbedtls_asn1_write_enum:0x80:"0A020080"

ASN.1 Write enum 255
mbedtls_asn1_write_enum:0xff:"0A0200ff"

ASN.1 Write enum 256
mbedtls_asn1_write_enum:0x100:"0A020100"

ASN.1 Write enum 32767
mbedtls_asn1_write_enum:0x7fff:"0A027fff"

ASN.1 Write enum 32768
mbedtls_asn1_write_enum:0x8000:"0A03008000"

ASN.1 Write enum 65535
mbedtls_asn1_write_enum:0xffff:"0A0300ffff"

ASN.1 Write enum 65536
mbedtls_asn1_write_enum:0x10000:"0A03010000"

ASN.1 Write enum 8388607
mbedtls_asn1_write_enum:0x7fffff:"0A037fffff"

ASN.1 Write enum 8388608
mbedtls_asn1_write_enum:0x800000:"0A0400800000"

ASN.1 Write enum 0x12345678
mbedtls_asn1_write_enum:0x12345678:"0A0412345678"

ASN.1 Write enum 2147483647
mbedtls_asn1_write_enum:0x7fffffff:"0A047fffffff"

#ASN.1 Write mpi 0
#mbedtls_asn1_write_mpi:"00":"020100"

Expand Down
21 changes: 21 additions & 0 deletions tests/suites/test_suite_asn1write.function
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,27 @@ exit:
}
/* END_CASE */


/* BEGIN_CASE */
void mbedtls_asn1_write_enum( int val, data_t *expected )
{
generic_write_data_t data = { NULL, NULL, NULL, NULL, 0 };
int ret;

for( data.size = 0; data.size < expected->len + 1; data.size++ )
{
if( ! generic_write_start_step( &data ) )
goto exit;
ret = mbedtls_asn1_write_enum( &data.p, data.start, val );
if( ! generic_write_finish_step( &data, expected, ret ) )
goto exit;
}

exit:
mbedtls_free( data.output );
}
/* END_CASE */

/* BEGIN_CASE depends_on:MBEDTLS_BIGNUM_C */
void mbedtls_asn1_write_mpi( data_t *val, data_t *expected )
{
Expand Down