Merge pull request #263 from hanno-arm/asn1_traversal_api
Introduce ASN.1 SEQUENCE traversal API
This commit is contained in:
commit
c69c2c5bf5
4 changed files with 379 additions and 52 deletions
|
@ -90,6 +90,18 @@
|
||||||
#define MBEDTLS_ASN1_CONSTRUCTED 0x20
|
#define MBEDTLS_ASN1_CONSTRUCTED 0x20
|
||||||
#define MBEDTLS_ASN1_CONTEXT_SPECIFIC 0x80
|
#define MBEDTLS_ASN1_CONTEXT_SPECIFIC 0x80
|
||||||
|
|
||||||
|
/* Slightly smaller way to check if tag is a string tag
|
||||||
|
* compared to canonical implementation. */
|
||||||
|
#define MBEDTLS_ASN1_IS_STRING_TAG( tag ) \
|
||||||
|
( ( tag ) < 32u && ( \
|
||||||
|
( ( 1u << ( tag ) ) & ( ( 1u << MBEDTLS_ASN1_BMP_STRING ) | \
|
||||||
|
( 1u << MBEDTLS_ASN1_UTF8_STRING ) | \
|
||||||
|
( 1u << MBEDTLS_ASN1_T61_STRING ) | \
|
||||||
|
( 1u << MBEDTLS_ASN1_IA5_STRING ) | \
|
||||||
|
( 1u << MBEDTLS_ASN1_UNIVERSAL_STRING ) | \
|
||||||
|
( 1u << MBEDTLS_ASN1_PRINTABLE_STRING ) | \
|
||||||
|
( 1u << MBEDTLS_ASN1_BIT_STRING ) ) ) != 0 ) )
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Bit masks for each of the components of an ASN.1 tag as specified in
|
* Bit masks for each of the components of an ASN.1 tag as specified in
|
||||||
* ITU X.690 (08/2015), section 8.1 "General rules for encoding",
|
* ITU X.690 (08/2015), section 8.1 "General rules for encoding",
|
||||||
|
@ -120,6 +132,10 @@
|
||||||
( ( MBEDTLS_OID_SIZE(oid_str) != (oid_buf)->len ) || \
|
( ( MBEDTLS_OID_SIZE(oid_str) != (oid_buf)->len ) || \
|
||||||
memcmp( (oid_str), (oid_buf)->p, (oid_buf)->len) != 0 )
|
memcmp( (oid_str), (oid_buf)->p, (oid_buf)->len) != 0 )
|
||||||
|
|
||||||
|
#define MBEDTLS_OID_CMP_RAW(oid_str, oid_buf, oid_buf_len) \
|
||||||
|
( ( MBEDTLS_OID_SIZE(oid_str) != (oid_buf_len) ) || \
|
||||||
|
memcmp( (oid_str), (oid_buf), (oid_buf_len) ) != 0 )
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
@ -327,6 +343,9 @@ int mbedtls_asn1_get_bitstring_null( unsigned char **p,
|
||||||
* \brief Parses and splits an ASN.1 "SEQUENCE OF <tag>".
|
* \brief Parses and splits an ASN.1 "SEQUENCE OF <tag>".
|
||||||
* Updates the pointer to immediately behind the full sequence tag.
|
* Updates the pointer to immediately behind the full sequence tag.
|
||||||
*
|
*
|
||||||
|
* This function allocates memory for the sequence elements. You can free
|
||||||
|
* the allocated memory with mbedtls_asn1_sequence_free().
|
||||||
|
*
|
||||||
* \note On error, this function may return a partial list in \p cur.
|
* \note On error, this function may return a partial list in \p cur.
|
||||||
* You must set `cur->next = NULL` before calling this function!
|
* You must set `cur->next = NULL` before calling this function!
|
||||||
* Otherwise it is impossible to distinguish a previously non-null
|
* Otherwise it is impossible to distinguish a previously non-null
|
||||||
|
@ -360,14 +379,133 @@ int mbedtls_asn1_get_bitstring_null( unsigned char **p,
|
||||||
* \return 0 if successful.
|
* \return 0 if successful.
|
||||||
* \return #MBEDTLS_ERR_ASN1_LENGTH_MISMATCH if the input contains
|
* \return #MBEDTLS_ERR_ASN1_LENGTH_MISMATCH if the input contains
|
||||||
* extra data after a valid SEQUENCE OF \p tag.
|
* extra data after a valid SEQUENCE OF \p tag.
|
||||||
|
* \return #MBEDTLS_ERR_ASN1_UNEXPECTED_TAG if the input starts with
|
||||||
|
* an ASN.1 SEQUENCE in which an element has a tag that
|
||||||
|
* is different from \p tag.
|
||||||
* \return #MBEDTLS_ERR_ASN1_ALLOC_FAILED if a memory allocation failed.
|
* \return #MBEDTLS_ERR_ASN1_ALLOC_FAILED if a memory allocation failed.
|
||||||
* \return An ASN.1 error code if the input does not start with
|
* \return An ASN.1 error code if the input does not start with
|
||||||
* a valid ASN.1 BIT STRING.
|
* a valid ASN.1 SEQUENCE.
|
||||||
*/
|
*/
|
||||||
int mbedtls_asn1_get_sequence_of( unsigned char **p,
|
int mbedtls_asn1_get_sequence_of( unsigned char **p,
|
||||||
const unsigned char *end,
|
const unsigned char *end,
|
||||||
mbedtls_asn1_sequence *cur,
|
mbedtls_asn1_sequence *cur,
|
||||||
int tag );
|
int tag );
|
||||||
|
/**
|
||||||
|
* \brief Free a heap-allocated linked list presentation of
|
||||||
|
* an ASN.1 sequence, including the first element.
|
||||||
|
*
|
||||||
|
* There are two common ways to manage the memory used for the representation
|
||||||
|
* of a parsed ASN.1 sequence:
|
||||||
|
* - Allocate a head node `mbedtls_asn1_sequence *head` with mbedtls_calloc().
|
||||||
|
* Pass this node as the `cur` argument to mbedtls_asn1_get_sequence_of().
|
||||||
|
* When you have finished processing the sequence,
|
||||||
|
* call mbedtls_asn1_sequence_free() on `head`.
|
||||||
|
* - Allocate a head node `mbedtls_asn1_sequence *head` in any manner,
|
||||||
|
* for example on the stack. Make sure that `head->next == NULL`.
|
||||||
|
* Pass `head` as the `cur` argument to mbedtls_asn1_get_sequence_of().
|
||||||
|
* When you have finished processing the sequence,
|
||||||
|
* call mbedtls_asn1_sequence_free() on `head->cur`,
|
||||||
|
* then free `head` itself in the appropriate manner.
|
||||||
|
*
|
||||||
|
* \param seq The address of the first sequence component. This may
|
||||||
|
* be \c NULL, in which case this functions returns
|
||||||
|
* immediately.
|
||||||
|
*/
|
||||||
|
void mbedtls_asn1_sequence_free( mbedtls_asn1_sequence *seq );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Traverse an ASN.1 SEQUENCE container and
|
||||||
|
* call a callback for each entry.
|
||||||
|
*
|
||||||
|
* This function checks that the input is a SEQUENCE of elements that
|
||||||
|
* each have a "must" tag, and calls a callback function on the elements
|
||||||
|
* that have a "may" tag.
|
||||||
|
*
|
||||||
|
* For example, to validate that the input is a SEQUENCE of `tag1` and call
|
||||||
|
* `cb` on each element, use
|
||||||
|
* ```
|
||||||
|
* mbedtls_asn1_traverse_sequence_of(&p, end, 0xff, tag1, 0, 0, cb, ctx);
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* To validate that the input is a SEQUENCE of ANY and call `cb` on
|
||||||
|
* each element, use
|
||||||
|
* ```
|
||||||
|
* mbedtls_asn1_traverse_sequence_of(&p, end, 0, 0, 0, 0, cb, ctx);
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* To validate that the input is a SEQUENCE of CHOICE {NULL, OCTET STRING}
|
||||||
|
* and call `cb` on each element that is an OCTET STRING, use
|
||||||
|
* ```
|
||||||
|
* mbedtls_asn1_traverse_sequence_of(&p, end, 0xfe, 0x04, 0xff, 0x04, cb, ctx);
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* The callback is called on the elements with a "may" tag from left to
|
||||||
|
* right. If the input is not a valid SEQUENCE of elements with a "must" tag,
|
||||||
|
* the callback is called on the elements up to the leftmost point where
|
||||||
|
* the input is invalid.
|
||||||
|
*
|
||||||
|
* \warning This function is still experimental and may change
|
||||||
|
* at any time.
|
||||||
|
*
|
||||||
|
* \param p The address of the pointer to the beginning of
|
||||||
|
* the ASN.1 SEQUENCE header. This is updated to
|
||||||
|
* point to the end of the ASN.1 SEQUENCE container
|
||||||
|
* on a successful invocation.
|
||||||
|
* \param end The end of the ASN.1 SEQUENCE container.
|
||||||
|
* \param tag_must_mask A mask to be applied to the ASN.1 tags found within
|
||||||
|
* the SEQUENCE before comparing to \p tag_must_value.
|
||||||
|
* \param tag_must_val The required value of each ASN.1 tag found in the
|
||||||
|
* SEQUENCE, after masking with \p tag_must_mask.
|
||||||
|
* Mismatching tags lead to an error.
|
||||||
|
* For example, a value of \c 0 for both \p tag_must_mask
|
||||||
|
* and \p tag_must_val means that every tag is allowed,
|
||||||
|
* while a value of \c 0xFF for \p tag_must_mask means
|
||||||
|
* that \p tag_must_val is the only allowed tag.
|
||||||
|
* \param tag_may_mask A mask to be applied to the ASN.1 tags found within
|
||||||
|
* the SEQUENCE before comparing to \p tag_may_value.
|
||||||
|
* \param tag_may_val The desired value of each ASN.1 tag found in the
|
||||||
|
* SEQUENCE, after masking with \p tag_may_mask.
|
||||||
|
* Mismatching tags will be silently ignored.
|
||||||
|
* For example, a value of \c 0 for \p tag_may_mask and
|
||||||
|
* \p tag_may_val means that any tag will be considered,
|
||||||
|
* while a value of \c 0xFF for \p tag_may_mask means
|
||||||
|
* that all tags with value different from \p tag_may_val
|
||||||
|
* will be ignored.
|
||||||
|
* \param cb The callback to trigger for each component
|
||||||
|
* in the ASN.1 SEQUENCE that matches \p tag_may_val.
|
||||||
|
* The callback function is called with the following
|
||||||
|
* parameters:
|
||||||
|
* - \p ctx.
|
||||||
|
* - The tag of the current element.
|
||||||
|
* - A pointer to the start of the current element's
|
||||||
|
* content inside the input.
|
||||||
|
* - The length of the content of the current element.
|
||||||
|
* If the callback returns a non-zero value,
|
||||||
|
* the function stops immediately,
|
||||||
|
* forwarding the callback's return value.
|
||||||
|
* \param ctx The context to be passed to the callback \p cb.
|
||||||
|
*
|
||||||
|
* \return \c 0 if successful the entire ASN.1 SEQUENCE
|
||||||
|
* was traversed without parsing or callback errors.
|
||||||
|
* \return #MBEDTLS_ERR_ASN1_LENGTH_MISMATCH if the input
|
||||||
|
* contains extra data after a valid SEQUENCE
|
||||||
|
* of elements with an accepted tag.
|
||||||
|
* \return #MBEDTLS_ERR_ASN1_UNEXPECTED_TAG if the input starts
|
||||||
|
* with an ASN.1 SEQUENCE in which an element has a tag
|
||||||
|
* that is not accepted.
|
||||||
|
* \return An ASN.1 error code if the input does not start with
|
||||||
|
* a valid ASN.1 SEQUENCE.
|
||||||
|
* \return A non-zero error code forwarded from the callback
|
||||||
|
* \p cb in case the latter returns a non-zero value.
|
||||||
|
*/
|
||||||
|
int mbedtls_asn1_traverse_sequence_of(
|
||||||
|
unsigned char **p,
|
||||||
|
const unsigned char *end,
|
||||||
|
unsigned char tag_must_mask, unsigned char tag_must_val,
|
||||||
|
unsigned char tag_may_mask, unsigned char tag_may_val,
|
||||||
|
int (*cb)( void *ctx, int tag,
|
||||||
|
unsigned char* start, size_t len ),
|
||||||
|
void *ctx );
|
||||||
|
|
||||||
#if defined(MBEDTLS_BIGNUM_C)
|
#if defined(MBEDTLS_BIGNUM_C)
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -247,6 +247,58 @@ int mbedtls_asn1_get_bitstring( unsigned char **p, const unsigned char *end,
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Traverse an ASN.1 "SEQUENCE OF <tag>"
|
||||||
|
* and call a callback for each entry found.
|
||||||
|
*/
|
||||||
|
int mbedtls_asn1_traverse_sequence_of(
|
||||||
|
unsigned char **p,
|
||||||
|
const unsigned char *end,
|
||||||
|
unsigned char tag_must_mask, unsigned char tag_must_val,
|
||||||
|
unsigned char tag_may_mask, unsigned char tag_may_val,
|
||||||
|
int (*cb)( void *ctx, int tag,
|
||||||
|
unsigned char *start, size_t len ),
|
||||||
|
void *ctx )
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
/* Get main sequence tag */
|
||||||
|
if( ( ret = mbedtls_asn1_get_tag( p, end, &len,
|
||||||
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
|
||||||
|
{
|
||||||
|
return( ret );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( *p + len != end )
|
||||||
|
return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
|
||||||
|
|
||||||
|
while( *p < end )
|
||||||
|
{
|
||||||
|
unsigned char const tag = *(*p)++;
|
||||||
|
|
||||||
|
if( ( tag & tag_must_mask ) != tag_must_val )
|
||||||
|
return( MBEDTLS_ERR_ASN1_UNEXPECTED_TAG );
|
||||||
|
|
||||||
|
if( ( ret = mbedtls_asn1_get_len( p, end, &len ) ) != 0 )
|
||||||
|
return( ret );
|
||||||
|
|
||||||
|
if( ( tag & tag_may_mask ) == tag_may_val )
|
||||||
|
{
|
||||||
|
if( cb != NULL )
|
||||||
|
{
|
||||||
|
ret = cb( ctx, tag, *p, len );
|
||||||
|
if( ret != 0 )
|
||||||
|
return( ret );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*p += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get a bit string without unused bits
|
* Get a bit string without unused bits
|
||||||
*/
|
*/
|
||||||
|
@ -269,7 +321,51 @@ int mbedtls_asn1_get_bitstring_null( unsigned char **p, const unsigned char *end
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mbedtls_asn1_sequence_free( mbedtls_asn1_sequence *seq )
|
||||||
|
{
|
||||||
|
while( seq != NULL )
|
||||||
|
{
|
||||||
|
mbedtls_asn1_sequence *next = seq->next;
|
||||||
|
mbedtls_platform_zeroize( seq, sizeof( *seq ) );
|
||||||
|
mbedtls_free( seq );
|
||||||
|
seq = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int tag;
|
||||||
|
mbedtls_asn1_sequence *cur;
|
||||||
|
} asn1_get_sequence_of_cb_ctx_t;
|
||||||
|
|
||||||
|
static int asn1_get_sequence_of_cb( void *ctx,
|
||||||
|
int tag,
|
||||||
|
unsigned char *start,
|
||||||
|
size_t len )
|
||||||
|
{
|
||||||
|
asn1_get_sequence_of_cb_ctx_t *cb_ctx =
|
||||||
|
(asn1_get_sequence_of_cb_ctx_t *) ctx;
|
||||||
|
mbedtls_asn1_sequence *cur =
|
||||||
|
cb_ctx->cur;
|
||||||
|
|
||||||
|
if( cur->buf.p != NULL )
|
||||||
|
{
|
||||||
|
cur->next =
|
||||||
|
mbedtls_calloc( 1, sizeof( mbedtls_asn1_sequence ) );
|
||||||
|
|
||||||
|
if( cur->next == NULL )
|
||||||
|
return( MBEDTLS_ERR_ASN1_ALLOC_FAILED );
|
||||||
|
|
||||||
|
cur = cur->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur->buf.p = start;
|
||||||
|
cur->buf.len = len;
|
||||||
|
cur->buf.tag = tag;
|
||||||
|
|
||||||
|
cb_ctx->cur = cur;
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parses and splits an ASN.1 "SEQUENCE OF <tag>"
|
* Parses and splits an ASN.1 "SEQUENCE OF <tag>"
|
||||||
|
@ -279,49 +375,11 @@ int mbedtls_asn1_get_sequence_of( unsigned char **p,
|
||||||
mbedtls_asn1_sequence *cur,
|
mbedtls_asn1_sequence *cur,
|
||||||
int tag)
|
int tag)
|
||||||
{
|
{
|
||||||
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
asn1_get_sequence_of_cb_ctx_t cb_ctx = { tag, cur };
|
||||||
size_t len;
|
memset( cur, 0, sizeof( mbedtls_asn1_sequence ) );
|
||||||
mbedtls_asn1_buf *buf;
|
return( mbedtls_asn1_traverse_sequence_of(
|
||||||
|
p, end, 0xFF, tag, 0, 0,
|
||||||
/* Get main sequence tag */
|
asn1_get_sequence_of_cb, &cb_ctx ) );
|
||||||
if( ( ret = mbedtls_asn1_get_tag( p, end, &len,
|
|
||||||
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
|
|
||||||
return( ret );
|
|
||||||
|
|
||||||
if( *p + len != end )
|
|
||||||
return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
|
|
||||||
|
|
||||||
while( *p < end )
|
|
||||||
{
|
|
||||||
buf = &(cur->buf);
|
|
||||||
buf->tag = **p;
|
|
||||||
|
|
||||||
if( ( ret = mbedtls_asn1_get_tag( p, end, &buf->len, tag ) ) != 0 )
|
|
||||||
return( ret );
|
|
||||||
|
|
||||||
buf->p = *p;
|
|
||||||
*p += buf->len;
|
|
||||||
|
|
||||||
/* Allocate and assign next pointer */
|
|
||||||
if( *p < end )
|
|
||||||
{
|
|
||||||
cur->next = (mbedtls_asn1_sequence*)mbedtls_calloc( 1,
|
|
||||||
sizeof( mbedtls_asn1_sequence ) );
|
|
||||||
|
|
||||||
if( cur->next == NULL )
|
|
||||||
return( MBEDTLS_ERR_ASN1_ALLOC_FAILED );
|
|
||||||
|
|
||||||
cur = cur->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set final sequence entry's next pointer to NULL */
|
|
||||||
cur->next = NULL;
|
|
||||||
|
|
||||||
if( *p != end )
|
|
||||||
return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
|
|
||||||
|
|
||||||
return( 0 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int mbedtls_asn1_get_alg( unsigned char **p,
|
int mbedtls_asn1_get_alg( unsigned char **p,
|
||||||
|
|
|
@ -481,6 +481,60 @@ get_sequence_of:"1000":0x04:"":MBEDTLS_ERR_ASN1_UNEXPECTED_TAG
|
||||||
Not a SEQUENCE (not SEQUENCE)
|
Not a SEQUENCE (not SEQUENCE)
|
||||||
get_sequence_of:"3100":0x04:"":MBEDTLS_ERR_ASN1_UNEXPECTED_TAG
|
get_sequence_of:"3100":0x04:"":MBEDTLS_ERR_ASN1_UNEXPECTED_TAG
|
||||||
|
|
||||||
|
Traverse empty SEQUENCE
|
||||||
|
traverse_sequence_of:"3000":0:0:0:0:"":0
|
||||||
|
|
||||||
|
Traverse empty SEQUENCE plus trailing garbage
|
||||||
|
traverse_sequence_of:"30007e":0:0:0:0:"":MBEDTLS_ERR_ASN1_LENGTH_MISMATCH
|
||||||
|
|
||||||
|
Traverse SEQUENCE of INTEGER: 1 INTEGER
|
||||||
|
traverse_sequence_of:"30050203123456":0xff:0x02:0:0:"4,0x02,3":0
|
||||||
|
|
||||||
|
Traverse SEQUENCE of INTEGER: 2 INTEGERs
|
||||||
|
traverse_sequence_of:"30080203123456020178":0xff:0x02:0:0:"4,0x02,3,9,0x02,1":0
|
||||||
|
|
||||||
|
Traverse SEQUENCE of INTEGER: INTEGER, NULL
|
||||||
|
traverse_sequence_of:"300702031234560500":0xff:0x02:0:0:"4,0x02,3":MBEDTLS_ERR_ASN1_UNEXPECTED_TAG
|
||||||
|
|
||||||
|
Traverse SEQUENCE of INTEGER: NULL, INTEGER
|
||||||
|
traverse_sequence_of:"300705000203123456":0xff:0x02:0:0:"":MBEDTLS_ERR_ASN1_UNEXPECTED_TAG
|
||||||
|
|
||||||
|
Traverse SEQUENCE of ANY: NULL, INTEGER
|
||||||
|
traverse_sequence_of:"300705000203123456":0:0:0:0:"4,0x05,0,6,0x02,3":0
|
||||||
|
|
||||||
|
Traverse SEQUENCE of ANY, skip non-INTEGER: INTEGER, NULL
|
||||||
|
traverse_sequence_of:"300702031234560500":0:0:0xff:0x02:"4,0x02,3":0
|
||||||
|
|
||||||
|
Traverse SEQUENCE of ANY, skip non-INTEGER: NULL, INTEGER
|
||||||
|
traverse_sequence_of:"300705000203123456":0:0:0xff:0x02:"6,0x02,3":0
|
||||||
|
|
||||||
|
Traverse SEQUENCE of INTEGER, skip everything
|
||||||
|
traverse_sequence_of:"30080203123456020178":0xff:0x02:0:1:"":0
|
||||||
|
|
||||||
|
Traverse SEQUENCE of {NULL, OCTET STRING}, skip NULL: OS, NULL
|
||||||
|
traverse_sequence_of:"300704031234560500":0xfe:0x04:0xff:0x04:"4,0x04,3":0
|
||||||
|
|
||||||
|
Traverse SEQUENCE of {NULL, OCTET STRING}, skip NULL: NULL, OS
|
||||||
|
traverse_sequence_of:"300705000403123456":0xfe:0x04:0xff:0x04:"6,0x04,3":0
|
||||||
|
|
||||||
|
Traverse SEQUENCE of {NULL, OCTET STRING}, skip everything
|
||||||
|
traverse_sequence_of:"300705000403123456":0xfe:0x04:0:1:"":0
|
||||||
|
|
||||||
|
Traverse SEQUENCE of INTEGER, stop at 0: NULL
|
||||||
|
traverse_sequence_of:"30020500":0xff:0x02:0:0:"":MBEDTLS_ERR_ASN1_UNEXPECTED_TAG
|
||||||
|
|
||||||
|
Traverse SEQUENCE of INTEGER, stop at 0: INTEGER
|
||||||
|
traverse_sequence_of:"30050203123456":0xff:0x02:0:0:"":RET_TRAVERSE_STOP
|
||||||
|
|
||||||
|
Traverse SEQUENCE of INTEGER, stop at 0: INTEGER, NULL
|
||||||
|
traverse_sequence_of:"300702031234560500":0xff:0x02:0:0:"":RET_TRAVERSE_STOP
|
||||||
|
|
||||||
|
Traverse SEQUENCE of INTEGER, stop at 1: INTEGER, NULL
|
||||||
|
traverse_sequence_of:"300702031234560500":0xff:0x02:0:0:"4,0x02,3":MBEDTLS_ERR_ASN1_UNEXPECTED_TAG
|
||||||
|
|
||||||
|
Traverse SEQUENCE of INTEGER, stop at 1: INTEGER, INTEGER
|
||||||
|
traverse_sequence_of:"30080203123456020178":0xff:0x02:0:0:"4,0x02,3":RET_TRAVERSE_STOP
|
||||||
|
|
||||||
AlgorithmIdentifier, no params
|
AlgorithmIdentifier, no params
|
||||||
get_alg:"300506034f4944":4:3:0:0:0:7:0
|
get_alg:"300506034f4944":4:3:0:0:0:7:0
|
||||||
|
|
||||||
|
|
|
@ -170,6 +170,53 @@ exit:
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
const unsigned char *input_start;
|
||||||
|
const char *description;
|
||||||
|
} traverse_state_t;
|
||||||
|
|
||||||
|
/* Value returned by traverse_callback if description runs out. */
|
||||||
|
#define RET_TRAVERSE_STOP 1
|
||||||
|
/* Value returned by traverse_callback if description has an invalid format
|
||||||
|
* (see traverse_sequence_of). */
|
||||||
|
#define RET_TRAVERSE_ERROR 2
|
||||||
|
|
||||||
|
|
||||||
|
static int traverse_callback( void *ctx, int tag,
|
||||||
|
unsigned char *content, size_t len )
|
||||||
|
{
|
||||||
|
traverse_state_t *state = ctx;
|
||||||
|
size_t offset;
|
||||||
|
const char *rest = state->description;
|
||||||
|
unsigned long n;
|
||||||
|
|
||||||
|
TEST_ASSERT( content > state->input_start );
|
||||||
|
offset = content - state->input_start;
|
||||||
|
test_set_step( offset );
|
||||||
|
|
||||||
|
if( *rest == 0 )
|
||||||
|
return( RET_TRAVERSE_STOP );
|
||||||
|
n = strtoul( rest, (char **) &rest, 0 );
|
||||||
|
TEST_EQUAL( n, offset );
|
||||||
|
TEST_EQUAL( *rest, ',' );
|
||||||
|
++rest;
|
||||||
|
n = strtoul( rest, (char **) &rest, 0 );
|
||||||
|
TEST_EQUAL( n, (unsigned) tag );
|
||||||
|
TEST_EQUAL( *rest, ',' );
|
||||||
|
++rest;
|
||||||
|
n = strtoul( rest, (char **) &rest, 0 );
|
||||||
|
TEST_EQUAL( n, len );
|
||||||
|
if( *rest == ',' )
|
||||||
|
++rest;
|
||||||
|
|
||||||
|
state->description = rest;
|
||||||
|
return( 0 );
|
||||||
|
|
||||||
|
exit:
|
||||||
|
return( RET_TRAVERSE_ERROR );
|
||||||
|
}
|
||||||
|
|
||||||
/* END_HEADER */
|
/* END_HEADER */
|
||||||
|
|
||||||
/* BEGIN_DEPENDENCIES
|
/* BEGIN_DEPENDENCIES
|
||||||
|
@ -507,8 +554,15 @@ void get_sequence_of( const data_t *input, int tag,
|
||||||
const char *description,
|
const char *description,
|
||||||
int expected_result )
|
int expected_result )
|
||||||
{
|
{
|
||||||
|
/* The description string is a comma-separated list of integers.
|
||||||
|
* For each element in the SEQUENCE in input, description contains
|
||||||
|
* two integers: the offset of the element (offset from the start
|
||||||
|
* of input to the tag of the element) and the length of the
|
||||||
|
* element's contents.
|
||||||
|
* "offset1,length1,..." */
|
||||||
|
|
||||||
mbedtls_asn1_sequence head = { { 0, 0, NULL }, NULL };
|
mbedtls_asn1_sequence head = { { 0, 0, NULL }, NULL };
|
||||||
mbedtls_asn1_sequence *cur, *next;
|
mbedtls_asn1_sequence *cur;
|
||||||
unsigned char *p = input->x;
|
unsigned char *p = input->x;
|
||||||
const char *rest = description;
|
const char *rest = description;
|
||||||
unsigned long n;
|
unsigned long n;
|
||||||
|
@ -549,13 +603,36 @@ void get_sequence_of( const data_t *input, int tag,
|
||||||
}
|
}
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
cur = head.next;
|
mbedtls_asn1_sequence_free( head.next );
|
||||||
while( cur != NULL )
|
}
|
||||||
{
|
/* END_CASE */
|
||||||
next = cur->next;
|
|
||||||
mbedtls_free( cur );
|
/* BEGIN_CASE */
|
||||||
cur = next;
|
void traverse_sequence_of( const data_t *input,
|
||||||
}
|
int tag_must_mask, int tag_must_val,
|
||||||
|
int tag_may_mask, int tag_may_val,
|
||||||
|
const char *description,
|
||||||
|
int expected_result )
|
||||||
|
{
|
||||||
|
/* The description string is a comma-separated list of integers.
|
||||||
|
* For each element in the SEQUENCE in input, description contains
|
||||||
|
* three integers: the offset of the element's content (offset from
|
||||||
|
* the start of input to the content of the element), the element's tag,
|
||||||
|
* and the length of the element's contents.
|
||||||
|
* "offset1,tag1,length1,..." */
|
||||||
|
|
||||||
|
unsigned char *p = input->x;
|
||||||
|
traverse_state_t traverse_state = {input->x, description};
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = mbedtls_asn1_traverse_sequence_of( &p, input->x + input->len,
|
||||||
|
(uint8_t) tag_must_mask, (uint8_t) tag_must_val,
|
||||||
|
(uint8_t) tag_may_mask, (uint8_t) tag_may_val,
|
||||||
|
traverse_callback, &traverse_state );
|
||||||
|
if( ret == RET_TRAVERSE_ERROR )
|
||||||
|
goto exit;
|
||||||
|
TEST_EQUAL( ret, expected_result );
|
||||||
|
TEST_EQUAL( *traverse_state.description, 0 );
|
||||||
}
|
}
|
||||||
/* END_CASE */
|
/* END_CASE */
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue