diff --git a/certs/ocsp/include.am b/certs/ocsp/include.am index 73c5f285d..92a72b81e 100644 --- a/certs/ocsp/include.am +++ b/certs/ocsp/include.am @@ -32,4 +32,7 @@ EXTRA_DIST += \ certs/ocsp/server5-key.pem \ certs/ocsp/server5-cert.pem \ certs/ocsp/root-ca-key.pem \ - certs/ocsp/root-ca-cert.pem + certs/ocsp/root-ca-cert.pem \ + certs/ocsp/test-response.der \ + certs/ocsp/test-response-rsapss.der \ + certs/ocsp/test-response-nointern.der diff --git a/certs/ocsp/renewcerts.sh b/certs/ocsp/renewcerts.sh index 50e9e3d79..d5d411953 100755 --- a/certs/ocsp/renewcerts.sh +++ b/certs/ocsp/renewcerts.sh @@ -79,3 +79,27 @@ update_cert server2 "www2.wolfssl.com" intermediate1-ca update_cert server3 "www3.wolfssl.com" intermediate2-ca v3_req2 07 update_cert server4 "www4.wolfssl.com" intermediate2-ca v3_req2 08 # REVOKED update_cert server5 "www5.wolfssl.com" intermediate3-ca v3_req3 09 + + +# Create response DER buffer for test +openssl ocsp -port 22221 -ndays 1000 -index index-ca-and-intermediate-cas.txt -rsigner ocsp-responder-cert.pem -rkey ocsp-responder-key.pem -CA root-ca-cert.pem -partial_chain & +PID=$! + +openssl ocsp -issuer ./root-ca-cert.pem -cert ./intermediate1-ca-cert.pem -url http://localhost:22221/ -respout test-response.der -noverify +openssl ocsp -issuer ./root-ca-cert.pem -cert ./intermediate1-ca-cert.pem -url http://localhost:22221/ -respout test-response-nointern.der -no_intern -noverify +kill $PID +wait $PID + + +# now start up a responder that signs using rsa-pss +openssl ocsp -port 22221 -ndays 1000 -index index-ca-and-intermediate-cas.txt -rsigner ocsp-responder-cert.pem -rkey ocsp-responder-key.pem -CA root-ca-cert.pem -rsigopt rsa_padding_mode:pss & +PID=$! + +openssl ocsp -issuer ./root-ca-cert.pem -cert ./intermediate1-ca-cert.pem -url http://localhost:22221/ -respout test-response-rsapss.der -noverify +# can verify with the following command +# openssl ocsp -respin test-response-nointern.der -CAfile root-ca-cert.pem -issuer intermediate1-ca-cert.pem + +kill $PID +wait $PID + +exit 0 diff --git a/certs/ocsp/test-response-nointern.der b/certs/ocsp/test-response-nointern.der new file mode 100644 index 000000000..4d4115cbe Binary files /dev/null and b/certs/ocsp/test-response-nointern.der differ diff --git a/certs/ocsp/test-response-rsapss.der b/certs/ocsp/test-response-rsapss.der new file mode 100644 index 000000000..ca99d28b7 Binary files /dev/null and b/certs/ocsp/test-response-rsapss.der differ diff --git a/certs/ocsp/test-response.der b/certs/ocsp/test-response.der new file mode 100644 index 000000000..7ebfd0424 Binary files /dev/null and b/certs/ocsp/test-response.der differ diff --git a/src/ocsp.c b/src/ocsp.c index e31ef23f7..d18e5739d 100644 --- a/src/ocsp.c +++ b/src/ocsp.c @@ -826,6 +826,7 @@ OcspResponse* wolfSSL_d2i_OCSP_RESPONSE(OcspResponse** response, OcspResponse *resp = NULL; word32 idx = 0; int length = 0; + int ret; if (data == NULL) return NULL; @@ -867,7 +868,10 @@ OcspResponse* wolfSSL_d2i_OCSP_RESPONSE(OcspResponse** response, XMEMCPY(resp->source, *data, len); resp->maxIdx = len; - if (OcspResponseDecode(resp, NULL, NULL, 1) != 0) { + ret = OcspResponseDecode(resp, NULL, NULL, 1); + if (ret != 0 && ret != ASN_OCSP_CONFIRM_E) { + /* for just converting from a DER to an internal structure the CA may + * not yet be known to this function for signature verification */ wolfSSL_OCSP_RESPONSE_free(resp); return NULL; } diff --git a/tests/api.c b/tests/api.c index 690814b14..99e3ca2fb 100644 --- a/tests/api.c +++ b/tests/api.c @@ -1605,6 +1605,94 @@ static int test_wolfSSL_CertManagerCheckOCSPResponse(void) return 0; } +static int test_wolfSSL_CheckOCSPResponse(void) +{ +#if defined(HAVE_OCSP) && !defined(NO_RSA) && defined(OPENSSL_ALL) + const char* responseFile = "./certs/ocsp/test-response.der"; + const char* responseNoInternFile = "./certs/ocsp/test-response-nointern.der"; + const char* caFile = "./certs/ocsp/root-ca-cert.pem"; + OcspResponse* res = NULL; + byte data[4096]; + const unsigned char* pt; + int dataSz; + XFILE f; + WOLFSSL_OCSP_BASICRESP* bs; + WOLFSSL_X509_STORE* st; + WOLFSSL_X509* issuer; + + + printf(testingFmt, "wolfSSL_CheckOCSPResponse()"); + + f = XFOPEN(responseFile, "rb"); + AssertTrue(f != XBADFILE); + dataSz = (word32)XFREAD(data, 1, sizeof(data), f); + AssertIntGT(dataSz, 0); + XFCLOSE(f); + + pt = data; + res = wolfSSL_d2i_OCSP_RESPONSE(NULL, &pt, dataSz); + AssertNotNull(res); + issuer = wolfSSL_X509_load_certificate_file(caFile, SSL_FILETYPE_PEM); + AssertNotNull(issuer); + st = wolfSSL_X509_STORE_new(); + AssertNotNull(st); + AssertIntEQ(wolfSSL_X509_STORE_add_cert(st, issuer), WOLFSSL_SUCCESS); + bs = wolfSSL_OCSP_response_get1_basic(res); + AssertNotNull(bs); + AssertIntEQ(wolfSSL_OCSP_basic_verify(bs, NULL, st, 0), WOLFSSL_SUCCESS); + wolfSSL_OCSP_BASICRESP_free(bs); + wolfSSL_OCSP_RESPONSE_free(res); + wolfSSL_X509_STORE_free(st); + wolfSSL_X509_free(issuer); + + /* check loading a response with optional certs */ + f = XFOPEN(responseNoInternFile, "rb"); + AssertTrue(f != XBADFILE); + dataSz = (word32)XFREAD(data, 1, sizeof(data), f); + AssertIntGT(dataSz, 0); + XFCLOSE(f); + + pt = data; + res = wolfSSL_d2i_OCSP_RESPONSE(NULL, &pt, dataSz); + AssertNotNull(res); + wolfSSL_OCSP_RESPONSE_free(res); + +#if defined(WC_RSA_PSS) + { + const char* responsePssFile = "./certs/ocsp/test-response-rsapss.der"; + + /* check loading a response with RSA-PSS signature */ + f = XFOPEN(responsePssFile, "rb"); + AssertTrue(f != XBADFILE); + dataSz = (word32)XFREAD(data, 1, sizeof(data), f); + AssertIntGT(dataSz, 0); + XFCLOSE(f); + + pt = data; + res = wolfSSL_d2i_OCSP_RESPONSE(NULL, &pt, dataSz); + AssertNotNull(res); + + /* try to verify the response */ + issuer = wolfSSL_X509_load_certificate_file(caFile, SSL_FILETYPE_PEM); + AssertNotNull(issuer); + st = wolfSSL_X509_STORE_new(); + AssertNotNull(st); + AssertIntEQ(wolfSSL_X509_STORE_add_cert(st, issuer), WOLFSSL_SUCCESS); + bs = wolfSSL_OCSP_response_get1_basic(res); + AssertNotNull(bs); + AssertIntEQ(wolfSSL_OCSP_basic_verify(bs, NULL, st, 0), WOLFSSL_SUCCESS); + wolfSSL_OCSP_BASICRESP_free(bs); + wolfSSL_OCSP_RESPONSE_free(res); + wolfSSL_X509_STORE_free(st); + wolfSSL_X509_free(issuer); + } +#endif + + printf(resultFmt, passed); +#endif /* HAVE_OCSP */ + return 0; +} + static int test_wolfSSL_CertManagerLoadCABuffer(void) { int ret; @@ -58080,6 +58168,7 @@ TEST_CASE testCases[] = { TEST_DECL(test_wolfSSL_CTX_use_PrivateKey_file), TEST_DECL(test_wolfSSL_CTX_load_verify_locations), TEST_DECL(test_wolfSSL_CertManagerCheckOCSPResponse), + TEST_DECL(test_wolfSSL_CheckOCSPResponse), TEST_DECL(test_wolfSSL_CertManagerLoadCABuffer), TEST_DECL(test_wolfSSL_CertManagerGetCerts), TEST_DECL(test_wolfSSL_CertManagerSetVerify), diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 4f15d22d4..43fea6399 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -34264,6 +34264,10 @@ static const ASNItem ocspBasicRespASN[] = { /* SIGALGO */ { 1, ASN_SEQUENCE, 1, 1, 0, }, /* SIGALGO_OID */ { 2, ASN_OBJECT_ID, 0, 0, 0 }, /* SIGALGO_NULL */ { 2, ASN_TAG_NULL, 0, 0, 1 }, + /* parameters */ +#ifdef WC_RSA_PSS +/* SIGALGO_PARAMS */ { 2, ASN_SEQUENCE, 1, 0, 1 }, +#endif /* signature */ /* SIGNATURE */ { 1, ASN_BIT_STRING, 0, 0, 0 }, /* certs */ @@ -34276,6 +34280,9 @@ enum { OCSPBASICRESPASN_IDX_SIGALGO, OCSPBASICRESPASN_IDX_SIGALGO_OID, OCSPBASICRESPASN_IDX_SIGALGO_NULL, +#ifdef WC_RSA_PSS + OCSPBASICRESPASN_IDX_SIGNATURE_PARAMS, +#endif OCSPBASICRESPASN_IDX_SIGNATURE, OCSPBASICRESPASN_IDX_CERTS, OCSPBASICRESPASN_IDX_CERTS_SEQ, @@ -34291,9 +34298,13 @@ static int DecodeBasicOcspResponse(byte* source, word32* ioIndex, #ifndef WOLFSSL_ASN_TEMPLATE int length; word32 idx = *ioIndex; + #ifndef WOLFSSL_NO_OCSP_OPTIONAL_CERTS word32 end_index; + #endif int ret; int sigLength; + const byte* sigParams = NULL; + word32 sigParamsSz = 0; WOLFSSL_ENTER("DecodeBasicOcspResponse"); (void)heap; @@ -34303,14 +34314,34 @@ static int DecodeBasicOcspResponse(byte* source, word32* ioIndex, if (idx + length > size) return ASN_INPUT_E; + #ifndef WOLFSSL_NO_OCSP_OPTIONAL_CERTS end_index = idx + length; + #endif if ((ret = DecodeResponseData(source, &idx, resp, size)) < 0) return ret; /* ASN_PARSE_E, ASN_BEFORE_DATE_E, ASN_AFTER_DATE_E */ /* Get the signature algorithm */ - if (GetAlgoId(source, &idx, &resp->sigOID, oidSigType, size) < 0) + if (GetAlgoId(source, &idx, &resp->sigOID, oidSigType, size) < 0) { return ASN_PARSE_E; + } +#ifdef WC_RSA_PSS + else if (resp->sigOID == CTC_RSASSAPSS) { + word32 sz; + int len; + const byte* params; + + sz = idx; + params = source + idx; + if (GetSequence(source, &idx, &len, size) < 0) + ret = ASN_PARSE_E; + if (ret == 0) { + idx += len; + sigParams = params; + sigParamsSz = idx - sz; + } + } +#endif ret = CheckBitString(source, &idx, &sigLength, size, 1, NULL); if (ret != 0) @@ -34378,7 +34409,8 @@ static int DecodeBasicOcspResponse(byte* source, word32* ioIndex, &cert->sigCtx, resp->response, resp->responseSz, cert->publicKey, cert->pubKeySize, cert->keyOID, - resp->sig, resp->sigSz, resp->sigOID, NULL, 0, NULL); + resp->sig, resp->sigSz, resp->sigOID, sigParams, sigParamsSz, + NULL); if (ret != 0) { WOLFSSL_MSG("\tOCSP Confirm signature failed"); @@ -34415,7 +34447,8 @@ static int DecodeBasicOcspResponse(byte* source, word32* ioIndex, /* ConfirmSignature is blocking here */ sigValid = ConfirmSignature(&sigCtx, resp->response, resp->responseSz, ca->publicKey, ca->pubKeySize, ca->keyOID, - resp->sig, resp->sigSz, resp->sigOID, NULL, 0, NULL); + resp->sig, resp->sigSz, resp->sigOID, sigParams, sigParamsSz, + NULL); } if (ca == NULL || sigValid != 0) { WOLFSSL_MSG("\tOCSP Confirm signature failed"); @@ -34431,6 +34464,8 @@ static int DecodeBasicOcspResponse(byte* source, word32* ioIndex, DECL_ASNGETDATA(dataASN, ocspBasicRespASN_Length); int ret = 0; word32 idx = *ioIndex; + const byte* sigParams = NULL; + word32 sigParamsSz = 0; #ifndef WOLFSSL_NO_OCSP_OPTIONAL_CERTS #ifdef WOLFSSL_SMALL_STACK DecodedCert* cert = NULL; @@ -34463,6 +34498,16 @@ static int DecodeBasicOcspResponse(byte* source, word32* ioIndex, ret = ASN_PARSE_E; } } +#ifdef WC_RSA_PSS + if (ret == 0 && (dataASN[OCSPBASICRESPASN_IDX_SIGNATURE_PARAMS].tag != 0)) { + sigParams = GetASNItem_Addr( + dataASN[OCSPBASICRESPASN_IDX_SIGNATURE_PARAMS], + source); + sigParamsSz = + GetASNItem_Length(dataASN[OCSPBASICRESPASN_IDX_SIGNATURE_PARAMS], + source); + } +#endif if (ret == 0) { /* Get the signature OID and signature. */ resp->sigOID = dataASN[OCSPBASICRESPASN_IDX_SIGALGO_OID].data.oid.sum; @@ -34535,7 +34580,8 @@ static int DecodeBasicOcspResponse(byte* source, word32* ioIndex, /* Check the signature of the response CA public key. */ sigValid = ConfirmSignature(&sigCtx, resp->response, resp->responseSz, ca->publicKey, ca->pubKeySize, ca->keyOID, - resp->sig, resp->sigSz, resp->sigOID, NULL, 0, NULL); + resp->sig, resp->sigSz, resp->sigOID, sigParams, sigParamsSz, + NULL); } if ((ca == NULL) || (sigValid != 0)) { /* Didn't find certificate or signature verificate failed. */