From 8b80cb10d61a6533da994aac644409b0eca7264c Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Thu, 20 Feb 2025 16:07:22 +0000 Subject: [PATCH 01/14] ocsp: responderID.ByKey is SHA-1 Digest len Check that responderID.ByKey is exactly WC_SHA_DIGEST_SIZE as per RFC 6960. KEYID_SIZE can change across build configuration. --- tests/api/test_ocsp.c | 2 +- wolfcrypt/src/asn.c | 15 ++++++++++----- wolfssl/wolfcrypt/asn.h | 3 ++- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/tests/api/test_ocsp.c b/tests/api/test_ocsp.c index a32e604de..6eb818426 100644 --- a/tests/api/test_ocsp.c +++ b/tests/api/test_ocsp.c @@ -222,7 +222,7 @@ int test_ocsp_basic_verify(void) ExpectIntEQ(response->responseStatus, 0); ExpectIntEQ(response->responderIdType, OCSP_RESPONDER_ID_KEY); ExpectBufEQ(response->responderId.keyHash, cert.subjectKeyHash, - OCSP_DIGEST_SIZE); + OCSP_RESPONDER_ID_KEY_SZ); wolfSSL_OCSP_RESPONSE_free(response); /* decoding with no embedded certificates */ diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 8507503d3..1969b3429 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -36964,7 +36964,7 @@ static int DecodeResponseData(byte* source, word32* ioIndex, if (GetOctetString(source, &idx, &length, size) < 0) return ASN_PARSE_E; - if (length != KEYID_SIZE) + if (length != OCSP_RESPONDER_ID_KEY_SZ) return ASN_PARSE_E; resp->responderIdType = OCSP_RESPONDER_ID_KEY; XMEMCPY(resp->responderId.keyHash, source + idx, length); @@ -37027,7 +37027,7 @@ static int DecodeResponseData(byte* source, word32* ioIndex, int ret = 0; byte version; word32 dateSz = 0; - word32 responderByKeySz = KEYID_SIZE; + word32 responderByKeySz = OCSP_RESPONDER_ID_KEY_SZ; word32 idx = *ioIndex; OcspEntry* single = NULL; @@ -37073,7 +37073,8 @@ static int DecodeResponseData(byte* source, word32* ioIndex, resp->responderId.nameHash, WC_SHA); } else { resp->responderIdType = OCSP_RESPONDER_ID_KEY; - if (dataASN[OCSPRESPDATAASN_IDX_BYKEY_OCT].length != KEYID_SIZE) { + if (dataASN[OCSPRESPDATAASN_IDX_BYKEY_OCT].length + != OCSP_RESPONDER_ID_KEY_SZ) { ret = ASN_PARSE_E; } else { resp->responderIdType = OCSP_RESPONDER_ID_KEY; @@ -37226,10 +37227,14 @@ enum { static int OcspRespIdMatch(OcspResponse *resp, const byte *NameHash, const byte *keyHash) { + if (resp->responderIdType == OCSP_RESPONDER_ID_INVALID) + return 0; if (resp->responderIdType == OCSP_RESPONDER_ID_NAME) return XMEMCMP(NameHash, resp->responderId.nameHash, SIGNER_DIGEST_SIZE) == 0; - return XMEMCMP(keyHash, resp->responderId.keyHash, KEYID_SIZE) == 0; + /* OCSP_RESPONDER_ID_KEY */ + return ((int)KEYID_SIZE == OCSP_RESPONDER_ID_KEY_SZ) && + XMEMCMP(keyHash, resp->responderId.keyHash, KEYID_SIZE) == 0; } #ifndef WOLFSSL_NO_OCSP_ISSUER_CHECK @@ -37268,7 +37273,7 @@ static Signer *OcspFindSigner(OcspResponse *resp, WOLFSSL_CERT_MANAGER *cm) if (s) return s; } - else { + else if ((int)KEYID_SIZE == OCSP_RESPONDER_ID_KEY_SZ) { s = GetCAByKeyHash(cm, resp->responderId.keyHash); if (s) return s; diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index 3e9387e69..67de9651d 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -2732,6 +2732,7 @@ struct OcspEntry WC_BITFIELD used:1; /* entry used */ }; +#define OCSP_RESPONDER_ID_KEY_SZ 20 enum responderIdType { OCSP_RESPONDER_ID_INVALID = 0, OCSP_RESPONDER_ID_NAME = 1, @@ -2750,7 +2751,7 @@ struct OcspResponse { enum responderIdType responderIdType; union { - byte keyHash[KEYID_SIZE]; + byte keyHash[OCSP_RESPONDER_ID_KEY_SZ]; byte nameHash[KEYID_SIZE]; } responderId ; From c24b7d1041d1d53ba17b0feeb2dc9f5e4533a289 Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Thu, 20 Feb 2025 21:04:28 +0000 Subject: [PATCH 02/14] ocsp: use SHA-256 for responder name if no-sha --- wolfcrypt/src/asn.c | 4 ++-- wolfssl/wolfcrypt/asn.h | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 1969b3429..8792d382a 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -36950,7 +36950,7 @@ static int DecodeResponseData(byte* source, word32* ioIndex, /* compute the hash of the name */ resp->responderIdType = OCSP_RESPONDER_ID_NAME; ret = CalcHashId_ex(source + idx, length, - resp->responderId.nameHash, WC_SHA); + resp->responderId.nameHash, OCSP_RESPONDER_ID_HASH_TYPE); if (ret != 0) return ret; idx += length; @@ -37070,7 +37070,7 @@ static int DecodeResponseData(byte* source, word32* ioIndex, ret = CalcHashId_ex( dataASN[OCSPRESPDATAASN_IDX_BYNAME].data.ref.data, dataASN[OCSPRESPDATAASN_IDX_BYNAME].data.ref.length, - resp->responderId.nameHash, WC_SHA); + resp->responderId.nameHash, OCSP_RESPONDER_ID_HASH_TYPE); } else { resp->responderIdType = OCSP_RESPONDER_ID_KEY; if (dataASN[OCSPRESPDATAASN_IDX_BYKEY_OCT].length diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index 67de9651d..abe037334 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -2733,6 +2733,11 @@ struct OcspEntry }; #define OCSP_RESPONDER_ID_KEY_SZ 20 +#if !defined(NO_SHA) +#define OCSP_RESPONDER_ID_HASH_TYPE WC_SHA +#else +#define OCSP_RESPONDER_ID_HASH_TYPE WC_SHA256 +#endif enum responderIdType { OCSP_RESPONDER_ID_INVALID = 0, OCSP_RESPONDER_ID_NAME = 1, From 78ca784826ddc99ead997683fd8bc9afa9a65e21 Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Thu, 20 Feb 2025 21:50:52 +0000 Subject: [PATCH 03/14] test: ocsp: fix output file name in script --- tests/api/create_ocsp_test_blobs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/api/create_ocsp_test_blobs.py b/tests/api/create_ocsp_test_blobs.py index 435d625cb..a887efe42 100644 --- a/tests/api/create_ocsp_test_blobs.py +++ b/tests/api/create_ocsp_test_blobs.py @@ -401,7 +401,7 @@ if __name__ == '__main__': }, ] - with open('./tests/api/ocsp_test_blobs.h', 'w') as f: + with open('./tests/api/test_ocsp_test_blobs.h', 'w') as f: f.write( """/* * This file is generated automatically by running ./tests/api/create_ocsp_test_blobs.py. From 740fb6bafc3daec92d60f5e6466106495601491d Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Thu, 20 Feb 2025 21:51:37 +0000 Subject: [PATCH 04/14] test: gate ocsp test when SHA-1 is disabled tests blobs contains sha-1 hashes in certificate status --- tests/api/test_ocsp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/api/test_ocsp.c b/tests/api/test_ocsp.c index 6eb818426..5e172fa50 100644 --- a/tests/api/test_ocsp.c +++ b/tests/api/test_ocsp.c @@ -34,7 +34,7 @@ #include #include -#if defined(HAVE_OCSP) +#if defined(HAVE_OCSP) && !defined(NO_SHA) struct ocsp_cb_ctx { byte* response; int responseSz; @@ -158,12 +158,12 @@ int test_ocsp_response_parsing(void) return EXPECT_SUCCESS(); } -#else /* HAVE_OCSP */ +#else /* HAVE_OCSP && !NO_SHA */ int test_ocsp_response_parsing(void) { return TEST_SKIPPED; } -#endif /* HAVE_OCSP */ +#endif /* HAVE_OCSP && !NO_SHA */ #if defined(HAVE_OCSP) && (defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA)) static int test_ocsp_create_x509store(WOLFSSL_X509_STORE** store, From 4016120f37909a46b293843aab884f839add501f Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Tue, 25 Feb 2025 09:38:11 +0000 Subject: [PATCH 05/14] ocsp: populate digest type in cert_to_id - Added validation for digest type in `wolfSSL_OCSP_cert_to_id` function. - Defined `OCSP_DIGEST` based on available hash types. - Set `hashAlgoOID` in `certId` based on `OCSP_DIGEST`. - Updated `asn.h` to define `OCSP_DIGEST` and `OCSP_DIGEST_SIZE` based on available hash types. --- src/ocsp.c | 13 ++++++++++++- wolfssl/wolfcrypt/asn.h | 8 ++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/ocsp.c b/src/ocsp.c index 45780ecbd..61f68bd44 100644 --- a/src/ocsp.c +++ b/src/ocsp.c @@ -727,13 +727,23 @@ WOLFSSL_OCSP_CERTID* wolfSSL_OCSP_cert_to_id( WOLFSSL_CERT_MANAGER* cm = NULL; int ret = -1; DerBuffer* derCert = NULL; + int dgstType; #ifdef WOLFSSL_SMALL_STACK DecodedCert *cert = NULL; #else DecodedCert cert[1]; #endif - (void)dgst; + if (dgst == NULL) { + dgstType = WC_HASH_TYPE_SHA; + } + else if (wolfSSL_EVP_get_hashinfo(dgst, &dgstType, NULL) != + WOLFSSL_SUCCESS) { + return NULL; + } + + if (dgstType != OCSP_DIGEST) + return NULL; cm = wolfSSL_CertManagerNew(); if (cm == NULL @@ -785,6 +795,7 @@ WOLFSSL_OCSP_CERTID* wolfSSL_OCSP_cert_to_id( goto out; } else { + certId->hashAlgoOID = wc_HashGetOID(OCSP_DIGEST); XMEMCPY(certId->issuerHash, cert->issuerHash, OCSP_DIGEST_SIZE); XMEMCPY(certId->issuerKeyHash, cert->issuerKeyHash, OCSP_DIGEST_SIZE); XMEMCPY(certId->status->serial, cert->serial, (size_t)cert->serialSz); diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index abe037334..798d013f4 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -2707,6 +2707,14 @@ struct CertStatus { typedef struct OcspEntry OcspEntry; +#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) +#define OCSP_DIGEST WC_HASH_TYPE_SM3 +#elif defined(NO_SHA) +#define OCSP_DIGEST WC_HASH_TYPE_SHA256 +#else +#define OCSP_DIGEST WC_HASH_TYPE_SHA +#endif + #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SM3) #define OCSP_DIGEST_SIZE WC_SM3_DIGEST_SIZE #elif defined(NO_SHA) From 3bd4b35657d411cf50e0ba9c98ebcad4c9e96259 Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Tue, 25 Feb 2025 11:40:38 +0000 Subject: [PATCH 06/14] ocsp: support CERT_ID encoding in i2d_OCSP_CERTID --- src/ocsp.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 155 insertions(+), 11 deletions(-) diff --git a/src/ocsp.c b/src/ocsp.c index 61f68bd44..c73b71000 100644 --- a/src/ocsp.c +++ b/src/ocsp.c @@ -833,6 +833,103 @@ void wolfSSL_OCSP_BASICRESP_free(WOLFSSL_OCSP_BASICRESP* basicResponse) wolfSSL_OCSP_RESPONSE_free(basicResponse); } +/* Calculate size needed for CertID DER encoding following RFC 6960: + CertID ::= SEQUENCE { + hashAlgorithm AlgorithmIdentifier, + issuerNameHash OCTET STRING, + issuerKeyHash OCTET STRING, + serialNumber CertificateSerialNumber } +*/ +static int OcspGetCertIdRawSize(WOLFSSL_OCSP_CERTID* id, word32* totalSz, + word32* intSize) +{ + word32 idx = 0; + int ret; + + if (id == NULL || totalSz == NULL || id->status == NULL) + return BAD_FUNC_ARG; + + ret = SetAlgoID(id->hashAlgoOID, NULL, oidHashType, 0); + if (ret < 0) + return ret; + idx += ret; + + /* issuerNameHash */ + ret = SetOctetString(OCSP_DIGEST_SIZE, NULL); + if (ret < 0) + return ret; + idx += ret + OCSP_DIGEST_SIZE; + + /* issuerKeyHash */ + ret = SetOctetString(OCSP_DIGEST_SIZE, NULL); + if (ret < 0) + return ret; + idx += ret + OCSP_DIGEST_SIZE; + + /* serialNumber */ + ret = SetASNInt(id->status->serialSz, id->status->serial[0], NULL); + if (ret < 0) + return ret; + idx += ret + id->status->serialSz; + + /* Set sequence - get size */ + ret = SetSequence(idx, NULL); + if (ret < 0) + return ret; + + *totalSz = idx + ret; + if (intSize) + *intSize = idx; + return 0; +} + +/* Encode CertID following RFC 6960 ASN.1 structure */ +static int OcspEncodeCertID(WOLFSSL_OCSP_CERTID* id, byte* output, word32 size) +{ + word32 idx = 0; + int ret; + + if (id == NULL || output == NULL || id->status == NULL) + return BAD_FUNC_ARG; + + ret = SetSequence(size, output); + if (ret < 0) + return ret; + idx += ret; + + /* hashAlgorithm */ + ret = SetAlgoID(id->hashAlgoOID, output + idx, oidHashType, 0); + if (ret < 0) + return ret; + idx += ret; + + /* issuerNameHash */ + ret = SetOctetString(OCSP_DIGEST_SIZE, output + idx); + if (ret < 0) + return ret; + idx += ret; + XMEMCPY(output + idx, id->issuerHash, OCSP_DIGEST_SIZE); + idx += OCSP_DIGEST_SIZE; + + /* issuerKeyHash */ + ret = SetOctetString(OCSP_DIGEST_SIZE, output + idx); + if (ret < 0) + return ret; + idx += ret; + XMEMCPY(output + idx, id->issuerKeyHash, OCSP_DIGEST_SIZE); + idx += OCSP_DIGEST_SIZE; + + /* serialNumber */ + ret = SetASNInt(id->status->serialSz, id->status->serial[0], output + idx); + if (ret < 0) + return ret; + idx += ret; + XMEMCPY(output + idx, id->status->serial, id->status->serialSz); + idx += id->status->serialSz; + + return idx; +} + static int OcspRespIdMatches(OcspResponse* resp, const byte* NameHash, const byte* keyHash) { @@ -1295,22 +1392,69 @@ int wolfSSL_i2d_OCSP_REQUEST_bio(WOLFSSL_BIO* out, int wolfSSL_i2d_OCSP_CERTID(WOLFSSL_OCSP_CERTID* id, unsigned char** data) { - if (id == NULL || data == NULL) - return WOLFSSL_FAILURE; + int allocated = 0; + word32 derSz = 0; + word32 intSz = 0; + int ret; + WOLFSSL_ENTER("wolfSSL_i2d_OCSP_CERTID"); - if (*data != NULL) { - XMEMCPY(*data, id->rawCertId, (size_t)id->rawCertIdSize); - *data = *data + id->rawCertIdSize; + if (id == NULL) { + return -1; + } + + if (data == NULL) { + if (id->rawCertId != NULL) + return id->rawCertIdSize; + + ret = OcspGetCertIdRawSize(id, &derSz, NULL); + if (ret != 0) { + WOLFSSL_MSG("Failed to calculate CertID size"); + return -1; + } + return derSz; + } + + if (id->rawCertId == NULL) { + /* Calculate required size */ + ret = OcspGetCertIdRawSize(id, &derSz, &intSz); + if (ret != 0) { + WOLFSSL_MSG("Failed to calculate CertID size"); + return -1; + } } else { - *data = (unsigned char*)XMALLOC((size_t)id->rawCertIdSize, NULL, DYNAMIC_TYPE_OPENSSL); - if (*data == NULL) { - return WOLFSSL_FAILURE; - } - XMEMCPY(*data, id->rawCertId, (size_t)id->rawCertIdSize); + derSz = id->rawCertIdSize; } - return id->rawCertIdSize; + if (*data == NULL) { + /* Allocate buffer for DER encoding */ + *data = (byte*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_OPENSSL); + if (*data == NULL) { + WOLFSSL_MSG("Failed to allocate memory for CertID DER encoding"); + return -1; + } + allocated = 1; + } + + if (id->rawCertId != NULL) { + XMEMCPY(*data, id->rawCertId, id->rawCertIdSize); + } + else { + ret = OcspEncodeCertID(id, *data, intSz); + if (ret < 0) { + WOLFSSL_MSG("Failed to encode CertID"); + if (allocated) { + XFREE(data, NULL, DYNAMIC_TYPE_OPENSSL); + *data = NULL; + } + return -1; + } + } + + if (!allocated) + *data += derSz; + + return derSz; } WOLFSSL_OCSP_CERTID* wolfSSL_d2i_OCSP_CERTID(WOLFSSL_OCSP_CERTID** cidOut, From dfc5e61508a738f47313a493ddedabb645880397 Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Tue, 25 Feb 2025 14:10:16 +0000 Subject: [PATCH 07/14] asn: ocsp: refactor out CERT ID decoding It will be reused in d2i_CERT_ID --- wolfcrypt/src/asn.c | 211 +++++++++++++++++++++++++--------------- wolfssl/wolfcrypt/asn.h | 3 +- 2 files changed, 135 insertions(+), 79 deletions(-) diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 8792d382a..671f313f9 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -36360,17 +36360,7 @@ static int GetEnumerated(const byte* input, word32* inOutIdx, int *value, static const ASNItem singleResponseASN[] = { /* SEQ */ { 0, ASN_SEQUENCE, 1, 1, 0 }, /* certId */ -/* CID_SEQ */ { 1, ASN_SEQUENCE, 1, 1, 0 }, - /* hashAlgorithm */ -/* CID_HASHALGO_SEQ */ { 2, ASN_SEQUENCE, 1, 1, 0 }, -/* CID_HASHALGO_OID */ { 3, ASN_OBJECT_ID, 0, 0, 0 }, -/* CID_HASHALGO_NULL */ { 3, ASN_TAG_NULL, 0, 0, 1 }, - /* issuerNameHash */ -/* CID_ISSUERHASH */ { 2, ASN_OCTET_STRING, 0, 0, 0 }, - /* issuerKeyHash */ -/* CID_ISSUERKEYHASH */ { 2, ASN_OCTET_STRING, 0, 0, 0 }, - /* serialNumber */ -/* CID_SERIAL */ { 2, ASN_INTEGER, 0, 0, 0 }, +/* CID_SEQ */ { 1, ASN_SEQUENCE, 1, 0, 0 }, /* certStatus - CHOICE */ /* good [0] IMPLICIT NULL */ /* CS_GOOD */ { 1, ASN_CONTEXT_SPECIFIC | 0, 0, 0, 2 }, @@ -36396,12 +36386,6 @@ static const ASNItem singleResponseASN[] = { enum { SINGLERESPONSEASN_IDX_SEQ = 0, SINGLERESPONSEASN_IDX_CID_SEQ, - SINGLERESPONSEASN_IDX_CID_HASHALGO_SEQ, - SINGLERESPONSEASN_IDX_CID_HASHALGO_OID, - SINGLERESPONSEASN_IDX_CID_HASHALGO_NULL, - SINGLERESPONSEASN_IDX_CID_ISSUERHASH, - SINGLERESPONSEASN_IDX_CID_ISSUERKEYHASH, - SINGLERESPONSEASN_IDX_CID_SERIAL, SINGLERESPONSEASN_IDX_CS_GOOD, SINGLERESPONSEASN_IDX_CS_REVOKED, SINGLERESPONSEASN_IDX_CS_REVOKED_TIME, @@ -36416,13 +36400,139 @@ enum { /* Number of items in ASN.1 template for OCSP single response. */ #define singleResponseASN_Length (sizeof(singleResponseASN) / sizeof(ASNItem)) + +static const ASNItem certIDASNItems[] = { + /* hashAlgorithm */ +/* CID_HASHALGO_SEQ */ { 0, ASN_SEQUENCE, 1, 1, 0 }, +/* CID_HASHALGO_OID */ { 1, ASN_OBJECT_ID, 0, 0, 0 }, +/* CID_HASHALGO_NULL */ { 1, ASN_TAG_NULL, 0, 0, 1 }, + /* issuerNameHash */ +/* CID_ISSUERHASH */ { 0, ASN_OCTET_STRING, 0, 0, 0 }, + /* issuerKeyHash */ +/* CID_ISSUERKEYHASH */ { 0, ASN_OCTET_STRING, 0, 0, 0 }, + /* serialNumber */ +/* CID_SERIAL */ { 0, ASN_INTEGER, 0, 0, 0 }, +}; + +enum { + CERTIDASN_IDX_CID_HASHALGO_SEQ, + CERTIDASN_IDX_CID_HASHALGO_OID, + CERTIDASN_IDX_CID_HASHALGO_NULL, + CERTIDASN_IDX_CID_ISSUERHASH, + CERTIDASN_IDX_CID_ISSUERKEYHASH, + CERTIDASN_IDX_CID_SERIAL, +}; + +#define certidasn_Length (sizeof(certIDASNItems) / sizeof(ASNItem)) #endif +#ifndef WOLFSSL_ASN_TEMPLATE +static int OcspDecodeCertIDInt(const byte* input, word32* inOutIdx, word32 inSz, + OcspEntry* entry) +{ + int length; + word32 oid; + int ret; + /* Hash algorithm */ + ret = GetAlgoId(input, inOutIdx, &oid, oidHashType, inSz); + if (ret < 0) + return ret; + entry->hashAlgoOID = oid; + /* Save reference to the hash of CN */ + ret = GetOctetString(input, inOutIdx, &length, inSz); + if (ret < 0) + return ret; + if (length != OCSP_DIGEST_SIZE) + return ASN_PARSE_E; + XMEMCPY(entry->issuerHash, input + *inOutIdx, length); + *inOutIdx += length; + /* Save reference to the hash of the issuer public key */ + ret = GetOctetString(input, inOutIdx, &length, inSz); + if (ret < 0) + return ret; + if (length != OCSP_DIGEST_SIZE) + return ASN_PARSE_E; + XMEMCPY(entry->issuerKeyHash, input + *inOutIdx, length); + *inOutIdx += length; + + /* Get serial number */ + if (wc_GetSerialNumber(input, inOutIdx, entry->status->serial, + &entry->status->serialSz, inSz) < 0) + return ASN_PARSE_E; + return 0; +} +#else +static int OcspDecodeCertIDInt(const byte* input, word32* inOutIdx, word32 inSz, + OcspEntry* entry) +{ + DECL_ASNGETDATA(dataASN, certidasn_Length); + word32 issuerKeyHashLen = OCSP_DIGEST_SIZE; + word32 issuerHashLen = OCSP_DIGEST_SIZE; + word32 serialSz = EXTERNAL_SERIAL_SIZE; + word32 digestSz; + int ret = 0; + + WOLFSSL_ENTER("DecodeCertIdTemplate"); + CALLOC_ASNGETDATA(dataASN, certidasn_Length, ret, NULL); + if (ret != 0) + return ret; + + GetASN_OID(&dataASN[CERTIDASN_IDX_CID_HASHALGO_OID], oidHashType); + GetASN_Buffer(&dataASN[CERTIDASN_IDX_CID_ISSUERHASH], entry->issuerHash, + &issuerHashLen); + GetASN_Buffer(&dataASN[CERTIDASN_IDX_CID_ISSUERKEYHASH], + entry->issuerKeyHash, &issuerKeyHashLen); + GetASN_Buffer(&dataASN[CERTIDASN_IDX_CID_SERIAL], entry->status->serial, + &serialSz); + ret = GetASN_Items(certIDASNItems, dataASN, certidasn_Length, + 1, input, inOutIdx, inSz); + if (ret != 0) { + goto out; + } + entry->status->serialSz = serialSz; + entry->hashAlgoOID = + dataASN[CERTIDASN_IDX_CID_HASHALGO_OID].data.oid.sum; + digestSz = wc_HashGetDigestSize(wc_OidGetHash(entry->hashAlgoOID)); + if (issuerKeyHashLen != digestSz || issuerHashLen != digestSz) { + ret = ASN_PARSE_E; + goto out; + } +out: + FREE_ASNGETDATA(dataASN, NULL); + return ret; +} +#endif + +int OcspDecodeCertID(const byte *input, word32 *inOutIdx, word32 inSz, + OcspEntry *entry) +{ + word32 seqIdx = 0; + int len = inSz; + int ret; + +#ifndef WOLFSSL_ASN_TEMPLATE + ret = GetSequence(input, inOutIdx, &len, inSz); +#else + ret = GetASN_Sequence(input, inOutIdx, &len, inSz, 0); +#endif + if (ret < 0) + return ASN_PARSE_E; + ret = OcspDecodeCertIDInt(input + *inOutIdx, &seqIdx, len, entry); + if (ret < 0) + return ASN_PARSE_E; + if (seqIdx != (word32)len) + return ASN_PARSE_E; + *inOutIdx += len; + + return 0; +} + + static int DecodeSingleResponse(byte* source, word32* ioIndex, word32 size, int wrapperSz, OcspEntry* single) { #ifndef WOLFSSL_ASN_TEMPLATE - word32 idx = *ioIndex, prevIndex, oid, localIdx, certIdIdx; + word32 idx = *ioIndex, prevIndex, localIdx, certIdIdx; int length; int ret; byte tag; @@ -36440,31 +36550,8 @@ static int DecodeSingleResponse(byte* source, word32* ioIndex, word32 size, if (GetSequence(source, &idx, &length, size) < 0) return ASN_PARSE_E; single->rawCertId = source + certIdIdx; - /* Hash algorithm */ - ret = GetAlgoId(source, &idx, &oid, oidIgnoreType, size); + ret = OcspDecodeCertIDInt(source, &idx, size, single); if (ret < 0) - return ret; - single->hashAlgoOID = oid; - /* Save reference to the hash of CN */ - ret = GetOctetString(source, &idx, &length, size); - if (ret < 0) - return ret; - if (length > (int)sizeof(single->issuerHash)) - return BUFFER_E; - XMEMCPY(single->issuerHash, source + idx, length); - idx += length; - /* Save reference to the hash of the issuer public key */ - ret = GetOctetString(source, &idx, &length, size); - if (ret < 0) - return ret; - if (length > (int)sizeof(single->issuerKeyHash)) - return BUFFER_E; - XMEMCPY(single->issuerKeyHash, source + idx, length); - idx += length; - - /* Get serial number */ - if (wc_GetSerialNumber(source, &idx, single->status->serial, - &single->status->serialSz, size) < 0) return ASN_PARSE_E; single->rawCertIdSize = idx - certIdIdx; @@ -36577,13 +36664,10 @@ static int DecodeSingleResponse(byte* source, word32* ioIndex, word32 size, #else /* WOLFSSL_ASN_TEMPLATE */ DECL_ASNGETDATA(dataASN, singleResponseASN_Length); int ret = 0; - word32 ocspDigestSize = OCSP_DIGEST_SIZE; CertStatus* cs = NULL; - word32 serialSz; - word32 issuerHashLen; - word32 issuerKeyHashLen; word32 thisDateLen; word32 nextDateLen; + word32 certIdSeqIdx; (void)wrapperSz; @@ -36592,25 +36676,12 @@ static int DecodeSingleResponse(byte* source, word32* ioIndex, word32 size, CALLOC_ASNGETDATA(dataASN, singleResponseASN_Length, ret, NULL); if (ret == 0) { - /* Certificate Status field. */ cs = single->status; - /* Set maximum lengths for data. */ - issuerHashLen = OCSP_DIGEST_SIZE; - issuerKeyHashLen = OCSP_DIGEST_SIZE; - serialSz = EXTERNAL_SERIAL_SIZE; thisDateLen = MAX_DATE_SIZE; nextDateLen = MAX_DATE_SIZE; /* Set OID type, buffers to hold data and variables to hold size. */ - GetASN_OID(&dataASN[SINGLERESPONSEASN_IDX_CID_HASHALGO_OID], - oidHashType); - GetASN_Buffer(&dataASN[SINGLERESPONSEASN_IDX_CID_ISSUERHASH], - single->issuerHash, &issuerHashLen); - GetASN_Buffer(&dataASN[SINGLERESPONSEASN_IDX_CID_ISSUERKEYHASH], - single->issuerKeyHash, &issuerKeyHashLen); - GetASN_Buffer(&dataASN[SINGLERESPONSEASN_IDX_CID_SERIAL], cs->serial, - &serialSz); GetASN_Buffer(&dataASN[SINGLERESPONSEASN_IDX_THISUPDATE_GT], cs->thisDate, &thisDateLen); GetASN_Buffer(&dataASN[SINGLERESPONSEASN_IDX_NEXTUPDATE_GT], @@ -36621,27 +36692,11 @@ static int DecodeSingleResponse(byte* source, word32* ioIndex, word32 size, 1, source, ioIndex, size); } if (ret == 0) { - single->hashAlgoOID = - dataASN[SINGLERESPONSEASN_IDX_CID_HASHALGO_OID].data.oid.sum; - ocspDigestSize = (word32)wc_HashGetDigestSize( - wc_OidGetHash((int)single->hashAlgoOID)); - } - /* Validate the issuer hash length is the size required. */ - if ((ret == 0) && (issuerHashLen != ocspDigestSize)) { - ret = ASN_PARSE_E; - } - /* Validate the issuer key hash length is the size required. */ - if (ret == 0) { - if (issuerKeyHashLen != ocspDigestSize) { - ret = ASN_PARSE_E; - } + certIdSeqIdx = 0; + ret = OcspDecodeCertIDInt(dataASN[SINGLERESPONSEASN_IDX_CID_SEQ].data.ref.data, + &certIdSeqIdx, dataASN[SINGLERESPONSEASN_IDX_CID_SEQ].data.ref.length, single); } if (ret == 0) { - /* Store serial size. */ - cs->serialSz = (int)serialSz; - /* Set the hash algorithm OID */ - single->hashAlgoOID = - dataASN[SINGLERESPONSEASN_IDX_CID_HASHALGO_OID].data.oid.sum; /* Determine status by which item was found. */ if (dataASN[SINGLERESPONSEASN_IDX_CS_GOOD].tag != 0) { diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index 798d013f4..15efecd5a 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -2831,7 +2831,8 @@ WOLFSSL_LOCAL word32 EncodeOcspRequestExtensions(OcspRequest* req, byte* output, WOLFSSL_LOCAL int CompareOcspReqResp(OcspRequest* req, OcspResponse* resp); - +WOLFSSL_LOCAL int OcspDecodeCertID(const byte* input, word32* inOutIdx, word32 inSz, + OcspEntry* entry); #endif /* HAVE_OCSP */ From 5f05209c774a5006bd4cab38003553d643f4ad51 Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Tue, 25 Feb 2025 15:40:36 +0000 Subject: [PATCH 08/14] ocsp: fix wolfSSL_d2i_OCSP_CERTID --- src/ocsp.c | 64 +++++++++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/src/ocsp.c b/src/ocsp.c index c73b71000..5794691bb 100644 --- a/src/ocsp.c +++ b/src/ocsp.c @@ -1462,44 +1462,48 @@ WOLFSSL_OCSP_CERTID* wolfSSL_d2i_OCSP_CERTID(WOLFSSL_OCSP_CERTID** cidOut, int length) { WOLFSSL_OCSP_CERTID *cid = NULL; + int isAllocated = 0; + word32 idx = 0; + int ret; - if ((cidOut != NULL) && (derIn != NULL) && (*derIn != NULL) && - (length > 0)) { + if (derIn == NULL || *derIn == NULL || length <= 0) + return NULL; + if (cidOut != NULL && *cidOut != NULL) { cid = *cidOut; - - /* If a NULL is passed we allocate the memory for the caller. */ - if (cid == NULL) { - cid = (WOLFSSL_OCSP_CERTID*)XMALLOC(sizeof(*cid), NULL, - DYNAMIC_TYPE_OPENSSL); - } - else if (cid->rawCertId != NULL) { - XFREE(cid->rawCertId, NULL, DYNAMIC_TYPE_OPENSSL); - cid->rawCertId = NULL; - cid->rawCertIdSize = 0; - } - - if (cid != NULL) { - cid->rawCertId = (byte*)XMALLOC((size_t)length + 1, NULL, DYNAMIC_TYPE_OPENSSL); - if (cid->rawCertId != NULL) { - XMEMCPY(cid->rawCertId, *derIn, (size_t)length); - cid->rawCertIdSize = length; - - /* Per spec. advance past the data that is being returned - * to the caller. */ - *cidOut = cid; - *derIn = *derIn + length; - - return cid; - } - } + FreeOcspEntry(cid, NULL); + } else { + cid = (WOLFSSL_OCSP_CERTID*)XMALLOC(sizeof(WOLFSSL_OCSP_CERTID), + NULL, DYNAMIC_TYPE_OPENSSL); + if (cid == NULL) + return NULL; + isAllocated = 1; } - if ((cid != NULL) && ((cidOut == NULL) || (cid != *cidOut))) { + XMEMSET(cid, 0, sizeof(WOLFSSL_OCSP_CERTID)); + cid->status = XMALLOC(sizeof(CertStatus), NULL, DYNAMIC_TYPE_OCSP_STATUS); + if (cid->status == NULL) { XFREE(cid, NULL, DYNAMIC_TYPE_OPENSSL); + return NULL; + } + XMEMSET(cid->status, 0, sizeof(CertStatus)); + cid->ownStatus = 1; + + ret = OcspDecodeCertID(*derIn, &idx, length, cid); + if (ret != 0) { + FreeOcspEntry(cid, NULL); + if (isAllocated) { + XFREE(cid, NULL, DYNAMIC_TYPE_OPENSSL); + } + return NULL; } - return NULL; + *derIn += idx; + + if (isAllocated && cidOut != NULL) + *cidOut = cid; + + return cid; } const WOLFSSL_OCSP_CERTID* wolfSSL_OCSP_SINGLERESP_get0_id( From 5eef98a5ea2d03886c5ea821a450255cdaa7d61d Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Tue, 25 Feb 2025 11:41:02 +0000 Subject: [PATCH 09/14] ocsp: add OCSP CERT ID encode/decode test --- tests/api.c | 1 + tests/api/test_ocsp.c | 66 +++++++++++++++++++++++++++++++++++++++++++ tests/api/test_ocsp.h | 1 + 3 files changed, 68 insertions(+) diff --git a/tests/api.c b/tests/api.c index 354b0eb7b..4f6162bb5 100644 --- a/tests/api.c +++ b/tests/api.c @@ -95500,6 +95500,7 @@ TEST_CASE testCases[] = { TEST_DECL(test_ocsp_status_callback), TEST_DECL(test_ocsp_basic_verify), TEST_DECL(test_ocsp_response_parsing), + TEST_DECL(test_ocsp_certid_enc_dec), /* This test needs to stay at the end to clean up any caches allocated. */ TEST_DECL(test_wolfSSL_Cleanup) }; diff --git a/tests/api/test_ocsp.c b/tests/api/test_ocsp.c index 5e172fa50..ca2cdc208 100644 --- a/tests/api/test_ocsp.c +++ b/tests/api/test_ocsp.c @@ -592,3 +592,69 @@ int test_ocsp_status_callback(void) && defined(HAVE_CERTIFICATE_STATUS_REQUEST) && \ !defined(WOLFSSL_NO_TLS12) \ && defined(OPENSSL_ALL) */ + +#if !defined (NO_SHA) && defined(OPENSSL_ALL) && defined(HAVE_OCSP) +int test_ocsp_certid_enc_dec(void) +{ + EXPECT_DECLS; + WOLFSSL_OCSP_CERTID* certIdDec = NULL; + WOLFSSL_OCSP_CERTID* certId = NULL; + WOLFSSL_X509* subject = NULL; + WOLFSSL_X509* issuer = NULL; + unsigned char* temp = NULL; + unsigned char* der2 = NULL; + unsigned char* der = NULL; + int derSz = 0, derSz1 = 0; + + /* Load test certificates */ + ExpectNotNull( + subject = wolfSSL_X509_load_certificate_file( + "./certs/ocsp/intermediate1-ca-cert.pem", WOLFSSL_FILETYPE_PEM)); + ExpectNotNull(issuer = wolfSSL_X509_load_certificate_file( + "./certs/ocsp/root-ca-cert.pem", WOLFSSL_FILETYPE_PEM)); + + /* Create CERTID from certificates */ + ExpectNotNull(certId = wolfSSL_OCSP_cert_to_id(NULL, subject, issuer)); + + /* get len */ + ExpectIntGT(derSz = wolfSSL_i2d_OCSP_CERTID(certId, NULL), 0); + + /* encode it */ + ExpectIntGT(derSz1 = wolfSSL_i2d_OCSP_CERTID(certId, &der), 0); + ExpectIntEQ(derSz, derSz1); + + temp = der2 = XMALLOC(derSz, NULL, DYNAMIC_TYPE_OPENSSL); + ExpectNotNull(der2); + /* encode without allocation */ + ExpectIntGT(derSz1 = wolfSSL_i2d_OCSP_CERTID(certId, &der2), 0); + ExpectIntEQ(derSz, derSz1); + ExpectPtrEq(der2, temp + derSz); + ExpectBufEQ(der, temp, derSz); + XFREE(temp, NULL, DYNAMIC_TYPE_OPENSSL); + + /* save original */ + temp = der; + /* decode it */ + ExpectNotNull(certIdDec = wolfSSL_d2i_OCSP_CERTID(NULL, + (const unsigned char**)&der, derSz)); + /* check ptr is advanced */ + ExpectPtrEq(der, temp + derSz); + der = der2; + XFREE(temp, NULL, DYNAMIC_TYPE_OPENSSL); + + /* compare */ + ExpectIntEQ(wolfSSL_OCSP_id_cmp(certId, certIdDec), 0); + + wolfSSL_OCSP_CERTID_free(certId); + wolfSSL_OCSP_CERTID_free(certIdDec); + wolfSSL_X509_free(subject); + wolfSSL_X509_free(issuer); + + return EXPECT_SUCCESS(); +} +#else +int test_ocsp_certid_enc_dec(void) +{ + return TEST_SKIPPED; +} +#endif diff --git a/tests/api/test_ocsp.h b/tests/api/test_ocsp.h index 8ba5a634c..55065b9d6 100644 --- a/tests/api/test_ocsp.h +++ b/tests/api/test_ocsp.h @@ -22,6 +22,7 @@ #ifndef WOLFSSL_TEST_OCSP_H #define WOLFSSL_TEST_OCSP_H +int test_ocsp_certid_enc_dec(void); int test_ocsp_status_callback(void); int test_ocsp_basic_verify(void); int test_ocsp_response_parsing(void); From 07c7b21b10055c670f061d6027dc3cf9b5784ed6 Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Tue, 25 Feb 2025 16:53:09 +0000 Subject: [PATCH 10/14] tests: api: fix test for d2i_CERT_ID refactor --- tests/api.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tests/api.c b/tests/api.c index 4f6162bb5..c5e9ca8ec 100644 --- a/tests/api.c +++ b/tests/api.c @@ -71456,10 +71456,9 @@ static int test_wolfSSL_d2i_OCSP_CERTID(void) WOLFSSL_OCSP_CERTID* certId = NULL; ExpectNotNull(certId = wolfSSL_d2i_OCSP_CERTID(&certId, &rawCertIdPtr, sizeof(rawCertId))); - ExpectIntEQ(certId->rawCertIdSize, sizeof(rawCertId)); if (certId != NULL) { XFREE(certId->rawCertId, NULL, DYNAMIC_TYPE_OPENSSL); - XFREE(certId, NULL, DYNAMIC_TYPE_OPENSSL); + wolfSSL_OCSP_CERTID_free(certId); } } @@ -71477,10 +71476,9 @@ static int test_wolfSSL_d2i_OCSP_CERTID(void) ExpectNotNull(certIdGood = wolfSSL_d2i_OCSP_CERTID(&certId, &rawCertIdPtr, sizeof(rawCertId))); ExpectPtrEq(certIdGood, certId); - ExpectIntEQ(certId->rawCertIdSize, sizeof(rawCertId)); if (certId != NULL) { XFREE(certId->rawCertId, NULL, DYNAMIC_TYPE_OPENSSL); - XFREE(certId, NULL, DYNAMIC_TYPE_TMP_BUFFER); + wolfSSL_OCSP_CERTID_free(certId); certId = NULL; } } @@ -71489,8 +71487,6 @@ static int test_wolfSSL_d2i_OCSP_CERTID(void) * always be returned. */ { WOLFSSL_OCSP_CERTID* certId = NULL; - ExpectNull(certIdBad = wolfSSL_d2i_OCSP_CERTID(NULL, &rawCertIdPtr, - sizeof(rawCertId))); ExpectNull(certIdBad = wolfSSL_d2i_OCSP_CERTID(&certId, NULL, sizeof(rawCertId))); ExpectNull(certIdBad = wolfSSL_d2i_OCSP_CERTID(&certId, &rawCertIdPtr, 0)); From 512f9286504106791662539852f2fea059699ed9 Mon Sep 17 00:00:00 2001 From: David Garske Date: Wed, 26 Feb 2025 14:45:23 -0800 Subject: [PATCH 11/14] Fix cast warnings with g++. --- src/ocsp.c | 3 ++- tests/api/test_ocsp.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ocsp.c b/src/ocsp.c index 5794691bb..88d75f365 100644 --- a/src/ocsp.c +++ b/src/ocsp.c @@ -1481,7 +1481,8 @@ WOLFSSL_OCSP_CERTID* wolfSSL_d2i_OCSP_CERTID(WOLFSSL_OCSP_CERTID** cidOut, } XMEMSET(cid, 0, sizeof(WOLFSSL_OCSP_CERTID)); - cid->status = XMALLOC(sizeof(CertStatus), NULL, DYNAMIC_TYPE_OCSP_STATUS); + cid->status = (CertStatus*)XMALLOC(sizeof(CertStatus), NULL, + DYNAMIC_TYPE_OCSP_STATUS); if (cid->status == NULL) { XFREE(cid, NULL, DYNAMIC_TYPE_OPENSSL); return NULL; diff --git a/tests/api/test_ocsp.c b/tests/api/test_ocsp.c index ca2cdc208..b315ee6b5 100644 --- a/tests/api/test_ocsp.c +++ b/tests/api/test_ocsp.c @@ -623,7 +623,7 @@ int test_ocsp_certid_enc_dec(void) ExpectIntGT(derSz1 = wolfSSL_i2d_OCSP_CERTID(certId, &der), 0); ExpectIntEQ(derSz, derSz1); - temp = der2 = XMALLOC(derSz, NULL, DYNAMIC_TYPE_OPENSSL); + temp = der2 = (unsigned char*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_OPENSSL); ExpectNotNull(der2); /* encode without allocation */ ExpectIntGT(derSz1 = wolfSSL_i2d_OCSP_CERTID(certId, &der2), 0); From 814f0f8a096346a5bf9927fca3b797d1c2b3637d Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Thu, 27 Feb 2025 12:46:18 +0000 Subject: [PATCH 12/14] Refactor CERT_ID encoding as per review comments --- src/ocsp.c | 140 ++++++++++++++++-------------------------- tests/api/test_ocsp.c | 3 +- 2 files changed, 55 insertions(+), 88 deletions(-) diff --git a/src/ocsp.c b/src/ocsp.c index 88d75f365..e64fee50f 100644 --- a/src/ocsp.c +++ b/src/ocsp.c @@ -833,101 +833,76 @@ void wolfSSL_OCSP_BASICRESP_free(WOLFSSL_OCSP_BASICRESP* basicResponse) wolfSSL_OCSP_RESPONSE_free(basicResponse); } -/* Calculate size needed for CertID DER encoding following RFC 6960: +/* Calculate ancode CertID DER encoding following RFC 6960: CertID ::= SEQUENCE { hashAlgorithm AlgorithmIdentifier, issuerNameHash OCTET STRING, issuerKeyHash OCTET STRING, serialNumber CertificateSerialNumber } */ -static int OcspGetCertIdRawSize(WOLFSSL_OCSP_CERTID* id, word32* totalSz, - word32* intSize) +static int OcspEncodeCertID(WOLFSSL_OCSP_CERTID* id, byte* output, + word32* totalSz, word32* intSize) { word32 idx = 0; int ret; - if (id == NULL || totalSz == NULL || id->status == NULL) + if (id == NULL || totalSz == NULL || intSize == NULL || + (output != NULL && (*totalSz == 0 || *totalSz <= *intSize))) return BAD_FUNC_ARG; - ret = SetAlgoID(id->hashAlgoOID, NULL, oidHashType, 0); + if (output != NULL) { + ret = SetSequence(*intSize, output); + if (ret < 0) + return ret; + idx += ret; + } + + ret = SetAlgoID(id->hashAlgoOID, ((output != NULL) ? output + idx : output), + oidHashType, 0); if (ret < 0) return ret; idx += ret; /* issuerNameHash */ - ret = SetOctetString(OCSP_DIGEST_SIZE, NULL); - if (ret < 0) - return ret; - idx += ret + OCSP_DIGEST_SIZE; - - /* issuerKeyHash */ - ret = SetOctetString(OCSP_DIGEST_SIZE, NULL); - if (ret < 0) - return ret; - idx += ret + OCSP_DIGEST_SIZE; - - /* serialNumber */ - ret = SetASNInt(id->status->serialSz, id->status->serial[0], NULL); - if (ret < 0) - return ret; - idx += ret + id->status->serialSz; - - /* Set sequence - get size */ - ret = SetSequence(idx, NULL); - if (ret < 0) - return ret; - - *totalSz = idx + ret; - if (intSize) - *intSize = idx; - return 0; -} - -/* Encode CertID following RFC 6960 ASN.1 structure */ -static int OcspEncodeCertID(WOLFSSL_OCSP_CERTID* id, byte* output, word32 size) -{ - word32 idx = 0; - int ret; - - if (id == NULL || output == NULL || id->status == NULL) - return BAD_FUNC_ARG; - - ret = SetSequence(size, output); + ret = SetOctetString(OCSP_DIGEST_SIZE, ((output != NULL) ? output + idx : output)); if (ret < 0) return ret; idx += ret; - - /* hashAlgorithm */ - ret = SetAlgoID(id->hashAlgoOID, output + idx, oidHashType, 0); - if (ret < 0) - return ret; - idx += ret; - - /* issuerNameHash */ - ret = SetOctetString(OCSP_DIGEST_SIZE, output + idx); - if (ret < 0) - return ret; - idx += ret; - XMEMCPY(output + idx, id->issuerHash, OCSP_DIGEST_SIZE); + if (output != NULL) + XMEMCPY(output + idx, id->issuerHash, OCSP_DIGEST_SIZE); idx += OCSP_DIGEST_SIZE; /* issuerKeyHash */ - ret = SetOctetString(OCSP_DIGEST_SIZE, output + idx); + ret = SetOctetString(OCSP_DIGEST_SIZE, ((output != NULL) ? output + idx : output)); if (ret < 0) return ret; idx += ret; - XMEMCPY(output + idx, id->issuerKeyHash, OCSP_DIGEST_SIZE); + if (output != NULL) + XMEMCPY(output + idx, id->issuerKeyHash, OCSP_DIGEST_SIZE); idx += OCSP_DIGEST_SIZE; /* serialNumber */ - ret = SetASNInt(id->status->serialSz, id->status->serial[0], output + idx); + ret = SetASNInt(id->status->serialSz, id->status->serial[0], ((output != NULL) ? output + idx : output)); if (ret < 0) return ret; idx += ret; - XMEMCPY(output + idx, id->status->serial, id->status->serialSz); + if (output != NULL) + XMEMCPY(output + idx, id->status->serial, id->status->serialSz); idx += id->status->serialSz; - return idx; + if (output == NULL) { + *intSize = idx; + ret = SetSequence(idx, NULL); + if (ret < 0) + return ret; + idx += ret; + *totalSz = idx; + } + else if (idx != *totalSz) { + return BUFFER_E; + } + + return 0; } static int OcspRespIdMatches(OcspResponse* resp, const byte* NameHash, @@ -1398,34 +1373,24 @@ int wolfSSL_i2d_OCSP_CERTID(WOLFSSL_OCSP_CERTID* id, unsigned char** data) int ret; WOLFSSL_ENTER("wolfSSL_i2d_OCSP_CERTID"); - if (id == NULL) { + if (id == NULL) return -1; + + if (id->rawCertId != NULL) { + derSz = id->rawCertIdSize; + } + else { + ret = OcspEncodeCertID(id, NULL, &derSz, &intSz); + if (ret != 0) { + WOLFSSL_MSG("Failed to calculate CertID size"); + return -1; + } } if (data == NULL) { - if (id->rawCertId != NULL) - return id->rawCertIdSize; - - ret = OcspGetCertIdRawSize(id, &derSz, NULL); - if (ret != 0) { - WOLFSSL_MSG("Failed to calculate CertID size"); - return -1; - } return derSz; } - if (id->rawCertId == NULL) { - /* Calculate required size */ - ret = OcspGetCertIdRawSize(id, &derSz, &intSz); - if (ret != 0) { - WOLFSSL_MSG("Failed to calculate CertID size"); - return -1; - } - } - else { - derSz = id->rawCertIdSize; - } - if (*data == NULL) { /* Allocate buffer for DER encoding */ *data = (byte*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_OPENSSL); @@ -1440,11 +1405,11 @@ int wolfSSL_i2d_OCSP_CERTID(WOLFSSL_OCSP_CERTID* id, unsigned char** data) XMEMCPY(*data, id->rawCertId, id->rawCertIdSize); } else { - ret = OcspEncodeCertID(id, *data, intSz); + ret = OcspEncodeCertID(id, *data, &derSz, &intSz); if (ret < 0) { WOLFSSL_MSG("Failed to encode CertID"); if (allocated) { - XFREE(data, NULL, DYNAMIC_TYPE_OPENSSL); + XFREE(*data, NULL, DYNAMIC_TYPE_OPENSSL); *data = NULL; } return -1; @@ -1472,9 +1437,10 @@ WOLFSSL_OCSP_CERTID* wolfSSL_d2i_OCSP_CERTID(WOLFSSL_OCSP_CERTID** cidOut, if (cidOut != NULL && *cidOut != NULL) { cid = *cidOut; FreeOcspEntry(cid, NULL); - } else { - cid = (WOLFSSL_OCSP_CERTID*)XMALLOC(sizeof(WOLFSSL_OCSP_CERTID), - NULL, DYNAMIC_TYPE_OPENSSL); + } + else { + cid = (WOLFSSL_OCSP_CERTID*)XMALLOC(sizeof(WOLFSSL_OCSP_CERTID), NULL, + DYNAMIC_TYPE_OPENSSL); if (cid == NULL) return NULL; isAllocated = 1; diff --git a/tests/api/test_ocsp.c b/tests/api/test_ocsp.c index b315ee6b5..3f4175c7d 100644 --- a/tests/api/test_ocsp.c +++ b/tests/api/test_ocsp.c @@ -623,7 +623,8 @@ int test_ocsp_certid_enc_dec(void) ExpectIntGT(derSz1 = wolfSSL_i2d_OCSP_CERTID(certId, &der), 0); ExpectIntEQ(derSz, derSz1); - temp = der2 = (unsigned char*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_OPENSSL); + if (EXPECT_SUCCESS()) + temp = der2 = (unsigned char*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_OPENSSL); ExpectNotNull(der2); /* encode without allocation */ ExpectIntGT(derSz1 = wolfSSL_i2d_OCSP_CERTID(certId, &der2), 0); From 83f56445498daf3bb18fea8027e92f1cc700e199 Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Thu, 27 Feb 2025 19:27:12 +0000 Subject: [PATCH 13/14] ocsp: Fix OcspEncodeCertID SetAlgoID return check --- src/ocsp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ocsp.c b/src/ocsp.c index e64fee50f..8ded866ac 100644 --- a/src/ocsp.c +++ b/src/ocsp.c @@ -859,8 +859,8 @@ static int OcspEncodeCertID(WOLFSSL_OCSP_CERTID* id, byte* output, ret = SetAlgoID(id->hashAlgoOID, ((output != NULL) ? output + idx : output), oidHashType, 0); - if (ret < 0) - return ret; + if (ret <= 0) + return -1; idx += ret; /* issuerNameHash */ From 194db7e84479632a5e4885ab3fb06a19a50054f2 Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Thu, 27 Feb 2025 19:36:45 +0000 Subject: [PATCH 14/14] tests: gate ocsp test on SM2 || SM3 we don't properly support SM2 and SM3 hash algo id properly yet --- tests/api.c | 3 ++- tests/api/test_ocsp.c | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/api.c b/tests/api.c index c5e9ca8ec..6f1f5a335 100644 --- a/tests/api.c +++ b/tests/api.c @@ -71324,7 +71324,8 @@ static int test_wolfSSL_OCSP_id_get0_info(void) { EXPECT_DECLS; #if (defined(OPENSSL_ALL) || defined(WOLFSSL_HAPROXY)) && \ - defined(HAVE_OCSP) && !defined(NO_FILESYSTEM) && !defined(NO_RSA) + defined(HAVE_OCSP) && !defined(NO_FILESYSTEM) && !defined(NO_RSA) && \ + !defined(WOLFSSL_SM2) && !defined(WOLFSSL_SM3) X509* cert = NULL; X509* issuer = NULL; OCSP_CERTID* id = NULL; diff --git a/tests/api/test_ocsp.c b/tests/api/test_ocsp.c index 3f4175c7d..7d2c9fddf 100644 --- a/tests/api/test_ocsp.c +++ b/tests/api/test_ocsp.c @@ -593,7 +593,8 @@ int test_ocsp_status_callback(void) !defined(WOLFSSL_NO_TLS12) \ && defined(OPENSSL_ALL) */ -#if !defined (NO_SHA) && defined(OPENSSL_ALL) && defined(HAVE_OCSP) +#if !defined(NO_SHA) && defined(OPENSSL_ALL) && defined(HAVE_OCSP) && \ + !defined(WOLFSSL_SM3) && !defined(WOLFSSL_SM2) int test_ocsp_certid_enc_dec(void) { EXPECT_DECLS; @@ -653,7 +654,7 @@ int test_ocsp_certid_enc_dec(void) return EXPECT_SUCCESS(); } -#else +#else /* !NO_SHA && OPENSSL_ALL && HAVE_OCSP && !WOLFSSL_SM3 && !WOLFSSL_SM2 */ int test_ocsp_certid_enc_dec(void) { return TEST_SKIPPED;