1
0
mirror of https://github.com/wolfSSL/wolfssl.git synced 2026-10-24 04:09:07 +03:00

Merge pull request #11152 from yosuke-wolfssl/fix/f_7074

Require a trusted TSA certificate in wc_TspResponse_Verify
This commit is contained in:
philljj
2026-08-12 14:18:48 -05:00
committed by GitHub
5 changed files with 131 additions and 75 deletions

View File

@@ -1595,9 +1595,10 @@ int wc_TspTstInfo_SignWithPkcs7(const TspTstInfo* tstInfo, wc_PKCS7* pkcs7,
Only the certHash of the first ESSCertID(v2) of the attribute is
checked. The TSA name of the TSTInfo, when present, must correspond to
a subject name of the signer's certificate. Trust in the TSA's
certificate must be established by the caller. Define
WC_TSP_MIN_HASH_STRENGTH_BITS to require a minimum security strength of
the hash algorithms used.
certificate must be established by the caller: the verified signer is
available as pkcs7->verifyCert and pkcs7->verifyCertSz for that decision.
Define WC_TSP_MIN_HASH_STRENGTH_BITS to require a minimum security
strength of the hash algorithms used.
Pointers in tstInfo reference the content of the PKCS7 object - the
PKCS7 object and the token buffer must remain available while tstInfo
@@ -1644,6 +1645,8 @@ int wc_TspTstInfo_SignWithPkcs7(const TspTstInfo* tstInfo, wc_PKCS7* pkcs7,
\endcode
\sa wc_TspResponse_Decode
\sa wc_TspResponse_Verify
\sa wc_TspResponse_VerifyWithCm
\sa wc_TspTstInfo_CheckRequest
\sa wc_TspTstInfo_CheckGenTime
\sa wc_TspTstInfo_CheckTsaName
@@ -1657,21 +1660,15 @@ int wc_TspTstInfo_VerifyWithPKCS7(wc_PKCS7* pkcs7, byte* token, word32 tokenSz,
\brief This function verifies the time-stamp token of a response and
decodes its TSTInfo content. A convenience wrapper around
wc_TspTstInfo_VerifyWithPKCS7() that manages the PKCS7 object. The response
must be granted and have a token. When cert is not NULL, the signer must
be that trusted TSA certificate; the certificate is also used to verify
the signature when the token does not include the signer's certificate.
When cert is NULL the token must include the signer's certificate: the
token's signature is verified against that embedded certificate but NO
trust anchoring is performed - any self-signed certificate carrying the
time-stamping EKU is accepted. The NULL-cert form verifies the signature
only; the caller must establish trust in the signer by other means. To
anchor the signer to a trusted CA, use wc_TspResponse_VerifyWithCm().
must be granted and have a token. The trusted TSA certificate is required:
the signer must be that certificate, which is also used to verify the
signature when the token does not include the signer's certificate.
Pointers in tstInfo reference the token of the response - the response
and its token buffer must remain available while tstInfo is in use.
\return 0 Returned on successfully verifying the response.
\return BAD_FUNC_ARG Returned when resp is NULL.
\return BAD_FUNC_ARG Returned when resp or cert is NULL, or certSz is 0.
\return TSP_VERIFY_E Returned when the response was not granted, has no
token, the token does not verify or the signer is not the trusted TSA
certificate.
@@ -1679,10 +1676,9 @@ int wc_TspTstInfo_VerifyWithPKCS7(wc_PKCS7* pkcs7, byte* token, word32 tokenSz,
\param [in] resp Pointer to the TspResponse structure with a token to
verify.
\param [in] cert DER encoded certificate of the trusted TSA. May be NULL
when the token includes the signer's certificate - the NULL-cert form
verifies the signature only and establishes no trust.
\param [in] certSz Length of the certificate in bytes.
\param [in] cert DER encoded certificate of the trusted TSA. Must not be
NULL.
\param [in] certSz Length of the certificate in bytes. Must not be 0.
\param [out] tstInfo Pointer to the TspTstInfo structure to fill. May be
NULL.
@@ -1697,6 +1693,7 @@ int wc_TspTstInfo_VerifyWithPKCS7(wc_PKCS7* pkcs7, byte* token, word32 tokenSz,
}
\endcode
\sa wc_TspResponse_VerifyWithCm
\sa wc_TspTstInfo_VerifyWithPKCS7
\sa wc_TspTstInfo_CheckRequest
\sa wc_TspTstInfo_CheckGenTime
@@ -1762,7 +1759,8 @@ int wc_TspResponse_VerifyWithCm(TspResponse* resp, void* cm,
does not hash the data.
\return 0 Returned on successfully verifying the response and data.
\return BAD_FUNC_ARG Returned when resp or data is NULL.
\return BAD_FUNC_ARG Returned when resp, cert or data is NULL, or certSz
is 0.
\return TSP_VERIFY_E Returned when the token does not verify or the data
does not match the message imprint.
\return HASH_TYPE_E Returned when the imprint's hash algorithm is not
@@ -1771,9 +1769,9 @@ int wc_TspResponse_VerifyWithCm(TspResponse* resp, void* cm,
\param [in] resp Pointer to the TspResponse structure with a token to
verify.
\param [in] cert DER encoded certificate of the trusted TSA. May be NULL -
see wc_TspResponse_Verify().
\param [in] certSz Length of the certificate in bytes.
\param [in] cert DER encoded certificate of the trusted TSA. Must not be
NULL - see wc_TspResponse_Verify().
\param [in] certSz Length of the certificate in bytes. Must not be 0.
\param [in] data Data that was time-stamped.
\param [in] dataSz Length of the data in bytes.
\param [out] tstInfo Pointer to the TspTstInfo structure to fill. May be
@@ -1793,6 +1791,7 @@ int wc_TspResponse_VerifyWithCm(TspResponse* resp, void* cm,
\endcode
\sa wc_TspResponse_Verify
\sa wc_TspResponse_VerifyWithCm
\sa wc_TspTstInfo_VerifyData
*/
int wc_TspResponse_VerifyData(TspResponse* resp, const byte* cert,

View File

@@ -2698,24 +2698,27 @@ int test_wc_TspResponse_Verify(void)
TEST_SUCCESS);
/* Bad arguments. */
ExpectIntEQ(wc_TspResponse_Verify(NULL, NULL, 0, &tstDec),
ExpectIntEQ(wc_TspResponse_Verify(NULL, tsa_cert_der_2048,
sizeof_tsa_cert_der_2048, &tstDec), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* The trusted TSA certificate is required - the certificate in the token
* is not a trust anchor. */
ExpectIntEQ(wc_TspResponse_Verify(&resp, NULL, 0, &tstDec),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_TspResponse_Verify(&resp, tsa_cert_der_2048, 0, &tstDec),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* Verifies with the certificate in the token - no certificate needed.
* The returned TSTInfo references the response's token, which is still
* available after the call. */
ExpectIntEQ(wc_TspResponse_Verify(&resp, NULL, 0, &tstDec), 0);
/* The signer matches the trusted TSA certificate. The returned TSTInfo
* references the response's token, still available after the call. */
ExpectIntEQ(wc_TspResponse_Verify(&resp, tsa_cert_der_2048,
sizeof_tsa_cert_der_2048, &tstDec), 0);
ExpectIntEQ(tstDec.version, 1);
ExpectIntEQ(tstDec.genTimeSz, (word32)sizeof(tsGenTime) - 1);
ExpectBufEQ(tstDec.genTime, tsGenTime, (int)sizeof(tsGenTime) - 1);
ExpectIntEQ(tstDec.serialSz, (word32)sizeof(tsSerial));
ExpectBufEQ(tstDec.serial, tsSerial, (int)sizeof(tsSerial));
/* The TSTInfo object is optional. */
ExpectIntEQ(wc_TspResponse_Verify(&resp, NULL, 0, NULL), 0);
/* The signer matches the trusted TSA certificate. */
ExpectIntEQ(wc_TspResponse_Verify(&resp, tsa_cert_der_2048,
sizeof_tsa_cert_der_2048, &tstDec), 0);
sizeof_tsa_cert_der_2048, NULL), 0);
wc_FreeRng(&rng);
#endif
@@ -2779,17 +2782,18 @@ int test_wc_TspResponse_Verify_status(void)
/* A response that was not granted has no token to trust. */
resp.status = WC_TSP_PKISTATUS_REJECTION;
ExpectIntEQ(wc_TspResponse_Verify(&resp, NULL, 0, &tstDec),
WC_NO_ERR_TRACE(TSP_VERIFY_E));
ExpectIntEQ(wc_TspResponse_Verify(&resp, tsa_cert_der_2048,
sizeof_tsa_cert_der_2048, &tstDec), WC_NO_ERR_TRACE(TSP_VERIFY_E));
resp.status = WC_TSP_PKISTATUS_GRANTED_WITH_MODS;
ExpectIntEQ(wc_TspResponse_Verify(&resp, NULL, 0, &tstDec), 0);
ExpectIntEQ(wc_TspResponse_Verify(&resp, tsa_cert_der_2048,
sizeof_tsa_cert_der_2048, &tstDec), 0);
/* A granted response with no token does not verify. */
resp.status = WC_TSP_PKISTATUS_GRANTED;
resp.token = NULL;
resp.tokenSz = 0;
ExpectIntEQ(wc_TspResponse_Verify(&resp, NULL, 0, &tstDec),
WC_NO_ERR_TRACE(TSP_VERIFY_E));
ExpectIntEQ(wc_TspResponse_Verify(&resp, tsa_cert_der_2048,
sizeof_tsa_cert_der_2048, &tstDec), WC_NO_ERR_TRACE(TSP_VERIFY_E));
wc_FreeRng(&rng);
#endif
@@ -2816,7 +2820,8 @@ int test_wc_TspResponse_Verify_modified(void)
if (EXPECT_SUCCESS()) {
token[tokenSz - 5] ^= 0x80;
}
ExpectIntLT(wc_TspResponse_Verify(&resp, NULL, 0, &tstDec), 0);
ExpectIntLT(wc_TspResponse_Verify(&resp, tsa_cert_der_2048,
sizeof_tsa_cert_der_2048, &tstDec), 0);
wc_FreeRng(&rng);
#endif
@@ -2844,11 +2849,55 @@ int test_wc_TspResponse_Verify_nocerts(void)
resp.token = token;
resp.tokenSz = tokenSz;
/* Cannot verify without the TSA's certificate. */
ExpectIntLT(wc_TspResponse_Verify(&resp, NULL, 0, &tstDec), 0);
/* The TSA's certificate is required - the token-level case with no
* certificate is covered by test_wc_TspTstInfo_VerifyWithPKCS7_nocerts. */
ExpectIntEQ(wc_TspResponse_Verify(&resp, NULL, 0, &tstDec),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* Verifies when the TSA's certificate is supplied. */
ExpectIntEQ(wc_TspResponse_Verify(&resp, tsa_cert_der_2048,
sizeof_tsa_cert_der_2048, &tstDec), 0);
/* A different certificate is not the signer. */
ExpectIntLT(wc_TspResponse_Verify(&resp, client_cert_der_2048,
sizeof_client_cert_der_2048, &tstDec), 0);
wc_FreeRng(&rng);
#endif
return EXPECT_RESULT();
}
int test_wc_TspResponse_Verify_no_anchor(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TSP) && defined(HAVE_PKCS7) && defined(HAVE_ECC) && \
defined(USE_CERT_BUFFERS_256) && !defined(NO_RSA) && \
!defined(NO_SHA256) && !defined(WC_NO_RNG) && \
defined(WOLFSSL_TSP_REQUESTER) && defined(WOLFSSL_TSP_RESPONDER)
WC_RNG rng;
TspTstInfo tstDec;
TspResponse resp;
byte token[3072];
word32 tokenSz = (word32)sizeof(token);
ExpectIntEQ(wc_InitRng(&rng), 0);
/* A granted response signed by a TSA the caller does not trust. */
ExpectIntEQ(test_tsp_make_token(token, &tokenSz, tsa_ecc_cert_der_256,
sizeof_tsa_ecc_cert_der_256, tsa_ecc_key_der_256,
sizeof_tsa_ecc_key_der_256, ECDSAk, &rng), TEST_SUCCESS);
ExpectIntEQ(wc_TspResponse_Init(&resp), 0);
resp.status = WC_TSP_PKISTATUS_GRANTED;
resp.token = token;
resp.tokenSz = tokenSz;
/* The token carries a self-signed certificate with the time-stamping EKU
* that verifies its own signature - it is not a trust anchor. */
ExpectIntEQ(wc_TspResponse_Verify(&resp, NULL, 0, &tstDec),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* The trusted TSA is not the signer of this token. */
ExpectIntEQ(wc_TspResponse_Verify(&resp, tsa_cert_der_2048,
sizeof_tsa_cert_der_2048, &tstDec), WC_NO_ERR_TRACE(TSP_VERIFY_E));
/* Pinning the certificate that actually signed the token verifies. */
ExpectIntEQ(wc_TspResponse_Verify(&resp, tsa_ecc_cert_der_256,
sizeof_tsa_ecc_cert_der_256, &tstDec), 0);
wc_FreeRng(&rng);
#endif
@@ -2892,23 +2941,30 @@ int test_wc_TspResponse_VerifyData(void)
resp.tokenSz = tokenSz;
/* Bad arguments. */
ExpectIntEQ(wc_TspResponse_VerifyData(NULL, NULL, 0, data,
(word32)sizeof(data) - 1, &tstDec), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_TspResponse_VerifyData(&resp, NULL, 0, NULL, 0, &tstDec),
ExpectIntEQ(wc_TspResponse_VerifyData(NULL, tsa_cert_der_2048,
sizeof_tsa_cert_der_2048, data, (word32)sizeof(data) - 1, &tstDec),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_TspResponse_VerifyData(&resp, tsa_cert_der_2048,
sizeof_tsa_cert_der_2048, NULL, 0, &tstDec),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* The trusted TSA certificate is required. */
ExpectIntEQ(wc_TspResponse_VerifyData(&resp, NULL, 0, data,
(word32)sizeof(data) - 1, &tstDec), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_TspResponse_VerifyData(&resp, tsa_cert_der_2048, 0, data,
(word32)sizeof(data) - 1, &tstDec), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* Verifies the token and that it is over the data - no hashing by the
* caller. */
ExpectIntEQ(wc_TspResponse_VerifyData(&resp, NULL, 0, data,
(word32)sizeof(data) - 1, &tstDec), 0);
ExpectIntEQ(wc_TspResponse_VerifyData(&resp, tsa_cert_der_2048,
sizeof_tsa_cert_der_2048, data, (word32)sizeof(data) - 1, &tstDec), 0);
ExpectIntEQ(tstDec.imprint.hashSz, (word32)sizeof(dataHash));
/* The TSTInfo object is optional. */
ExpectIntEQ(wc_TspResponse_VerifyData(&resp, NULL, 0, data,
(word32)sizeof(data) - 1, NULL), 0);
ExpectIntEQ(wc_TspResponse_VerifyData(&resp, tsa_cert_der_2048,
sizeof_tsa_cert_der_2048, data, (word32)sizeof(data) - 1, NULL), 0);
/* Different data does not match the message imprint. */
ExpectIntEQ(wc_TspResponse_VerifyData(&resp, NULL, 0,
(const byte*)"different data", 14, &tstDec),
ExpectIntEQ(wc_TspResponse_VerifyData(&resp, tsa_cert_der_2048,
sizeof_tsa_cert_der_2048, (const byte*)"different data", 14, &tstDec),
WC_NO_ERR_TRACE(TSP_VERIFY_E));
/* wc_TspTstInfo_VerifyData directly - bad args and match/mismatch. */

View File

@@ -81,6 +81,7 @@ int test_wc_TspResponse_Verify_wrong_cert(void);
int test_wc_TspResponse_Verify_status(void);
int test_wc_TspResponse_Verify_modified(void);
int test_wc_TspResponse_Verify_nocerts(void);
int test_wc_TspResponse_Verify_no_anchor(void);
int test_wc_TspResponse_VerifyData(void);
int test_wc_TspTstInfo_SetFromRequest(void);
@@ -142,6 +143,7 @@ int test_wc_TspTstInfo_SetFromRequest(void);
TEST_DECL_GROUP("tsp", test_wc_TspResponse_Verify_status), \
TEST_DECL_GROUP("tsp", test_wc_TspResponse_Verify_modified), \
TEST_DECL_GROUP("tsp", test_wc_TspResponse_Verify_nocerts), \
TEST_DECL_GROUP("tsp", test_wc_TspResponse_Verify_no_anchor), \
TEST_DECL_GROUP("tsp", test_wc_TspResponse_VerifyData), \
TEST_DECL_GROUP("tsp", test_wc_TspTstInfo_SetFromRequest)

View File

@@ -2089,13 +2089,13 @@ static int Tsp_VerifyCertChain(const byte* cert, word32 certSz, void* cm,
}
/* Verify the time-stamp token of a TimeStampResp, establishing trust in the
* signer by either pinning a certificate or chaining to a certificate
* manager. Used by wc_TspResponse_Verify() and wc_TspResponse_VerifyWithCm().
* signer by pinning a certificate (cert) or chaining to a certificate manager
* (cm). Callers pass exactly one - wc_TspResponse_Verify[WithCm]() enforce it.
*
* @param [in] resp TimeStampResp object with a token to verify.
* @param [in] cert DER encoded trusted TSA certificate to pin, or NULL.
* @param [in] cert Trusted TSA certificate to pin, NULL when cm is used.
* @param [in] certSz Length of certificate in bytes.
* @param [in] cm Certificate manager to chain against, or NULL.
* @param [in] cm Certificate manager to chain to, NULL when cert used.
* @param [out] tstInfo TSTInfo object to fill. May be NULL.
* @return 0 on success.
* @return BAD_FUNC_ARG when resp is NULL.
@@ -2242,30 +2242,23 @@ static int TspResponse_Verify(TspResponse* resp, const byte* cert,
* response must have a token. The token's signature is verified and the
* signer's certificate checked - see wc_TspTstInfo_VerifyWithPKCS7().
*
* When a certificate is given it is the trusted TSA - the signer of the token
* The certificate is required and is the trusted TSA - the signer of the token
* must be that certificate. This establishes trust by pinning the TSA's
* certificate. The certificate is also used to verify the signature when the
* token does not include the signer's certificate - certReq was not set in
* the request. When the certificate is NULL the token must include the
* signer's certificate: the token's signature is verified against that
* embedded certificate but no trust anchoring is performed - any self-signed
* certificate carrying the time-stamping EKU is accepted. The NULL-cert form
* verifies the signature only; the caller must trust the signer by other
* means. To anchor the signer to a trusted CA, use
* the request. To anchor the signer to a trusted CA instead, use
* wc_TspResponse_VerifyWithCm().
*
* Pointers in tstInfo reference the token of the response - the response and
* its token buffer must remain available while tstInfo is in use.
*
* @param [in] resp TimeStampResp object with a token to verify.
* @param [in] cert DER encoded certificate of the trusted TSA. May be
* NULL when the token includes the signer's certificate
* - the NULL-cert form verifies the signature only and
* establishes no trust.
* @param [in] certSz Length of certificate in bytes.
* @param [in] cert DER encoded certificate of the trusted TSA. Must not
* be NULL.
* @param [in] certSz Length of certificate in bytes. Must not be 0.
* @param [out] tstInfo TSTInfo object to fill. May be NULL.
* @return 0 on success.
* @return BAD_FUNC_ARG when resp is NULL.
* @return BAD_FUNC_ARG when resp or cert is NULL, or certSz is 0.
* @return TSP_VERIFY_E when the response was not granted, has no token, the
* token does not verify - see wc_TspTstInfo_VerifyWithPKCS7() - or the
* signer is not the trusted TSA certificate.
@@ -2278,6 +2271,12 @@ int wc_TspResponse_Verify(TspResponse* resp, const byte* cert, word32 certSz,
WOLFSSL_ENTER("wc_TspResponse_Verify");
/* A trusted TSA certificate is required - one carried in the token is not
* a trust anchor as it would verify its own signature. */
if ((cert == NULL) || (certSz == 0)) {
return BAD_FUNC_ARG;
}
/* Pin the signer to the given certificate - no certificate manager. */
ret = TspResponse_Verify(resp, cert, certSz, NULL, tstInfo);
@@ -2340,14 +2339,14 @@ int wc_TspResponse_VerifyWithCm(TspResponse* resp, void* cm,
* algorithm and comparing to the imprint. The caller does not hash the data.
*
* @param [in] resp TimeStampResp object with a token to verify.
* @param [in] cert DER encoded certificate of the trusted TSA. May be
* NULL - see wc_TspResponse_Verify().
* @param [in] certSz Length of certificate in bytes.
* @param [in] cert DER encoded certificate of the trusted TSA. Must not
* be NULL - see wc_TspResponse_Verify().
* @param [in] certSz Length of certificate in bytes. Must not be 0.
* @param [in] data Data that was time-stamped.
* @param [in] dataSz Length of data in bytes.
* @param [out] tstInfo TSTInfo object to fill. May be NULL.
* @return 0 on success.
* @return BAD_FUNC_ARG when resp or data is NULL.
* @return BAD_FUNC_ARG when resp, cert or data is NULL, or certSz is 0.
* @return TSP_VERIFY_E when the token does not verify or the data does not
* match the message imprint.
* @return HASH_TYPE_E when the imprint's hash algorithm is not supported.
@@ -2361,8 +2360,8 @@ int wc_TspResponse_VerifyData(TspResponse* resp, const byte* cert,
WOLFSSL_ENTER("wc_TspResponse_VerifyData");
/* Validate parameter - resp is checked by wc_TspResponse_Verify(). */
if (data == NULL) {
/* Validate parameters - resp is checked by wc_TspResponse_Verify(). */
if ((data == NULL) || (cert == NULL) || (certSz == 0)) {
return BAD_FUNC_ARG;
}
/* A TSTInfo is needed for the data check - use a local when not wanted. */

View File

@@ -424,10 +424,9 @@ WOLFSSL_API int wc_TspResponse_SetStatus(TspResponse* resp, word32 status,
WOLFSSL_API const char* wc_TspStatus_ToString(word32 status);
WOLFSSL_API const char* wc_TspFailInfo_ToString(word32 failInfo);
#ifdef HAVE_PKCS7
/* Verify a response's token with the TSA's certificate - manages the PKCS7
* object. A NULL cert verifies the signature against the token's embedded
* certificate only and establishes no trust; use wc_TspResponse_VerifyWithCm()
* to anchor the signer to a trusted CA. */
/* Verify a response's token against the trusted TSA certificate - manages the
* PKCS7 object. The certificate is required: one in the token is no anchor.
* See wc_TspResponse_VerifyWithCm() to anchor the signer to a trusted CA. */
#ifdef WOLFSSL_TSP_VERIFIER
WOLFSSL_API int wc_TspResponse_Verify(TspResponse* resp, const byte* cert,
word32 certSz, TspTstInfo* tstInfo);
@@ -438,7 +437,8 @@ WOLFSSL_API int wc_TspResponse_Verify(TspResponse* resp, const byte* cert,
WOLFSSL_API int wc_TspResponse_VerifyWithCm(TspResponse* resp, void* cm,
TspTstInfo* tstInfo);
#endif /* WOLFSSL_TSP_VERIFIER */
/* Verify a response's token and that it is over the given data. */
/* Verify a response's token and that it is over the given data. The trusted
* TSA certificate is required. */
#ifdef WOLFSSL_TSP_VERIFIER
WOLFSSL_API int wc_TspResponse_VerifyData(TspResponse* resp, const byte* cert,
word32 certSz, const byte* data, word32 dataSz, TspTstInfo* tstInfo);