diff --git a/src/x509.c b/src/x509.c index 3842b2feb60..47ce72b7aa5 100644 --- a/src/x509.c +++ b/src/x509.c @@ -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) { diff --git a/tests/api/test_x509.c b/tests/api/test_x509.c index 61ae6b705c7..aee18ecd550 100644 --- a/tests/api/test_x509.c +++ b/tests/api/test_x509.c @@ -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(); +} diff --git a/tests/api/test_x509.h b/tests/api/test_x509.h index d150cbacdf0..a0d6bac3b1a 100644 --- a/tests/api/test_x509.h +++ b/tests/api/test_x509.h @@ -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 */