From 5af05a964ad379360a1c7634916dc3f92316a322 Mon Sep 17 00:00:00 2001 From: v1rtu3x <149050962+v1rtu3x@users.noreply.github.com> Date: Fri, 16 Oct 2026 13:53:40 +0300 Subject: [PATCH 1/2] x509: Accept basicConstraints with omitted cA RFC 5280 defines cA as BOOLEAN DEFAULT FALSE, so a basicConstraints extension containing only pathLenConstraint (SEQUENCE { INTEGER n }) is syntactically valid and must be interpreted as cA=FALSE. The fix for CVE-2026-49300 rejected this encoding outright, breaking compatibility with certificates emitted by devices such as Eaton/CODESYS PLCs. Tolerate MBEDTLS_ERR_ASN1_UNEXPECTED_TAG from the cA BOOLEAN parse, keeping cA FALSE and letting the existing INTEGER parser validate pathLenConstraint. The INTEGER value is never used to determine cA, so the CVE fix is preserved. Fixes #11006 Signed-off-by: v1rtu3x <149050962+v1rtu3x@users.noreply.github.com> (cherry picked from commit 62dd8a556c01cc289d4fb3f19352a78ede90dac2) --- .../x509-basic-constraints-integer-first.txt | 5 +++++ library/x509_crt.c | 12 +++++----- tests/suites/test_suite_x509parse.data | 20 +++++++++++++++-- tests/suites/test_suite_x509parse.function | 22 +++++++++++++++++++ 4 files changed, 52 insertions(+), 7 deletions(-) create mode 100644 ChangeLog.d/x509-basic-constraints-integer-first.txt diff --git a/ChangeLog.d/x509-basic-constraints-integer-first.txt b/ChangeLog.d/x509-basic-constraints-integer-first.txt new file mode 100644 index 0000000000..409a626aa0 --- /dev/null +++ b/ChangeLog.d/x509-basic-constraints-integer-first.txt @@ -0,0 +1,5 @@ +Bugfix + * Accept a basicConstraints extension that omits cA and contains only + pathLenConstraint, interpreting it as cA=FALSE as specified by RFC 5280. + This restores compatibility with certificates emitted by some devices + without accepting them as CA certificates. Fixes #11006. diff --git a/library/x509_crt.c b/library/x509_crt.c index f9e36470cb..4a40a25b38 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -519,17 +519,19 @@ static int x509_get_basic_constraints(unsigned char **p, } if ((ret = mbedtls_asn1_get_bool(p, end, ca_istrue)) != 0) { - /* If the SEQUENCE starts with an INTEGER and not a BOOLEAN, - * according to RFC 5280, it's syntactically valid, but it's - * something that a CA MUST NOT produce. So we reject it. + /* cA is DEFAULT FALSE. If it is absent, the first element must + * be pathLenConstraint. Keep cA false and let the INTEGER parser + * below validate the element. * * Note: historically, from XySSL 0.9 to Mbed TLS 3.6.6/4.1.0, * `SEQUENCE { INTEGER n }` was interpreted as cA=FALSE if n == 0 * and cA=TRUE if n != 0. This was dangerous since * `SEQUENCE { INTEGER n }` should be parsed as cA=FALSE - * according to RFC 5280, so we stopped doing it. + * according to RFC 5280. */ - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); + if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) { + return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret); + } } /* `SEQUENCE { BOOLEAN FALSE }` is not DER since default-value fields * must be omitted in DER. But it seems harmless, and Mbed TLS has diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data index f8e60298eb..d3837a41d8 100644 --- a/tests/suites/test_suite_x509parse.data +++ b/tests/suites/test_suite_x509parse.data @@ -2070,11 +2070,27 @@ mbedtls_x509_crt_parse_file:"../framework/data_files/parse_input/server5.basic-c X509 CRT ASN1: basicConstraints: no cA but pathLenConstraint (bad signature) depends_on:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_MD_CAN_SHA256 -mbedtls_x509_crt_parse_file:"../framework/data_files/parse_input/server5.basic-constraints-integer-first.badsign.crt":MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, MBEDTLS_ERR_ASN1_UNEXPECTED_TAG):0 +mbedtls_x509_crt_parse_file:"../framework/data_files/parse_input/server5.basic-constraints-integer-first.badsign.crt":0:1 + +X509 CRT ASN1: basicConstraints: no cA, pathLen only: not a CA +depends_on:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_MD_CAN_SHA256 +mbedtls_x509_get_ca_istrue:"../framework/data_files/parse_input/server5.basic-constraints-integer-first.badsign.crt":0 X509 CRT ASN1: basicConstraints: no cA but pathLenConstraint (good self signature) depends_on:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_MD_CAN_SHA256 -mbedtls_x509_crt_parse_file:"../framework/data_files/parse_input/server5.basic-constraints-integer-first.selfsigned.crt":MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, MBEDTLS_ERR_ASN1_UNEXPECTED_TAG):0 +mbedtls_x509_crt_parse_file:"../framework/data_files/parse_input/server5.basic-constraints-integer-first.selfsigned.crt":0:1 + +X509 CRT ASN1: basicConstraints: no cA but zero pathLenConstraint +depends_on:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_MD_CAN_SHA256 +x509_crt_parse_basic_constraints:"308201573081fea003020102020c53a2cb4b124ead837da894b2300a06082a8648ce3d040302300e310c300a06035504030c03457665301e170d3236303531323039353330345a170d3336303531323039353330345a300e310c300a06035504030c034576653059301306072a8648ce3d020106082a8648ce3d0301070342000437cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f768225962924ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edffa3423040300f0603551d130101ff04053003020100300e0603551d0f0101ff040403020780301d0603551d0e041604145061a58fd407d9d782010ce5657f8c6346a713be300a06082a8648ce3d0403020348003045022100d67d572af0aa540cd0f9d86d43788c178ca9501d8c0f4f6690c773f4b82c4b9a022011620feee62aca3944b8321636849030014ef80604550031312bb707b7f2bf04":0:0:0 + +X509 CRT ASN1: basicConstraints: invalid cA BOOLEAN length +depends_on:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_MD_CAN_SHA256 +x509_crt_parse_basic_constraints:"308201573081fea003020102020c53a2cb4b124ead837da894b2300a06082a8648ce3d040302300e310c300a06035504030c03457665301e170d3236303531323039353330345a170d3336303531323039353330345a300e310c300a06035504030c034576653059301306072a8648ce3d020106082a8648ce3d0301070342000437cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f768225962924ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edffa3423040300f0603551d130101ff040530030100ff300e0603551d0f0101ff040403020780301d0603551d0e041604145061a58fd407d9d782010ce5657f8c6346a713be300a06082a8648ce3d0403020348003045022100d67d572af0aa540cd0f9d86d43788c178ca9501d8c0f4f6690c773f4b82c4b9a022011620feee62aca3944b8321636849030014ef80604550031312bb707b7f2bf04":MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, MBEDTLS_ERR_ASN1_INVALID_LENGTH):0:0 + +X509 CRT ASN1: basicConstraints: neither cA nor pathLenConstraint +depends_on:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_MD_CAN_SHA256 +x509_crt_parse_basic_constraints:"308201573081fea003020102020c53a2cb4b124ead837da894b2300a06082a8648ce3d040302300e310c300a06035504030c03457665301e170d3236303531323039353330345a170d3336303531323039353330345a300e310c300a06035504030c034576653059301306072a8648ce3d020106082a8648ce3d0301070342000437cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f768225962924ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edffa3423040300f0603551d130101ff04053003050100300e0603551d0f0101ff040403020780301d0603551d0e041604145061a58fd407d9d782010ce5657f8c6346a713be300a06082a8648ce3d0403020348003045022100d67d572af0aa540cd0f9d86d43788c178ca9501d8c0f4f6690c773f4b82c4b9a022011620feee62aca3944b8321636849030014ef80604550031312bb707b7f2bf04":MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, MBEDTLS_ERR_ASN1_UNEXPECTED_TAG):0:0 X509 CRT ASN1 (TBS, inv extBasicConstraint, no pathlen length) depends_on:MBEDTLS_RSA_C:MBEDTLS_MD_CAN_SHA256 diff --git a/tests/suites/test_suite_x509parse.function b/tests/suites/test_suite_x509parse.function index a35a03f540..ba5a27f7e6 100644 --- a/tests/suites/test_suite_x509parse.function +++ b/tests/suites/test_suite_x509parse.function @@ -1121,6 +1121,28 @@ exit: } /* END_CASE */ +/* BEGIN_CASE depends_on:MBEDTLS_X509_CRT_PARSE_C */ +void x509_crt_parse_basic_constraints(data_t *buf, int result, + int ca_istrue, int path_len_constraint) +{ + mbedtls_x509_crt crt; + + mbedtls_x509_crt_init(&crt); + USE_PSA_INIT(); + + TEST_EQUAL(mbedtls_x509_crt_parse_der(&crt, buf->x, buf->len), result); + if (result == 0) { + TEST_EQUAL(mbedtls_x509_crt_get_ca_istrue(&crt), ca_istrue); + /* max_pathlen is 1 higher than pathLenConstraint. */ + TEST_EQUAL(crt.max_pathlen, path_len_constraint + 1); + } + +exit: + mbedtls_x509_crt_free(&crt); + USE_PSA_DONE(); +} +/* END_CASE */ + /* BEGIN_CASE depends_on:MBEDTLS_X509_CRT_PARSE_C */ void x509parse_crt(data_t *buf, char *result_str, int result) { From 07192886c15159f1c106b2fd6f4a04d662969852 Mon Sep 17 00:00:00 2001 From: v1rtu3x <149050962+v1rtu3x@users.noreply.github.com> Date: Tue, 20 Oct 2026 11:50:52 +0300 Subject: [PATCH 2/2] tests: Clarify pathLenConstraint values in test descriptions Signed-off-by: v1rtu3x <149050962+v1rtu3x@users.noreply.github.com> (cherry picked from commit 1b3bbfd4a24b3d3c17cf5ac94c4576bba81f6ce5) --- tests/suites/test_suite_x509parse.data | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data index d3837a41d8..e09cc1e61c 100644 --- a/tests/suites/test_suite_x509parse.data +++ b/tests/suites/test_suite_x509parse.data @@ -2072,7 +2072,7 @@ X509 CRT ASN1: basicConstraints: no cA but pathLenConstraint (bad signature) depends_on:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_MD_CAN_SHA256 mbedtls_x509_crt_parse_file:"../framework/data_files/parse_input/server5.basic-constraints-integer-first.badsign.crt":0:1 -X509 CRT ASN1: basicConstraints: no cA, pathLen only: not a CA +X509 CRT ASN1: basicConstraints: no cA, pathLenConstraint=1 depends_on:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_MD_CAN_SHA256 mbedtls_x509_get_ca_istrue:"../framework/data_files/parse_input/server5.basic-constraints-integer-first.badsign.crt":0 @@ -2080,7 +2080,7 @@ X509 CRT ASN1: basicConstraints: no cA but pathLenConstraint (good self signatur depends_on:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_MD_CAN_SHA256 mbedtls_x509_crt_parse_file:"../framework/data_files/parse_input/server5.basic-constraints-integer-first.selfsigned.crt":0:1 -X509 CRT ASN1: basicConstraints: no cA but zero pathLenConstraint +X509 CRT ASN1: basicConstraints: no cA but pathLenConstraint=0 depends_on:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_ECP_HAVE_SECP256R1:MBEDTLS_MD_CAN_SHA256 x509_crt_parse_basic_constraints:"308201573081fea003020102020c53a2cb4b124ead837da894b2300a06082a8648ce3d040302300e310c300a06035504030c03457665301e170d3236303531323039353330345a170d3336303531323039353330345a300e310c300a06035504030c034576653059301306072a8648ce3d020106082a8648ce3d0301070342000437cc56d976091e5a723ec7592dff206eee7cf9069174d0ad14b5f768225962924ee500d82311ffea2fd2345d5d16bd8a88c26b770d55cd8a2a0efa01c8b4edffa3423040300f0603551d130101ff04053003020100300e0603551d0f0101ff040403020780301d0603551d0e041604145061a58fd407d9d782010ce5657f8c6346a713be300a06082a8648ce3d0403020348003045022100d67d572af0aa540cd0f9d86d43788c178ca9501d8c0f4f6690c773f4b82c4b9a022011620feee62aca3944b8321636849030014ef80604550031312bb707b7f2bf04":0:0:0