adds partial client support to TLS Extension Status Request, a.k.a. OCSP stapling;

missing:
 - compare OcspRequest and OcspResponse;
 - execute contingence plan;
 - add nonce extension;
This commit is contained in:
Moisés Guimarães
2015-10-23 17:08:15 -03:00
parent 82f86adb8e
commit daf3155d3c
8 changed files with 401 additions and 31 deletions

View File

@ -1595,6 +1595,18 @@ then
AM_CFLAGS="$AM_CFLAGS -DHAVE_TLS_EXTENSIONS -DHAVE_TRUNCATED_HMAC"
fi
# Certificate Status Request : a.k.a. OCSP stapling
AC_ARG_ENABLE([statusrequest],
[ --enable-statusrequest Enable Certificate Status Request (default: disabled)],
[ ENABLED_CERTIFICATE_STATUS_REQUEST=$enableval ],
[ ENABLED_CERTIFICATE_STATUS_REQUEST=no ]
)
if test "x$ENABLED_CERTIFICATE_STATUS_REQUEST" = "xyes"
then
AM_CFLAGS="$AM_CFLAGS -DHAVE_TLS_EXTENSIONS -DHAVE_CERTIFICATE_STATUS_REQUEST"
fi
# Renegotiation Indication - (FAKE Secure Renegotiation)
AC_ARG_ENABLE([renegotiation-indication],
[AS_HELP_STRING([--enable-renegotiation-indication],[Enable Renegotiation Indication (default: disabled)])],
@ -2492,6 +2504,7 @@ echo " * Server Name Indication: $ENABLED_SNI"
echo " * ALPN: $ENABLED_ALPN"
echo " * Maximum Fragment Length: $ENABLED_MAX_FRAGMENT"
echo " * Truncated HMAC: $ENABLED_TRUNCATED_HMAC"
echo " * Status Request: $ENABLED_CERTIFICATE_STATUS_REQUEST"
echo " * Supported Elliptic Curves: $ENABLED_SUPPORTED_CURVES"
echo " * Session Ticket: $ENABLED_SESSION_TICKET"
echo " * Renegotiation Indication: $ENABLED_RENEGOTIATION_INDICATION"

View File

@ -425,7 +425,10 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args)
byte maxFragment = 0;
#endif
#ifdef HAVE_TRUNCATED_HMAC
byte truncatedHMAC = 0;
byte truncatedHMAC = 0;
#endif
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST
byte statusRequest = 0;
#endif
@ -465,8 +468,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args)
StackTrap();
while ((ch = mygetopt(argc, argv,
"?gdeDusmNrwRitfxXUPCh:p:v:l:A:c:k:Z:b:zS:L:ToO:aB:"))
!= -1) {
"?gdeDusmNrwRitfxXUPCh:p:v:l:A:c:k:Z:b:zS:L:ToO:aB:W")) != -1) {
switch (ch) {
case '?' :
Usage();
@ -653,6 +655,12 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args)
#endif
break;
case 'W' :
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST
statusRequest = 1;
#endif
break;
case 'o' :
#ifdef HAVE_OCSP
useOcsp = 1;
@ -938,6 +946,12 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args)
if (wolfSSL_CTX_UseTruncatedHMAC(ctx) != SSL_SUCCESS)
err_sys("UseTruncatedHMAC failed");
#endif
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST
if (statusRequest)
if (wolfSSL_CTX_UseCertificateStatusRequest(ctx, WOLFSSL_CSR_OCSP)
!= SSL_SUCCESS)
err_sys("UseCertificateStatusRequest failed");
#endif
#ifdef HAVE_SESSION_TICKET
if (wolfSSL_CTX_UseSessionTicket(ctx) != SSL_SUCCESS)
err_sys("UseSessionTicket failed");
@ -1320,4 +1334,3 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args)
}
#endif

View File

@ -4357,7 +4357,6 @@ static int DoCertificate(WOLFSSL* ssl, byte* input, word32* inOutIdx,
#if defined(HAVE_OCSP) || defined(HAVE_CRL)
if (ret == 0) {
int doCrlLookup = 1;
(void)doCrlLookup;
#ifdef HAVE_OCSP
if (ssl->ctx->cm->ocspEnabled && ssl->ctx->cm->ocspCheckAll) {
WOLFSSL_MSG("Doing Non Leaf OCSP check");
@ -4380,6 +4379,8 @@ static int DoCertificate(WOLFSSL* ssl, byte* input, word32* inOutIdx,
WOLFSSL_MSG("\tCRL check not ok");
}
}
#else
(void)doCrlLookup;
#endif /* HAVE_CRL */
}
#endif /* HAVE_OCSP || HAVE_CRL */
@ -4447,7 +4448,6 @@ static int DoCertificate(WOLFSSL* ssl, byte* input, word32* inOutIdx,
#if defined(HAVE_OCSP) || defined(HAVE_CRL)
if (fatal == 0) {
int doCrlLookup = 1;
(void)doCrlLookup;
#ifdef HAVE_OCSP
if (ssl->ctx->cm->ocspEnabled) {
WOLFSSL_MSG("Doing Leaf OCSP check");
@ -4469,6 +4469,8 @@ static int DoCertificate(WOLFSSL* ssl, byte* input, word32* inOutIdx,
fatal = 0;
}
}
#else
(void)doCrlLookup;
#endif /* HAVE_CRL */
}
#endif /* HAVE_OCSP || HAVE_CRL */
@ -4776,6 +4778,101 @@ static int DoCertificate(WOLFSSL* ssl, byte* input, word32* inOutIdx,
return ret;
}
static int DoCertificateStatus(WOLFSSL* ssl, byte* input, word32* inOutIdx,
word32 size)
{
int ret = 0;
byte status_type;
word32 status_length;
if (size < ENUM_LEN + OPAQUE24_LEN)
return BUFFER_ERROR;
status_type = input[(*inOutIdx)++];
c24to32(input + *inOutIdx, &status_length);
*inOutIdx += OPAQUE24_LEN;
if (size != ENUM_LEN + OPAQUE24_LEN + status_length)
return BUFFER_ERROR;
switch (status_type) {
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST)
case WOLFSSL_CSR_OCSP: {
#ifdef WOLFSSL_SMALL_STACK
CertStatus* status;
OcspResponse* response;
#else
CertStatus status[1];
OcspResponse response[1];
#endif
do {
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST
if (ssl->status_request) {
ssl->status_request = 0;
break;
}
#endif
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
if (ssl->status_request_v2) {
ssl->status_request_v2 = 0;
break;
}
#endif
return BUFFER_ERROR;
} while(0);
#ifdef WOLFSSL_SMALL_STACK
status = (CertStatus*)XMALLOC(sizeof(CertStatus), NULL,
DYNAMIC_TYPE_TMP_BUFFER);
response = (OcspResponse*)XMALLOC(sizeof(OcspResponse), NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (status == NULL || response == NULL) {
if (status) XFREE(status, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (response) XFREE(response, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return MEMORY_ERROR;
}
#endif
InitOcspResponse(response, status, input +*inOutIdx, status_length);
if ((ret = OcspResponseDecode(response)) == 0) {
if (response->responseStatus != OCSP_SUCCESSFUL)
ret = FATAL_ERROR;
/* TODO CSR */
/*else if (CompareOcspReqResp(request, response) != 0)
ret = FATAL_ERROR; */
else if (response->status->status != CERT_GOOD)
ret = FATAL_ERROR;
}
*inOutIdx += status_length;
#ifdef WOLFSSL_SMALL_STACK
XFREE(status, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(response, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
}
break;
#endif
default:
ret = BUFFER_ERROR;
}
if (ret != 0)
SendAlert(ssl, alert_fatal, bad_certificate_status_response);
return ret;
}
#endif /* !NO_CERTS */
@ -4971,6 +5068,26 @@ static int SanityCheckMsgReceived(WOLFSSL* ssl, byte type)
#endif
break;
#ifndef NO_WOLFSSL_CLIENT
case certificate_status:
if (ssl->msgsReceived.got_certificate_status) {
WOLFSSL_MSG("Duplicate CertificateSatatus received");
return DUPLICATE_MSG_E;
}
ssl->msgsReceived.got_certificate_status = 1;
if (ssl->msgsReceived.got_certificate == 0) {
WOLFSSL_MSG("No Certificate before CertificateStatus");
return OUT_OF_ORDER_E;
}
if (ssl->msgsReceived.got_server_key_exchange != 0) {
WOLFSSL_MSG("CertificateStatus after ServerKeyExchange");
return OUT_OF_ORDER_E;
}
break;
#endif
#ifndef NO_WOLFSSL_CLIENT
case server_key_exchange:
if (ssl->msgsReceived.got_server_key_exchange) {
@ -4979,10 +5096,18 @@ static int SanityCheckMsgReceived(WOLFSSL* ssl, byte type)
}
ssl->msgsReceived.got_server_key_exchange = 1;
if ( ssl->msgsReceived.got_server_hello == 0) {
WOLFSSL_MSG("No ServerHello before Cert");
if (ssl->msgsReceived.got_server_hello == 0) {
WOLFSSL_MSG("No ServerHello before ServerKeyExchange");
return OUT_OF_ORDER_E;
}
if (ssl->msgsReceived.got_certificate_status == 0) {
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST
if (ssl->status_request) {
WOLFSSL_MSG("No CertificateStatus before ServerKeyExchange");
return OUT_OF_ORDER_E;
}
#endif
}
break;
#endif
@ -5224,7 +5349,12 @@ static int DoHandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
#ifndef NO_CERTS
case certificate:
WOLFSSL_MSG("processing certificate");
ret = DoCertificate(ssl, input, inOutIdx, size);
ret = DoCertificate(ssl, input, inOutIdx, size);
break;
case certificate_status:
WOLFSSL_MSG("processing certificate status");
ret = DoCertificateStatus(ssl, input, inOutIdx, size);
break;
#endif

View File

@ -794,6 +794,27 @@ int wolfSSL_CTX_UseTruncatedHMAC(WOLFSSL_CTX* ctx)
#endif /* NO_WOLFSSL_CLIENT */
#endif /* HAVE_TRUNCATED_HMAC */
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST
int wolfSSL_UseCertificateStatusRequest(WOLFSSL* ssl, byte status_type)
{
if (ssl == NULL || ssl->options.side != WOLFSSL_CLIENT_END)
return BAD_FUNC_ARG;
return TLSX_UseCertificateStatusRequest(&ssl->extensions, status_type);
}
int wolfSSL_CTX_UseCertificateStatusRequest(WOLFSSL_CTX* ctx, byte status_type)
{
if (ctx == NULL || ctx->method->side != WOLFSSL_CLIENT_END)
return BAD_FUNC_ARG;
return TLSX_UseCertificateStatusRequest(&ctx->extensions, status_type);
}
#endif /* HAVE_CERTIFICATE_STATUS_REQUEST */
/* Elliptic Curves */
#ifdef HAVE_SUPPORTED_CURVES
#ifndef NO_WOLFSSL_CLIENT

152
src/tls.c
View File

@ -1885,6 +1885,139 @@ int TLSX_UseTruncatedHMAC(TLSX** extensions)
#endif /* HAVE_TRUNCATED_HMAC */
/******************************************************************************/
/* Certificate Status Request */
/******************************************************************************/
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST
#ifndef HAVE_OCSP
#error Status Request Extension requires OCSP. \
Use --enable-ocsp in the configure script or define HAVE_OCSP.
#endif
static void TLSX_CSR_Free(CertificateStatusRequest* csr)
{
switch (csr->status_type) {
case WOLFSSL_CSR_OCSP:
/* nothing to release for now... */
break;
}
XFREE(csr, NULL, DYNAMIC_TYPE_TLSX);
}
static word16 TLSX_CSR_GetSize(CertificateStatusRequest* csr, byte isRequest)
{
/* shut up compiler warnings */
(void) csr; (void) isRequest;
#ifndef NO_WOLFSSL_CLIENT
if (isRequest) {
switch (csr->status_type) {
case WOLFSSL_CSR_OCSP:
return ENUM_LEN + 2 * OPAQUE16_LEN;
}
}
#endif
return 0;
}
static word16 TLSX_CSR_Write(CertificateStatusRequest* csr, byte* output,
byte isRequest)
{
/* shut up compiler warnings */
(void) csr; (void) output; (void) isRequest;
#ifndef NO_WOLFSSL_CLIENT
if (isRequest) {
word16 offset = 0;
/* type */
output[offset++] = csr->status_type;
switch (csr->status_type) {
case WOLFSSL_CSR_OCSP:
/* responder id list */
c16toa(0, output + offset);
offset += OPAQUE16_LEN;
/* request extensions */
c16toa(0, output + offset);
offset += OPAQUE16_LEN;
break;
}
return offset;
}
#endif
return 0;
}
static int TLSX_CSR_Parse(WOLFSSL* ssl, byte* input, word16 length,
byte isRequest)
{
/* shut up compiler warnings */
(void) ssl; (void) input;
if (!isRequest) {
ssl->status_request = 1;
return length ? BUFFER_ERROR : 0; /* extension_data MUST be empty. */
}
return 0;
}
int TLSX_UseCertificateStatusRequest(TLSX** extensions, byte status_type)
{
CertificateStatusRequest* csr = NULL;
int ret = 0;
if (!extensions)
return BAD_FUNC_ARG;
csr = (CertificateStatusRequest*)XMALLOC(sizeof(CertificateStatusRequest),
NULL, DYNAMIC_TYPE_TLSX);
if (!csr)
return MEMORY_E;
csr->status_type = status_type;
switch (status_type) {
case WOLFSSL_CSR_OCSP:
/* nothing to handle for now... */
break;
default:
XFREE(csr, NULL, DYNAMIC_TYPE_TLSX);
return BAD_FUNC_ARG;
}
if ((ret = TLSX_Push(extensions, TLSX_STATUS_REQUEST, csr)) != 0) {
XFREE(csr, NULL, DYNAMIC_TYPE_TLSX);
return ret;
}
return SSL_SUCCESS;
}
#define CSR_FREE_ALL TLSX_CSR_Free
#define CSR_GET_SIZE TLSX_CSR_GetSize
#define CSR_WRITE TLSX_CSR_Write
#define CSR_PARSE TLSX_CSR_Parse
#else
#define CSR_FREE_ALL(data)
#define CSR_GET_SIZE(a, b) 0
#define CSR_WRITE(a, b, c) 0
#define CSR_PARSE(a, b, c, d) 0
#endif /* HAVE_CERTIFICATE_STATUS_REQUEST */
/******************************************************************************/
/* Supported Elliptic Curves */
/******************************************************************************/
@ -3094,6 +3227,10 @@ void TLSX_FreeAll(TLSX* list)
EC_FREE_ALL(extension->data);
break;
case TLSX_STATUS_REQUEST:
CSR_FREE_ALL(extension->data);
break;
case TLSX_RENEGOTIATION_INFO:
SCR_FREE_ALL(extension->data);
break;
@ -3161,6 +3298,10 @@ static word16 TLSX_GetSize(TLSX* list, byte* semaphore, byte isRequest)
length += EC_GET_SIZE(extension->data);
break;
case TLSX_STATUS_REQUEST:
length += CSR_GET_SIZE(extension->data, isRequest);
break;
case TLSX_RENEGOTIATION_INFO:
length += SCR_GET_SIZE(extension->data, isRequest);
break;
@ -3230,6 +3371,11 @@ static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore,
offset += EC_WRITE(extension->data, output + offset);
break;
case TLSX_STATUS_REQUEST:
offset += CSR_WRITE(extension->data, output + offset,
isRequest);
break;
case TLSX_RENEGOTIATION_INFO:
offset += SCR_WRITE(extension->data, output + offset,
isRequest);
@ -3723,6 +3869,12 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest,
ret = EC_PARSE(ssl, input + offset, size, isRequest);
break;
case TLSX_STATUS_REQUEST:
WOLFSSL_MSG("Certificate Status Request extension received");
ret = CSR_PARSE(ssl, input + offset, size, isRequest);
break;
case TLSX_RENEGOTIATION_INFO:
WOLFSSL_MSG("Secure Renegotiation extension received");

View File

@ -43,7 +43,11 @@
#include <wolfssl/wolfcrypt/random.h>
#include <wolfssl/wolfcrypt/hash.h>
#ifdef NO_INLINE
#include <wolfssl/wolfcrypt/misc.h>
#else
#include <wolfcrypt/src/misc.c>
#endif
#ifndef NO_RC4
#include <wolfssl/wolfcrypt/arc4.h>
@ -8856,18 +8860,11 @@ int EncodeOcspRequest(OcspRequest* req)
algoSz = SetAlgoID(SHAh, algoArray, hashType, 0);
#endif
req->issuerHash = req->cert->issuerHash;
issuerSz = SetDigest(req->cert->issuerHash, KEYID_SIZE, issuerArray);
issuerSz = SetDigest(req->issuerHash, KEYID_SIZE, issuerArray);
issuerKeySz = SetDigest(req->issuerKeyHash, KEYID_SIZE, issuerKeyArray);
snSz = SetSerialNumber(req->serial, req->serialSz, snArray);
extSz = 0;
req->issuerKeyHash = req->cert->issuerKeyHash;
issuerKeySz = SetDigest(req->cert->issuerKeyHash,
KEYID_SIZE, issuerKeyArray);
req->serial = req->cert->serial;
req->serialSz = req->cert->serialSz;
snSz = SetSerialNumber(req->cert->serial, req->cert->serialSz, snArray);
extSz = 0;
if (req->useNonce) {
WC_RNG rng;
if (wc_InitRng(&rng) != 0) {
@ -8885,25 +8882,30 @@ int EncodeOcspRequest(OcspRequest* req)
}
totalSz = algoSz + issuerSz + issuerKeySz + snSz;
for (i = 4; i >= 0; i--) {
seqSz[i] = SetSequence(totalSz, seqArray[i]);
totalSz += seqSz[i];
if (i == 2) totalSz += extSz;
}
totalSz = 0;
for (i = 0; i < 5; i++) {
XMEMCPY(output + totalSz, seqArray[i], seqSz[i]);
totalSz += seqSz[i];
}
XMEMCPY(output + totalSz, algoArray, algoSz);
totalSz += algoSz;
XMEMCPY(output + totalSz, issuerArray, issuerSz);
totalSz += issuerSz;
XMEMCPY(output + totalSz, issuerKeyArray, issuerKeySz);
totalSz += issuerKeySz;
XMEMCPY(output + totalSz, snArray, snSz);
totalSz += snSz;
if (extSz != 0) {
XMEMCPY(output + totalSz, extArray, extSz);
totalSz += extSz;
@ -8918,14 +8920,16 @@ void InitOcspRequest(OcspRequest* req, DecodedCert* cert, byte useNonce,
{
WOLFSSL_ENTER("InitOcspRequest");
req->cert = cert;
req->useNonce = useNonce;
req->nonceSz = 0;
req->issuerHash = NULL;
req->issuerKeyHash = NULL;
req->serial = NULL;
req->dest = dest;
req->destSz = destSz;
ForceZero(req, sizeof(OcspRequest));
req->cert = cert;
req->useNonce = useNonce;
req->issuerHash = cert->issuerHash;
req->issuerKeyHash = cert->issuerKeyHash;
req->serial = cert->serial;
req->serialSz = cert->serialSz;
req->dest = dest;
req->destSz = destSz;
}

View File

@ -1463,7 +1463,8 @@ typedef enum {
TLSX_SERVER_NAME = 0x0000, /* a.k.a. SNI */
TLSX_MAX_FRAGMENT_LENGTH = 0x0001,
TLSX_TRUNCATED_HMAC = 0x0004,
TLSX_SUPPORTED_GROUPS = 0x000a,
TLSX_STATUS_REQUEST = 0x0005, /* a.k.a. OCSP stappling */
TLSX_SUPPORTED_GROUPS = 0x000a, /* a.k.a. Supported Curves */
TLSX_APPLICATION_LAYER_PROTOCOL = 0x0010, /* a.k.a. ALPN */
TLSX_QUANTUM_SAFE_HYBRID = 0x0018, /* a.k.a. QSH */
TLSX_SESSION_TICKET = 0x0023,
@ -1498,6 +1499,7 @@ WOLFSSL_LOCAL int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length,
#elif defined(HAVE_SNI) \
|| defined(HAVE_MAX_FRAGMENT) \
|| defined(HAVE_TRUNCATED_HMAC) \
|| defined(HAVE_CERTIFICATE_STATUS_REQUEST) \
|| defined(HAVE_SUPPORTED_CURVES) \
|| defined(HAVE_ALPN) \
|| defined(HAVE_QSH) \
@ -1569,6 +1571,18 @@ WOLFSSL_LOCAL int TLSX_UseTruncatedHMAC(TLSX** extensions);
#endif /* HAVE_TRUNCATED_HMAC */
/** Certificate Status Request - RFC 6066 (session 8) */
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST
typedef struct {
byte status_type;
} CertificateStatusRequest;
WOLFSSL_LOCAL int TLSX_UseCertificateStatusRequest(TLSX** extensions,
byte status_type);
#endif
/** Supported Elliptic Curves - RFC 4492 (session 4) */
#ifdef HAVE_SUPPORTED_CURVES
@ -2301,6 +2315,7 @@ typedef struct MsgsReceived {
word16 got_hello_verify_request:1;
word16 got_session_ticket:1;
word16 got_certificate:1;
word16 got_certificate_status:1;
word16 got_server_key_exchange:1;
word16 got_certificate_request:1;
word16 got_server_hello_done:1;
@ -2452,6 +2467,9 @@ struct WOLFSSL {
#ifdef HAVE_TRUNCATED_HMAC
byte truncated_hmac;
#endif
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST
byte status_request;
#endif
#ifdef HAVE_SECURE_RENEGOTIATION
SecureRenegotiation* secure_renegotiation; /* valid pointer indicates */
#endif /* user turned on */

View File

@ -188,6 +188,7 @@ enum AlertDescription {
#endif
no_renegotiation = 100,
unrecognized_name = 112, /**< RFC 6066, section 3 */
bad_certificate_status_response = 113, /**< RFC 6066, section 8 */
no_application_protocol = 120
};
@ -1406,6 +1407,24 @@ WOLFSSL_API int wolfSSL_CTX_UseTruncatedHMAC(WOLFSSL_CTX* ctx);
#endif
#endif
/* Certificate Status Request */
/* Certificate Status Type */
enum {
WOLFSSL_CSR_OCSP = 1
};
#ifdef HAVE_CERTIFICATE_STATUS_REQUEST
#ifndef NO_WOLFSSL_CLIENT
WOLFSSL_API int wolfSSL_UseCertificateStatusRequest(WOLFSSL* ssl,
unsigned char status_type);
WOLFSSL_API int wolfSSL_CTX_UseCertificateStatusRequest(WOLFSSL_CTX* ctx,
unsigned char status_type);
#endif
#endif
/* Elliptic Curves */
enum {
WOLFSSL_ECC_SECP160R1 = 0x10,