From 6def89e84ed6c84101537b950e6466b834f7ed0e Mon Sep 17 00:00:00 2001 From: Andres Amaya Garcia Date: Thu, 24 Aug 2017 16:14:14 +0100 Subject: [PATCH] Parse the OCSPResponse top level components Add parsing for the OCSPResponse top level components: OCSPResponse ::= SEQUENCE { responseStatus OCSPResponseStatus, responseBytes [0] EXPLICIT ResponseBytes OPTIONAL } The added code does the following: 1. Parse the top level SEQUENCE 2. Call x509_ocsp_get_response_status() which will parse the responseStatus in the future 3. If there is any data left in the buffer, parses the EXPLICIT tag and calls x509_ocsp_get_response_bytes() which will parse the responseBytes in the future At this stage, the main framework for the code is being set up. The idea is that each function will parse the top level components of the ASN1 objects and hand over the parsing of each of the individual sub-components to other functions. Also, note that each function its responsible for checking that: 1. At the begining, there is enough space in the buffer p to parse whatever is being processed before end. 2. Prior to returning, the length specified in the ASN1 encoding matches the number of bytes consumed from the buffer p. 3. The lengths of any intermediate sub-components (such as EXPLICIT tags) parsed matches the number of bytes consumed by the called functions x509_ocsp_get_*(). --- include/mbedtls/x509_ocsp.h | 3 ++ library/x509_ocsp.c | 104 ++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+) diff --git a/include/mbedtls/x509_ocsp.h b/include/mbedtls/x509_ocsp.h index 83b62152fe..8e8ae9822c 100644 --- a/include/mbedtls/x509_ocsp.h +++ b/include/mbedtls/x509_ocsp.h @@ -37,6 +37,9 @@ #include typedef struct mbedtls_x509_ocsp_response { + mbedtls_x509_buf raw; /**< The raw response data (DER). */ + + uint8_t resp_status; /**< The OCSP response status */ } mbedtls_x509_ocsp_response; int mbedtls_x509_ocsp_response_info( char *buf, size_t size, diff --git a/library/x509_ocsp.c b/library/x509_ocsp.c index 8dc7ee53dc..663807570b 100644 --- a/library/x509_ocsp.c +++ b/library/x509_ocsp.c @@ -44,9 +44,113 @@ #include #include +static int x509_ocsp_get_response_status( unsigned char **p, + const unsigned char *end, + uint8_t *resp_status ) +{ + return( 0 ); +} + +static int x509_ocsp_get_response_bytes( unsigned char **p, + const unsigned char *end, + mbedtls_x509_buf *resp_type ) +{ + return( 0 ); +} + int mbedtls_x509_ocsp_parse_response( mbedtls_x509_ocsp_response *resp, unsigned char *buf, size_t buflen ) { + int ret; + size_t len; + unsigned char *p, *end; + + if( resp == NULL || buf == NULL ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + p = buf; + len = buflen; + end = p + len; + + /* + * OCSPResponse ::= SEQUENCE { + * responseStatus OCSPResponseStatus, + * responseBytes [0] EXPLICIT ResponseBytes OPTIONAL } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); + } + + /* This check is a small optimisation to ensure the buffer length matches + * before we attempt to parse the OCSPResponse. In reality, this check is + * not needed + */ + if( p + len != end ) + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + /* + * We do not need to check that len > end - p as this is done by + * mbedtls_asn1_get_tag(). + */ + + /* Populate a new buffer for the raw field */ + resp->raw.tag = MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE; + resp->raw.len = len; + resp->raw.p = mbedtls_calloc( 1, resp->raw.len ); + if( resp->raw.p == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + memcpy( resp->raw.p, p, resp->raw.len ); + + p = resp->raw.p; + end = p + resp->raw.len; + + /* + * OCSPResponseStatus ::= ENUMERATED { + * successful (0), -- Response has valid confirmations + * malformedRequest (1), -- Illegal confirmation request + * internalError (2), -- Internal error in issuer + * tryLater (3), -- Try again later + * -- (4) is not used + * sigRequired (5), -- Must sign the request + * unauthorized (6) -- Request unauthorized } + */ + if( ( ret = x509_ocsp_get_response_status( &p, end, + &resp->resp_status ) ) != 0 ) + { + return( ret ); + } + + /* ResponseBytes is optional, skip if not found */ + if( p == end ) + return( 0 ); + + /* Get the [0] EXPLICIT tag for the optional ResponseBytes */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0 ) ) != 0 ) + { + return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); + } + + if( p + len != end ) + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + if( ( ret = x509_ocsp_get_response_bytes( resp, &p, end ) ) != 0 ) + return( ret ); + + /* This might seems slightly redundant, but the idea is that each parsing + * function checks the begin and end bounds for the section of the + * OCSPResponse that it parses. This implies that some checks will be + * duplicated, but it makes it easier to reason about. + */ + if( p != end ) + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + return( 0 ); }