1. improved DTLS cookie generation, uses HMAC and parts of Client Hello

message
2. add function to set the cookie Hmac key
3. removed server state for hello verify message
This commit is contained in:
John Safranek
2015-09-11 17:55:43 -07:00
parent de64092a70
commit b62e5d57fe
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 */