diff --git a/examples/server/server.c b/examples/server/server.c index 3c8ac1e65..7d9af8d99 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -64,6 +64,16 @@ int myHsDoneCb(WOLFSSL* ssl, void* user_ctx); #endif +#if defined(HAVE_SESSION_TICKET) && defined(HAVE_CHACHA) && \ + defined(HAVE_POLY1305) + #include + static int TicketInit(void); + static void TicketCleanup(void); + static int myTicketEncCb(WOLFSSL* ssl, byte key_name[16], byte iv[16], + byte mac[32], int enc, byte* ticket, int inLen, + int* outLen); +#endif + static void NonBlockingSSL_Accept(SSL* ssl) { @@ -415,6 +425,13 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) if (ctx == NULL) err_sys("unable to get ctx"); +#if defined(HAVE_SESSION_TICKET) && defined(HAVE_CHACHA) && \ + defined(HAVE_POLY1305) + if (TicketInit() != 0) + err_sys("unable to setup Session Ticket Key context"); + wolfSSL_CTX_set_TicketEncCb(ctx, myTicketEncCb); +#endif + if (cipherList) if (SSL_CTX_set_cipher_list(ctx, cipherList) != SSL_SUCCESS) err_sys("server can't set cipher list 1"); @@ -648,6 +665,11 @@ while (1) { /* allow resume option */ fdCloseSession(Task_self()); #endif +#if defined(HAVE_SESSION_TICKET) && defined(HAVE_CHACHA) && \ + defined(HAVE_POLY1305) + TicketCleanup(); +#endif + #ifndef CYASSL_TIRTOS return 0; #endif @@ -732,3 +754,89 @@ while (1) { /* allow resume option */ } #endif + +#if defined(HAVE_SESSION_TICKET) && defined(HAVE_CHACHA) && \ + defined(HAVE_POLY1305) + typedef struct key_ctx { + byte name[WOLFSSL_TICKET_NAME_SZ]; /* name for this context */ + byte key[16]; /* cipher key */ + } key_ctx; + + static key_ctx myKey_ctx; + static RNG rng; + + static int TicketInit(void) + { + int ret = wc_InitRng(&rng); + if (ret != 0) return ret; + + ret = wc_RNG_GenerateBlock(&rng, myKey_ctx.key, sizeof(myKey_ctx.key)); + if (ret != 0) return ret; + + ret = wc_RNG_GenerateBlock(&rng, myKey_ctx.name,sizeof(myKey_ctx.name)); + if (ret != 0) return ret; + + return 0; + } + + static void TicketCleanup(void) + { + wc_FreeRng(&rng); + } + + static int myTicketEncCb(WOLFSSL* ssl, + byte key_name[WOLFSSL_TICKET_NAME_SZ], + byte iv[WOLFSSL_TICKET_IV_SZ], + byte mac[WOLFSSL_TICKET_MAC_SZ], + int enc, byte* ticket, int inLen, int* outLen) + { + (void)ssl; + + int ret; + word16 sLen = htons(inLen); + byte aad[WOLFSSL_TICKET_NAME_SZ + WOLFSSL_TICKET_IV_SZ + 2]; + int aadSz = WOLFSSL_TICKET_NAME_SZ + WOLFSSL_TICKET_IV_SZ + 2; + byte* tmp = aad; + + if (enc) { + XMEMCPY(key_name, myKey_ctx.name, WOLFSSL_TICKET_NAME_SZ); + + ret = wc_RNG_GenerateBlock(&rng, iv, WOLFSSL_TICKET_IV_SZ); + if (ret != 0) return WOLFSSL_TICKET_RET_REJECT; + + /* build aad from key name, iv, and length */ + XMEMCPY(tmp, key_name, WOLFSSL_TICKET_NAME_SZ); + tmp += WOLFSSL_TICKET_NAME_SZ; + XMEMCPY(tmp, iv, WOLFSSL_TICKET_IV_SZ); + tmp += WOLFSSL_TICKET_IV_SZ; + XMEMCPY(tmp, &sLen, 2); + + ret = wc_ChaCha20Poly1305_Encrypt(myKey_ctx.key, iv, + aad, aadSz, + ticket, inLen, + ticket, + mac); + if (ret != 0) return WOLFSSL_TICKET_RET_REJECT; + *outLen = inLen; /* no padding in this mode */ + } else { + /* decrypt */ + /* build aad from key name, iv, and length */ + XMEMCPY(tmp, key_name, WOLFSSL_TICKET_NAME_SZ); + tmp += WOLFSSL_TICKET_NAME_SZ; + XMEMCPY(tmp, iv, WOLFSSL_TICKET_IV_SZ); + tmp += WOLFSSL_TICKET_IV_SZ; + XMEMCPY(tmp, &sLen, 2); + + ret = wc_ChaCha20Poly1305_Decrypt(myKey_ctx.key, iv, + aad, aadSz, + ticket, inLen, + mac, + ticket); + if (ret != 0) return WOLFSSL_TICKET_RET_REJECT; + *outLen = inLen; /* no padding in this mode */ + } + + return WOLFSSL_TICKET_RET_OK; + } + +#endif diff --git a/src/internal.c b/src/internal.c index 13e8dd35f..4e534dce0 100644 --- a/src/internal.c +++ b/src/internal.c @@ -417,6 +417,10 @@ int InitSSL_Ctx(WOLFSSL_CTX* ctx, WOLFSSL_METHOD* method) } #endif +#if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_SERVER) + ctx->ticketHint = SESSION_TICKET_HINT_DEFAULT; +#endif + return 0; } @@ -4909,6 +4913,10 @@ static int DoHandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, if (ssl->keys.encryptionOn) { *inOutIdx += ssl->keys.padSz; } + if (ssl->options.resuming) { + WOLFSSL_MSG("Not resuming as thought"); + ssl->options.resuming = 0; + } break; case finished: @@ -8007,6 +8015,12 @@ const char* wolfSSL_ERR_reason_error_string(unsigned long e) case SOCKET_PEER_CLOSED_E: return "Peer closed underlying transport Error"; + case BAD_TICKET_KEY_CB_SZ: + return "Bad user session ticket key callback Size Error"; + + case BAD_TICKET_MSG_SZ: + return "Bad session ticket message Size Error"; + default : return "unknown error number"; } @@ -9323,8 +9337,9 @@ static void PickHashSigAlgo(WOLFSSL* ssl, #endif #ifdef HAVE_SESSION_TICKET - ret = ret || - (!ssl->expect_session_ticket && ssl->session.ticketLen > 0); + /* server may send blank ticket which may not be expected to indicate + * exisiting one ok but will also be sending a new one */ + ret = ret || (ssl->session.ticketLen > 0); #endif ret = ret || @@ -11339,6 +11354,7 @@ int DoSessionTicket(WOLFSSL* ssl, word32 length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; int sendSz; int ret; + byte sessIdSz = ID_LEN; length = VERSION_SZ + RAN_LEN + ID_LEN + ENUM_LEN @@ -11347,6 +11363,14 @@ int DoSessionTicket(WOLFSSL* ssl, #ifdef HAVE_TLS_EXTENSIONS length += TLSX_GetResponseSize(ssl); + + #ifdef HAVE_SESSION_TICKET + if (ssl->options.useTicket && ssl->arrays->sessionIDSz == 0) { + /* no session id */ + length -= ID_LEN; + sessIdSz = 0; + } + #endif /* HAVE_SESSION_TICKET */ #endif /* check for avalaible size */ @@ -11392,17 +11416,19 @@ int DoSessionTicket(WOLFSSL* ssl, } #endif /* then session id */ - output[idx++] = ID_LEN; + output[idx++] = sessIdSz; + if (sessIdSz) { - if (!ssl->options.resuming) { - ret = wc_RNG_GenerateBlock(ssl->rng, ssl->arrays->sessionID, ID_LEN); - if (ret != 0) - return ret; + if (!ssl->options.resuming) { + ret = wc_RNG_GenerateBlock(ssl->rng, ssl->arrays->sessionID, + sessIdSz); + if (ret != 0) return ret; + } + + XMEMCPY(output + idx, ssl->arrays->sessionID, sessIdSz); + idx += sessIdSz; } - XMEMCPY(output + idx, ssl->arrays->sessionID, ID_LEN); - idx += ID_LEN; - /* then cipher suite */ output[idx++] = ssl->options.cipherSuite0; output[idx++] = ssl->options.cipherSuite; @@ -13069,6 +13095,7 @@ int DoSessionTicket(WOLFSSL* ssl, /* session id */ if (sessionSz) { XMEMCPY(ssl->arrays->sessionID, input + idx, sessionSz); + ssl->arrays->sessionIDSz = (byte)sessionSz; idx += sessionSz; ssl->options.resuming = 1; } @@ -13090,7 +13117,14 @@ int DoSessionTicket(WOLFSSL* ssl, /* DoClientHello uses same resume code */ if (ssl->options.resuming) { /* let's try */ int ret = -1; - WOLFSSL_SESSION* session = GetSession(ssl,ssl->arrays->masterSecret); + WOLFSSL_SESSION* session = GetSession(ssl, + ssl->arrays->masterSecret); + #ifdef HAVE_SESSION_TICKET + if (ssl->options.useTicket == 1) { + session = &ssl->session; + } + #endif + if (!session) { WOLFSSL_MSG("Session lookup for resume failed"); ssl->options.resuming = 0; @@ -13217,6 +13251,7 @@ int DoSessionTicket(WOLFSSL* ssl, return BUFFER_ERROR; XMEMCPY(ssl->arrays->sessionID, input + i, ID_LEN); + ssl->arrays->sessionIDSz = ID_LEN; i += ID_LEN; ssl->options.resuming = 1; /* client wants to resume */ WOLFSSL_MSG("Client wants to resume session"); @@ -13379,7 +13414,13 @@ int DoSessionTicket(WOLFSSL* ssl, if (ssl->options.resuming && (!ssl->options.dtls || ssl->options.acceptState == HELLO_VERIFY_SENT)) { /* let's try */ int ret = -1; - WOLFSSL_SESSION* session = GetSession(ssl,ssl->arrays->masterSecret); + WOLFSSL_SESSION* session = GetSession(ssl, + ssl->arrays->masterSecret); + #ifdef HAVE_SESSION_TICKET + if (ssl->options.useTicket == 1) { + session = &ssl->session; + } + #endif if (!session) { WOLFSSL_MSG("Session lookup for resume failed"); @@ -13655,6 +13696,171 @@ int DoSessionTicket(WOLFSSL* ssl, return SendBuffered(ssl); } + +#ifdef HAVE_SESSION_TICKET + +#define WOLFSSL_TICKET_FIXED_SZ (WOLFSSL_TICKET_NAME_SZ + \ + WOLFSSL_TICKET_IV_SZ + WOLFSSL_TICKET_MAC_SZ + LENGTH_SZ) +#define WOLFSSL_TICKET_ENC_SZ (SESSION_TICKET_LEN - WOLFSSL_TICKET_FIXED_SZ) + + /* our ticket format */ + typedef struct InternalTicket { + ProtocolVersion pv; /* version when ticket created */ + byte suite[SUITE_LEN]; /* cipher suite when created */ + byte msecret[SECRET_LEN]; /* master secret */ + word32 timestamp; /* born on */ + } InternalTicket; + + /* fit within SESSION_TICKET_LEN */ + typedef struct ExternalTicket { + byte key_name[WOLFSSL_TICKET_NAME_SZ]; /* key context name */ + byte iv[WOLFSSL_TICKET_IV_SZ]; /* this ticket's iv */ + byte enc_len[LENGTH_SZ]; /* encrypted length */ + byte enc_ticket[WOLFSSL_TICKET_ENC_SZ]; /* encrypted internal ticket */ + byte mac[WOLFSSL_TICKET_MAC_SZ]; /* total mac */ + /* !! if add to structure, add to TICKET_FIXED_SZ !! */ + } ExternalTicket; + + /* create a new session ticket, 0 on success */ + static int CreateTicket(WOLFSSL* ssl) + { + InternalTicket it; + ExternalTicket* et = (ExternalTicket*)ssl->session.ticket; + int encLen; + int ret; + + /* build internal */ + it.pv.major = ssl->version.major; + it.pv.minor = ssl->version.minor; + + it.suite[0] = ssl->options.cipherSuite0; + it.suite[1] = ssl->options.cipherSuite; + + XMEMCPY(it.msecret, ssl->arrays->masterSecret, SECRET_LEN); + c32toa(LowResTimer(), (byte*)&it.timestamp); + + /* build external */ + XMEMCPY(et->enc_ticket, &it, sizeof(InternalTicket)); + + /* encrypt */ + encLen = WOLFSSL_TICKET_ENC_SZ; /* max size user can use */ + ret = ssl->ctx->ticketEncCb(ssl, et->key_name, et->iv, et->mac, 1, + et->enc_ticket, sizeof(InternalTicket), + &encLen); + if (ret == WOLFSSL_TICKET_RET_OK) { + if (encLen < (int)sizeof(InternalTicket) || + encLen > WOLFSSL_TICKET_ENC_SZ) { + WOLFSSL_MSG("Bad user ticket encrypt size"); + return BAD_TICKET_KEY_CB_SZ; + } + c16toa((word16)encLen, et->enc_len); + ssl->session.ticketLen = (word16)(encLen + WOLFSSL_TICKET_FIXED_SZ); + if (encLen < WOLFSSL_TICKET_ENC_SZ) { + /* move mac up since whole enc buffer not used */ + XMEMMOVE(et->enc_ticket +encLen, et->mac,WOLFSSL_TICKET_MAC_SZ); + } + } + + return ret; + } + + + /* Parse ticket sent by client */ + int DoClientTicket(WOLFSSL* ssl, const byte* input, word32 len) + { + ExternalTicket* et; + InternalTicket* it; + int ret; + int outLen; + word16 inLen; + + if (len > SESSION_TICKET_LEN || + len < (word32)(sizeof(InternalTicket) + WOLFSSL_TICKET_FIXED_SZ)) { + return BAD_TICKET_MSG_SZ; + } + + et = (ExternalTicket*)input; + it = (InternalTicket*)et->enc_ticket; + + /* decrypt */ + ato16(et->enc_len, &inLen); + if (inLen > (word16)(len - WOLFSSL_TICKET_FIXED_SZ)) { + return BAD_TICKET_MSG_SZ; + } + outLen = inLen; /* may be reduced by user padding */ + ret = ssl->ctx->ticketEncCb(ssl, et->key_name, et->iv, + et->enc_ticket + inLen, 0, + et->enc_ticket, inLen, &outLen); + if (ret == WOLFSSL_TICKET_RET_FATAL || ret < 0) return ret; + if (outLen > inLen || outLen < (int)sizeof(InternalTicket)) { + WOLFSSL_MSG("Bad user ticket decrypt len"); + return BAD_TICKET_KEY_CB_SZ; + } + + /* get master secret */ + if (ret == WOLFSSL_TICKET_RET_OK || ret == WOLFSSL_TICKET_RET_CREATE) + XMEMCPY(ssl->arrays->masterSecret, it->msecret, SECRET_LEN); + + return ret; + } + + + /* send Session Ticket */ + int SendTicket(WOLFSSL* ssl) + { + byte* output; + int ret; + int sendSz; + word32 length = SESSION_HINT_SZ + LENGTH_SZ; + word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + length += DTLS_RECORD_EXTRA; + idx += DTLS_RECORD_EXTRA; + } + #endif + + if (ssl->options.createTicket) { + ret = CreateTicket(ssl); + if (ret != 0) return ret; + } + + length += ssl->session.ticketLen; + sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) + return ret; + + /* get ouput buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + AddHeaders(output, length, session_ticket, ssl); + + /* hint */ + c32toa(ssl->ctx->ticketHint, output + idx); + idx += SESSION_HINT_SZ; + + /* length */ + c16toa(ssl->session.ticketLen, output + idx); + idx += LENGTH_SZ; + + /* ticket */ + XMEMCPY(output + idx, ssl->session.ticket, ssl->session.ticketLen); + /* idx += ssl->session.ticketLen; */ + + ret = HashOutput(ssl, output, sendSz, 0); + if (ret != 0) return ret; + ssl->buffers.outputBuffer.length += sendSz; + + return SendBuffered(ssl); + } + +#endif /* HAVE_SESSION_TICKET */ + + #ifdef WOLFSSL_DTLS int SendHelloVerifyRequest(WOLFSSL* ssl) { diff --git a/src/ssl.c b/src/ssl.c index b68664b7f..d6c76fe05 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -865,6 +865,21 @@ int wolfSSL_Rehandshake(WOLFSSL* ssl) #endif /* HAVE_SECURE_RENEGOTIATION */ +/* Session Ticket */ +#if !defined(NO_WOLFSSL_SERVER) && defined(HAVE_SESSION_TICKET) +/* SSL_SUCCESS on ok */ +int wolfSSL_CTX_set_TicketEncCb(WOLFSSL_CTX* ctx, SessionTicketEncCb cb) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; + + ctx->ticketEncCb = cb; + + return SSL_SUCCESS; +} + +#endif /* !defined(NO_WOLFSSL_CLIENT) && defined(HAVE_SESSION_TICKET) */ + /* Session Ticket */ #if !defined(NO_WOLFSSL_CLIENT) && defined(HAVE_SESSION_TICKET) int wolfSSL_UseSessionTicket(WOLFSSL* ssl) @@ -905,7 +920,7 @@ WOLFSSL_API int wolfSSL_set_SessionTicket(WOLFSSL* ssl, byte* buf, word32 bufSz) if (bufSz > 0) XMEMCPY(ssl->session.ticket, buf, bufSz); - ssl->session.ticketLen = bufSz; + ssl->session.ticketLen = (word16)bufSz; return SSL_SUCCESS; } @@ -5562,6 +5577,18 @@ int wolfSSL_dtls_got_timeout(WOLFSSL* ssl) WOLFSSL_MSG("accept state ACCEPT_SECOND_REPLY_DONE"); case ACCEPT_SECOND_REPLY_DONE : +#ifdef HAVE_SESSION_TICKET + if (ssl->options.createTicket) { + if ( (ssl->error = SendTicket(ssl)) != 0) { + WOLFSSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } + } +#endif /* HAVE_SESSION_TICKET */ + ssl->options.acceptState = TICKET_SENT; + WOLFSSL_MSG("accept state TICKET_SENT"); + + case TICKET_SENT: if ( (ssl->error = SendChangeCipher(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); return SSL_FATAL_ERROR; @@ -5808,6 +5835,11 @@ WOLFSSL_SESSION* GetSession(WOLFSSL* ssl, byte* masterSecret) if (ssl->options.haveSessionId == 0) return NULL; +#ifdef HAVE_SESSION_TICKET + if (ssl->options.side == WOLFSSL_SERVER_END && ssl->options.useTicket == 1) + return NULL; +#endif + if (ssl->arrays) id = ssl->arrays->sessionID; else @@ -5896,6 +5928,11 @@ int AddSession(WOLFSSL* ssl) if (ssl->options.haveSessionId == 0) return 0; +#ifdef HAVE_SESSION_TICKET + if (ssl->options.side == WOLFSSL_SERVER_END && ssl->options.useTicket == 1) + return 0; +#endif + row = HashSession(ssl->arrays->sessionID, ID_LEN, &error) % SESSION_ROWS; if (error != 0) { WOLFSSL_MSG("Hash session failed"); diff --git a/src/tls.c b/src/tls.c index 523b80697..ca94c5b71 100644 --- a/src/tls.c +++ b/src/tls.c @@ -1800,14 +1800,15 @@ static void TLSX_SessionTicket_ValidateRequest(WOLFSSL* ssl) static word16 TLSX_SessionTicket_GetSize(SessionTicket* ticket, int isRequest) { - return isRequest && ticket ? ticket->size : 0; + (void)isRequest; + return ticket ? ticket->size : 0; } static word16 TLSX_SessionTicket_Write(SessionTicket* ticket, byte* output, int isRequest) { - int offset = 0; /* empty ticket */ - + word16 offset = 0; /* empty ticket */ + if (isRequest && ticket) { XMEMCPY(output + offset, ticket->data, ticket->size); offset += ticket->size; @@ -1820,18 +1821,61 @@ static word16 TLSX_SessionTicket_Write(SessionTicket* ticket, byte* output, static int TLSX_SessionTicket_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest) { + int ret = 0; + if (!isRequest) { + /* client side */ if (length != 0) return BUFFER_ERROR; - + ssl->expect_session_ticket = 1; } +#ifndef NO_WOLFSSL_SERVER else { - /* TODO server side */ - (void)input; - } + /* server side */ + if (ssl->ctx->ticketEncCb == NULL) { + WOLFSSL_MSG("Client sent session ticket, server has no callback"); + return 0; + } - return 0; + if (length == 0) { + /* blank ticket */ + ret = TLSX_UseSessionTicket(&ssl->extensions, NULL); + if (ret == SSL_SUCCESS) { + ret = 0; + TLSX_SetResponse(ssl, SESSION_TICKET); /* send blank ticket */ + ssl->options.createTicket = 1; /* will send ticket msg */ + ssl->options.useTicket = 1; + } + } else { + /* got actual ticket from client */ + ret = DoClientTicket(ssl, input, length); + if (ret == WOLFSSL_TICKET_RET_OK) { /* use ticket to resume */ + WOLFSSL_MSG("Using exisitng client ticket"); + ssl->options.useTicket = 1; + ssl->options.resuming = 1; + } else if (ret == WOLFSSL_TICKET_RET_CREATE) { + WOLFSSL_MSG("Using existing client ticket, creating new one"); + ret = TLSX_UseSessionTicket(&ssl->extensions, NULL); + if (ret == SSL_SUCCESS) { + ret = 0; + TLSX_SetResponse(ssl, SESSION_TICKET); + /* send blank ticket */ + ssl->options.createTicket = 1; /* will send ticket msg */ + ssl->options.useTicket = 1; + ssl->options.resuming = 1; + } + } else if (ret == WOLFSSL_TICKET_RET_REJECT) { + WOLFSSL_MSG("Process client ticket rejected, not using"); + ret = 0; /* not fatal */ + } else if (ret == WOLFSSL_TICKET_RET_FATAL || ret < 0) { + WOLFSSL_MSG("Process client ticket fatal error, not using"); + } + } + } +#endif /* NO_WOLFSSL_SERVER */ + + return ret; } WOLFSSL_LOCAL SessionTicket* TLSX_SessionTicket_Create(word32 lifetime, diff --git a/wolfssl/error-ssl.h b/wolfssl/error-ssl.h index 0df2edb6e..abeb5bdd9 100644 --- a/wolfssl/error-ssl.h +++ b/wolfssl/error-ssl.h @@ -129,6 +129,9 @@ enum wolfSSL_ErrorCodes { SNI_UNSUPPORTED = -396, /* SSL 3.0 does not support SNI */ SOCKET_PEER_CLOSED_E = -397, /* Underlying transport closed */ + BAD_TICKET_KEY_CB_SZ = -398, /* Bad session ticket key cb size */ + BAD_TICKET_MSG_SZ = -399, /* Bad session ticket msg size */ + /* add strings to SetErrorString !!!!! */ /* begin negotiation parameter errors */ diff --git a/wolfssl/internal.h b/wolfssl/internal.h index d95c2f97d..edba235dc 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -764,6 +764,7 @@ enum Misc { VERIFY_HEADER = 2, /* always use 2 bytes */ EXT_ID_SZ = 2, /* always use 2 bytes */ MAX_DH_SIZE = 513, /* 4096 bit plus possible leading 0 */ + SESSION_HINT_SZ = 4, /* session timeout hint */ MAX_SUITE_SZ = 200, /* 100 suites for now! */ RAN_LEN = 32, /* random length */ @@ -910,6 +911,10 @@ enum Misc { #define SESSION_TICKET_LEN 256 #endif +#ifndef SESSION_TICKET_HINT_DEFAULT + #define SESSION_TICKET_HINT_DEFAULT 300 +#endif + /* don't use extra 3/4k stack space unless need to */ #ifdef HAVE_NTRU @@ -1535,6 +1540,10 @@ struct WOLFSSL_CTX { #endif #ifdef HAVE_TLS_EXTENSIONS TLSX* extensions; /* RFC 6066 TLS Extensions data */ + #if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_SEVER) + SessionTicketEncCb ticketEncCb; /* enc/dec session ticket Cb */ + int ticketHint; /* ticket hint in seconds */ + #endif #endif #ifdef ATOMIC_USER CallbackMacEncrypt MacEncryptCb; /* Atomic User Mac/Encrypt Cb */ @@ -1797,6 +1806,7 @@ enum AcceptState { CERT_REQ_SENT, SERVER_HELLO_DONE, ACCEPT_SECOND_REPLY_DONE, + TICKET_SENT, CHANGE_CIPHER_SENT, ACCEPT_FINISHED_DONE, ACCEPT_THIRD_REPLY_DONE @@ -1889,7 +1899,11 @@ typedef struct Options { #endif #ifdef HAVE_ANON word16 haveAnon:1; /* User wants to allow Anon suites */ -#endif /* HAVE_ANON */ +#endif +#ifdef HAVE_SESSION_TICKET + word16 createTicket:1; /* Server to create new Ticket */ + word16 useTicket:1; /* Use Ticket not session cache */ +#endif /* need full byte values for this section */ byte processReply; /* nonblocking resume */ @@ -2353,6 +2367,8 @@ static const byte tls_server[FINISHED_LABEL_SZ + 1] = "server finished"; /* internal functions */ WOLFSSL_LOCAL int SendChangeCipher(WOLFSSL*); +WOLFSSL_LOCAL int SendTicket(WOLFSSL*); +WOLFSSL_LOCAL int DoClientTicket(WOLFSSL*, const byte*, word32); WOLFSSL_LOCAL int SendData(WOLFSSL*, const void*, int); WOLFSSL_LOCAL int SendCertificate(WOLFSSL*); WOLFSSL_LOCAL int SendCertificateRequest(WOLFSSL*); diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 9b9884989..67ffde075 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -1359,8 +1359,8 @@ WOLFSSL_API int wolfSSL_Rehandshake(WOLFSSL* ssl); /* Session Ticket */ #ifdef HAVE_SESSION_TICKET -#ifndef NO_WOLFSSL_CLIENT +#ifndef NO_WOLFSSL_CLIENT WOLFSSL_API int wolfSSL_UseSessionTicket(WOLFSSL* ssl); WOLFSSL_API int wolfSSL_CTX_UseSessionTicket(WOLFSSL_CTX* ctx); WOLFSSL_API int wolfSSL_get_SessionTicket(WOLFSSL*, unsigned char*, unsigned int*); @@ -1368,9 +1368,32 @@ WOLFSSL_API int wolfSSL_set_SessionTicket(WOLFSSL*, unsigned char*, unsigned int typedef int (*CallbackSessionTicket)(WOLFSSL*, const unsigned char*, int, void*); WOLFSSL_API int wolfSSL_set_SessionTicket_cb(WOLFSSL*, CallbackSessionTicket, void*); +#endif /* NO_WOLFSSL_CLIENT */ -#endif -#endif +#ifndef NO_WOLFSSL_SERVER + +#define WOLFSSL_TICKET_NAME_SZ 16 +#define WOLFSSL_TICKET_IV_SZ 16 +#define WOLFSSL_TICKET_MAC_SZ 32 + +enum TicketEncRet { + WOLFSSL_TICKET_RET_FATAL = -1, /* fatal error, don't use ticket */ + WOLFSSL_TICKET_RET_OK = 0, /* ok, use ticket */ + WOLFSSL_TICKET_RET_REJECT, /* don't use ticket, but not fatal */ + WOLFSSL_TICKET_RET_CREATE /* existing ticket ok and create new one */ +}; + +typedef int (*SessionTicketEncCb)(WOLFSSL*, + unsigned char key_name[WOLFSSL_TICKET_NAME_SZ], + unsigned char iv[WOLFSSL_TICKET_IV_SZ], + unsigned char mac[WOLFSSL_TICKET_MAC_SZ], + int enc, unsigned char*, int, int*); +WOLFSSL_API int wolfSSL_CTX_set_TicketEncCb(WOLFSSL_CTX* ctx, + SessionTicketEncCb); + +#endif /* NO_WOLFSSL_SERVER */ + +#endif /* HAVE_SESSION_TICKET */ #define WOLFSSL_CRL_MONITOR 0x01 /* monitor this dir flag */ #define WOLFSSL_CRL_START_MON 0x02 /* start monitoring flag */