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"); }