From 458fab99875ba83ce9bcf65d29c4c017bc993be7 Mon Sep 17 00:00:00 2001 From: akasakariko <148060537+akasakariko@users.noreply.github.com> Date: Thu, 22 Oct 2026 21:07:17 +0900 Subject: [PATCH] Reject a non-CA issuer in the cert_write program cert_write signs a certificate with the issuer key without checking that the issuer certificate may issue certificates. A certificate whose basicConstraints extension has cA=FALSE, or whose keyUsage extension does not include keyCertSign, was therefore accepted as a CA. Check the issuer certificate after loading it and reject it when it is explicitly not a CA. Certificates without a basicConstraints extension are still accepted, for compatibility with v1 and v2 certificates, which cannot carry extensions. Fixes #10779. Signed-off-by: akasakariko <148060537+akasakariko@users.noreply.github.com> --- ChangeLog.d/cert-write-issuer-not-ca.txt | 6 ++++ programs/x509/cert_write.c | 40 ++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 ChangeLog.d/cert-write-issuer-not-ca.txt diff --git a/ChangeLog.d/cert-write-issuer-not-ca.txt b/ChangeLog.d/cert-write-issuer-not-ca.txt new file mode 100644 index 0000000000..c94bf95a55 --- /dev/null +++ b/ChangeLog.d/cert-write-issuer-not-ca.txt @@ -0,0 +1,6 @@ +Bugfix + * Fix the `cert_write` sample program accepting an issuer certificate + that is not allowed to issue certificates. A certificate whose + basicConstraints extension has cA=FALSE, or whose keyUsage extension + does not include keyCertSign, is now rejected instead of being used to + sign a certificate. Fixes #10779. diff --git a/programs/x509/cert_write.c b/programs/x509/cert_write.c index 947d73f54a..b1ddc66e8e 100644 --- a/programs/x509/cert_write.c +++ b/programs/x509/cert_write.c @@ -294,6 +294,40 @@ static int parse_serial_decimal_format(unsigned char *obuf, size_t obufmax, return 0; } +/* + * Check that a certificate may be used to issue other certificates. + * + * RFC 5280 section 4.2.1.9 requires a CA certificate to have the + * basicConstraints extension with cA set to TRUE, and section 4.2.1.3 + * requires the keyCertSign bit to be set in the keyUsage extension of a + * certificate that signs certificates, if that extension is present. + * + * Certificates without a basicConstraints extension are accepted so that + * v1 and v2 certificates, which cannot carry extensions, keep working. + * + * This prints the reason for a rejection. Return 0 if the certificate may + * be used to issue certificates, or -1 otherwise. + */ +static int check_issuer_can_sign(const mbedtls_x509_crt *issuer_crt) +{ + if (mbedtls_x509_crt_get_ca_istrue(issuer_crt) == 0) { + mbedtls_printf(" failed\n ! the issuer certificate is not a CA: " + "the basicConstraints extension has cA=FALSE\n\n"); + return -1; + } + + if (mbedtls_x509_crt_has_ext_type(issuer_crt, MBEDTLS_X509_EXT_KEY_USAGE) && + mbedtls_x509_crt_check_key_usage(issuer_crt, + MBEDTLS_X509_KU_KEY_CERT_SIGN) != 0) { + mbedtls_printf(" failed\n ! the issuer certificate cannot sign " + "certificates: the keyUsage extension does not have " + "keyCertSign\n\n"); + return -1; + } + + return 0; +} + int main(int argc, char *argv[]) { int ret = 1; @@ -793,6 +827,12 @@ usage: opt.issuer_name = issuer_name; + /* Refuse to issue a certificate from a certificate that is not + * allowed to sign certificates. */ + if (check_issuer_can_sign(&issuer_crt) != 0) { + goto exit; + } + mbedtls_printf(" ok\n"); }