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_*().
This commit is contained in:
Andres Amaya Garcia
2017-08-24 16:14:14 +01:00
committed by Andres Amaya Garcia
parent 22b1db8a4c
commit 6def89e84e
2 changed files with 107 additions and 0 deletions

View File

@@ -37,6 +37,9 @@
#include <stdint.h>
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,

View File

@@ -44,9 +44,113 @@
#include <stdint.h>
#include <string.h>
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 );
}