Encode basicConstraints critical flag and pathlen into generated CSRs

This commit is contained in:
Chris Conlon
2026-07-31 17:46:16 -06:00
parent 41b7a0209a
commit 9e5c365cd1
3 changed files with 110 additions and 5 deletions
+22 -4
View File
@@ -11846,6 +11846,18 @@ WOLF_STACK_OF(WOLFSSL_X509_OBJECT)* wolfSSL_sk_X509_OBJECT_deep_copy(
cert->version = req->version;
cert->isCA = req->isCa;
cert->basicConstSet = req->basicConstSet;
cert->basicConstCrit = req->basicConstCrit;
if (req->pathLengthSet) {
if (req->pathLength > WOLFSSL_MAX_PATH_LEN) {
WOLFSSL_MSG("Basic Constraints path length too large");
WOLFSSL_ERROR_VERBOSE(ASN_PATHLEN_SIZE_E);
ret = WOLFSSL_FAILURE;
}
else {
cert->pathLen = (byte)req->pathLength;
cert->pathLenSet = req->pathLengthSet;
}
}
#ifdef WOLFSSL_CERT_EXT
if (req->subjKeyIdSz != 0) {
if (req->subjKeyIdSz > CTC_MAX_SKID_SIZE) {
@@ -11859,8 +11871,7 @@ WOLF_STACK_OF(WOLFSSL_X509_OBJECT)* wolfSSL_sk_X509_OBJECT_deep_copy(
ret = WOLFSSL_FAILURE;
}
else {
XMEMCPY(cert->skid, req->subjKeyId,
req->subjKeyIdSz);
XMEMCPY(cert->skid, req->subjKeyId, req->subjKeyIdSz);
cert->skidSz = (int)req->subjKeyIdSz;
}
}
@@ -12009,8 +12020,15 @@ static int CertFromX509(Cert* cert, WOLFSSL_X509* x509)
cert->isCA = wolfSSL_X509_get_isCA(x509);
cert->basicConstCrit = x509->basicConstCrit;
cert->basicConstSet = x509->basicConstSet;
cert->pathLen = (byte)x509->pathLength;
cert->pathLenSet = x509->pathLengthSet;
if (x509->pathLengthSet) {
if (x509->pathLength > WOLFSSL_MAX_PATH_LEN) {
WOLFSSL_MSG("Basic Constraints path length too large");
WOLFSSL_ERROR_VERBOSE(ASN_PATHLEN_SIZE_E);
return WOLFSSL_FAILURE;
}
cert->pathLen = (byte)x509->pathLength;
cert->pathLenSet = x509->pathLengthSet;
}
#ifdef WOLFSSL_CERT_EXT
if (x509->subjKeyIdSz <= CTC_MAX_SKID_SIZE) {
+85
View File
@@ -1061,3 +1061,88 @@ int test_x509_ReqCertFromX509_skid_boundary(void)
#endif
return EXPECT_RESULT();
}
/* Test that a critical flag and pathlen of a basicConstraints extension added
* to an X509_REQ are encoded into the signed CSR. */
int test_x509_ReqCertFromX509_ext_critical(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_CERT_REQ) && defined(WOLFSSL_CERT_GEN) && \
defined(OPENSSL_ALL) && defined(WOLFSSL_ASN_TEMPLATE) && \
defined(HAVE_ECC) && defined(USE_CERT_BUFFERS_256)
WOLFSSL_EVP_PKEY* priv = NULL;
WOLFSSL_EVP_PKEY* pub = NULL;
WOLFSSL_X509* req = NULL;
WOLFSSL_X509* parsed = NULL;
WOLFSSL_X509_NAME* name = NULL;
WOLFSSL_X509_EXTENSION* ext = NULL;
WOLFSSL_ASN1_OBJECT* obj = NULL;
unsigned char* der = NULL;
int derSz = 0;
const unsigned char* ecPriv = ecc_clikey_der_256;
const unsigned char* ecPub = ecc_clikeypub_der_256;
ExpectNotNull(priv = wolfSSL_d2i_PrivateKey(EVP_PKEY_EC, NULL, &ecPriv,
(long)sizeof_ecc_clikey_der_256));
ExpectNotNull(pub = wolfSSL_d2i_PUBKEY(NULL, &ecPub,
(long)sizeof_ecc_clikeypub_der_256));
ExpectNotNull(req = wolfSSL_X509_REQ_new());
ExpectNotNull(name = wolfSSL_X509_NAME_new());
ExpectIntEQ(wolfSSL_X509_NAME_add_entry_by_txt(name, "commonName",
MBSTRING_UTF8, (const byte*)"Test", 4, -1, 0), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_X509_REQ_set_subject_name(req, name), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_X509_REQ_set_pubkey(req, pub), WOLFSSL_SUCCESS);
/* Add basicConstraints critical, CA:TRUE, pathlen:1. The pathlen
* ASN1_INTEGER attached to ext->obj is freed with ext. */
ExpectNotNull(ext = wolfSSL_X509_EXTENSION_new());
ExpectIntEQ(wolfSSL_X509_EXTENSION_set_critical(ext, 1), WOLFSSL_SUCCESS);
ExpectNotNull(obj = wolfSSL_OBJ_nid2obj(WC_NID_basic_constraints));
ExpectIntEQ(wolfSSL_X509_EXTENSION_set_object(ext, obj), WOLFSSL_SUCCESS);
if (EXPECT_SUCCESS() && ext != NULL && ext->obj != NULL) {
ext->obj->ca = 1;
ext->obj->pathlen = wolfSSL_ASN1_INTEGER_new();
ExpectNotNull(ext->obj->pathlen);
if (ext->obj->pathlen != NULL) {
ext->obj->pathlen->length = 1;
}
}
ExpectIntEQ(wolfSSL_X509_add_ext(req, ext, -1), WOLFSSL_SUCCESS);
/* Signing invokes wolfssl_x509_make_der() -> ReqCertFromX509(). */
ExpectIntEQ(wolfSSL_X509_REQ_sign(req, priv, wolfSSL_EVP_sha256()),
WOLFSSL_SUCCESS);
ExpectIntGT((derSz = wolfSSL_i2d_X509_REQ(req, &der)), 0);
ExpectNotNull(der);
/* Verify criticality and pathlen were encoded into the DER. */
ExpectNotNull(parsed = wolfSSL_X509_REQ_d2i(NULL, der, derSz));
if (parsed != NULL) {
ExpectIntEQ(parsed->isCa, 1);
ExpectIntEQ(parsed->basicConstSet, 1);
ExpectIntEQ(parsed->basicConstCrit, 1);
ExpectIntEQ(parsed->pathLengthSet, 1);
ExpectIntEQ((int)parsed->pathLength, 1);
}
/* Path length above WOLFSSL_MAX_PATH_LEN must fail to sign. */
if (EXPECT_SUCCESS() && req != NULL) {
req->pathLength = WOLFSSL_MAX_PATH_LEN + 1;
ExpectIntNE(wolfSSL_X509_REQ_sign(req, priv, wolfSSL_EVP_sha256()),
WOLFSSL_SUCCESS);
}
wolfSSL_X509_free(parsed);
XFREE(der, NULL, DYNAMIC_TYPE_OPENSSL);
wolfSSL_ASN1_OBJECT_free(obj);
wolfSSL_X509_EXTENSION_free(ext);
wolfSSL_X509_NAME_free(name);
wolfSSL_X509_free(req);
wolfSSL_EVP_PKEY_free(pub);
wolfSSL_EVP_PKEY_free(priv);
#endif
return EXPECT_RESULT();
}
+3 -1
View File
@@ -30,6 +30,7 @@ int test_x509_time_field_overread_via_tls(void);
int test_x509_CertFromX509_akid_overflow(void);
int test_x509_ReqCertFromX509_skid_overflow(void);
int test_x509_ReqCertFromX509_skid_boundary(void);
int test_x509_ReqCertFromX509_ext_critical(void);
#define TEST_X509_DECLS \
TEST_DECL_GROUP("x509", test_x509_rfc2818_verification_callback), \
@@ -39,6 +40,7 @@ int test_x509_ReqCertFromX509_skid_boundary(void);
TEST_DECL_GROUP("x509", test_x509_time_field_overread_via_tls), \
TEST_DECL_GROUP("x509", test_x509_CertFromX509_akid_overflow), \
TEST_DECL_GROUP("x509", test_x509_ReqCertFromX509_skid_overflow), \
TEST_DECL_GROUP("x509", test_x509_ReqCertFromX509_skid_boundary)
TEST_DECL_GROUP("x509", test_x509_ReqCertFromX509_skid_boundary), \
TEST_DECL_GROUP("x509", test_x509_ReqCertFromX509_ext_critical)
#endif /* WOLFCRYPT_TEST_X509_H */