mirror of
https://github.com/yuzu-emu/mbedtls.git
synced 2025-02-25 15:06:53 +00:00
Introduce ASN.1 API for traversing ASN.1 SEQUENCEs
This commit adds a new function `mbedtls_asn1_traverse_sequence_of()` which traverses an ASN.1 SEQUENCE and calls a user-provided callback for each entry. It allows to put the following constraints on the tags allowed in the SEQUENCE: - A tag mask and mandatory tag value w.r.t. that mask. A non-matching tag leads to an MBEDTLS_ERR_ASN1_UNEXPECTED_TAG error. For example, it the mask if 0xFF, this means that only a single tag will be allowed in the SEQUENCE. - A tag mask and optional tag value w.r.t. that mask. A non-matching tag is silently ignored. The main use for this flexibility is the traversal of the `SubjectAlternativeNames` extension, where some parts of the tag are fixed but some are flexible to indicate which type of name the entry describes.
This commit is contained in:
parent
5984d30f4b
commit
8730610ae0
|
@ -291,6 +291,58 @@ int mbedtls_asn1_get_sequence_of( unsigned char **p,
|
|||
mbedtls_asn1_sequence *cur,
|
||||
int tag);
|
||||
|
||||
/**
|
||||
* \brief Traverse an ASN.1 SEQUENCE container and
|
||||
* call a callback for each entry.
|
||||
*
|
||||
* \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. 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 A negative ASN.1 error code on a parsing failure.
|
||||
* \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,
|
||||
uint8_t tag_must_mask, uint8_t tag_must_val,
|
||||
uint8_t tag_may_mask, uint8_t tag_may_val,
|
||||
int (*cb)( void *ctx, int tag,
|
||||
unsigned char* start, size_t len ),
|
||||
void *ctx );
|
||||
|
||||
#if defined(MBEDTLS_BIGNUM_C)
|
||||
/**
|
||||
* \brief Retrieve a MPI value from an integer ASN.1 tag.
|
||||
|
|
|
@ -230,6 +230,93 @@ int mbedtls_asn1_get_bitstring_null( unsigned char **p, const unsigned char *end
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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,
|
||||
uint8_t tag_must_mask, uint8_t tag_must_val,
|
||||
uint8_t tag_may_mask, uint8_t 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( ( tag & tag_may_mask ) == tag_may_val )
|
||||
{
|
||||
if( ( ret = mbedtls_asn1_get_len( p, end, &len ) ) != 0 )
|
||||
return( ret );
|
||||
|
||||
if( cb != NULL )
|
||||
{
|
||||
ret = cb( ctx, tag, *p, len );
|
||||
if( ret != 0 )
|
||||
return( ret );
|
||||
}
|
||||
}
|
||||
|
||||
*p += len;
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
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>"
|
||||
|
@ -239,44 +326,11 @@ int mbedtls_asn1_get_sequence_of( unsigned char **p,
|
|||
mbedtls_asn1_sequence *cur,
|
||||
int tag)
|
||||
{
|
||||
int ret;
|
||||
size_t len;
|
||||
mbedtls_asn1_buf *buf;
|
||||
|
||||
/* 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( 1 )
|
||||
{
|
||||
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;
|
||||
|
||||
if( *p == end )
|
||||
{
|
||||
cur->next = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
asn1_get_sequence_of_cb_ctx_t cb_ctx = { tag, cur };
|
||||
memset( cur, 0, sizeof( mbedtls_asn1_sequence ) );
|
||||
return( mbedtls_asn1_traverse_sequence_of(
|
||||
p, end, 0xFF, tag, 0, 0,
|
||||
asn1_get_sequence_of_cb, &cb_ctx ) );
|
||||
}
|
||||
|
||||
int mbedtls_asn1_get_alg( unsigned char **p,
|
||||
|
|
Loading…
Reference in a new issue