Merge branch 'dtls-cookie'

This commit is contained in:
John Safranek
2015-09-14 16:13:49 -07:00
4 changed files with 183 additions and 94 deletions

View File

@@ -112,6 +112,9 @@ static int BuildMessage(WOLFSSL* ssl, byte* output, int outSz,
#ifdef HAVE_STUNNEL
static int SNI_Callback(WOLFSSL* ssl);
#endif
#ifdef WOLFSSL_DTLS
static int SendHelloVerifyRequest(WOLFSSL*, const byte*, byte);
#endif /* WOLFSSL_DTLS */
#endif
@@ -479,7 +482,6 @@ int InitSSL_Ctx(WOLFSSL_CTX* ctx, WOLFSSL_METHOD* method)
if (method->version.major == DTLS_MAJOR) {
ctx->CBIORecv = EmbedReceiveFrom;
ctx->CBIOSend = EmbedSendTo;
ctx->CBIOCookie = EmbedGenerateCookie;
}
#endif
#endif /* WOLFSSL_USER_IO */
@@ -1907,6 +1909,16 @@ int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx)
return ret;
}
#if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_SERVER)
if (ssl->options.dtls && ssl->options.side == WOLFSSL_SERVER_END) {
ret = wolfSSL_DTLS_SetCookieSecret(ssl, NULL, 0);
if (ret != 0) {
WOLFSSL_MSG("DTLS Cookie Secret error");
return ret;
}
}
#endif /* WOLFSSL_DTLS && !NO_WOLFSSL_SERVER */
#ifdef HAVE_SECRET_CALLBACK
ssl->sessionSecretCb = NULL;
ssl->sessionSecretCtx = NULL;
@@ -5112,7 +5124,9 @@ static int DoHandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
/* above checks handshake state */
/* hello_request not hashed */
if (type != hello_request) {
/* Also, skip hashing the client_hello message here for DTLS. It will be
* hashed later if the DTLS cookie is correct. */
if (type != hello_request && !(ssl->options.dtls && type == client_hello)) {
ret = HashInput(ssl, input + *inOutIdx, size);
if (ret != 0) return ret;
}
@@ -14262,6 +14276,13 @@ int DoSessionTicket(WOLFSSL* ssl,
Suites clSuites;
word32 i = *inOutIdx;
word32 begin = i;
#ifdef WOLFSSL_DTLS
Hmac cookieHmac;
byte peerCookie[MAX_COOKIE_LEN];
byte peerCookieSz;
byte cookieType;
byte cookieSz;
#endif /* WOLFSSL_DTLS */
#ifdef WOLFSSL_CALLBACKS
if (ssl->hsInfoOn) AddPacketName("ClientHello", &ssl->handShakeInfo);
@@ -14275,6 +14296,33 @@ int DoSessionTicket(WOLFSSL* ssl,
/* protocol version */
XMEMCPY(&pv, input + i, OPAQUE16_LEN);
ssl->chVersion = pv; /* store */
#ifdef WOLFSSL_DTLS
if (ssl->options.dtls) {
int ret;
#if defined(NO_SHA) && defined(NO_SHA256)
#error "DTLS needs either SHA or SHA-256"
#endif /* NO_SHA && NO_SHA256 */
#ifndef NO_SHA
cookieType = SHA;
cookieSz = SHA_DIGEST_SIZE;
#endif /* NO_SHA */
#ifndef NO_SHA256
cookieType = SHA256;
cookieSz = SHA256_DIGEST_SIZE;
#endif /* NO_SHA256 */
ret = wc_HmacSetKey(&cookieHmac, cookieType,
ssl->buffers.dtlsCookieSecret.buffer,
ssl->buffers.dtlsCookieSecret.length);
if (ret != 0) return ret;
ret = wc_HmacUpdate(&cookieHmac,
ssl->buffers.dtlsCtx.peer.sa,
ssl->buffers.dtlsCtx.peer.sz);
if (ret != 0) return ret;
ret = wc_HmacUpdate(&cookieHmac, input + i, OPAQUE16_LEN);
if (ret != 0) return ret;
}
#endif /* WOLFSSL_DTLS */
i += OPAQUE16_LEN;
if ((!ssl->options.dtls && ssl->version.minor > pv.minor) ||
@@ -14325,6 +14373,12 @@ int DoSessionTicket(WOLFSSL* ssl,
/* random */
XMEMCPY(ssl->arrays->clientRandom, input + i, RAN_LEN);
#ifdef WOLFSSL_DTLS
if (ssl->options.dtls) {
int ret = wc_HmacUpdate(&cookieHmac, input + i, RAN_LEN);
if (ret != 0) return ret;
}
#endif /* WOLFSSL_DTLS */
i += RAN_LEN;
#ifdef SHOW_SECRETS
@@ -14345,6 +14399,12 @@ int DoSessionTicket(WOLFSSL* ssl,
return BUFFER_ERROR;
XMEMCPY(ssl->arrays->sessionID, input + i, ID_LEN);
#ifdef WOLFSSL_DTLS
if (ssl->options.dtls) {
int ret = wc_HmacUpdate(&cookieHmac, input + i - 1, ID_LEN + 1);
if (ret != 0) return ret;
}
#endif /* WOLFSSL_DTLS */
ssl->arrays->sessionIDSz = ID_LEN;
i += ID_LEN;
ssl->options.resuming = 1; /* client wants to resume */
@@ -14362,30 +14422,18 @@ int DoSessionTicket(WOLFSSL* ssl,
if ((i - begin) + OPAQUE8_LEN > helloSz)
return BUFFER_ERROR;
b = input[i++];
peerCookieSz = input[i++];
if (b) {
byte cookie[MAX_COOKIE_LEN];
if (b > MAX_COOKIE_LEN)
if (peerCookieSz) {
if (peerCookieSz > MAX_COOKIE_LEN)
return BUFFER_ERROR;
if ((i - begin) + b > helloSz)
if ((i - begin) + peerCookieSz > helloSz)
return BUFFER_ERROR;
if (ssl->ctx->CBIOCookie == NULL) {
WOLFSSL_MSG("Your Cookie callback is null, please set");
return COOKIE_ERROR;
}
XMEMCPY(peerCookie, input + i, peerCookieSz);
if ((ssl->ctx->CBIOCookie(ssl, cookie, COOKIE_SZ,
ssl->IOCB_CookieCtx) != COOKIE_SZ)
|| (b != COOKIE_SZ)
|| (XMEMCMP(cookie, input + i, b) != 0)) {
return COOKIE_ERROR;
}
i += b;
i += peerCookieSz;
}
}
#endif
@@ -14405,6 +14453,14 @@ int DoSessionTicket(WOLFSSL* ssl,
return BUFFER_ERROR;
XMEMCPY(clSuites.suites, input + i, clSuites.suiteSz);
#ifdef WOLFSSL_DTLS
if (ssl->options.dtls) {
int ret = wc_HmacUpdate(&cookieHmac,
input + i - OPAQUE16_LEN,
clSuites.suiteSz + OPAQUE16_LEN);
if (ret != 0) return ret;
}
#endif /* WOLFSSL_DTLS */
i += clSuites.suiteSz;
clSuites.hashSigAlgoSz = 0;
@@ -14414,6 +14470,43 @@ int DoSessionTicket(WOLFSSL* ssl,
if ((i - begin) + b > helloSz)
return BUFFER_ERROR;
#ifdef WOLFSSL_DTLS
if (ssl->options.dtls) {
byte newCookie[MAX_COOKIE_LEN];
int ret;
ret = wc_HmacUpdate(&cookieHmac, input + i - 1, b + 1);
if (ret != 0) return ret;
ret = wc_HmacFinal(&cookieHmac, newCookie);
if (ret != 0) return ret;
/* If a cookie callback is set, call it to overwrite the cookie.
* This should be deprecated. The code now calculates the cookie
* using an HMAC as expected. */
if (ssl->ctx->CBIOCookie != NULL &&
ssl->ctx->CBIOCookie(ssl, newCookie, cookieSz,
ssl->IOCB_CookieCtx) != cookieSz) {
return COOKIE_ERROR;
}
/* Check the cookie, see if we progress the state machine. */
if (peerCookieSz != cookieSz ||
XMEMCMP(peerCookie, newCookie, cookieSz) != 0) {
/* Send newCookie to client in a HelloVerifyRequest message
* and let the state machine alone. */
ssl->msgsReceived.got_client_hello = 0;
*inOutIdx += helloSz;
return SendHelloVerifyRequest(ssl, newCookie, cookieSz);
}
/* This was skipped in the DTLS case so we could handle the hello
* verify request. */
ret = HashInput(ssl, input + *inOutIdx, helloSz);
if (ret != 0) return ret;
}
#endif /* WOLFSSL_DTLS */
if (ssl->options.usingCompression) {
int match = 0;
@@ -14519,8 +14612,7 @@ int DoSessionTicket(WOLFSSL* ssl,
ssl->options.haveSessionId = 1;
/* ProcessOld uses same resume code */
if (ssl->options.resuming && (!ssl->options.dtls ||
ssl->options.acceptState == HELLO_VERIFY_SENT)) { /* let's try */
if (ssl->options.resuming) {
int ret = -1;
WOLFSSL_SESSION* session = GetSession(ssl,
ssl->arrays->masterSecret);
@@ -15002,10 +15094,10 @@ int DoSessionTicket(WOLFSSL* ssl,
#ifdef WOLFSSL_DTLS
int SendHelloVerifyRequest(WOLFSSL* ssl)
static int SendHelloVerifyRequest(WOLFSSL* ssl,
const byte* cookie, byte cookieSz)
{
byte* output;
byte cookieSz = COOKIE_SZ;
int length = VERSION_SZ + ENUM_LEN + cookieSz;
int idx = DTLS_RECORD_HEADER_SZ + DTLS_HANDSHAKE_HEADER_SZ;
int sendSz = length + idx;
@@ -15030,17 +15122,10 @@ int DoSessionTicket(WOLFSSL* ssl,
output[idx++] = DTLS_MINOR;
output[idx++] = cookieSz;
if (ssl->ctx->CBIOCookie == NULL) {
WOLFSSL_MSG("Your Cookie callback is null, please set");
if (cookie == NULL || cookieSz == 0)
return COOKIE_ERROR;
}
if ((ret = ssl->ctx->CBIOCookie(ssl, output + idx, cookieSz,
ssl->IOCB_CookieCtx)) < 0)
return ret;
ret = HashOutput(ssl, output, sendSz, 0);
if (ret != 0)
return ret;
XMEMCPY(output + idx, cookie, cookieSz);
#ifdef WOLFSSL_CALLBACKS
if (ssl->hsInfoOn)
@@ -15049,7 +15134,6 @@ int DoSessionTicket(WOLFSSL* ssl,
AddPacketInfo("HelloVerifyRequest", &ssl->timeoutInfo, output,
sendSz, ssl->heap);
#endif
ssl->options.serverState = SERVER_HELLOVERIFYREQUEST_COMPLETE;
ssl->buffers.outputBuffer.length += sendSz;

114
src/ssl.c
View File

@@ -5465,6 +5465,64 @@ int wolfSSL_dtls_got_timeout(WOLFSSL* ssl)
#endif /* LEANPSK */
#if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_SERVER)
/* Not an SSL function, return 0 for success, error code otherwise */
/* Prereq: ssl's RNG needs to be initialized. */
int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl,
const byte* secret, word32 secretSz)
{
WOLFSSL_ENTER("wolfSSL_DTLS_SetCookieSecret");
if (ssl == NULL) {
WOLFSSL_MSG("need a SSL object");
return BAD_FUNC_ARG;
}
if (secret != NULL && secretSz == 0) {
WOLFSSL_MSG("can't have a new secret without a size");
return BAD_FUNC_ARG;
}
/* If secretSz is 0, use the default size. */
if (secretSz == 0)
secretSz = COOKIE_SECRET_SZ;
if (secretSz != ssl->buffers.dtlsCookieSecret.length) {
byte* newSecret;
if (ssl->buffers.dtlsCookieSecret.buffer != NULL) {
XMEMSET(ssl->buffers.dtlsCookieSecret.buffer, 0,
ssl->buffers.dtlsCookieSecret.length);
XFREE(ssl->buffers.dtlsCookieSecret.buffer,
ssl->heap, DYNAMIC_TYPE_NONE);
}
newSecret = (byte*)XMALLOC(secretSz, ssl->heap, DYNAMIC_TYPE_NONE);
if (newSecret == NULL) {
ssl->buffers.dtlsCookieSecret.buffer = NULL;
ssl->buffers.dtlsCookieSecret.length = 0;
WOLFSSL_MSG("couldn't allocate new cookie secret");
return MEMORY_ERROR;
}
ssl->buffers.dtlsCookieSecret.buffer = newSecret;
ssl->buffers.dtlsCookieSecret.length = secretSz;
}
/* If the supplied secret is NULL, randomly generate a new secret. */
if (secret == NULL)
wc_RNG_GenerateBlock(ssl->rng,
ssl->buffers.dtlsCookieSecret.buffer, secretSz);
else
XMEMCPY(ssl->buffers.dtlsCookieSecret.buffer, secret, secretSz);
WOLFSSL_LEAVE("wolfSSL_DTLS_SetCookieSecret", 0);
return 0;
}
#endif /* WOLFSSL_DTLS && !NO_WOLFSSL_SERVER */
/* client only parts */
#ifndef NO_WOLFSSL_CLIENT
@@ -5883,62 +5941,6 @@ int wolfSSL_dtls_got_timeout(WOLFSSL* ssl)
WOLFSSL_MSG("accept state ACCEPT_CLIENT_HELLO_DONE");
case ACCEPT_CLIENT_HELLO_DONE :
#ifdef WOLFSSL_DTLS
if (ssl->options.dtls)
if ( (ssl->error = SendHelloVerifyRequest(ssl)) != 0) {
WOLFSSL_ERROR(ssl->error);
return SSL_FATAL_ERROR;
}
#endif
ssl->options.acceptState = HELLO_VERIFY_SENT;
WOLFSSL_MSG("accept state HELLO_VERIFY_SENT");
case HELLO_VERIFY_SENT:
#ifdef WOLFSSL_DTLS
if (ssl->options.dtls) {
ssl->options.clientState = NULL_STATE; /* get again */
/* reset messages received */
XMEMSET(&ssl->msgsReceived, 0, sizeof(ssl->msgsReceived));
/* re-init hashes, exclude first hello and verify request */
#ifndef NO_OLD_TLS
wc_InitMd5(&ssl->hsHashes->hashMd5);
if ( (ssl->error = wc_InitSha(&ssl->hsHashes->hashSha))
!= 0) {
WOLFSSL_ERROR(ssl->error);
return SSL_FATAL_ERROR;
}
#endif
if (IsAtLeastTLSv1_2(ssl)) {
#ifndef NO_SHA256
if ( (ssl->error = wc_InitSha256(
&ssl->hsHashes->hashSha256)) != 0) {
WOLFSSL_ERROR(ssl->error);
return SSL_FATAL_ERROR;
}
#endif
#ifdef WOLFSSL_SHA384
if ( (ssl->error = wc_InitSha384(
&ssl->hsHashes->hashSha384)) != 0) {
WOLFSSL_ERROR(ssl->error);
return SSL_FATAL_ERROR;
}
#endif
#ifdef WOLFSSL_SHA512
if ( (ssl->error = wc_InitSha512(
&ssl->hsHashes->hashSha512)) != 0) {
WOLFSSL_ERROR(ssl->error);
return SSL_FATAL_ERROR;
}
#endif
}
while (ssl->options.clientState < CLIENT_HELLO_COMPLETE)
if ( (ssl->error = ProcessReply(ssl)) < 0) {
WOLFSSL_ERROR(ssl->error);
return SSL_FATAL_ERROR;
}
}
#endif
ssl->options.acceptState = ACCEPT_FIRST_REPLY_DONE;
WOLFSSL_MSG("accept state ACCEPT_FIRST_REPLY_DONE");

View File

@@ -842,6 +842,7 @@ enum Misc {
RAN_LEN = 32, /* random length */
SEED_LEN = RAN_LEN * 2, /* tls prf seed length */
ID_LEN = 32, /* session id length */
COOKIE_SECRET_SZ = 14, /* dtls cookie secret size */
MAX_COOKIE_LEN = 32, /* max dtls cookie size */
COOKIE_SZ = 20, /* use a 20 byte cookie */
SUITE_LEN = 2, /* cipher suite sz length */
@@ -1951,7 +1952,6 @@ enum ConnectState {
enum AcceptState {
ACCEPT_BEGIN = 0,
ACCEPT_CLIENT_HELLO_DONE,
HELLO_VERIFY_SENT,
ACCEPT_FIRST_REPLY_DONE,
SERVER_HELLO_SENT,
CERT_SENT,
@@ -1993,6 +1993,9 @@ typedef struct Buffers {
#endif
#ifdef WOLFSSL_DTLS
WOLFSSL_DTLS_CTX dtlsCtx; /* DTLS connection context */
#ifndef NO_WOLFSSL_SERVER
buffer dtlsCookieSecret; /* DTLS cookie secret */
#endif /* NO_WOLFSSL_SERVER */
#endif
#ifdef HAVE_PK_CALLBACKS
#ifdef HAVE_ECC
@@ -2603,9 +2606,6 @@ WOLFSSL_LOCAL int GrowInputBuffer(WOLFSSL* ssl, int size, int usedLength);
#ifndef NO_WOLFSSL_SERVER
WOLFSSL_LOCAL int SendServerHello(WOLFSSL*);
WOLFSSL_LOCAL int SendServerHelloDone(WOLFSSL*);
#ifdef WOLFSSL_DTLS
WOLFSSL_LOCAL int SendHelloVerifyRequest(WOLFSSL*);
#endif
#endif /* NO_WOLFSSL_SERVER */
#ifdef WOLFSSL_DTLS

View File

@@ -1041,6 +1041,9 @@ typedef int (*CallbackGenCookie)(WOLFSSL* ssl, unsigned char* buf, int sz,
WOLFSSL_API void wolfSSL_CTX_SetGenCookie(WOLFSSL_CTX*, CallbackGenCookie);
WOLFSSL_API void wolfSSL_SetCookieCtx(WOLFSSL* ssl, void *ctx);
WOLFSSL_API void* wolfSSL_GetCookieCtx(WOLFSSL* ssl);
WOLFSSL_API int wolfSSL_DTLS_SetCookieSecret(WOLFSSL*,
const unsigned char*,
unsigned int);
/* I/O Callback default errors */