Introduce X.509 CRT frame structure

This commit restructures the parsing of X.509 CRTs in the following way:

First, it introduces a 'frame' structure `mbedtls_x509_crt_frame`, which
contains pointers to some structured fields of a CRT as well as copies of
primitive fields. For example, there's a pointer-length pair delimiting the raw
public key data in the CRT, but there's a C-uint8 to store the CRT version
(not a pointer-length pair delimiting the ASN.1 structure holding the version).

Setting up a frame from a raw CRT buffer does not require any memory outside
of the frame structure itself; it's just attaches a 'template' to the buffer
that allows to inspect the structured parts of the CRT afterwards.

Note that the frame structure does not correspond to a particular ASN.1
structure; for example, it contains pointers to delimit the three parts
of a CRT (TBS, SignatureAlgorithm, Signature), but also pointers to the
fields of the TBS, and pointers into the Extensions substructure of the TBS.

Further, the commit introduces an internal function `x509_crt_parse_frame()`
which sets up a frame from a raw CRT buffer, as well as several small helper
functions which help setting up the more complex structures (Subject, Issuer, PK)
from the frame.

These functions are then put to use to rewrite the existing parsing function
`mbedtls_x509_crt_parse_der_core()` by setting up a CRT frame from the input
buffer, residing on the stack, and afterwards copying the respective fields
to the actual `mbedtls_x509_crt` structure and performing the deeper parsing
through the various helper functions.
This commit is contained in:
Hanno Becker 2019-02-15 15:27:59 +00:00
parent c6573a27a1
commit 21f5567571
2 changed files with 567 additions and 264 deletions

View file

@ -47,6 +47,58 @@ extern "C" {
* \{
*/
typedef struct mbedtls_x509_crt_frame
{
/* Keep these 8-bit fields at the front of the structure to allow them to
* be fetched in a single instruction on Thumb2; putting them at the back
* requires an intermediate address calculation. */
uint8_t version; /**< The X.509 version. (1=v1, 2=v2, 3=v3) */
uint8_t ca_istrue; /**< Optional Basic Constraint extension value:
* 1 if this certificate belongs to a CA, 0 otherwise. */
uint8_t max_pathlen; /**< Optional Basic Constraint extension value:
* The maximum path length to the root certificate.
* Path length is 1 higher than RFC 5280 'meaning', so 1+ */
uint8_t ns_cert_type; /**< Optional Netscape certificate type extension value:
* See the values in x509.h */
unsigned int key_usage; /**< Optional key usage extension value: See the values in x509.h */
uint32_t ext_types; /**< Bitfield indicating which extensions are present.
* See the values in x509.h. */
mbedtls_md_type_t sig_md; /**< The hash algorithm used to hash CRT before signing. */
mbedtls_pk_type_t sig_pk; /**< The signature algorithm used to sign the CRT hash. */
mbedtls_x509_time valid_from; /**< The start time of certificate validity. */
mbedtls_x509_time valid_to; /**< The end time of certificate validity. */
mbedtls_x509_buf_raw raw; /**< The raw certificate data in DER. */
mbedtls_x509_buf_raw tbs; /**< The part of the CRT that is [T]o [B]e [S]igned. */
mbedtls_x509_buf_raw serial; /**< The unique ID for certificate issued by a specific CA. */
mbedtls_x509_buf_raw pubkey_raw; /**< The raw public key data (DER). */
mbedtls_x509_buf_raw issuer_id; /**< Optional X.509 v2/v3 issuer unique identifier. */
mbedtls_x509_buf_raw issuer_raw; /**< The raw issuer data (DER). Used for quick comparison. */
mbedtls_x509_buf_raw subject_id; /**< Optional X.509 v2/v3 subject unique identifier. */
mbedtls_x509_buf_raw subject_raw; /**< The raw subject data (DER). Used for quick comparison. */
mbedtls_x509_buf_raw sig; /**< Signature: hash of the tbs part signed with the private key. */
mbedtls_x509_buf_raw sig_alg; /**< The signature algorithm used for \p sig. */
mbedtls_x509_buf_raw v3_ext; /**< The raw data for the extension list in the certificate.
* Might be useful for manual inspection of extensions that
* Mbed TLS doesn't yet support. */
mbedtls_x509_buf_raw subject_alt_raw; /**< The raw data for the SubjectAlternativeNames extension. */
mbedtls_x509_buf_raw ext_key_usage_raw; /**< The raw data for the ExtendedKeyUsage extension. */
mbedtls_x509_buf_raw issuer_raw_with_hdr;
mbedtls_x509_buf_raw subject_raw_with_hdr;
} mbedtls_x509_crt_frame;
/**
* Container for an X.509 certificate. The certificate may be chained.
*/

View file

@ -78,6 +78,18 @@
#endif /* !_WIN32 || EFIX64 || EFI32 */
#endif
static int x509_crt_parse_frame( unsigned char *start,
unsigned char *end,
mbedtls_x509_crt_frame *frame );
static int x509_crt_subject_from_frame( mbedtls_x509_crt_frame *frame,
mbedtls_x509_name *subject );
static int x509_crt_issuer_from_frame( mbedtls_x509_crt_frame *frame,
mbedtls_x509_name *issuer );
static int x509_crt_subject_alt_from_frame( mbedtls_x509_crt_frame *frame,
mbedtls_x509_sequence *subject_alt );
static int x509_crt_ext_key_usage_from_frame( mbedtls_x509_crt_frame *frame,
mbedtls_x509_sequence *ext_key_usage );
/*
* Item in a verification chain: cert and flags for it
*/
@ -553,7 +565,7 @@ static int x509_crt_get_ext_cb( void *ctx,
size_t ext_len )
{
int ret;
mbedtls_x509_crt *crt = (mbedtls_x509_crt *) ctx;
mbedtls_x509_crt_frame *frame = (mbedtls_x509_crt_frame *) ctx;
size_t len;
unsigned char *end, *end_ext_octet;
mbedtls_x509_buf extn_oid = { 0, 0, NULL };
@ -615,10 +627,10 @@ static int x509_crt_get_ext_cb( void *ctx,
}
/* Forbid repeated extensions */
if( ( crt->ext_types & ext_type ) != 0 )
if( ( frame->ext_types & ext_type ) != 0 )
return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS );
crt->ext_types |= ext_type;
frame->ext_types |= ext_type;
switch( ext_type )
{
case MBEDTLS_X509_EXT_BASIC_CONSTRAINTS:
@ -633,45 +645,57 @@ static int x509_crt_get_ext_cb( void *ctx,
if( ret != 0 )
goto err;
crt->ca_istrue = ca_istrue;
crt->max_pathlen = max_pathlen;
frame->ca_istrue = ca_istrue;
frame->max_pathlen = max_pathlen;
break;
}
case MBEDTLS_X509_EXT_KEY_USAGE:
/* Parse key usage */
ret = x509_get_key_usage( &p, end_ext_octet,
&crt->key_usage );
&frame->key_usage );
if( ret != 0 )
goto err;
break;
case MBEDTLS_X509_EXT_SUBJECT_ALT_NAME:
/* Copy reference to raw subject alt name data. */
crt->subject_alt_raw.p = p;
crt->subject_alt_raw.len = end_ext_octet - p;
if( ( ret = x509_get_subject_alt_name( p, end_ext_octet,
&crt->subject_alt_names ) ) != 0 )
{
return( ret );
}
frame->subject_alt_raw.p = p;
frame->subject_alt_raw.len = end_ext_octet - p;
ret = mbedtls_asn1_traverse_sequence_of( &p, end_ext_octet,
MBEDTLS_ASN1_TAG_CLASS_MASK,
MBEDTLS_ASN1_CONTEXT_SPECIFIC,
MBEDTLS_ASN1_TAG_VALUE_MASK,
2 /* SubjectAlt DNS */,
NULL, NULL );
if( ret != 0 )
goto err;
break;
case MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE:
/* Parse extended key usage */
crt->ext_key_usage_raw.p = p;
crt->ext_key_usage_raw.len = end_ext_octet - p;
if( ( ret = x509_get_ext_key_usage( &p, end_ext_octet,
&crt->ext_key_usage ) ) != 0 )
frame->ext_key_usage_raw.p = p;
frame->ext_key_usage_raw.len = end_ext_octet - p;
if( frame->ext_key_usage_raw.len == 0 )
{
return( ret );
ret = MBEDTLS_ERR_ASN1_INVALID_LENGTH;
goto err;
}
/* Check structural sanity of extension. */
ret = mbedtls_asn1_traverse_sequence_of( &p, end_ext_octet,
0xFF, MBEDTLS_ASN1_OID,
0, 0, NULL, NULL );
if( ret != 0 )
goto err;
break;
case MBEDTLS_X509_EXT_NS_CERT_TYPE:
/* Parse netscape certificate type */
ret = x509_get_ns_cert_type( &p, end_ext_octet,
&crt->ns_cert_type );
&frame->ns_cert_type );
if( ret != 0 )
goto err;
break;
@ -695,31 +719,18 @@ err:
return( ret );
}
static int x509_get_crt_ext( unsigned char **p,
unsigned char *end,
mbedtls_x509_crt *crt )
static int x509_crt_frame_parse_ext( mbedtls_x509_crt_frame *frame )
{
int ret;
size_t len;
unsigned char *p = frame->v3_ext.p;
unsigned char *end = p + frame->v3_ext.len;
if( *p == end )
if( p == end )
return( 0 );
ret = mbedtls_asn1_get_tag( p, end, &len,
MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 3 );
if( ret != 0 )
{
goto err;
}
end = *p + len;
ret = mbedtls_asn1_traverse_sequence_of( p, end,
ret = mbedtls_asn1_traverse_sequence_of( &p, end,
0xFF, MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED,
0, 0, x509_crt_get_ext_cb, crt );
if( ret != 0 )
goto err;
err:
0, 0, x509_crt_get_ext_cb, frame );
if( ret == MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE )
return( ret );
@ -732,6 +743,363 @@ err:
return( ret );
}
static int x509_crt_parse_frame( unsigned char *start,
unsigned char *end,
mbedtls_x509_crt_frame *frame )
{
int ret;
unsigned char *p;
size_t len;
mbedtls_x509_buf tmp;
unsigned char *tbs_start;
mbedtls_x509_buf outer_sig_alg;
size_t inner_sig_alg_len;
unsigned char *inner_sig_alg_start;
memset( frame, 0, sizeof( *frame ) );
/*
* Certificate ::= SEQUENCE {
* tbsCertificate TBSCertificate,
* signatureAlgorithm AlgorithmIdentifier,
* signatureValue BIT STRING
* }
*
*/
p = start;
frame->raw.p = p;
if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
{
return( MBEDTLS_ERR_X509_INVALID_FORMAT );
}
/* NOTE: We are currently not checking that the `Certificate`
* structure spans the entire buffer. */
end = p + len;
frame->raw.len = end - frame->raw.p;
/*
* TBSCertificate ::= SEQUENCE { ...
*/
frame->tbs.p = p;
if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
{
return( ret + MBEDTLS_ERR_X509_INVALID_FORMAT );
}
tbs_start = p;
/* Breadth-first parsing: Jump over TBS for now. */
p += len;
frame->tbs.len = p - frame->tbs.p;
/*
* AlgorithmIdentifier ::= SEQUENCE { ...
*/
outer_sig_alg.p = p;
if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
{
return( MBEDTLS_ERR_X509_INVALID_ALG + ret );
}
p += len;
outer_sig_alg.len = p - outer_sig_alg.p;
/*
* signatureValue BIT STRING
*/
ret = mbedtls_x509_get_sig( &p, end, &tmp );
if( ret != 0 )
return( ret );
frame->sig.p = tmp.p;
frame->sig.len = tmp.len;
/* Check that we consumed the entire `Certificate` structure. */
if( p != end )
{
return( MBEDTLS_ERR_X509_INVALID_FORMAT +
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
}
/* Parse TBSCertificate structure
*
* TBSCertificate ::= SEQUENCE {
* version [0] EXPLICIT Version DEFAULT v1,
* serialNumber CertificateSerialNumber,
* signature AlgorithmIdentifier,
* issuer Name,
* validity Validity,
* subject Name,
* subjectPublicKeyInfo SubjectPublicKeyInfo,
* issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
* -- If present, version MUST be v2 or v3
* subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
* -- If present, version MUST be v2 or v3
* extensions [3] EXPLICIT Extensions OPTIONAL
* -- If present, version MUST be v3
* }
*/
end = frame->tbs.p + frame->tbs.len;
p = tbs_start;
/*
* Version ::= INTEGER { v1(0), v2(1), v3(2) }
*/
{
int version;
ret = x509_get_version( &p, end, &version );
if( ret != 0 )
return( ret );
if( version < 0 || version > 2 )
return( MBEDTLS_ERR_X509_UNKNOWN_VERSION );
frame->version = version + 1;
}
/*
* CertificateSerialNumber ::= INTEGER
*/
ret = mbedtls_x509_get_serial( &p, end, &tmp );
if( ret != 0 )
return( ret );
frame->serial.p = tmp.p;
frame->serial.len = tmp.len;
/*
* signature AlgorithmIdentifier
*/
inner_sig_alg_start = p;
ret = mbedtls_x509_get_sig_alg_raw( &p, end, &frame->sig_md,
&frame->sig_pk, NULL );
if( ret != 0 )
return( ret );
inner_sig_alg_len = p - inner_sig_alg_start;
frame->sig_alg.p = inner_sig_alg_start;
frame->sig_alg.len = inner_sig_alg_len;
/* Consistency check:
* Inner and outer AlgorithmIdentifier structures must coincide:
*
* Quoting RFC 5280, Section 4.1.1.2:
* This field MUST contain the same algorithm identifier as the
* signature field in the sequence tbsCertificate (Section 4.1.2.3).
*/
if( outer_sig_alg.len != inner_sig_alg_len ||
memcmp( outer_sig_alg.p, inner_sig_alg_start, inner_sig_alg_len ) != 0 )
{
return( MBEDTLS_ERR_X509_SIG_MISMATCH );
}
/*
* issuer Name
*
* Name ::= CHOICE { -- only one possibility for now --
* rdnSequence RDNSequence }
*
* RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
*/
frame->issuer_raw_with_hdr.p = p;
ret = mbedtls_asn1_get_tag( &p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE );
if( ret != 0 )
return( ret + MBEDTLS_ERR_X509_INVALID_FORMAT );
frame->issuer_raw.p = p;
frame->issuer_raw.len = len;
p += len;
ret = mbedtls_x509_name_cmp_raw( &frame->issuer_raw,
&frame->issuer_raw,
NULL, NULL );
if( ret != 0 )
return( ret );
frame->issuer_raw_with_hdr.len = p - frame->issuer_raw_with_hdr.p;
/*
* Validity ::= SEQUENCE { ...
*/
ret = x509_get_dates( &p, end, &frame->valid_from, &frame->valid_to );
if( ret != 0 )
return( ret );
/*
* subject Name
*
* Name ::= CHOICE { -- only one possibility for now --
* rdnSequence RDNSequence }
*
* RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
*/
frame->subject_raw_with_hdr.p = p;
ret = mbedtls_asn1_get_tag( &p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE );
if( ret != 0 )
return( ret + MBEDTLS_ERR_X509_INVALID_FORMAT );
frame->subject_raw.p = p;
frame->subject_raw.len = len;
p += len;
ret = mbedtls_x509_name_cmp_raw( &frame->subject_raw,
&frame->subject_raw,
NULL, NULL );
if( ret != 0 )
return( ret );
frame->subject_raw_with_hdr.len = p - frame->subject_raw_with_hdr.p;
/*
* SubjectPublicKeyInfo
*/
frame->pubkey_raw.p = p;
ret = mbedtls_asn1_get_tag( &p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE );
if( ret != 0 )
return( ret + MBEDTLS_ERR_PK_KEY_INVALID_FORMAT );
p += len;
frame->pubkey_raw.len = p - frame->pubkey_raw.p;
/*
* issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
* -- If present, version shall be v2 or v3
*/
if( frame->version == 2 || frame->version == 3 )
{
ret = x509_get_uid( &p, end, &tmp, 1 /* implicit tag */ );
if( ret != 0 )
return( ret );
frame->issuer_id.p = tmp.p;
frame->issuer_id.len = tmp.len;
}
/*
* subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
* -- If present, version shall be v2 or v3
*/
if( frame->version == 2 || frame->version == 3 )
{
ret = x509_get_uid( &p, end, &tmp, 2 /* implicit tag */ );
if( ret != 0 )
return( ret );
frame->subject_id.p = tmp.p;
frame->subject_id.len = tmp.len;
}
/*
* extensions [3] EXPLICIT Extensions OPTIONAL
* -- If present, version shall be v3
*/
#if !defined(MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3)
if( frame->version == 3 )
#endif
{
if( p != end )
{
ret = mbedtls_asn1_get_tag( &p, end, &len,
MBEDTLS_ASN1_CONTEXT_SPECIFIC |
MBEDTLS_ASN1_CONSTRUCTED | 3 );
if( len == 0 )
ret = MBEDTLS_ERR_ASN1_OUT_OF_DATA;
if( ret != 0 )
return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
frame->v3_ext.p = p;
frame->v3_ext.len = len;
p += len;
}
ret = x509_crt_frame_parse_ext( frame );
if( ret != 0 )
return( ret );
}
/* Wrapup: Check that we consumed the entire `TBSCertificate` structure. */
if( p != end )
{
return( MBEDTLS_ERR_X509_INVALID_FORMAT +
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
}
return( 0 );
}
static int x509_crt_subject_from_frame( mbedtls_x509_crt_frame *frame,
mbedtls_x509_name *subject )
{
unsigned char *p = frame->subject_raw.p;
unsigned char *end = p + frame->subject_raw.len;
return( mbedtls_x509_get_name( &p, end, subject ) );
}
static int x509_crt_issuer_from_frame( mbedtls_x509_crt_frame *frame,
mbedtls_x509_name *issuer )
{
unsigned char *p = frame->issuer_raw.p;
unsigned char *end = p + frame->issuer_raw.len;
return( mbedtls_x509_get_name( &p, end, issuer ) );
}
static int x509_crt_subject_alt_from_frame( mbedtls_x509_crt_frame *frame,
mbedtls_x509_sequence *subject_alt )
{
int ret;
unsigned char *p = frame->subject_alt_raw.p;
unsigned char *end = p + frame->subject_alt_raw.len;
memset( subject_alt, 0, sizeof( *subject_alt ) );
if( ( frame->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) == 0 )
return( 0 );
ret = x509_get_subject_alt_name( p, end, subject_alt );
if( ret != 0 )
ret += MBEDTLS_ERR_X509_INVALID_EXTENSIONS;
return( ret );
}
static int x509_crt_ext_key_usage_from_frame( mbedtls_x509_crt_frame *frame,
mbedtls_x509_sequence *ext_key_usage )
{
int ret;
unsigned char *p = frame->ext_key_usage_raw.p;
unsigned char *end = p + frame->ext_key_usage_raw.len;
memset( ext_key_usage, 0, sizeof( *ext_key_usage ) );
if( ( frame->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE ) == 0 )
return( 0 );
ret = x509_get_ext_key_usage( &p, end, ext_key_usage );
if( ret != 0 )
{
ret += MBEDTLS_ERR_X509_INVALID_EXTENSIONS;
return( ret );
}
return( 0 );
}
static int x509_crt_pk_from_frame( mbedtls_x509_crt_frame *frame,
mbedtls_pk_context *pk )
{
unsigned char *p = frame->pubkey_raw.p;
unsigned char *end = p + frame->pubkey_raw.len;
return( mbedtls_pk_parse_subpubkey( &p, end, pk ) );
}
/*
* Parse and fill a single X.509 certificate in DER format
*/
@ -741,261 +1109,144 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt,
int make_copy )
{
int ret;
size_t len;
unsigned char *p, *end, *crt_end;
mbedtls_x509_buf sig_params1, sig_params2, sig_oid2;
mbedtls_x509_crt_frame frame;
memset( &sig_params1, 0, sizeof( mbedtls_x509_buf ) );
memset( &sig_params2, 0, sizeof( mbedtls_x509_buf ) );
memset( &sig_oid2, 0, sizeof( mbedtls_x509_buf ) );
/*
* Check for valid input
*/
if( crt == NULL || buf == NULL )
return( MBEDTLS_ERR_X509_BAD_INPUT_DATA );
/* Use the original buffer until we figure out actual length. */
p = (unsigned char*) buf;
len = buflen;
end = p + len;
/*
* Certificate ::= SEQUENCE {
* tbsCertificate TBSCertificate,
* signatureAlgorithm AlgorithmIdentifier,
* signatureValue BIT STRING }
*/
if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
if( make_copy == 0 )
{
mbedtls_x509_crt_free( crt );
return( MBEDTLS_ERR_X509_INVALID_FORMAT );
}
end = crt_end = p + len;
crt->raw.len = crt_end - buf;
if( make_copy != 0 )
{
/* Create and populate a new buffer for the raw field. */
crt->raw.p = p = mbedtls_calloc( 1, crt->raw.len );
if( crt->raw.p == NULL )
return( MBEDTLS_ERR_X509_ALLOC_FAILED );
memcpy( crt->raw.p, buf, crt->raw.len );
crt->own_buffer = 1;
p += crt->raw.len - len;
end = crt_end = p + len;
crt->raw.p = (unsigned char*) buf;
crt->raw.len = buflen;
crt->own_buffer = 0;
}
else
{
crt->raw.p = (unsigned char*) buf;
crt->own_buffer = 0;
crt->raw.p = mbedtls_calloc( 1, buflen );
if( crt->raw.p == NULL )
return( MBEDTLS_ERR_X509_ALLOC_FAILED );
crt->raw.len = buflen;
memcpy( crt->raw.p, buf, buflen );
crt->own_buffer = 1;
}
/*
* TBSCertificate ::= SEQUENCE {
/* Parse CRT frame.
* This omits:
* - Issuer, Subject
* - ExtKeyUsage, SubjectAltNames,
* - Time
* - PK
*/
crt->tbs.p = p;
ret = x509_crt_parse_frame( crt->raw.p,
crt->raw.p + crt->raw.len,
&frame );
if( ret != 0 )
goto exit;
if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
{
mbedtls_x509_crt_free( crt );
return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret );
}
end = p + len;
crt->tbs.len = end - crt->tbs.p;
/*
* Version ::= INTEGER { v1(0), v2(1), v3(2) }
/* Currently, we accept DER encoded CRTs with trailing garbage
* and promise to not account for the garbage in the `raw` field.
*
* CertificateSerialNumber ::= INTEGER
*
* signature AlgorithmIdentifier
*/
if( ( ret = x509_get_version( &p, end, &crt->version ) ) != 0 ||
( ret = mbedtls_x509_get_serial( &p, end, &crt->serial ) ) != 0 ||
( ret = mbedtls_x509_get_alg( &p, end, &crt->sig_oid,
&sig_params1 ) ) != 0 )
{
mbedtls_x509_crt_free( crt );
return( ret );
}
* Note that this means that `crt->raw.len` is not necessarily the
* full size of the heap buffer allocated at `crt->raw.p` in case
* of copy-mode, but this is not a problem: freeing the buffer doesn't
* need the size, and the garbage data doesn't need zeroization. */
crt->raw.len = frame->raw.len;
if( crt->version < 0 || crt->version > 2 )
{
mbedtls_x509_crt_free( crt );
return( MBEDTLS_ERR_X509_UNKNOWN_VERSION );
}
crt->version++;
if( ( ret = mbedtls_x509_get_sig_alg( &crt->sig_oid, &sig_params1,
&crt->sig_md, &crt->sig_pk,
&crt->sig_opts ) ) != 0 )
{
mbedtls_x509_crt_free( crt );
return( ret );
}
/* Copy frame to legacy CRT structure -- that's inefficient, but if
* memory matters, the new CRT structure should be used anyway. */
crt->tbs.p = frame.tbs.p;
crt->tbs.len = frame.tbs.len;
crt->serial.p = frame.serial.p;
crt->serial.len = frame.serial.len;
crt->issuer_raw.p = frame.issuer_raw_with_hdr.p;
crt->issuer_raw.len = frame.issuer_raw_with_hdr.len;
crt->subject_raw.p = frame.subject_raw_with_hdr.p;
crt->subject_raw.len = frame.subject_raw_with_hdr.len;
crt->issuer_raw_no_hdr = frame.issuer_raw;
crt->subject_raw_no_hdr = frame.subject_raw;
crt->issuer_id.p = frame.issuer_id.p;
crt->issuer_id.len = frame.issuer_id.len;
crt->subject_id.p = frame.subject_id.p;
crt->subject_id.len = frame.subject_id.len;
crt->pk_raw.p = frame.pubkey_raw.p;
crt->pk_raw.len = frame.pubkey_raw.len;
crt->ext_key_usage_raw = frame.ext_key_usage_raw;
crt->subject_alt_raw = frame.subject_alt_raw;
crt->sig.p = frame.sig.p;
crt->sig.len = frame.sig.len;
crt->valid_from = frame.valid_from;
crt->valid_to = frame.valid_to;
crt->v3_ext.p = frame.v3_ext.p;
crt->v3_ext.len = frame.v3_ext.len;
crt->version = frame.version;
crt->ca_istrue = frame.ca_istrue;
crt->max_pathlen = frame.max_pathlen;
crt->ext_types = frame.ext_types;
crt->key_usage = frame.key_usage;
crt->ns_cert_type = frame.ns_cert_type;
/*
* issuer Name
* Obtain the remaining fields from the frame.
*/
crt->issuer_raw.p = p;
if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
{
mbedtls_x509_crt_free( crt );
return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret );
}
crt->issuer_raw_no_hdr.p = p;
/* sig_oid: Previously, needed for convenience in
* mbedtls_x509_crt_info(), now pure legacy burden. */
unsigned char *tmp = frame.sig_alg.p;
unsigned char *end = tmp + frame.sig_alg.len;
mbedtls_x509_buf sig_oid, sig_params;
if( ( ret = mbedtls_x509_get_name( &p, p + len, &crt->issuer ) ) != 0 )
{
mbedtls_x509_crt_free( crt );
return( ret );
}
crt->issuer_raw_no_hdr.len = p - crt->issuer_raw_no_hdr.p;
crt->issuer_raw.len = p - crt->issuer_raw.p;
/*
* Validity ::= SEQUENCE {
* notBefore Time,
* notAfter Time }
*
*/
if( ( ret = x509_get_dates( &p, end, &crt->valid_from,
&crt->valid_to ) ) != 0 )
{
mbedtls_x509_crt_free( crt );
return( ret );
}
/*
* subject Name
*/
crt->subject_raw.p = p;
if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
{
mbedtls_x509_crt_free( crt );
return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret );
}
crt->subject_raw_no_hdr.p = p;
if( len && ( ret = mbedtls_x509_get_name( &p, p + len, &crt->subject ) ) != 0 )
{
mbedtls_x509_crt_free( crt );
return( ret );
}
crt->subject_raw_no_hdr.len = p - crt->subject_raw_no_hdr.p;
crt->subject_raw.len = p - crt->subject_raw.p;
/*
* SubjectPublicKeyInfo
*/
crt->pk_raw.p = p;
if( ( ret = mbedtls_pk_parse_subpubkey( &p, end, &crt->pk ) ) != 0 )
{
mbedtls_x509_crt_free( crt );
return( ret );
}
crt->pk_raw.len = p - crt->pk_raw.p;
/*
* issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
* -- If present, version shall be v2 or v3
* subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
* -- If present, version shall be v2 or v3
* extensions [3] EXPLICIT Extensions OPTIONAL
* -- If present, version shall be v3
*/
if( crt->version == 2 || crt->version == 3 )
{
ret = x509_get_uid( &p, end, &crt->issuer_id, 1 );
ret = mbedtls_x509_get_alg( &tmp, end,
&sig_oid, &sig_params );
if( ret != 0 )
{
mbedtls_x509_crt_free( crt );
return( ret );
/* This should never happen, because we check
* the sanity of the AlgorithmIdentifier structure
* during frame parsing. */
ret = MBEDTLS_ERR_X509_FATAL_ERROR;
goto exit;
}
crt->sig_oid = sig_oid;
/* Signature parameters */
tmp = frame.sig_alg.p;
ret = mbedtls_x509_get_sig_alg_raw( &tmp, end,
&crt->sig_md, &crt->sig_pk,
&crt->sig_opts );
if( ret != 0 )
{
/* Again, this should never happen. */
ret = MBEDTLS_ERR_X509_FATAL_ERROR;
goto exit;
}
}
if( crt->version == 2 || crt->version == 3 )
{
ret = x509_get_uid( &p, end, &crt->subject_id, 2 );
if( ret != 0 )
{
mbedtls_x509_crt_free( crt );
return( ret );
}
}
ret = x509_crt_pk_from_frame( &frame, &crt->pk );
if( ret != 0 )
goto exit;
#if !defined(MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3)
if( crt->version == 3 )
#endif
{
ret = x509_get_crt_ext( &p, end, crt );
if( ret != 0 )
{
mbedtls_x509_crt_free( crt );
return( ret );
}
}
ret = x509_crt_subject_from_frame( &frame, &crt->subject );
if( ret != 0 )
goto exit;
if( p != end )
{
ret = x509_crt_issuer_from_frame( &frame, &crt->issuer );
if( ret != 0 )
goto exit;
ret = x509_crt_subject_alt_from_frame( &frame, &crt->subject_alt_names );
if( ret != 0 )
goto exit;
ret = x509_crt_ext_key_usage_from_frame( &frame, &crt->ext_key_usage );
if( ret != 0 )
goto exit;
exit:
if( ret != 0 )
mbedtls_x509_crt_free( crt );
return( MBEDTLS_ERR_X509_INVALID_FORMAT +
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
}
end = crt_end;
/*
* }
* -- end of TBSCertificate
*
* signatureAlgorithm AlgorithmIdentifier,
* signatureValue BIT STRING
*/
if( ( ret = mbedtls_x509_get_alg( &p, end, &sig_oid2, &sig_params2 ) ) != 0 )
{
mbedtls_x509_crt_free( crt );
return( ret );
}
if( crt->sig_oid.len != sig_oid2.len ||
memcmp( crt->sig_oid.p, sig_oid2.p, crt->sig_oid.len ) != 0 ||
sig_params1.len != sig_params2.len ||
( sig_params1.len != 0 &&
memcmp( sig_params1.p, sig_params2.p, sig_params1.len ) != 0 ) )
{
mbedtls_x509_crt_free( crt );
return( MBEDTLS_ERR_X509_SIG_MISMATCH );
}
if( ( ret = mbedtls_x509_get_sig( &p, end, &crt->sig ) ) != 0 )
{
mbedtls_x509_crt_free( crt );
return( ret );
}
if( p != end )
{
mbedtls_x509_crt_free( crt );
return( MBEDTLS_ERR_X509_INVALID_FORMAT +
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
}
return( 0 );
return( ret );
}
/*