mirror of
https://github.com/yuzu-emu/mbedtls.git
synced 2025-01-30 23:11:10 +00:00
Add a new X.509 API call for copy-less parsing of CRTs
Context: The existing API `mbedtls_x509_parse_crt_der()` for parsing DER encoded X.509 CRTs unconditionally makes creates a copy of the input buffer in RAM. While this comes at the benefit of easy use, -- specifically: allowing the user to free or re-use the input buffer right after the call -- it creates a significant memory overhead, as the CRT is duplicated in memory (at least temporarily). This might not be tolerable a resource constrained device. As a remedy, this commit adds a new X.509 API call `mbedtls_x509_parse_crt_der_nocopy()` which has the same signature as `mbedtls_x509_parse_crt_der()` and almost the same semantics, with one difference: The input buffer must persist and be unmodified for the lifetime of the established instance of `mbedtls_x509_crt`, that is, until `mbedtls_x509_crt_free()` is called.
This commit is contained in:
parent
f352f75f6b
commit
1a65dcd44f
|
@ -52,6 +52,8 @@ extern "C" {
|
||||||
*/
|
*/
|
||||||
typedef struct mbedtls_x509_crt
|
typedef struct mbedtls_x509_crt
|
||||||
{
|
{
|
||||||
|
int own_buffer; /**< Indicates if \c raw is owned
|
||||||
|
* by the structure or not. */
|
||||||
mbedtls_x509_buf raw; /**< The raw certificate data (DER). */
|
mbedtls_x509_buf raw; /**< The raw certificate data (DER). */
|
||||||
mbedtls_x509_buf tbs; /**< The raw certificate body (DER). The part that is To Be Signed. */
|
mbedtls_x509_buf tbs; /**< The raw certificate body (DER). The part that is To Be Signed. */
|
||||||
|
|
||||||
|
@ -220,15 +222,57 @@ extern const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_suiteb;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Parse a single DER formatted certificate and add it
|
* \brief Parse a single DER formatted certificate and add it
|
||||||
* to the chained list.
|
* to the end of the provided chained list.
|
||||||
*
|
*
|
||||||
* \param chain points to the start of the chain
|
* \param chain The pointer to the start of the CRT chain to attach to.
|
||||||
* \param buf buffer holding the certificate DER data
|
* When parsing the first CRT in a chain, this should point
|
||||||
* \param buflen size of the buffer
|
* to an instance of ::mbedtls_x509_crt initialized through
|
||||||
|
* mbedtls_x509_crt_init().
|
||||||
|
* \param buf The buffer holding the DER encoded certificate.
|
||||||
|
* \param buflen The size in Bytes of \p buf.
|
||||||
*
|
*
|
||||||
* \return 0 if successful, or a specific X509 or PEM error code
|
* \note This function makes an internal copy of the CRT buffer
|
||||||
|
* \p buf. In particular, \p buf may be destroyed or reused
|
||||||
|
* after this call returns. To avoid duplicating the CRT
|
||||||
|
* buffer (at the cost of stricter lifetime constraints),
|
||||||
|
* use mbedtls_x509_crt_parse_der_nocopy() instead.
|
||||||
|
*
|
||||||
|
* \return \c 0 if successful.
|
||||||
|
* \return A negative error code on failure.
|
||||||
*/
|
*/
|
||||||
int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain, const unsigned char *buf,
|
int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain,
|
||||||
|
const unsigned char *buf,
|
||||||
|
size_t buflen );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Parse a single DER formatted certificate and add it
|
||||||
|
* to the end of the provided chained list. This is a
|
||||||
|
* variant of mbedtls_x509_crt_parse_der() which takes
|
||||||
|
* temporary ownership of the CRT buffer until the CRT
|
||||||
|
* is destroyed.
|
||||||
|
*
|
||||||
|
* \param chain The pointer to the start of the CRT chain to attach to.
|
||||||
|
* When parsing the first CRT in a chain, this should point
|
||||||
|
* to an instance of ::mbedtls_x509_crt initialized through
|
||||||
|
* mbedtls_x509_crt_init().
|
||||||
|
* \param buf The address of the readable buffer holding the DER encoded
|
||||||
|
* certificate to use. On success, this buffer must be
|
||||||
|
* retained and not be changed for the liftetime of the
|
||||||
|
* CRT chain \p chain, that is, until \p chain is destroyed
|
||||||
|
* through a call to mbedtls_x509_crt_free().
|
||||||
|
* \param buflen The size in Bytes of \p buf.
|
||||||
|
*
|
||||||
|
* \note This call is functionally equivalent to
|
||||||
|
* mbedtls_x509_crt_parse_der(), but it avoids creating a
|
||||||
|
* copy of the input buffer at the cost of stronger lifetime
|
||||||
|
* constraints. This is useful in constrained environments
|
||||||
|
* where duplication of the CRT cannot be tolerated.
|
||||||
|
*
|
||||||
|
* \return \c 0 if successful.
|
||||||
|
* \return A negative error code on failure.
|
||||||
|
*/
|
||||||
|
int mbedtls_x509_crt_parse_der_nocopy( mbedtls_x509_crt *chain,
|
||||||
|
const unsigned char *buf,
|
||||||
size_t buflen );
|
size_t buflen );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -829,8 +829,10 @@ static int x509_get_crt_ext( unsigned char **p,
|
||||||
/*
|
/*
|
||||||
* Parse and fill a single X.509 certificate in DER format
|
* Parse and fill a single X.509 certificate in DER format
|
||||||
*/
|
*/
|
||||||
static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, const unsigned char *buf,
|
static int x509_crt_parse_der_core( mbedtls_x509_crt *crt,
|
||||||
size_t buflen )
|
const unsigned char *buf,
|
||||||
|
size_t buflen,
|
||||||
|
int make_copy )
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
@ -847,7 +849,7 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, const unsigned char *
|
||||||
if( crt == NULL || buf == NULL )
|
if( crt == NULL || buf == NULL )
|
||||||
return( MBEDTLS_ERR_X509_BAD_INPUT_DATA );
|
return( MBEDTLS_ERR_X509_BAD_INPUT_DATA );
|
||||||
|
|
||||||
// Use the original buffer until we figure out actual length
|
/* Use the original buffer until we figure out actual length. */
|
||||||
p = (unsigned char*) buf;
|
p = (unsigned char*) buf;
|
||||||
len = buflen;
|
len = buflen;
|
||||||
end = p + len;
|
end = p + len;
|
||||||
|
@ -865,25 +867,26 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, const unsigned char *
|
||||||
return( MBEDTLS_ERR_X509_INVALID_FORMAT );
|
return( MBEDTLS_ERR_X509_INVALID_FORMAT );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( len > (size_t) ( end - p ) )
|
end = crt_end = p + len;
|
||||||
{
|
|
||||||
mbedtls_x509_crt_free( crt );
|
|
||||||
return( MBEDTLS_ERR_X509_INVALID_FORMAT +
|
|
||||||
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
|
|
||||||
}
|
|
||||||
crt_end = p + len;
|
|
||||||
|
|
||||||
// Create and populate a new buffer for the raw field
|
|
||||||
crt->raw.len = crt_end - buf;
|
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 );
|
crt->raw.p = p = mbedtls_calloc( 1, crt->raw.len );
|
||||||
if( p == NULL )
|
if( crt->raw.p == NULL )
|
||||||
return( MBEDTLS_ERR_X509_ALLOC_FAILED );
|
return( MBEDTLS_ERR_X509_ALLOC_FAILED );
|
||||||
|
|
||||||
memcpy( p, buf, crt->raw.len );
|
memcpy( crt->raw.p, buf, crt->raw.len );
|
||||||
|
crt->own_buffer = 1;
|
||||||
|
|
||||||
// Direct pointers to the new buffer
|
|
||||||
p += crt->raw.len - len;
|
p += crt->raw.len - len;
|
||||||
end = crt_end = p + len;
|
end = crt_end = p + len;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
crt->raw.p = (unsigned char*) buf;
|
||||||
|
crt->own_buffer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TBSCertificate ::= SEQUENCE {
|
* TBSCertificate ::= SEQUENCE {
|
||||||
|
@ -1086,8 +1089,10 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, const unsigned char *
|
||||||
* Parse one X.509 certificate in DER format from a buffer and add them to a
|
* Parse one X.509 certificate in DER format from a buffer and add them to a
|
||||||
* chained list
|
* chained list
|
||||||
*/
|
*/
|
||||||
int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain, const unsigned char *buf,
|
static int mbedtls_x509_crt_parse_der_internal( mbedtls_x509_crt *chain,
|
||||||
size_t buflen )
|
const unsigned char *buf,
|
||||||
|
size_t buflen,
|
||||||
|
int make_copy )
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
mbedtls_x509_crt *crt = chain, *prev = NULL;
|
mbedtls_x509_crt *crt = chain, *prev = NULL;
|
||||||
|
@ -1119,7 +1124,7 @@ int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain, const unsigned char *bu
|
||||||
crt = crt->next;
|
crt = crt->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( ( ret = x509_crt_parse_der_core( crt, buf, buflen ) ) != 0 )
|
if( ( ret = x509_crt_parse_der_core( crt, buf, buflen, make_copy ) ) != 0 )
|
||||||
{
|
{
|
||||||
if( prev )
|
if( prev )
|
||||||
prev->next = NULL;
|
prev->next = NULL;
|
||||||
|
@ -1133,11 +1138,27 @@ int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain, const unsigned char *bu
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int mbedtls_x509_crt_parse_der_nocopy( mbedtls_x509_crt *chain,
|
||||||
|
const unsigned char *buf,
|
||||||
|
size_t buflen )
|
||||||
|
{
|
||||||
|
return( mbedtls_x509_crt_parse_der_internal( chain, buf, buflen, 0 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain,
|
||||||
|
const unsigned char *buf,
|
||||||
|
size_t buflen )
|
||||||
|
{
|
||||||
|
return( mbedtls_x509_crt_parse_der_internal( chain, buf, buflen, 1 ) );
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse one or more PEM certificates from a buffer and add them to the chained
|
* Parse one or more PEM certificates from a buffer and add them to the chained
|
||||||
* list
|
* list
|
||||||
*/
|
*/
|
||||||
int mbedtls_x509_crt_parse( mbedtls_x509_crt *chain, const unsigned char *buf, size_t buflen )
|
int mbedtls_x509_crt_parse( mbedtls_x509_crt *chain,
|
||||||
|
const unsigned char *buf,
|
||||||
|
size_t buflen )
|
||||||
{
|
{
|
||||||
#if defined(MBEDTLS_PEM_PARSE_C)
|
#if defined(MBEDTLS_PEM_PARSE_C)
|
||||||
int success = 0, first_error = 0, total_failed = 0;
|
int success = 0, first_error = 0, total_failed = 0;
|
||||||
|
@ -2675,7 +2696,7 @@ void mbedtls_x509_crt_free( mbedtls_x509_crt *crt )
|
||||||
mbedtls_free( seq_prv );
|
mbedtls_free( seq_prv );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( cert_cur->raw.p != NULL )
|
if( cert_cur->raw.p != NULL && cert_cur->own_buffer )
|
||||||
{
|
{
|
||||||
mbedtls_platform_zeroize( cert_cur->raw.p, cert_cur->raw.len );
|
mbedtls_platform_zeroize( cert_cur->raw.p, cert_cur->raw.len );
|
||||||
mbedtls_free( cert_cur->raw.p );
|
mbedtls_free( cert_cur->raw.p );
|
||||||
|
|
Loading…
Reference in a new issue