Skip to content

Commit 0a9cce6

Browse files
committed
ocsp response: add nonce extension support
1 parent de58a4d commit 0a9cce6

3 files changed

Lines changed: 191 additions & 38 deletions

File tree

src/ocsp.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2496,7 +2496,7 @@ int wc_OcspResponder_SetCertStatus(OcspResponder* responder,
24962496

24972497
static int OcspResponse_WriteResponse(OcspResponder* responder, byte* response,
24982498
word32* responseSz, OcspResponderCa* ca,
2499-
OcspResponderCertStatus* certStatus)
2499+
OcspResponderCertStatus* certStatus, OcspRequest* req)
25002500
{
25012501
OcspResponse resp;
25022502
CertStatus status;
@@ -2563,6 +2563,12 @@ static int OcspResponse_WriteResponse(OcspResponder* responder, byte* response,
25632563
resp.certSz = ca->certDerSz;
25642564
}
25652565

2566+
/* Copy nonce from request to response if present */
2567+
if (req != NULL && req->nonceSz > 0) {
2568+
resp.nonce = req->nonce;
2569+
resp.nonceSz = req->nonceSz;
2570+
}
2571+
25662572
/* Only support sha-1 hashes for now */
25672573
wc_static_assert((int)KEYID_SIZE == (int)WC_SHA_DIGEST_SIZE);
25682574
entry.hashAlgoOID = SHAh;
@@ -2643,7 +2649,7 @@ int wc_OcspResponder_WriteResponse(OcspResponder* responder,
26432649
WOLFSSL_MSG("Found CA and certificate status");
26442650

26452651
ret = OcspResponse_WriteResponse(responder, response, responseSz, ca,
2646-
certStatus);
2652+
certStatus, &req);
26472653
if (ret != 0) {
26482654
WOLFSSL_MSG("Failed to write OCSP response");
26492655
goto out;

tests/api/test_ocsp.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1108,7 +1108,7 @@ static int ocspResponderTest_Run(OcspResponderTestConfig* config, int sendCerts)
11081108

11091109
/* Create OCSP request from target certificate */
11101110
ExpectNotNull(clientReq = wc_OcspRequest_new(NULL));
1111-
ExpectIntEQ(wc_InitOcspRequest(clientReq, &targetCert, 0, NULL), 0);
1111+
ExpectIntEQ(wc_InitOcspRequest(clientReq, &targetCert, 1, NULL), 0);
11121112
ExpectIntGT(reqSz = wc_EncodeOcspRequest(clientReq, reqBuf,
11131113
sizeof(reqBuf)), 0);
11141114

wolfcrypt/src/asn.c

Lines changed: 182 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -38978,6 +38978,82 @@ static int DecodeOcspRespExtensions(byte* source, word32* ioIndex,
3897838978
#endif
3897938979
}
3898038980

38981+
#ifdef WOLFSSL_ASN_TEMPLATE
38982+
/* ASN.1 template for OCSP nonce extension.
38983+
* RFC 6960, 4.4.1 - Nonce
38984+
* X.509: RFC 5280, 4.1 - Basic Certificate Fields. (Extension)
38985+
*/
38986+
static const ASNItem ocspNonceExtASN[] = {
38987+
/* SEQ */ { 0, ASN_SEQUENCE, 1, 1, 0 },
38988+
/* Extension */
38989+
/* EXT */ { 1, ASN_SEQUENCE, 1, 1, 0 },
38990+
/* extnId */
38991+
/* EXT_OID */ {2, ASN_OBJECT_ID, 0, 0, 0 },
38992+
/* critical not encoded. */
38993+
/* extnValue */
38994+
/* EXT_VAL */ {2, ASN_OCTET_STRING, 0, 1, 0 },
38995+
/* nonce */
38996+
/* EXT_NONCE */ {3, ASN_OCTET_STRING, 0, 0, 0 },
38997+
};
38998+
enum {
38999+
OCSPNONCEEXTASN_IDX_SEQ = 0,
39000+
OCSPNONCEEXTASN_IDX_EXT,
39001+
OCSPNONCEEXTASN_IDX_EXT_OID,
39002+
OCSPNONCEEXTASN_IDX_EXT_VAL,
39003+
OCSPNONCEEXTASN_IDX_EXT_NONCE,
39004+
};
39005+
39006+
/* Number of items in ASN.1 template for OCSP nonce extension. */
39007+
#define ocspNonceExtASN_Length (sizeof(ocspNonceExtASN) / sizeof(ASNItem))
39008+
#endif /* WOLFSSL_ASN_TEMPLATE */
39009+
39010+
/* Encode OCSP response extensions (currently only nonce) */
39011+
static int EncodeOcspRespExtensions(OcspResponse* resp, byte* out,
39012+
word32* outSz)
39013+
{
39014+
#ifndef WOLFSSL_ASN_TEMPLATE
39015+
(void)resp;
39016+
(void)output;
39017+
(void)size;
39018+
/* Encoding ocsp responses not supported in legacy ASN parsing */
39019+
return NOT_COMPILED_IN;
39020+
#else
39021+
DECL_ASNSETDATA(dataASN, ocspNonceExtASN_Length);
39022+
int sz = 0;
39023+
int ret = 0;
39024+
39025+
if (resp == NULL || outSz == NULL) {
39026+
return BAD_FUNC_ARG;
39027+
}
39028+
39029+
CALLOC_ASNSETDATA(dataASN, ocspNonceExtASN_Length, ret, resp->heap);
39030+
39031+
if (ret == 0) {
39032+
SetASN_OID(&dataASN[OCSPNONCEEXTASN_IDX_EXT_OID], OCSP_NONCE_OID,
39033+
oidOcspType);
39034+
SetASN_Buffer(&dataASN[OCSPNONCEEXTASN_IDX_EXT_NONCE],
39035+
resp->nonce, resp->nonceSz);
39036+
/* Calculate size of encoding. */
39037+
ret = SizeASN_Items(ocspNonceExtASN, dataASN,
39038+
ocspNonceExtASN_Length, &sz);
39039+
}
39040+
/* Check buffer big enough for encoding if supplied. */
39041+
if (ret == 0 && out != NULL && sz > (int)*outSz) {
39042+
ret = BUFFER_E;
39043+
}
39044+
if (ret == 0 && out != NULL) {
39045+
if (SetASN_Items(ocspNonceExtASN, dataASN, ocspNonceExtASN_Length,
39046+
out) != sz)
39047+
ret = ASN_PARSE_E;
39048+
}
39049+
if (ret == 0)
39050+
*outSz = sz;
39051+
39052+
FREE_ASNSETDATA(dataASN, resp->heap);
39053+
return ret;
39054+
#endif
39055+
}
39056+
3898139057
#ifdef WOLFSSL_ASN_TEMPLATE
3898239058
/* ASN.1 template for OCSP ResponseData.
3898339059
* RFC 6960, 4.2.1 - ASN.1 Specification of the OCSP Response
@@ -39030,6 +39106,7 @@ static int EncodeResponseData(OcspResponse* resp, byte* out, word32* outSz)
3903039106
int ret = 0;
3903139107
int sz = 0;
3903239108
word32 respListSz = 0;
39109+
word32 respExtSz = 0;
3903339110
OcspEntry* single = NULL;
3903439111

3903539112
if (resp == NULL || outSz == NULL) {
@@ -39076,14 +39153,25 @@ static int EncodeResponseData(OcspResponse* resp, byte* out, word32* outSz)
3907639153
else
3907739154
ret = BAD_FUNC_ARG;
3907839155
}
39156+
if (ret == 0) {
39157+
/* Encode responseExtensions if nonce is present */
39158+
if (resp->nonceSz > 0) {
39159+
ret = EncodeOcspRespExtensions(resp, NULL, &respExtSz);
39160+
if (ret == 0 && respExtSz > 0) {
39161+
SetASN_Buffer(&dataASN[OCSPRESPDATAASN_IDX_RESPEXT],
39162+
NULL, respExtSz);
39163+
}
39164+
}
39165+
else {
39166+
SetASNItem_NoOutNode(dataASN, ocspRespDataASN,
39167+
OCSPRESPDATAASN_IDX_RESPEXT,
39168+
ocspRespDataASN_Length);
39169+
}
39170+
}
3907939171
if (ret == 0) {
3908039172
SetASN_Int8Bit(&dataASN[OCSPRESPDATAASN_IDX_VER], 0);
3908139173
SetASN_Buffer(&dataASN[OCSPRESPDATAASN_IDX_RESP], NULL,
3908239174
respListSz);
39083-
/* TODO add responseExtensions support */
39084-
SetASNItem_NoOutNode(dataASN, ocspRespDataASN,
39085-
OCSPRESPDATAASN_IDX_RESPEXT,
39086-
ocspRespDataASN_Length);
3908739175
/* Calculate size of encoding. */
3908839176
ret = SizeASN_Items(ocspRespDataASN, dataASN, ocspRespDataASN_Length,
3908939177
&sz);
@@ -39109,6 +39197,12 @@ static int EncodeResponseData(OcspResponse* resp, byte* out, word32* outSz)
3910939197
}
3911039198
if (ret == 0 && respListSz != 0)
3911139199
ret = ASN_PARSE_E;
39200+
/* Encode response extensions if buffer was allocated */
39201+
if (ret == 0 && respExtSz > 0) {
39202+
ret = EncodeOcspRespExtensions(resp,
39203+
(byte*)dataASN[OCSPRESPDATAASN_IDX_RESPEXT].data.buffer.data,
39204+
&respExtSz);
39205+
}
3911239206
}
3911339207
if (ret == 0)
3911439208
*outSz = sz;
@@ -40197,35 +40291,6 @@ int OcspResponseDecode(OcspResponse* resp, void* cm, void* heap,
4019740291
#endif /* WOLFSSL_ASN_TEMPLATE */
4019840292
}
4019940293

40200-
#ifdef WOLFSSL_ASN_TEMPLATE
40201-
/* ASN.1 template for OCSP nonce extension.
40202-
* RFC 6960, 4.4.1 - Nonce
40203-
* X.509: RFC 5280, 4.1 - Basic Certificate Fields. (Extension)
40204-
*/
40205-
static const ASNItem ocspNonceExtASN[] = {
40206-
/* SEQ */ { 0, ASN_SEQUENCE, 1, 1, 0 },
40207-
/* Extension */
40208-
/* EXT */ { 1, ASN_SEQUENCE, 1, 1, 0 },
40209-
/* extnId */
40210-
/* EXT_OID */ {2, ASN_OBJECT_ID, 0, 0, 0 },
40211-
/* critical not encoded. */
40212-
/* extnValue */
40213-
/* EXT_VAL */ {2, ASN_OCTET_STRING, 0, 1, 0 },
40214-
/* nonce */
40215-
/* EXT_NONCE */ {3, ASN_OCTET_STRING, 0, 0, 0 },
40216-
};
40217-
enum {
40218-
OCSPNONCEEXTASN_IDX_SEQ = 0,
40219-
OCSPNONCEEXTASN_IDX_EXT,
40220-
OCSPNONCEEXTASN_IDX_EXT_OID,
40221-
OCSPNONCEEXTASN_IDX_EXT_VAL,
40222-
OCSPNONCEEXTASN_IDX_EXT_NONCE,
40223-
};
40224-
40225-
/* Number of items in ASN.1 template for OCSP nonce extension. */
40226-
#define ocspNonceExtASN_Length (sizeof(ocspNonceExtASN) / sizeof(ASNItem))
40227-
#endif /* WOLFSSL_ASN_TEMPLATE */
40228-
4022940294
word32 EncodeOcspRequestExtensions(OcspRequest* req, byte* output, word32 size)
4023040295
{
4023140296
const byte NonceObjId[] = { 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
@@ -40526,6 +40591,85 @@ int EncodeOcspRequest(OcspRequest* req, byte* output, word32 size)
4052640591

4052740592
#ifdef HAVE_OCSP_RESPONDER
4052840593

40594+
#ifdef WOLFSSL_ASN_TEMPLATE
40595+
/* Decode OCSP request extensions.
40596+
* RFC 6960, 4.1.1 - ASN.1 Specification of the OCSP Request
40597+
*
40598+
* @param [in] source Buffer containing encoded extensions (inside [2]).
40599+
* @param [in] sz Length of buffer in bytes.
40600+
* @param [in, out] req OCSP request object to store nonce.
40601+
* @return 0 on success.
40602+
* @return ASN_PARSE_E when data is malformed.
40603+
*/
40604+
static int DecodeOcspReqExtensions(const byte* source, word32 sz,
40605+
OcspRequest* req)
40606+
{
40607+
DECL_ASNGETDATA(dataASN, certExtASN_Length);
40608+
int ret = 0;
40609+
word32 idx = 0;
40610+
word32 maxIdx;
40611+
int seqLen;
40612+
40613+
WOLFSSL_ENTER("DecodeOcspReqExtensions");
40614+
40615+
/* Skip the outer SEQUENCE that wraps all extensions */
40616+
if (GetSequence(source, &idx, &seqLen, sz) < 0) {
40617+
return ASN_PARSE_E;
40618+
}
40619+
maxIdx = idx + (word32)seqLen;
40620+
40621+
CALLOC_ASNGETDATA(dataASN, certExtASN_Length, ret, req->heap);
40622+
40623+
/* Step through all extensions. */
40624+
while ((ret == 0) && (idx < maxIdx)) {
40625+
byte isCrit = 0;
40626+
/* Clear dynamic data, set OID type to expect. */
40627+
XMEMSET(dataASN, 0, sizeof(*dataASN) * certExtASN_Length);
40628+
GetASN_OID(&dataASN[CERTEXTASN_IDX_OID], oidOcspType);
40629+
GetASN_Boolean(&dataASN[CERTEXTASN_IDX_CRIT], &isCrit);
40630+
/* Decode extension. */
40631+
ret = GetASN_Items(certExtASN, dataASN, certExtASN_Length, 0,
40632+
source, &idx, sz);
40633+
if (ret == 0) {
40634+
word32 oid = dataASN[CERTEXTASN_IDX_OID].data.oid.sum;
40635+
int length = (int)dataASN[CERTEXTASN_IDX_VAL].length;
40636+
40637+
if (oid == OCSP_NONCE_OID) {
40638+
/* Extract nonce data - get data inside inner OCTET_STRING */
40639+
ret = GetOctetString(source, &idx, &length, sz);
40640+
if (ret >= 0) {
40641+
ret = 0;
40642+
if (length <= (int)sizeof(req->nonce)) {
40643+
XMEMCPY(req->nonce, source + idx, (size_t)length);
40644+
req->nonceSz = length;
40645+
}
40646+
else {
40647+
/* Nonce too large */
40648+
ret = BUFFER_E;
40649+
}
40650+
}
40651+
}
40652+
else if (isCrit) {
40653+
/* Unknown critical extension - fail */
40654+
ret = ASN_PARSE_E;
40655+
}
40656+
/* Ignore all other extension types. */
40657+
40658+
/* Skip over rest of extension. */
40659+
idx += (word32)length;
40660+
}
40661+
}
40662+
40663+
/* Ensure all extension data was consumed */
40664+
if (ret == 0 && idx != maxIdx) {
40665+
ret = ASN_PARSE_E;
40666+
}
40667+
40668+
FREE_ASNGETDATA(dataASN, req->heap);
40669+
return ret;
40670+
}
40671+
#endif /* WOLFSSL_ASN_TEMPLATE */
40672+
4052940673
int DecodeOcspRequest(OcspRequest* req, const byte* input, word32 size)
4053040674
{
4053140675
#ifndef WOLFSSL_ASN_TEMPLATE
@@ -40572,9 +40716,12 @@ int DecodeOcspRequest(OcspRequest* req, const byte* input, word32 size)
4057240716
ret = ASN_PARSE_E;
4057340717
}
4057440718
if (ret == 0) {
40575-
/* Optional extensions not supported yet */
40719+
/* Parse optional extensions */
4057640720
if (dataASN[OCSPREQUESTASN_IDX_TBS_REQEXT].data.ref.data != NULL) {
40577-
ret = NOT_COMPILED_IN;
40721+
ret = DecodeOcspReqExtensions(
40722+
dataASN[OCSPREQUESTASN_IDX_TBS_REQEXT].data.ref.data,
40723+
dataASN[OCSPREQUESTASN_IDX_TBS_REQEXT].data.ref.length,
40724+
req);
4057840725
}
4057940726
}
4058040727
if (ret == 0) {

0 commit comments

Comments
 (0)