Merge pull request #3713 from SparkiDev/tls_def_sess_ticket_cb

TLS Session Ticket: default encryption callback
This commit is contained in:
toddouska
2021-02-10 16:13:33 -08:00
committed by GitHub
9 changed files with 687 additions and 22 deletions

View File

@ -165,9 +165,8 @@ THREAD_RETURN CYASSL_THREAD echoserver_test(void* args)
CyaSSL_CTX_set_default_passwd_cb(ctx, PasswordCallBack);
#endif
#if defined(HAVE_SESSION_TICKET) && \
((defined(HAVE_CHACHA) && defined(HAVE_POLY1305)) || \
defined(HAVE_AESGCM))
#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
((defined(HAVE_CHACHA) && defined(HAVE_POLY1305)) || defined(HAVE_AESGCM))
if (TicketInit() != 0)
err_sys("unable to setup Session Ticket Key context");
wolfSSL_CTX_set_TicketEncCb(ctx, myTicketEncCb);
@ -521,8 +520,8 @@ THREAD_RETURN CYASSL_THREAD echoserver_test(void* args)
fdCloseSession(Task_self());
#endif
#if defined(HAVE_SESSION_TICKET) && defined(HAVE_CHACHA) && \
defined(HAVE_POLY1305)
#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
((defined(HAVE_CHACHA) && defined(HAVE_POLY1305)) || defined(HAVE_AESGCM))
TicketCleanup();
#endif

View File

@ -1800,9 +1800,8 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args)
wolfSSL_CTX_SetIOSend(ctx, SimulateWantWriteIOSendCb);
}
#if defined(HAVE_SESSION_TICKET) && \
((defined(HAVE_CHACHA) && defined(HAVE_POLY1305)) || \
defined(HAVE_AESGCM))
#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
((defined(HAVE_CHACHA) && defined(HAVE_POLY1305)) || defined(HAVE_AESGCM))
if (TicketInit() != 0)
err_sys_ex(catastrophic, "unable to setup Session Ticket Key context");
wolfSSL_CTX_set_TicketEncCb(ctx, myTicketEncCb);
@ -2835,8 +2834,8 @@ exit:
fdCloseSession(Task_self());
#endif
#if defined(HAVE_SESSION_TICKET) && defined(HAVE_CHACHA) && \
defined(HAVE_POLY1305)
#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
((defined(HAVE_CHACHA) && defined(HAVE_POLY1305)) || defined(HAVE_AESGCM))
TicketCleanup();
#endif

View File

@ -42,6 +42,24 @@
* read timeout. By default we resend in two more cases, when we receive:
* - an out of order last msg of the peer's flight
* - a duplicate of the first msg from the peer's flight
* WOLFSSL_NO_DEF_TICKET_ENC_CB:
* No default ticket encryption callback.
* Server only.
* Application must set its own callback to use session tickets.
* WOLFSSL_TICKET_ENC_CHACHA20_POLY1305
* Use ChaCha20-Poly1305 to encrypt/decrypt session tickets in default
* callback. Default algorithm if none defined and algorithms compiled in.
* Server only.
* WOLFSSL_TICKET_ENC_AES128_GCM
* Use AES128-GCM to encrypt/decrypt session tickets in default callback.
* Server only. Default algorithm if ChaCha20/Poly1305 not compiled in.
* WOLFSSL_TICKET_ENC_AES256_GCM
* Use AES256-GCM to encrypt/decrypt session tickets in default callback.
* Server only.
* WOLFSSL_TICKET_DECRYPT_NO_CREATE
* Default callback will not request creation of new ticket on successful
* decryption.
* Server only.
*/
@ -129,10 +147,25 @@ WOLFSSL_CALLBACKS needs LARGE_STATIC_BUFFERS, please add LARGE_STATIC_BUFFERS
#ifdef WOLFSSL_DTLS
static int SendHelloVerifyRequest(WOLFSSL*, const byte*, byte);
#endif /* WOLFSSL_DTLS */
#endif
#endif /* !NO_WOLFSSL_SERVER */
#endif /* !WOLFSSL_NO_TLS12 */
#ifndef NO_WOLFSSL_SERVER
#if defined(HAVE_SESSION_TICKET) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB)
static int TicketEncCbCtx_Init(WOLFSSL_CTX* ctx,
TicketEncCbCtx* keyCtx);
static void TicketEncCbCtx_Free(TicketEncCbCtx* keyCtx);
static int DefTicketEncCb(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* userCtx);
#endif
#endif
#ifdef WOLFSSL_DTLS
static WC_INLINE int DtlsCheckWindow(WOLFSSL* ssl);
static WC_INLINE int DtlsUpdateWindow(WOLFSSL* ssl);
@ -1781,6 +1814,12 @@ int InitSSL_Ctx(WOLFSSL_CTX* ctx, WOLFSSL_METHOD* method, void* heap)
#endif /* HAVE_EXTENDED_MASTER && !NO_WOLFSSL_CLIENT */
#if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_SERVER)
#ifndef WOLFSSL_NO_DEF_TICKET_ENC_CB
ret = TicketEncCbCtx_Init(ctx, &ctx->ticketKeyCtx);
if (ret != 0) return ret;
ctx->ticketEncCb = DefTicketEncCb;
ctx->ticketEncCtx = (void*)&ctx->ticketKeyCtx;
#endif
ctx->ticketHint = SESSION_TICKET_HINT_DEFAULT;
#endif
@ -1913,7 +1952,7 @@ void SSL_CtxResourceFree(WOLFSSL_CTX* ctx)
#ifdef HAVE_ECC
if (ctx->staticKE.ecKey)
FreeDer(&ctx->staticKE.ecKey);
#endif
#endif
#endif
#ifdef WOLFSSL_STATIC_MEMORY
if (ctx->heap != NULL) {
@ -1949,6 +1988,10 @@ void FreeSSL_Ctx(WOLFSSL_CTX* ctx)
void* heap = ctx->heap;
WOLFSSL_MSG("CTX ref count down to 0, doing full free");
SSL_CtxResourceFree(ctx);
#if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_SERVER) && \
!defined(WOLFSSL_NO_DEF_TICKET_ENC_CB)
TicketEncCbCtx_Free(&ctx->ticketKeyCtx);
#endif
wc_FreeMutex(&ctx->countMutex);
#ifdef WOLFSSL_STATIC_MEMORY
if (ctx->onHeap == 0) {
@ -12970,7 +13013,6 @@ static int DoHandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
else {
ShrinkInputBuffer(ssl, NO_FORCED_FREE);
}
}
#if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLFSSL_NONBLOCK_OCSP)
@ -17138,7 +17180,7 @@ int CreateOcspResponse(WOLFSSL* ssl, OcspRequest** ocspRequest,
#endif /* !NO_WOLFSSL_SERVER */
#if (!defined(WOLFSSL_NO_TLS12) && !defined(NO_CERTS)) \
|| defined(HAVE_SESSION_TICKET)
|| (defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_SERVER))
static int cipherExtraData(WOLFSSL* ssl)
{
/* Cipher data that may be added by BuildMessage */
@ -29146,6 +29188,435 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
return ret;
}
#ifndef WOLFSSL_NO_DEF_TICKET_ENC_CB
/* Initialize the context for session ticket encryption.
*
* @param [in] ctx SSL context.
* @param [in] keyCtx Context for session ticket encryption.
* @return 0 on success.
* @return BAD_MUTEX_E when initializing mutex fails.
*/
static int TicketEncCbCtx_Init(WOLFSSL_CTX* ctx, TicketEncCbCtx* keyCtx)
{
int ret = 0;
XMEMSET(keyCtx, 0, sizeof(*keyCtx));
keyCtx->ctx = ctx;
#ifndef SINGLE_THREADED
ret = wc_InitMutex(&keyCtx->mutex);
#endif
return ret;
}
/* Setup the session ticket encryption context for this.
*
* Initialize RNG, generate name, generate primeary key and set primary key
* expirary.
*
* @param [in] keyCtx Context for session ticket encryption.
* @param [in] heap Dynamic memory allocation hint.
* @param [in] devId Device identifier.
* @return 0 on success.
* @return Other value when random number generator fails.
*/
static int TicketEncCbCtx_Setup(TicketEncCbCtx* keyCtx, void* heap, int devId)
{
int ret;
#ifndef SINGLE_THREADED
ret = 0;
/* Check that key wasn't set up while waiting. */
if (keyCtx->expirary[0] == 0)
#endif
{
ret = wc_InitRng_ex(&keyCtx->rng, heap, devId);
if (ret == 0) {
ret = wc_RNG_GenerateBlock(&keyCtx->rng, keyCtx->name,
sizeof(keyCtx->name));
}
if (ret == 0) {
/* Mask of the bottom bit - used for index of key. */
keyCtx->name[WOLFSSL_TICKET_NAME_SZ - 1] &= 0xfe;
/* Generate initial primary key. */
ret = wc_RNG_GenerateBlock(&keyCtx->rng, keyCtx->key[0],
WOLFSSL_TICKET_KEY_SZ);
}
if (ret == 0) {
keyCtx->expirary[0] = LowResTimer() + WOLFSSL_TICKET_KEY_LIFETIME;
}
}
return ret;
}
/* Free the context for session ticket encryption.
*
* Zeroize keys and name.
*
* @param [in] keyCtx Context for session ticket encryption.
*/
static void TicketEncCbCtx_Free(TicketEncCbCtx* keyCtx)
{
/* Zeroize sensitive data. */
ForceZero(keyCtx->name, sizeof(keyCtx->name));
ForceZero(keyCtx->key[0], sizeof(keyCtx->key[0]));
ForceZero(keyCtx->key[1], sizeof(keyCtx->key[1]));
#ifndef SINGLE_THREADED
wc_FreeMutex(&keyCtx->mutex);
#endif
wc_FreeRng(&keyCtx->rng);
}
#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) && \
!defined(WOLFSSL_TICKET_ENC_AES128_GCM) && \
!defined(WOLFSSL_TICKET_ENC_AES256_GCM)
/* Ticket encryption/decryption implementation.
*
* @param [in] key Key for encryption/decryption.
* @param [in] keyLen Length of key in bytes.
* @param [in] iv IV/Nonce for encryption/decryption.
* @param [in] aad Additional authentication data.
* @param [in] aadSz Length of additional authentication data.
* @param [in] in Data to encrypt/decrypt.
* @param [in] inLen Length of encrypted data.
* @param [out] out Resulting data from encrypt/decrypt.
* @param [out] outLen Size of resulting data.
* @param [in] tag Authentication tag for encrypted data.
* @param [in] heap Dynamic memory allocation data hint.
* @param [in] enc 1 when encrypting, 0 when decrypting.
* @return 0 on success.
* @return Other value when encryption/decryption fails.
*/
static int TicketEncDec(byte* key, int keyLen, byte* iv, byte* aad, int aadSz,
byte* in, int inLen, byte* out, int* outLen, byte* tag,
void* heap, int enc)
{
int ret;
(void)keyLen;
(void)heap;
if (enc) {
ret = wc_ChaCha20Poly1305_Encrypt(key, iv, aad, aadSz, in, inLen, out,
tag);
}
else {
ret = wc_ChaCha20Poly1305_Decrypt(key, iv, aad, aadSz, in, inLen, tag,
out);
}
*outLen = inLen;
return ret;
}
#elif defined(HAVE_AESGCM)
/* Ticket encryption/decryption implementation.
*
* @param [in] key Key for encryption/decryption.
* @param [in] keyLen Length of key in bytes.
* @param [in] iv IV/Nonce for encryption/decryption.
* @param [in] aad Additional authentication data.
* @param [in] aadSz Length of additional authentication data.
* @param [in] in Data to encrypt/decrypt.
* @param [in] inLen Length of encrypted data.
* @param [out] out Resulting data from encrypt/decrypt.
* @param [out] outLen Size of resulting data.
* @param [in] tag Authentication tag for encrypted data.
* @param [in] heap Dynamic memory allocation data hint.
* @param [in] enc 1 when encrypting, 0 when decrypting.
* @return 0 on success.
* @return MEMORY_E when dynamic memory allocation fails.
* @return Other value when encryption/decryption fails.
*/
static int TicketEncDec(byte* key, int keyLen, byte* iv, byte* aad, int aadSz,
byte* in, int inLen, byte* out, int* outLen, byte* tag,
void* heap, int enc)
{
int ret;
#ifdef WOLFSSL_SMALL_STACK
Aes* aes;
#else
Aes aes[1];
#endif
(void)heap;
#ifdef WOLFSSL_SMALL_STACK
aes = (Aes*)XMALLOC(sizeof(Aes), heap, DYNAMIC_TYPE_TMP_BUFFER);
if (aes == NULL)
return MEMORY_E;
#endif
if (enc) {
ret = wc_AesInit(aes, NULL, INVALID_DEVID);
if (ret == 0) {
ret = wc_AesGcmSetKey(aes, key, keyLen);
}
if (ret == 0) {
ret = wc_AesGcmEncrypt(aes, in, out, inLen, iv, GCM_NONCE_MID_SZ,
tag, AES_BLOCK_SIZE, aad, aadSz);
}
wc_AesFree(aes);
}
else {
ret = wc_AesInit(aes, NULL, INVALID_DEVID);
if (ret == 0) {
ret = wc_AesGcmSetKey(aes, key, keyLen);
}
if (ret == 0) {
ret = wc_AesGcmDecrypt(aes, in, out, inLen, iv, GCM_NONCE_MID_SZ,
tag, AES_BLOCK_SIZE, aad, aadSz);
}
wc_AesFree(aes);
}
#ifdef WOLFSSL_SMALL_STACK
XFREE(aes, heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
*outLen = inLen;
return ret;
}
#else
#error "No encryption algorithm available for default ticket encryption."
#endif
/* Choose a key to use for encryption.
*
* Generate a new key if the current ones are expired.
* If the secondary key has not been used and the primary key has expired then
* generate a new primary key.
*
* @param [in] Ticket encryption callback context.
* @param [in] Session ticket lifetime.
* @param [out] Index of key to use for encryption.
* @return 0 on success.
* @return Other value when random number generation fails.
*/
static int TicketEncCbCtx_ChooseKey(TicketEncCbCtx* keyCtx, int ticketHint,
int* keyIdx)
{
int ret = 0;
/* Get new current time as lock may have taken some time. */
word32 now = LowResTimer();
/* Check expirary of primary key for encrypt. */
if (keyCtx->expirary[0] >= now + ticketHint) {
*keyIdx = 0;
}
/* Check expirary of primary key for encrypt. */
else if (keyCtx->expirary[1] >= now + ticketHint) {
*keyIdx = 1;
}
/* No key available to use. */
else {
int genKey;
/* Generate which ever key is expired for decrypt - primary first. */
if (keyCtx->expirary[0] < now) {
genKey = 0;
}
else if (keyCtx->expirary[1] < now) {
genKey = 1;
}
/* Timeouts and expirary should not allow this to happen. */
else {
return BAD_STATE_E;
}
/* Generate the required key */
ret = wc_RNG_GenerateBlock(&keyCtx->rng, keyCtx->key[genKey],
WOLFSSL_TICKET_KEY_SZ);
if (ret == 0) {
keyCtx->expirary[genKey] = now + WOLFSSL_TICKET_KEY_LIFETIME;
*keyIdx = genKey;
}
}
return ret;
}
/* Default Session Ticket encryption/decryption callback.
*
* Use ChaCha20-Poly1305 or AES-GCM to encrypt/decrypt the ticket.
* Two keys are used:
* - When the first expires for encryption, then use the other.
* - Don't encrypt with key if the ticket lifetime will go beyond expirary.
* - Generate a new primary key when primary key expired for decrypt and
* no secondary key is activate for encryption.
* - Generate a new secondary key when expired and needed.
* - Calculate expirary starting from first encrypted ticket.
* - Key name has last bit set to indicate index of key.
* Keys expire for decryption after ticket key lifetime from the first encrypted
* ticket.
* Keys can only be use for encryption while the ticket hint does not exceed
* the key lifetime.
* Lifetime of a key must be greater than the lifetime of a ticket. This means
* that if one ticket is only valid for decryption, then the other will be
* valid for encryption.
* AAD = key_name | iv | ticket len (16-bits network order)
*
* @param [in] ssl SSL connection.
* @param [in,out] key_name Name of key from client.
* Encrypt: name of key returned.
* Decrypt: name from ticket message to check.
* @param [in] iv IV to use in encryption/decryption.
* @param [in] mac MAC for authentication of encrypted data.
* @param [in] enc 1 when encrypting ticket, 0 when decrypting.
* @param [in,out] ticket Encrypted/decrypted session ticket bytes.
* @param [in] inLen Length of incoming ticket.
* @param [out] outLen Length of outgoing ticket.
* @param [in] userCtx Context for encryption/decryption of ticket.
* @return WOLFSSL_TICKET_RET_OK when successful.
* @return WOLFSSL_TICKET_RET_CREATE when successful and a new ticket is to
* be created for TLS 1.2 and below.
* @return WOLFSSL_TICKET_RET_REJECT when failed to produce valid encrypted or
* decrypted ticket.
* @return WOLFSSL_TICKET_RET_FATAL when key name does not match.
*/
static int DefTicketEncCb(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* userCtx)
{
int ret;
TicketEncCbCtx* keyCtx = (TicketEncCbCtx*)userCtx;
WOLFSSL_CTX* ctx = keyCtx->ctx;
word16 sLen = XHTONS(inLen);
byte aad[WOLFSSL_TICKET_NAME_SZ + WOLFSSL_TICKET_IV_SZ + sizeof(sLen)];
int aadSz = WOLFSSL_TICKET_NAME_SZ + WOLFSSL_TICKET_IV_SZ + sizeof(sLen);
byte* p = aad;
int keyIdx = 0;
/* Check we have setup the RNG, name and primary key. */
if (keyCtx->expirary[0] == 0) {
#ifndef SINGLE_THREADED
/* Lock around access to expirary and key - stop initial key being
* generated twice at the same time. */
if (wc_LockMutex(&keyCtx->mutex) != 0) {
WOLFSSL_MSG("Couldn't lock key context mutex");
return WOLFSSL_TICKET_RET_REJECT;
}
#endif
/* Sets expirary of primary key in setup. */
ret = TicketEncCbCtx_Setup(keyCtx, ssl->ctx->heap, ssl->ctx->devId);
#ifndef SINGLE_THREADED
wc_UnLockMutex(&keyCtx->mutex);
#endif
if (ret != 0)
return ret;
}
if (enc) {
/* Return the name of the key - missing key index. */
XMEMCPY(key_name, keyCtx->name, WOLFSSL_TICKET_NAME_SZ);
/* Generate a new IV into buffer to be returned.
* Don't use the RNG in keyCtx as it's for generating private data. */
ret = wc_RNG_GenerateBlock(ssl->rng, iv, WOLFSSL_TICKET_IV_SZ);
if (ret != 0) {
return WOLFSSL_TICKET_RET_REJECT;
}
}
else {
/* Mask of last bit that is the key index. */
byte lastByte = key_name[WOLFSSL_TICKET_NAME_SZ - 1] & 0xfe;
/* For decryption, see if we know this key - check all but last byte. */
if (XMEMCMP(key_name, keyCtx->name, WOLFSSL_TICKET_NAME_SZ - 1) != 0) {
return WOLFSSL_TICKET_RET_FATAL;
}
/* Ensure last byte without index bit matches too. */
if (lastByte != keyCtx->name[WOLFSSL_TICKET_NAME_SZ - 1]) {
return WOLFSSL_TICKET_RET_FATAL;
}
}
/* Build AAD from: key name, iv, and length of ticket. */
XMEMCPY(p, keyCtx->name, WOLFSSL_TICKET_NAME_SZ);
p += WOLFSSL_TICKET_NAME_SZ;
XMEMCPY(p, iv, WOLFSSL_TICKET_IV_SZ);
p += WOLFSSL_TICKET_IV_SZ;
XMEMCPY(p, &sLen, sizeof(sLen));
/* Encrypt ticket. */
if (enc) {
word32 now;
now = LowResTimer();
/* As long as encryption expirary isn't imminent - no lock. */
if (keyCtx->expirary[0] > now + ctx->ticketHint) {
keyIdx = 0;
}
else if (keyCtx->expirary[1] > now + ctx->ticketHint) {
keyIdx = 1;
}
else {
#ifndef SINGLE_THREADED
/* Lock around access to expirary and key - stop key being generated
* twice at the same time. */
if (wc_LockMutex(&keyCtx->mutex) != 0) {
WOLFSSL_MSG("Couldn't lock key context mutex");
return WOLFSSL_TICKET_RET_REJECT;
}
#endif
ret = TicketEncCbCtx_ChooseKey(keyCtx, ctx->ticketHint, &keyIdx);
#ifndef SINGLE_THREADED
wc_UnLockMutex(&keyCtx->mutex);
#endif
if (ret != 0) {
return WOLFSSL_TICKET_RET_REJECT;
}
}
/* Set the name of the key to the index chosen. */
key_name[WOLFSSL_TICKET_NAME_SZ - 1] |= keyIdx;
/* Update AAD too. */
aad[WOLFSSL_TICKET_NAME_SZ - 1] |= keyIdx;
/* Encrypt ticket data. */
ret = TicketEncDec(keyCtx->key[keyIdx], WOLFSSL_TICKET_KEY_SZ, iv, aad,
aadSz, ticket, inLen, ticket, outLen, mac, ssl->heap,
1);
if (ret != 0) return WOLFSSL_TICKET_RET_REJECT;
}
/* Decrypt ticket. */
else {
/* Get index of key from name. */
keyIdx = key_name[WOLFSSL_TICKET_NAME_SZ - 1] & 0x1;
/* Update AAD with index. */
aad[WOLFSSL_TICKET_NAME_SZ - 1] |= keyIdx;
/* Check expirary */
if (keyCtx->expirary[keyIdx] <= LowResTimer()) {
return WOLFSSL_TICKET_RET_REJECT;
}
/* Decrypt ticket data. */
ret = TicketEncDec(keyCtx->key[keyIdx], WOLFSSL_TICKET_KEY_SZ, iv, aad,
aadSz, ticket, inLen, ticket, outLen, mac, ssl->heap,
0);
if (ret != 0) {
return WOLFSSL_TICKET_RET_REJECT;
}
}
#ifndef WOLFSSL_TICKET_DECRYPT_NO_CREATE
if (!IsAtLeastTLSv1_3(ssl->version) && !enc)
return WOLFSSL_TICKET_RET_CREATE;
#endif
return WOLFSSL_TICKET_RET_OK;
}
#endif /* !WOLFSSL_NO_DEF_TICKET_ENC_CB */
#endif /* HAVE_SESSION_TICKET */
#ifndef WOLFSSL_NO_TLS12
@ -29839,9 +30310,9 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
ssl->arrays->preMasterSz = private_key->dp->size;
ssl->peerEccKeyPresent = 1;
#if defined(WOLFSSL_TLS13) || defined(HAVE_FFDHE)
/* client_hello may have sent FFEDH2048, which sets namedGroup,
/* client_hello may have sent FFEDH2048, which sets namedGroup,
but that is not being used, so clear it */
/* resolves issue with server side wolfSSL_get_curve_name */
ssl->namedGroup = 0;

View File

@ -47412,11 +47412,79 @@ int wolfSSL_CTX_set_tlsext_ticket_key_cb(WOLFSSL_CTX *ctx, int (*cb)(
return WOLFSSL_SUCCESS;
}
#endif /* HAVE_SESSION_TICKET */
#endif /* OPENSSL_ALL || WOLFSSL_NGINX || WOLFSSL_HAPROXY ||
OPENSSL_EXTRA || HAVE_LIGHTY */
#if defined(HAVE_SESSION_TICKET) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
!defined(NO_WOLFSSL_SERVER)
/* Serialize the session ticket encryption keys.
*
* @param [in] ctx SSL/TLS context object.
* @param [in] keys Buffer to hold session ticket keys.
* @param [in] keylen Length of buffer.
* @return WOLFSSL_SUCCESS on success.
* @return WOLFSSL_FAILURE when ctx is NULL, keys is NULL or keylen is not the
* correct length.
*/
long wolfSSL_CTX_get_tlsext_ticket_keys(WOLFSSL_CTX *ctx,
unsigned char *keys, int keylen)
{
if (ctx == NULL || keys == NULL) {
return WOLFSSL_FAILURE;
}
if (keylen != WOLFSSL_TICKET_KEYS_SZ) {
return WOLFSSL_FAILURE;
}
XMEMCPY(keys, ctx->ticketKeyCtx.name, WOLFSSL_TICKET_NAME_SZ);
keys += WOLFSSL_TICKET_NAME_SZ;
XMEMCPY(keys, ctx->ticketKeyCtx.key[0], WOLFSSL_TICKET_KEY_SZ);
keys += WOLFSSL_TICKET_KEY_SZ;
XMEMCPY(keys, ctx->ticketKeyCtx.key[1], WOLFSSL_TICKET_KEY_SZ);
keys += WOLFSSL_TICKET_KEY_SZ;
c32toa(ctx->ticketKeyCtx.expirary[0], keys);
keys += OPAQUE32_LEN;
c32toa(ctx->ticketKeyCtx.expirary[1], keys);
return WOLFSSL_SUCCESS;
}
/* Deserialize the session ticket encryption keys.
*
* @param [in] ctx SSL/TLS context object.
* @param [in] keys Session ticket keys.
* @param [in] keylen Length of data.
* @return WOLFSSL_SUCCESS on success.
* @return WOLFSSL_FAILURE when ctx is NULL, keys is NULL or keylen is not the
* correct length.
*/
long wolfSSL_CTX_set_tlsext_ticket_keys(WOLFSSL_CTX *ctx,
unsigned char *keys, int keylen)
{
if (ctx == NULL || keys == NULL) {
return WOLFSSL_FAILURE;
}
if (keylen != WOLFSSL_TICKET_KEYS_SZ) {
return WOLFSSL_FAILURE;
}
XMEMCPY(ctx->ticketKeyCtx.name, keys, WOLFSSL_TICKET_NAME_SZ);
keys += WOLFSSL_TICKET_NAME_SZ;
XMEMCPY(ctx->ticketKeyCtx.key[0], keys, WOLFSSL_TICKET_KEY_SZ);
keys += WOLFSSL_TICKET_KEY_SZ;
XMEMCPY(ctx->ticketKeyCtx.key[1], keys, WOLFSSL_TICKET_KEY_SZ);
keys += WOLFSSL_TICKET_KEY_SZ;
ato32(keys, &ctx->ticketKeyCtx.expirary[0]);
keys += OPAQUE32_LEN;
ato32(keys, &ctx->ticketKeyCtx.expirary[1]);
return WOLFSSL_SUCCESS;
}
#endif
#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
#ifdef HAVE_OCSP
/* Not an OpenSSL API. */

View File

@ -2646,9 +2646,8 @@ static THREAD_RETURN WOLFSSL_THREAD test_server_nofail(void* args)
ctx = wolfSSL_CTX_new(method);
}
#if defined(HAVE_SESSION_TICKET) && \
((defined(HAVE_CHACHA) && defined(HAVE_POLY1305)) || \
defined(HAVE_AESGCM))
#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
((defined(HAVE_CHACHA) && defined(HAVE_POLY1305)) || defined(HAVE_AESGCM))
TicketInit();
wolfSSL_CTX_set_TicketEncCb(ctx, myTicketEncCb);
#endif
@ -2834,8 +2833,8 @@ done:
wc_ecc_fp_free(); /* free per thread cache */
#endif
#if defined(HAVE_SESSION_TICKET) && defined(HAVE_CHACHA) && \
defined(HAVE_POLY1305)
#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
((defined(HAVE_CHACHA) && defined(HAVE_POLY1305)) || defined(HAVE_AESGCM))
TicketCleanup();
#endif
@ -31678,6 +31677,53 @@ static void test_wolfSSL_SESSION(void)
#endif
}
static void test_wolfSSL_ticket_keys(void)
{
#if defined(HAVE_SESSION_TICKET) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
!defined(NO_WOLFSSL_SERVER)
WOLFSSL_CTX* ctx;
byte keys[WOLFSSL_TICKET_KEYS_SZ];
AssertNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
AssertIntEQ(wolfSSL_CTX_get_tlsext_ticket_keys(NULL, NULL, 0),
WOLFSSL_FAILURE);
AssertIntEQ(wolfSSL_CTX_get_tlsext_ticket_keys(ctx, NULL, 0),
WOLFSSL_FAILURE);
AssertIntEQ(wolfSSL_CTX_get_tlsext_ticket_keys(ctx, keys, 0),
WOLFSSL_FAILURE);
AssertIntEQ(wolfSSL_CTX_get_tlsext_ticket_keys(NULL, keys, 0),
WOLFSSL_FAILURE);
AssertIntEQ(wolfSSL_CTX_get_tlsext_ticket_keys(NULL, NULL, sizeof(keys)),
WOLFSSL_FAILURE);
AssertIntEQ(wolfSSL_CTX_get_tlsext_ticket_keys(ctx, NULL, sizeof(keys)),
WOLFSSL_FAILURE);
AssertIntEQ(wolfSSL_CTX_get_tlsext_ticket_keys(NULL, keys, sizeof(keys)),
WOLFSSL_FAILURE);
AssertIntEQ(wolfSSL_CTX_set_tlsext_ticket_keys(NULL, NULL, 0),
WOLFSSL_FAILURE);
AssertIntEQ(wolfSSL_CTX_set_tlsext_ticket_keys(ctx, NULL, 0),
WOLFSSL_FAILURE);
AssertIntEQ(wolfSSL_CTX_set_tlsext_ticket_keys(ctx, keys, 0),
WOLFSSL_FAILURE);
AssertIntEQ(wolfSSL_CTX_set_tlsext_ticket_keys(NULL, keys, 0),
WOLFSSL_FAILURE);
AssertIntEQ(wolfSSL_CTX_set_tlsext_ticket_keys(NULL, NULL, sizeof(keys)),
WOLFSSL_FAILURE);
AssertIntEQ(wolfSSL_CTX_set_tlsext_ticket_keys(ctx, NULL, sizeof(keys)),
WOLFSSL_FAILURE);
AssertIntEQ(wolfSSL_CTX_set_tlsext_ticket_keys(NULL, keys, sizeof(keys)),
WOLFSSL_FAILURE);
AssertIntEQ(wolfSSL_CTX_get_tlsext_ticket_keys(ctx, keys, sizeof(keys)),
WOLFSSL_SUCCESS);
AssertIntEQ(wolfSSL_CTX_set_tlsext_ticket_keys(ctx, keys, sizeof(keys)),
WOLFSSL_SUCCESS);
wolfSSL_CTX_free(ctx);
#endif
}
#ifndef NO_BIO
@ -40312,6 +40358,7 @@ void ApiTest(void)
test_wolfSSL_BIO_f_md();
#endif
test_wolfSSL_SESSION();
test_wolfSSL_ticket_keys();
test_wolfSSL_DES_ecb_encrypt();
test_wolfSSL_sk_GENERAL_NAME();
test_wolfSSL_MD4();

View File

@ -114,6 +114,15 @@
#ifdef HAVE_CURVE448
#include <wolfssl/wolfcrypt/curve448.h>
#endif
#ifndef WOLFSSL_NO_DEF_TICKET_ENC_CB
#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) && \
!defined(WOLFSSL_TICKET_ENC_AES128_GCM) && \
!defined(WOLFSSL_TICKET_ENC_AES256_GCM)
#include <wolfssl/wolfcrypt/chacha20_poly1305.h>
#else
#include <wolfssl/wolfcrypt/aes.h>
#endif
#endif
#include <wolfssl/wolfcrypt/wc_encrypt.h>
#include <wolfssl/wolfcrypt/hash.h>
@ -1585,6 +1594,26 @@ enum Misc {
#define SESSION_TICKET_HINT_DEFAULT 300
#endif
#if !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && !defined(WOLFSSL_NO_SERVER)
/* Check chosen encryption is available. */
#if !(defined(HAVE_CHACHA) && defined(HAVE_POLY1305)) && \
defined(WOLFSSL_TICKET_ENC_CHACHA20_POLY1305)
#error "ChaCha20-Poly1305 not availble for default ticket encryption"
#endif
#if !defined(HAVE_AESGCM) && (defined(WOLFSSL_TICKET_ENC_AES128_GCM) || \
defined(WOLFSSL_TICKET_ENC_AES256_GCM))
#error "AES-GCM not availble for default ticket encryption"
#endif
#ifndef WOLFSSL_TICKET_KEY_LIFETIME
/* Default lifetime is 1 hour from issue of first ticket with key. */
#define WOLFSSL_TICKET_KEY_LIFETIME (60 * 60)
#endif
#if WOLFSSL_TICKET_KEY_LIFETIME <= SESSION_TICKET_HINT_DEFAULT
#error "Ticket Key lifetime must be longer than ticket life hint."
#endif
#endif
/* don't use extra 3/4k stack space unless need to */
#ifdef HAVE_NTRU
@ -2473,6 +2502,28 @@ typedef struct SessionTicket {
word16 size;
} SessionTicket;
#if !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && !defined(WOLFSSL_NO_SERVER)
/* Data passed to default SessionTicket enc/dec callback. */
typedef struct TicketEncCbCtx {
/* Name for this context. */
byte name[WOLFSSL_TICKET_NAME_SZ];
/* Current keys - current and next. */
byte key[2][WOLFSSL_TICKET_KEY_SZ];
/* Expirary date of keys. */
word32 expirary[2];
/* Random number generator to use for generating name, keys and IV. */
WC_RNG rng;
#ifndef SINGLE_THREADED
/* Mutex for access to changing keys. */
wolfSSL_Mutex mutex;
#endif
/* Pointer back to SSL_CTX. */
WOLFSSL_CTX* ctx;
} TicketEncCbCtx;
#endif /* !WOLFSSL_NO_DEF_TICKET_ENC_CB && !WOLFSSL_NO_SERVER */
WOLFSSL_LOCAL int TLSX_UseSessionTicket(TLSX** extensions,
SessionTicket* ticket, void* heap);
WOLFSSL_LOCAL SessionTicket* TLSX_SessionTicket_Create(word32 lifetime,
@ -2868,6 +2919,9 @@ struct WOLFSSL_CTX {
SessionTicketEncCb ticketEncCb; /* enc/dec session ticket Cb */
void* ticketEncCtx; /* session encrypt context */
int ticketHint; /* ticket hint in seconds */
#ifndef WOLFSSL_NO_DEF_TICKET_ENC_CB
TicketEncCbCtx ticketKeyCtx;
#endif
#endif
#ifdef HAVE_SUPPORTED_CURVES
byte userCurves; /* indicates user called wolfSSL_CTX_UseSupportedCurve */

View File

@ -1069,6 +1069,9 @@ wolfSSL_X509_STORE_set_verify_cb((WOLFSSL_X509_STORE *)(s), (WOLFSSL_X509_STORE_
#define SSL_get_tlsext_status_exts wolfSSL_get_tlsext_status_exts
#define SSL_CTX_get_tlsext_ticket_keys wolfSSL_CTX_get_tlsext_ticket_keys
#define SSL_CTX_set_tlsext_ticket_keys wolfSSL_CTX_set_tlsext_ticket_keys
#define SSL_CTRL_CLEAR_NUM_RENEGOTIATIONS 11
#define SSL_CTRL_GET_TOTAL_RENEGOTIATIONS 12
#define SSL_CTRL_SET_TMP_DH 3

View File

@ -3193,6 +3193,22 @@ WOLFSSL_API long wolfSSL_SSL_get_secure_renegotiation_support(WOLFSSL* ssl);
/* Session Ticket */
#ifdef HAVE_SESSION_TICKET
#if !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && !defined(WOLFSSL_NO_SERVER)
#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) && \
!defined(WOLFSSL_TICKET_ENC_AES128_GCM) && \
!defined(WOLFSSL_TICKET_ENC_AES256_GCM)
#define WOLFSSL_TICKET_KEY_SZ CHACHA20_POLY1305_AEAD_KEYSIZE
#elif defined(WOLFSSL_TICKET_ENC_AES256_GCM)
#define WOLFSSL_TICKET_KEY_SZ AES_256_KEY_SIZE
#else
#define WOLFSSL_TICKET_KEY_SZ AES_128_KEY_SIZE
#endif
#define WOLFSSL_TICKET_KEYS_SZ (WOLFSSL_TICKET_NAME_SZ + \
2 * WOLFSSL_TICKET_KEY_SZ + \
sizeof(word32) * 2)
#endif
#ifndef NO_WOLFSSL_CLIENT
WOLFSSL_API int wolfSSL_UseSessionTicket(WOLFSSL* ssl);
WOLFSSL_API int wolfSSL_CTX_UseSessionTicket(WOLFSSL_CTX* ctx);
@ -3987,6 +4003,14 @@ WOLFSSL_API int PEM_write_bio_WOLFSSL_X509(WOLFSSL_BIO *bio,
#endif /* OPENSSL_ALL || WOLFSSL_NGINX || WOLFSSL_HAPROXY ||
OPENSSL_EXTRA || HAVE_LIGHTY */
#if defined(HAVE_SESSION_TICKET) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
!defined(NO_WOLFSSL_SERVER)
WOLFSSL_API long wolfSSL_CTX_get_tlsext_ticket_keys(WOLFSSL_CTX *ctx,
unsigned char *keys, int keylen);
WOLFSSL_API long wolfSSL_CTX_set_tlsext_ticket_keys(WOLFSSL_CTX *ctx,
unsigned char *keys, int keylen);
#endif
WOLFSSL_API void wolfSSL_get0_alpn_selected(const WOLFSSL *ssl,
const unsigned char **data, unsigned int *len);
WOLFSSL_API int wolfSSL_select_next_proto(unsigned char **out,

View File

@ -3926,7 +3926,7 @@ static WC_INLINE const char* mymktemp(char *tempfn, int len, int num)
#if defined(HAVE_SESSION_TICKET) && \
#if defined(HAVE_SESSION_TICKET) && defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && \
((defined(HAVE_CHACHA) && defined(HAVE_POLY1305)) || \
defined(HAVE_AESGCM))