From 502d4b45102a0665aa0b769c41ad1c7bdb96478e Mon Sep 17 00:00:00 2001 From: Nicola Di Lieto Date: Sat, 25 Apr 2020 14:41:25 +0200 Subject: [PATCH] New mbedtls_x509_crt_parse_der_ext() routine This routine is functionally equivalent to mbedtls_x509_crt_parse_der(), but it accepts an additional callback function which it calls with every unsupported certificate extension. Proposed solution to https://github.com/ARMmbed/mbedtls/issues/3241 Signed-off-by: Nicola Di Lieto --- include/mbedtls/x509_crt.h | 56 ++++++++++++++++++++++++++++++++++++++ library/x509_crt.c | 30 +++++++++++++++----- 2 files changed, 79 insertions(+), 7 deletions(-) diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h index e4fb13543..19de1e968 100644 --- a/include/mbedtls/x509_crt.h +++ b/include/mbedtls/x509_crt.h @@ -303,6 +303,62 @@ int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain, const unsigned char *buf, size_t buflen ); +/** + * \brief The type of certificate extension callbacks. + * + * Callbacks of this type are passed to and used by the + * mbedtls_x509_crt_parse_der_ext() routine when it encounters + * an unsupported extension. + * + * \param crt Pointer to the certificate being parsed + * \param oid Extension's OID + * \param critical If the extension is critical (per the RFC's definition) + * \param p On entry \c *p points to the start of the extension ASN.1 + * data. On successful completion \c *p must point to the + * first byte after it. + * On error, the value of \c *p is undefined. + * \param end End of extension data. + * + * \note The callback must fail and return a negative error code if + * it can not parse or does not support the extension. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +typedef int (*mbedtls_x509_crt_ext_cb_t)( mbedtls_x509_crt const *crt, + mbedtls_x509_buf const *oid, + int critical, + unsigned char **p, + const unsigned char *end ); + +/** + * \brief Parse a single DER formatted certificate and add it + * to the end of the provided chained list. + * + * \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 buffer holding the DER encoded certificate. + * \param buflen The size in Bytes of \p buf. + * \param cb A callback invoked for every unsupported certificate + * extension. + * + * \note This call is functionally equivalent to + * mbedtls_x509_crt_parse_der(), but it calls the callback + * with every unsupported certificate extension. + * The callback must return a negative error code if it + * does not know how to handle such an extension. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_x509_crt_parse_der_ext( mbedtls_x509_crt *chain, + const unsigned char *buf, + size_t buflen, + mbedtls_x509_crt_ext_cb_t cb + ); + /** * \brief Parse a single DER formatted certificate and add it * to the end of the provided chained list. This is a diff --git a/library/x509_crt.c b/library/x509_crt.c index 1e62ed5b0..9076b321b 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -892,7 +892,8 @@ static int x509_get_certificate_policies( unsigned char **p, */ static int x509_get_crt_ext( unsigned char **p, const unsigned char *end, - mbedtls_x509_crt *crt ) + mbedtls_x509_crt *crt, + mbedtls_x509_crt_ext_cb_t cb ) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; size_t len; @@ -955,6 +956,10 @@ static int x509_get_crt_ext( unsigned char **p, if( ret != 0 ) { + /* Give the callback (if any) a chance to handle the extension */ + if (cb && cb(crt, &extn_oid, is_critical, p, end_ext_octet) == 0) + continue; + /* No parser found, skip extension */ *p = end_ext_octet; @@ -1061,7 +1066,8 @@ static int x509_get_crt_ext( unsigned char **p, static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, const unsigned char *buf, size_t buflen, - int make_copy ) + int make_copy, + mbedtls_x509_crt_ext_cb_t cb ) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; size_t len; @@ -1260,7 +1266,7 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, if( crt->version == 3 ) #endif { - ret = x509_get_crt_ext( &p, end, crt ); + ret = x509_get_crt_ext( &p, end, crt, cb ); if( ret != 0 ) { mbedtls_x509_crt_free( crt ); @@ -1323,7 +1329,8 @@ static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, static int mbedtls_x509_crt_parse_der_internal( mbedtls_x509_crt *chain, const unsigned char *buf, size_t buflen, - int make_copy ) + int make_copy, + mbedtls_x509_crt_ext_cb_t cb ) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; mbedtls_x509_crt *crt = chain, *prev = NULL; @@ -1355,7 +1362,8 @@ static int mbedtls_x509_crt_parse_der_internal( mbedtls_x509_crt *chain, crt = crt->next; } - if( ( ret = x509_crt_parse_der_core( crt, buf, buflen, make_copy ) ) != 0 ) + ret = x509_crt_parse_der_core( crt, buf, buflen, make_copy, cb ); + if( ret != 0 ) { if( prev ) prev->next = NULL; @@ -1373,14 +1381,22 @@ 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 ) ); + return( mbedtls_x509_crt_parse_der_internal( chain, buf, buflen, 0, NULL ) ); +} + +int mbedtls_x509_crt_parse_der_ext( mbedtls_x509_crt *chain, + const unsigned char *buf, + size_t buflen, + mbedtls_x509_crt_ext_cb_t cb ) +{ + return( mbedtls_x509_crt_parse_der_internal( chain, buf, buflen, 1, cb ) ); } 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 ) ); + return( mbedtls_x509_crt_parse_der_internal( chain, buf, buflen, 1, NULL ) ); } /*