Added parameters to add callback function to handle unsupported extensions. Similar to how the callback functions work when parsing certificates. Also added new test cases.

Signed-off-by: Matthias Schulz <mschulz@hilscher.com>
This commit is contained in:
Matthias Schulz 2023-10-18 13:20:59 +02:00
parent 873a202d18
commit ab4082290e
4 changed files with 218 additions and 45 deletions

View file

@ -102,6 +102,64 @@ mbedtls_x509write_csr;
int mbedtls_x509_csr_parse_der(mbedtls_x509_csr *csr, int mbedtls_x509_csr_parse_der(mbedtls_x509_csr *csr,
const unsigned char *buf, size_t buflen); 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_csr_parse_der_with_ext_cb() routine when
* it encounters either an unsupported extension.
* Future versions of the library may invoke the callback
* in other cases, if and when the need arises.
*
* \param p_ctx An opaque context passed to the callback.
* \param csr The CSR being parsed.
* \param oid The OID of the extension.
* \param critical Whether the extension is critical.
* \param p Pointer to the start of the extension value
* (the content of the OCTET STRING).
* \param end End of extension value.
*
* \note The callback must fail and return a negative error code
* if it can not parse or does not support the extension.
* When the callback fails to parse a critical extension
* mbedtls_x509_csr_parse_der_with_ext_cb() also fails.
* When the callback fails to parse a non critical extension
* mbedtls_x509_csr_parse_der_with_ext_cb() simply skips
* the extension and continues parsing.
*
* \return \c 0 on success.
* \return A negative error code on failure.
*/
typedef int (*mbedtls_x509_csr_ext_cb_t)(void *p_ctx,
mbedtls_x509_csr const *csr,
mbedtls_x509_buf const *oid,
int critical,
const unsigned char *p,
const unsigned char *end);
/**
* \brief Load a Certificate Signing Request (CSR) in DER format
*
* \note CSR attributes (if any) are currently silently ignored.
*
* \note If #MBEDTLS_USE_PSA_CRYPTO is enabled, the PSA crypto
* subsystem must have been initialized by calling
* psa_crypto_init() before calling this function.
*
* \param csr CSR context to fill
* \param buf buffer holding the CRL data
* \param buflen size of the buffer
* \param cb A callback invoked for every unsupported certificate
* extension.
* \param p_ctx An opaque context passed to the callback.
*
* \return 0 if successful, or a specific X509 error code
*/
int mbedtls_x509_csr_parse_der_with_ext_cb(mbedtls_x509_csr *csr,
const unsigned char *buf, size_t buflen,
mbedtls_x509_csr_ext_cb_t cb,
void *p_ctx);
/** /**
* \brief Load a Certificate Signing Request (CSR), DER or PEM format * \brief Load a Certificate Signing Request (CSR), DER or PEM format
* *

View file

@ -73,11 +73,13 @@ static int x509_csr_get_version(unsigned char **p,
* Parse CSR extension requests in DER format * Parse CSR extension requests in DER format
*/ */
static int x509_csr_parse_extensions(mbedtls_x509_csr *csr, static int x509_csr_parse_extensions(mbedtls_x509_csr *csr,
unsigned char **p, const unsigned char *end) unsigned char **p, const unsigned char *end,
mbedtls_x509_csr_ext_cb_t cb,
void *p_ctx)
{ {
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t len; size_t len;
unsigned char *end_ext_data; unsigned char *end_ext_data, *end_ext_octet;
while (*p < end) { while (*p < end) {
mbedtls_x509_buf extn_oid = { 0, 0, NULL }; mbedtls_x509_buf extn_oid = { 0, 0, NULL };
@ -114,7 +116,9 @@ static int x509_csr_parse_extensions(mbedtls_x509_csr *csr,
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
} }
if (*p + len != end_ext_data) { end_ext_octet = *p + len;
if (end_ext_octet != end_ext_data) {
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
} }
@ -124,7 +128,28 @@ static int x509_csr_parse_extensions(mbedtls_x509_csr *csr,
*/ */
ret = mbedtls_oid_get_x509_ext_type(&extn_oid, &ext_type); ret = mbedtls_oid_get_x509_ext_type(&extn_oid, &ext_type);
if (ret == 0) { if (ret != 0) {
/* Give the callback (if any) a chance to handle the extension */
if (cb != NULL) {
ret = cb(p_ctx, csr, &extn_oid, is_critical, *p, end_ext_octet);
if (ret != 0 && is_critical) {
return ret;
}
*p = end_ext_octet;
continue;
}
/* No parser found, skip extension */
*p = end_ext_octet;
if (is_critical) {
/* Data is marked as critical: fail */
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
MBEDTLS_ERR_ASN1_UNEXPECTED_TAG);
}
continue;
}
/* Forbid repeated extensions */ /* Forbid repeated extensions */
if ((csr->ext_types & ext_type) != 0) { if ((csr->ext_types & ext_type) != 0) {
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
@ -158,16 +183,17 @@ static int x509_csr_parse_extensions(mbedtls_x509_csr *csr,
} }
break; break;
default: default:
break; /*
} * If this is a non-critical extension, which the oid layer
} else { * supports, but there isn't an x509 parser for it,
* skip the extension.
*/
if (is_critical) { if (is_critical) {
/* Data is marked as critical: fail */ return MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE;
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, } else {
MBEDTLS_ERR_ASN1_UNEXPECTED_TAG); *p = end_ext_octet;
} }
} }
*p = end_ext_data;
} }
if (*p != end) { if (*p != end) {
@ -182,7 +208,9 @@ static int x509_csr_parse_extensions(mbedtls_x509_csr *csr,
* Parse CSR attributes in DER format * Parse CSR attributes in DER format
*/ */
static int x509_csr_parse_attributes(mbedtls_x509_csr *csr, static int x509_csr_parse_attributes(mbedtls_x509_csr *csr,
const unsigned char *start, const unsigned char *end) const unsigned char *start, const unsigned char *end,
mbedtls_x509_csr_ext_cb_t cb,
void *p_ctx)
{ {
int ret; int ret;
size_t len; size_t len;
@ -221,7 +249,7 @@ static int x509_csr_parse_attributes(mbedtls_x509_csr *csr,
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
} }
if ((ret = x509_csr_parse_extensions(csr, p, *p + len)) != 0) { if ((ret = x509_csr_parse_extensions(csr, p, *p + len, cb, p_ctx)) != 0) {
return ret; return ret;
} }
@ -245,8 +273,10 @@ static int x509_csr_parse_attributes(mbedtls_x509_csr *csr,
/* /*
* Parse a CSR in DER format * Parse a CSR in DER format
*/ */
int mbedtls_x509_csr_parse_der(mbedtls_x509_csr *csr, static int mbedtls_x509_csr_parse_der_internal(mbedtls_x509_csr *csr,
const unsigned char *buf, size_t buflen) const unsigned char *buf, size_t buflen,
mbedtls_x509_csr_ext_cb_t cb,
void *p_ctx)
{ {
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t len; size_t len;
@ -370,7 +400,7 @@ int mbedtls_x509_csr_parse_der(mbedtls_x509_csr *csr,
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, ret); return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_FORMAT, ret);
} }
if ((ret = x509_csr_parse_attributes(csr, p, p + len)) != 0) { if ((ret = x509_csr_parse_attributes(csr, p, p + len, cb, p_ctx)) != 0) {
mbedtls_x509_csr_free(csr); mbedtls_x509_csr_free(csr);
return ret; return ret;
} }
@ -409,6 +439,26 @@ int mbedtls_x509_csr_parse_der(mbedtls_x509_csr *csr,
return 0; return 0;
} }
/*
* Parse a CSR in DER format
*/
int mbedtls_x509_csr_parse_der(mbedtls_x509_csr *csr,
const unsigned char *buf, size_t buflen)
{
return mbedtls_x509_csr_parse_der_internal(csr, buf, buflen, NULL, NULL);
}
/*
* Parse a CSR in DER format with callback for unknown extensions
*/
int mbedtls_x509_csr_parse_der_with_ext_cb(mbedtls_x509_csr *csr,
const unsigned char *buf, size_t buflen,
mbedtls_x509_csr_ext_cb_t cb,
void *p_ctx)
{
return mbedtls_x509_csr_parse_der_internal(csr, buf, buflen, cb, p_ctx);
}
/* /*
* Parse a CSR, allowing for PEM or raw DER encoding * Parse a CSR, allowing for PEM or raw DER encoding
*/ */

View file

@ -2940,9 +2940,17 @@ X509 CSR ASN.1 (OK)
depends_on:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_MD_CAN_SHA1:!MBEDTLS_X509_REMOVE_INFO depends_on:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_MD_CAN_SHA1:!MBEDTLS_X509_REMOVE_INFO
mbedtls_x509_csr_parse:"308201183081bf0201003034310b3009060355040613024e4c3111300f060355040a1308506f6c617253534c31123010060355040313096c6f63616c686f73743059301306072a8648ce3d020106082a8648ce3d0301070342000437cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f768225962924ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edffa029302706092a864886f70d01090e311a301830090603551d1304023000300b0603551d0f0404030205e0300906072a8648ce3d04010349003046022100b49fd8c8f77abfa871908dfbe684a08a793d0f490a43d86fcf2086e4f24bb0c2022100f829d5ccd3742369299e6294394717c4b723a0f68b44e831b6e6c3bcabf97243":"CSR version \: 1\nsubject name \: C=NL, O=PolarSSL, CN=localhost\nsigned using \: ECDSA with SHA1\nEC key size \: 256 bits\n\nkey usage \: Digital Signature, Non Repudiation, Key Encipherment\n":0 mbedtls_x509_csr_parse:"308201183081bf0201003034310b3009060355040613024e4c3111300f060355040a1308506f6c617253534c31123010060355040313096c6f63616c686f73743059301306072a8648ce3d020106082a8648ce3d0301070342000437cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f768225962924ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edffa029302706092a864886f70d01090e311a301830090603551d1304023000300b0603551d0f0404030205e0300906072a8648ce3d04010349003046022100b49fd8c8f77abfa871908dfbe684a08a793d0f490a43d86fcf2086e4f24bb0c2022100f829d5ccd3742369299e6294394717c4b723a0f68b44e831b6e6c3bcabf97243":"CSR version \: 1\nsubject name \: C=NL, O=PolarSSL, CN=localhost\nsigned using \: ECDSA with SHA1\nEC key size \: 256 bits\n\nkey usage \: Digital Signature, Non Repudiation, Key Encipherment\n":0
X509 CSR ASN.1 (critical extensions) X509 CSR ASN.1 (Unsupported critical extension)
depends_on:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_MD_CAN_SHA256:!MBEDTLS_X509_REMOVE_INFO depends_on:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_MD_CAN_SHA256:!MBEDTLS_X509_REMOVE_INFO
mbedtls_x509_csr_parse:"308201233081cb02010030413119301706035504030c1053656c66207369676e65642074657374310b300906035504061302444531173015060355040a0c0e41757468437274444220546573743059301306072a8648ce3d020106082a8648ce3d03010703420004c11ebb9951848a436ca2c8a73382f24bbb6c28a92e401d4889b0c361f377b92a8b0497ff2f5a5f6057ae85f704ab1850bef075914f68ed3aeb15a1ff1ebc0dc6a028302606092a864886f70d01090e311930173015060b2b0601040183890c8622020101ff0403010101300a06082a8648ce3d040302034700304402200c4108fd098525993d3fd5b113f0a1ead8750852baf55a2f8e670a22cabc0ba1022034db93a0fcb993912adcf2ea8cb4b66389af30e264d43c0daea03255e45d2ccc":"CSR version \: 1\nsubject name \: CN=Self signed test, C=DE, O=AuthCrtDB Test\nsigned using \: ECDSA with SHA256\nEC key size \: 256 bits\n":0 mbedtls_x509_csr_parse:"308201233081cb02010030413119301706035504030c1053656c66207369676e65642074657374310b300906035504061302444531173015060355040a0c0e41757468437274444220546573743059301306072a8648ce3d020106082a8648ce3d03010703420004c11ebb9951848a436ca2c8a73382f24bbb6c28a92e401d4889b0c361f377b92a8b0497ff2f5a5f6057ae85f704ab1850bef075914f68ed3aeb15a1ff1ebc0dc6a028302606092a864886f70d01090e311930173015060b2b0601040183890c8622020101ff0403010101300a06082a8648ce3d040302034700304402200c4108fd098525993d3fd5b113f0a1ead8750852baf55a2f8e670a22cabc0ba1022034db93a0fcb993912adcf2ea8cb4b66389af30e264d43c0daea03255e45d2ccc":"":MBEDTLS_ERR_X509_INVALID_EXTENSIONS+MBEDTLS_ERR_ASN1_UNEXPECTED_TAG
X509 CSR ASN.1 (Unsupported critical extension accepted by callback)
depends_on:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_MD_CAN_SHA256:!MBEDTLS_X509_REMOVE_INFO
mbedtls_x509_csr_parse_with_ext_cb:"308201233081cb02010030413119301706035504030c1053656c66207369676e65642074657374310b300906035504061302444531173015060355040a0c0e41757468437274444220546573743059301306072a8648ce3d020106082a8648ce3d03010703420004c11ebb9951848a436ca2c8a73382f24bbb6c28a92e401d4889b0c361f377b92a8b0497ff2f5a5f6057ae85f704ab1850bef075914f68ed3aeb15a1ff1ebc0dc6a028302606092a864886f70d01090e311930173015060b2b0601040183890c8622020101ff0403010101300a06082a8648ce3d040302034700304402200c4108fd098525993d3fd5b113f0a1ead8750852baf55a2f8e670a22cabc0ba1022034db93a0fcb993912adcf2ea8cb4b66389af30e264d43c0daea03255e45d2ccc":"CSR version \: 1\nsubject name \: CN=Self signed test, C=DE, O=AuthCrtDB Test\nsigned using \: ECDSA with SHA256\nEC key size \: 256 bits\n":0:1
X509 CSR ASN.1 (Unsupported critical extension rejected by callback)
depends_on:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_MD_CAN_SHA256:!MBEDTLS_X509_REMOVE_INFO
mbedtls_x509_csr_parse_with_ext_cb:"308201233081cb02010030413119301706035504030c1053656c66207369676e65642074657374310b300906035504061302444531173015060355040a0c0e41757468437274444220546573743059301306072a8648ce3d020106082a8648ce3d03010703420004c11ebb9951848a436ca2c8a73382f24bbb6c28a92e401d4889b0c361f377b92a8b0497ff2f5a5f6057ae85f704ab1850bef075914f68ed3aeb15a1ff1ebc0dc6a028302606092a864886f70d01090e311930173015060b2b0601040183890c8622020101ff0403010101300a06082a8648ce3d040302034700304402200c4108fd098525993d3fd5b113f0a1ead8750852baf55a2f8e670a22cabc0ba1022034db93a0fcb993912adcf2ea8cb4b66389af30e264d43c0daea03255e45d2ccc":"":MBEDTLS_ERR_X509_INVALID_EXTENSIONS+MBEDTLS_ERR_ASN1_UNEXPECTED_TAG:0
X509 CSR ASN.1 (bad first tag) X509 CSR ASN.1 (bad first tag)
mbedtls_x509_csr_parse:"3100":"":MBEDTLS_ERR_X509_INVALID_FORMAT mbedtls_x509_csr_parse:"3100":"":MBEDTLS_ERR_X509_INVALID_FORMAT

View file

@ -412,6 +412,33 @@ int parse_crt_ext_cb(void *p_ctx, mbedtls_x509_crt const *crt, mbedtls_x509_buf
MBEDTLS_ERR_ASN1_UNEXPECTED_TAG); MBEDTLS_ERR_ASN1_UNEXPECTED_TAG);
} }
} }
int parse_csr_ext_accept_cb(void *p_ctx, mbedtls_x509_csr const *csr, mbedtls_x509_buf const *oid,
int critical, const unsigned char *cp, const unsigned char *end)
{
(void) p_ctx;
(void) csr;
(void) oid;
(void) critical;
(void) cp;
(void) end;
return 0;
}
int parse_csr_ext_reject_cb(void *p_ctx, mbedtls_x509_csr const *csr, mbedtls_x509_buf const *oid,
int critical, const unsigned char *cp, const unsigned char *end)
{
(void) p_ctx;
(void) csr;
(void) oid;
(void) critical;
(void) cp;
(void) end;
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
MBEDTLS_ERR_ASN1_UNEXPECTED_TAG);
}
#endif /* MBEDTLS_X509_CRT_PARSE_C */ #endif /* MBEDTLS_X509_CRT_PARSE_C */
/* END_HEADER */ /* END_HEADER */
@ -1245,6 +1272,36 @@ exit:
} }
/* END_CASE */ /* END_CASE */
/* BEGIN_CASE depends_on:MBEDTLS_X509_CSR_PARSE_C:!MBEDTLS_X509_REMOVE_INFO */
void mbedtls_x509_csr_parse_with_ext_cb(data_t *csr_der, char *ref_out, int ref_ret, int accept)
{
mbedtls_x509_csr csr;
char my_out[1000];
int my_ret;
mbedtls_x509_csr_init(&csr);
USE_PSA_INIT();
memset(my_out, 0, sizeof(my_out));
my_ret = mbedtls_x509_csr_parse_der_with_ext_cb(&csr, csr_der->x, csr_der->len,
accept ? parse_csr_ext_accept_cb :
parse_csr_ext_reject_cb,
NULL);
TEST_EQUAL(my_ret, ref_ret);
if (ref_ret == 0) {
size_t my_out_len = mbedtls_x509_csr_info(my_out, sizeof(my_out), "", &csr);
TEST_EQUAL(my_out_len, strlen(ref_out));
TEST_EQUAL(strcmp(my_out, ref_out), 0);
}
exit:
mbedtls_x509_csr_free(&csr);
USE_PSA_DONE();
}
/* END_CASE */
/* BEGIN_CASE depends_on:MBEDTLS_FS_IO:MBEDTLS_X509_CSR_PARSE_C:!MBEDTLS_X509_REMOVE_INFO */ /* BEGIN_CASE depends_on:MBEDTLS_FS_IO:MBEDTLS_X509_CSR_PARSE_C:!MBEDTLS_X509_REMOVE_INFO */
void mbedtls_x509_csr_parse_file(char *csr_file, char *ref_out, int ref_ret) void mbedtls_x509_csr_parse_file(char *csr_file, char *ref_out, int ref_ret)
{ {