From a47f98ee19d9010e9f6b8d5edb126e3b53b34451 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moise=CC=81s=20Guimara=CC=83es?= Date: Mon, 26 Oct 2015 18:09:09 -0300 Subject: [PATCH] adds support to nonce extension in OCSP stapling (status request tls extension); fix nonce encoding, there was a missing ASN.1 OctetString header; --- examples/client/client.c | 4 +- src/ssl.c | 12 ++++-- src/tls.c | 79 +++++++++++++++++++++++++++++++++++----- wolfcrypt/src/asn.c | 60 ++++++++++++------------------ wolfssl/internal.h | 3 +- wolfssl/ssl.h | 9 ++++- wolfssl/wolfcrypt/asn.h | 10 +++-- 7 files changed, 118 insertions(+), 59 deletions(-) diff --git a/examples/client/client.c b/examples/client/client.c index 651bf0819..edfd05b6f 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -984,8 +984,8 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #endif #ifdef HAVE_CERTIFICATE_STATUS_REQUEST if (statusRequest) { - if (wolfSSL_UseCertificateStatusRequest(ssl, WOLFSSL_CSR_OCSP) - != SSL_SUCCESS) + if (wolfSSL_UseCertificateStatusRequest(ssl, WOLFSSL_CSR_OCSP, + WOLFSSL_CSR_OCSP_USE_NONCE) != SSL_SUCCESS) err_sys("UseCertificateStatusRequest failed"); wolfSSL_CTX_EnableOCSP(ctx, WOLFSSL_OCSP_NO_NONCE); diff --git a/src/ssl.c b/src/ssl.c index 8b5a2efb8..344e3c979 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -796,21 +796,25 @@ int wolfSSL_CTX_UseTruncatedHMAC(WOLFSSL_CTX* ctx) #ifdef HAVE_CERTIFICATE_STATUS_REQUEST -int wolfSSL_UseCertificateStatusRequest(WOLFSSL* ssl, byte status_type) +int wolfSSL_UseCertificateStatusRequest(WOLFSSL* ssl, byte status_type, + byte options) { if (ssl == NULL || ssl->options.side != WOLFSSL_CLIENT_END) return BAD_FUNC_ARG; - return TLSX_UseCertificateStatusRequest(&ssl->extensions, status_type); + return TLSX_UseCertificateStatusRequest(&ssl->extensions, status_type, + options); } -int wolfSSL_CTX_UseCertificateStatusRequest(WOLFSSL_CTX* ctx, byte status_type) +int wolfSSL_CTX_UseCertificateStatusRequest(WOLFSSL_CTX* ctx, byte status_type, + byte options) { if (ctx == NULL || ctx->method->side != WOLFSSL_CLIENT_END) return BAD_FUNC_ARG; - return TLSX_UseCertificateStatusRequest(&ctx->extensions, status_type); + return TLSX_UseCertificateStatusRequest(&ctx->extensions, status_type, + options); } #endif /* HAVE_CERTIFICATE_STATUS_REQUEST */ diff --git a/src/tls.c b/src/tls.c index 03fe2f409..77e3694d3 100644 --- a/src/tls.c +++ b/src/tls.c @@ -1909,6 +1909,8 @@ static void TLSX_CSR_Free(CertificateStatusRequest* csr) static word16 TLSX_CSR_GetSize(CertificateStatusRequest* csr, byte isRequest) { + word16 size = 0; + /* shut up compiler warnings */ (void) csr; (void) isRequest; @@ -1916,12 +1918,15 @@ static word16 TLSX_CSR_GetSize(CertificateStatusRequest* csr, byte isRequest) if (isRequest) { switch (csr->status_type) { case WOLFSSL_CSR_OCSP: - return ENUM_LEN + 2 * OPAQUE16_LEN; + size += ENUM_LEN + 2 * OPAQUE16_LEN; + + if (csr->request.ocsp.nonceSz) + size += MAX_OCSP_EXT_SZ; } } #endif - return 0; + return size; } static word16 TLSX_CSR_Write(CertificateStatusRequest* csr, byte* output, @@ -1933,6 +1938,7 @@ static word16 TLSX_CSR_Write(CertificateStatusRequest* csr, byte* output, #ifndef NO_WOLFSSL_CLIENT if (isRequest) { word16 offset = 0; + word16 length = 0; /* type */ output[offset++] = csr->status_type; @@ -1944,8 +1950,15 @@ static word16 TLSX_CSR_Write(CertificateStatusRequest* csr, byte* output, offset += OPAQUE16_LEN; /* request extensions */ - c16toa(0, output + offset); - offset += OPAQUE16_LEN; + if (csr->request.ocsp.nonceSz) + length = EncodeOcspRequestExtensions( + &csr->request.ocsp, + output + offset + OPAQUE16_LEN, + MAX_OCSP_EXT_SZ); + + c16toa(length, output + offset); + offset += OPAQUE16_LEN + length; + break; } @@ -1980,9 +1993,25 @@ static int TLSX_CSR_Parse(WOLFSSL* ssl, byte* input, word16 length, /* enable extension at ssl level */ ret = TLSX_UseCertificateStatusRequest(&ssl->extensions, - csr->status_type); + csr->status_type, csr->options); if (ret != SSL_SUCCESS) return ret; + + switch (csr->status_type) { + case WOLFSSL_CSR_OCSP: + /* propagate nonce */ + if (csr->request.ocsp.nonceSz) { + OcspRequest* request = + TLSX_CSR_GetRequest(ssl->extensions); + + if (request) { + XMEMCPY(request->nonce, csr->request.ocsp.nonce, + csr->request.ocsp.nonceSz); + request->nonceSz = csr->request.ocsp.nonceSz; + } + } + break; + } } ssl->status_request = 1; @@ -1998,15 +2027,29 @@ int TLSX_CSR_InitRequest(TLSX* extensions, DecodedCert* cert) { TLSX* extension = TLSX_Find(extensions, TLSX_STATUS_REQUEST); CertificateStatusRequest* csr = extension ? extension->data : NULL; + int ret = 0; if (csr) { switch (csr->status_type) { - case WOLFSSL_CSR_OCSP: - return InitOcspRequest(&csr->request.ocsp, cert, 0); + case WOLFSSL_CSR_OCSP: { + byte nonce[MAX_OCSP_NONCE_SZ]; + int nonceSz = csr->request.ocsp.nonceSz; + + /* preserve nonce */ + XMEMCPY(nonce, csr->request.ocsp.nonce, nonceSz); + + if ((ret = InitOcspRequest(&csr->request.ocsp, cert, 0)) != 0) + return ret; + + /* restore nonce */ + XMEMCPY(csr->request.ocsp.nonce, nonce, nonceSz); + csr->request.ocsp.nonceSz = nonceSz; + } + break; } } - return 0; + return ret; } void* TLSX_CSR_GetRequest(TLSX* extensions) @@ -2044,7 +2087,8 @@ int TLSX_CSR_ForceRequest(WOLFSSL* ssl) return 0; } -int TLSX_UseCertificateStatusRequest(TLSX** extensions, byte status_type) +int TLSX_UseCertificateStatusRequest(TLSX** extensions, byte status_type, + byte options) { CertificateStatusRequest* csr = NULL; int ret = 0; @@ -2060,6 +2104,23 @@ int TLSX_UseCertificateStatusRequest(TLSX** extensions, byte status_type) ForceZero(csr, sizeof(CertificateStatusRequest)); csr->status_type = status_type; + csr->options = options; + + switch (csr->status_type) { + case WOLFSSL_CSR_OCSP: + if (options & WOLFSSL_CSR_OCSP_USE_NONCE) { + WC_RNG rng; + + if (wc_InitRng(&rng) == 0) { + if (wc_RNG_GenerateBlock(&rng, csr->request.ocsp.nonce, + MAX_OCSP_NONCE_SZ) == 0) + csr->request.ocsp.nonceSz = MAX_OCSP_NONCE_SZ; + + wc_FreeRng(&rng); + } + } + break; + } if ((ret = TLSX_Push(extensions, TLSX_STATUS_REQUEST, csr)) != 0) { XFREE(csr, NULL, DYNAMIC_TYPE_TLSX); diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 1b8ba6504..57a5c38af 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -8786,53 +8786,40 @@ int OcspResponseDecode(OcspResponse* resp) } -static word32 SetOcspReqExtensions(word32 extSz, byte* output, - const byte* nonce, word32 nonceSz) +word32 EncodeOcspRequestExtensions(OcspRequest* req, byte* output, word32 size) { static const byte NonceObjId[] = { 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x02 }; - byte seqArray[5][MAX_SEQ_SZ]; - word32 seqSz[5], totalSz; + byte seqArray[6][MAX_SEQ_SZ]; + word32 seqSz[6], totalSz = (word32)sizeof(NonceObjId); WOLFSSL_ENTER("SetOcspReqExtensions"); - if (nonce == NULL || nonceSz == 0) return 0; + if (!req || !output || !req->nonceSz) + return 0; - seqArray[0][0] = ASN_OCTET_STRING; - seqSz[0] = 1 + SetLength(nonceSz, &seqArray[0][1]); + totalSz += req->nonceSz; + totalSz += seqSz[0] = SetOctetString(req->nonceSz, seqArray[0]); + totalSz += seqSz[1] = SetOctetString(req->nonceSz + seqSz[0], seqArray[1]); + seqArray[2][0] = ASN_OBJECT_ID; + totalSz += seqSz[2] = 1 + SetLength(sizeof(NonceObjId), &seqArray[2][1]); + totalSz += seqSz[3] = SetSequence(totalSz, seqArray[3]); + totalSz += seqSz[4] = SetSequence(totalSz, seqArray[4]); + totalSz += seqSz[5] = SetExplicit(2, totalSz, seqArray[5]); - seqArray[1][0] = ASN_OBJECT_ID; - seqSz[1] = 1 + SetLength(sizeof(NonceObjId), &seqArray[1][1]); - - totalSz = seqSz[0] + seqSz[1] + nonceSz + (word32)sizeof(NonceObjId); - - seqSz[2] = SetSequence(totalSz, seqArray[2]); - totalSz += seqSz[2]; - - seqSz[3] = SetSequence(totalSz, seqArray[3]); - totalSz += seqSz[3]; - - seqArray[4][0] = (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 2); - seqSz[4] = 1 + SetLength(totalSz, &seqArray[4][1]); - totalSz += seqSz[4]; - - if (totalSz < extSz) + if (totalSz < size) { totalSz = 0; - XMEMCPY(output + totalSz, seqArray[4], seqSz[4]); - totalSz += seqSz[4]; - XMEMCPY(output + totalSz, seqArray[3], seqSz[3]); - totalSz += seqSz[3]; - XMEMCPY(output + totalSz, seqArray[2], seqSz[2]); - totalSz += seqSz[2]; - XMEMCPY(output + totalSz, seqArray[1], seqSz[1]); - totalSz += seqSz[1]; + XMEMCPY(output + totalSz, seqArray[5], seqSz[5]); totalSz += seqSz[5]; + XMEMCPY(output + totalSz, seqArray[4], seqSz[4]); totalSz += seqSz[4]; + XMEMCPY(output + totalSz, seqArray[3], seqSz[3]); totalSz += seqSz[3]; + XMEMCPY(output + totalSz, seqArray[2], seqSz[2]); totalSz += seqSz[2]; XMEMCPY(output + totalSz, NonceObjId, sizeof(NonceObjId)); totalSz += (word32)sizeof(NonceObjId); - XMEMCPY(output + totalSz, seqArray[0], seqSz[0]); - totalSz += seqSz[0]; - XMEMCPY(output + totalSz, nonce, nonceSz); - totalSz += nonceSz; + XMEMCPY(output + totalSz, seqArray[1], seqSz[1]); totalSz += seqSz[1]; + XMEMCPY(output + totalSz, seqArray[0], seqSz[0]); totalSz += seqSz[0]; + XMEMCPY(output + totalSz, req->nonce, req->nonceSz); + totalSz += req->nonceSz; } return totalSz; @@ -8865,8 +8852,7 @@ int EncodeOcspRequest(OcspRequest* req, byte* output, word32 size) extSz = 0; if (req->nonceSz) - extSz = SetOcspReqExtensions(MAX_OCSP_EXT_SZ, extArray, - req->nonce, req->nonceSz); + extSz = EncodeOcspRequestExtensions(req, extArray, MAX_OCSP_EXT_SZ); totalSz = algoSz + issuerSz + issuerKeySz + snSz; for (i = 4; i >= 0; i--) { diff --git a/wolfssl/internal.h b/wolfssl/internal.h index ee961573e..76f7f108a 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1576,13 +1576,14 @@ WOLFSSL_LOCAL int TLSX_UseTruncatedHMAC(TLSX** extensions); typedef struct { byte status_type; + byte options; union { OcspRequest ocsp; } request; } CertificateStatusRequest; WOLFSSL_LOCAL int TLSX_UseCertificateStatusRequest(TLSX** extensions, - byte status_type); + byte status_type, byte options); WOLFSSL_LOCAL int TLSX_CSR_InitRequest(TLSX* extensions, DecodedCert* cert); WOLFSSL_LOCAL void* TLSX_CSR_GetRequest(TLSX* extensions); WOLFSSL_LOCAL int TLSX_CSR_ForceRequest(WOLFSSL* ssl); diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index b507df897..5243dabb2 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -1413,14 +1413,19 @@ enum { WOLFSSL_CSR_OCSP = 1 }; +/* Certificate Status Options (flags) */ +enum { + WOLFSSL_CSR_OCSP_USE_NONCE = 0x01 +}; + #ifdef HAVE_CERTIFICATE_STATUS_REQUEST #ifndef NO_WOLFSSL_CLIENT WOLFSSL_API int wolfSSL_UseCertificateStatusRequest(WOLFSSL* ssl, - unsigned char status_type); + unsigned char status_type, unsigned char options); WOLFSSL_API int wolfSSL_CTX_UseCertificateStatusRequest(WOLFSSL_CTX* ctx, - unsigned char status_type); + unsigned char status_type, unsigned char options); #endif #endif diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index f18402e35..76832d9a6 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -188,7 +188,7 @@ enum Misc_ASN { MAX_CERTPOL_SZ = CTC_MAX_CERTPOL_SZ, #endif MAX_OCSP_EXT_SZ = 58, /* Max OCSP Extension length */ - MAX_OCSP_NONCE_SZ = 18, /* OCSP Nonce size */ + MAX_OCSP_NONCE_SZ = 16, /* OCSP Nonce size */ EIGHTK_BUF = 8192, /* Tmp buffer size */ MAX_PUBLIC_KEY_SZ = MAX_NTRU_ENC_SZ + MAX_ALGO_SZ + MAX_SEQ_SZ * 2, /* use bigger NTRU size */ @@ -722,9 +722,11 @@ struct OcspRequest { WOLFSSL_LOCAL void InitOcspResponse(OcspResponse*, CertStatus*, byte*, word32); WOLFSSL_LOCAL int OcspResponseDecode(OcspResponse*); -WOLFSSL_LOCAL int InitOcspRequest(OcspRequest*, DecodedCert*, byte); -WOLFSSL_LOCAL void FreeOcspRequest(OcspRequest*); -WOLFSSL_LOCAL int EncodeOcspRequest(OcspRequest*, byte*, word32); +WOLFSSL_LOCAL int InitOcspRequest(OcspRequest*, DecodedCert*, byte); +WOLFSSL_LOCAL void FreeOcspRequest(OcspRequest*); +WOLFSSL_LOCAL int EncodeOcspRequest(OcspRequest*, byte*, word32); +WOLFSSL_LOCAL word32 EncodeOcspRequestExtensions(OcspRequest*, byte*, word32); + WOLFSSL_LOCAL int CompareOcspReqResp(OcspRequest*, OcspResponse*);