diff --git a/src/x509.c b/src/x509.c index de8033db7..2ba3f80e2 100644 --- a/src/x509.c +++ b/src/x509.c @@ -8148,6 +8148,7 @@ WOLF_STACK_OF(WOLFSSL_X509)* wolfSSL_X509_chain_up_ref( if (ret == WOLFSSL_SUCCESS) { cert->version = req->version; cert->isCA = req->isCa; + cert->basicConstSet = req->basicConstSet; #ifdef WOLFSSL_CERT_EXT if (req->subjKeyIdSz != 0) { XMEMCPY(cert->skid, req->subjKeyId, req->subjKeyIdSz); @@ -8239,6 +8240,7 @@ WOLF_STACK_OF(WOLFSSL_X509)* wolfSSL_X509_chain_up_ref( cert->sigType = wolfSSL_X509_get_signature_type(x509); cert->keyType = x509->pubKeyOID; cert->isCA = wolfSSL_X509_get_isCA(x509); + cert->basicConstSet = x509->basicConstSet; #ifdef WOLFSSL_CERT_EXT if (x509->subjKeyIdSz <= CTC_MAX_SKID_SIZE) { diff --git a/tests/api.c b/tests/api.c index edbeda3a0..c725dd984 100644 --- a/tests/api.c +++ b/tests/api.c @@ -38593,7 +38593,54 @@ static void test_wolfSSL_PEM_write_bio_X509(void) expectedLen = 1688; AssertIntEQ(wolfSSL_BIO_get_len(output), expectedLen); + /* Reset buffers and x509 */ + BIO_free(input); + BIO_free(output); X509_free(x509a); + + /* test CA and basicConstSet values are encoded when + * the cert is a CA */ + AssertNotNull(input = BIO_new_file( + "certs/server-cert.pem", "rb")); + + /* read PEM into X509 struct */ + AssertNotNull(PEM_read_bio_X509(input, &x509a, NULL, NULL)); + + /* write X509 back to PEM BIO */ + AssertNotNull(output = BIO_new(wolfSSL_BIO_s_mem())); + AssertIntEQ(PEM_write_bio_X509(output, x509a), WOLFSSL_SUCCESS); + + /* read exported X509 PEM back into struct, ensure isCa and + * basicConstSet values are maintained */ + AssertNotNull(PEM_read_bio_X509(output, &x509b, NULL, NULL)); + AssertIntEQ(x509b->isCa, 1); + AssertIntEQ(x509b->basicConstSet, 1); + + X509_free(x509a); + X509_free(x509b); + BIO_free(input); + BIO_free(output); + + /* test CA and basicConstSet values are encoded when + * the cert is not CA */ + AssertNotNull(input = BIO_new_file( + "certs/client-uri-cert.pem", "rb")); + + /* read PEM into X509 struct */ + AssertNotNull(PEM_read_bio_X509(input, &x509a, NULL, NULL)); + + /* write X509 back to PEM BIO */ + AssertNotNull(output = BIO_new(wolfSSL_BIO_s_mem())); + AssertIntEQ(PEM_write_bio_X509(output, x509a), WOLFSSL_SUCCESS); + + /* read exported X509 PEM back into struct, ensure isCa and + * basicConstSet values are maintained */ + AssertNotNull(PEM_read_bio_X509(output, &x509b, NULL, NULL)); + AssertIntEQ(x509b->isCa, 0); + AssertIntEQ(x509b->basicConstSet, 1); + + X509_free(x509a); + X509_free(x509b); BIO_free(input); BIO_free(output); diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index c2545dd00..0a829510b 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -22041,21 +22041,46 @@ static int SetExtensionsHeader(byte* out, word32 outSz, int extSz) } -/* encode CA basic constraint true, return total bytes written */ +/* encode CA basic constraints true + * return total bytes written */ static int SetCa(byte* out, word32 outSz) { - const byte ca[] = { 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, - 0x05, 0x30, 0x03, 0x01, 0x01, 0xff }; + /* ASN1->DER sequence for Basic Constraints True */ + const byte caBasicConstASN1[] = { + 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, + 0x05, 0x30, 0x03, 0x01, 0x01, 0xff + }; if (out == NULL) return BAD_FUNC_ARG; - if (outSz < sizeof(ca)) + if (outSz < sizeof(caBasicConstASN1)) return BUFFER_E; - XMEMCPY(out, ca, sizeof(ca)); + XMEMCPY(out, caBasicConstASN1, sizeof(caBasicConstASN1)); - return (int)sizeof(ca); + return (int)sizeof(caBasicConstASN1); +} + +/* encode basic constraints without CA Boolean + * return total bytes written */ +static int SetBC(byte* out, word32 outSz) +{ + /* ASN1->DER sequence for Basic Constraint without CA Boolean */ + const byte BasicConstASN1[] = { + 0x30, 0x09, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, + 0x02, 0x30, 0x00 + }; + + if (out == NULL) + return BAD_FUNC_ARG; + + if (outSz < sizeof(BasicConstASN1)) + return BUFFER_E; + + XMEMCPY(out, BasicConstASN1, sizeof(BasicConstASN1)); + + return (int)sizeof(BasicConstASN1); } #endif @@ -23589,6 +23614,12 @@ static int EncodeExtensions(Cert* cert, byte* output, word32 maxSz, /* TODO: consider adding path length field in Cert. */ dataASN[CERTEXTSASN_IDX_BC_PATHLEN].noOut = 1; } + else if (cert->basicConstSet) { + /* Set Basic Constraints to be a non Certificate Authority. */ + SetASN_Buffer(&dataASN[CERTEXTSASN_IDX_BC_OID], bcOID, sizeof(bcOID)); + dataASN[CERTEXTSASN_IDX_BC_CA].noOut = 1; + dataASN[CERTEXTSASN_IDX_BC_PATHLEN].noOut = 1; + } else { /* Don't write out Basic Constraints extension items. */ SetASNItem_NoOut(dataASN, CERTEXTSASN_IDX_BC_SEQ, @@ -24172,7 +24203,7 @@ static int EncodeCert(Cert* cert, DerCert* der, RsaKey* rsaKey, ecc_key* eccKey, /* set the extensions */ der->extensionsSz = 0; - /* CA */ + /* Set CA */ if (cert->isCA) { der->caSz = SetCa(der->ca, sizeof(der->ca)); if (der->caSz <= 0) @@ -24180,6 +24211,14 @@ static int EncodeCert(Cert* cert, DerCert* der, RsaKey* rsaKey, ecc_key* eccKey, der->extensionsSz += der->caSz; } + /* Set Basic Constraint */ + else if (cert->basicConstSet) { + der->caSz = SetBC(der->ca, sizeof(der->ca)); + if (der->caSz <= 0) + return EXTENSIONS_E; + + der->extensionsSz += der->caSz; + } else der->caSz = 0; @@ -25335,7 +25374,7 @@ static int EncodeCertReq(Cert* cert, DerCert* der, RsaKey* rsaKey, /* set the extensions */ der->extensionsSz = 0; - /* CA */ + /* Set CA */ if (cert->isCA) { der->caSz = SetCa(der->ca, sizeof(der->ca)); if (der->caSz <= 0) @@ -25343,6 +25382,14 @@ static int EncodeCertReq(Cert* cert, DerCert* der, RsaKey* rsaKey, der->extensionsSz += der->caSz; } + /* Set Basic Constraint */ + else if (cert->basicConstSet) { + der->caSz = SetBC(der->ca, sizeof(der->ca)); + if (der->caSz <= 0) + return EXTENSIONS_E; + + der->extensionsSz += der->caSz; + } else der->caSz = 0; diff --git a/wolfssl/wolfcrypt/asn_public.h b/wolfssl/wolfcrypt/asn_public.h index fcfff28d6..ac55d3be9 100644 --- a/wolfssl/wolfcrypt/asn_public.h +++ b/wolfssl/wolfcrypt/asn_public.h @@ -443,9 +443,10 @@ typedef struct Cert { CertExtension customCertExt[NUM_CUSTOM_EXT]; int customCertExtCount; #endif - void* decodedCert; /* internal DecodedCert allocated from heap */ - byte* der; /* Pointer to buffer of current DecodedCert cache */ - void* heap; /* heap hint */ + void* decodedCert; /* internal DecodedCert allocated from heap */ + byte* der; /* Pointer to buffer of current DecodedCert cache */ + void* heap; /* heap hint */ + byte basicConstSet:1; /* Indicator for when Basic Constaint is set */ } Cert;