diff --git a/cyassl/internal.h b/cyassl/internal.h index 29fe4df2d..e02432dc4 100644 --- a/cyassl/internal.h +++ b/cyassl/internal.h @@ -1233,7 +1233,7 @@ typedef enum { MAX_FRAGMENT_LENGTH = 0x0001, TRUNCATED_HMAC = 0x0004, ELLIPTIC_CURVES = 0x000a, - /*SESSION_TICKET = 0x0023, not used yet in switch statements */ + SESSION_TICKET = 0x0023, SECURE_RENEGOTIATION = 0xff01 } TLSX_Type; @@ -1317,7 +1317,6 @@ CYASSL_LOCAL int TLSX_UseTruncatedHMAC(TLSX** extensions); typedef struct EllipticCurve { word16 name; /* CurveNames */ struct EllipticCurve* next; /* List Behavior */ - } EllipticCurve; CYASSL_LOCAL int TLSX_UseSupportedCurve(TLSX** extensions, word16 name); @@ -1354,6 +1353,20 @@ CYASSL_LOCAL int TLSX_UseSecureRenegotiation(TLSX** extensions); #endif /* HAVE_SECURE_RENEGOTIATION */ +#ifdef HAVE_SESSION_TICKET + +typedef struct SessionTicket { + word32 lifetime; + byte* data; + word16 size; +} SessionTicket; + +CYASSL_LOCAL int TLSX_UseSessionTicket(TLSX** extensions, + SessionTicket* ticket); +CYASSL_LOCAL SessionTicket* TLSX_SessionTicket_Create(word32 lifetime, + byte* data, word16 size); +CYASSL_LOCAL void TLSX_SessionTicket_Free(SessionTicket* ticket); +#endif /* HAVE_SESSION_TICKET */ /* CyaSSL context type */ struct CYASSL_CTX { @@ -2043,6 +2056,23 @@ struct CYASSL { #ifdef HAVE_SECURE_RENEGOTIATION SecureRenegotiation* secure_renegotiation; /* valid pointer indicates */ #endif /* user turned on */ + #ifdef HAVE_SESSION_TICKET + #ifndef NO_CYASSL_CLIENT + /* + Create cantidate_ticket when processing New Session Ticket Handshake + Message. When the ticket is validated at Finished Handshake Message, + move canditate_ticket to session_ticket and call: + TLSX_UseSessionTicket(&ssl->extensions, ssl->session_ticket); + + If the session_ticket must be destroyed, call: + TLSX_UseSessionTicket(&ssl->extensions, NULL); + This function doesn't free an early ticket, but will erase it's + reference inside the extensions. + */ + SessionTicket* candidate_ticket; + SessionTicket* session_ticket; + #endif + #endif #endif /* HAVE_TLS_EXTENSIONS */ #ifdef HAVE_NETX NetX_Ctx nxCtx; /* NetX IO Context */ diff --git a/cyassl/ssl.h b/cyassl/ssl.h index 6416d5678..01b3f59cf 100644 --- a/cyassl/ssl.h +++ b/cyassl/ssl.h @@ -1316,7 +1316,17 @@ CYASSL_API int CyaSSL_CTX_UseSupportedCurve(CYASSL_CTX* ctx, CYASSL_API int CyaSSL_UseSecureRenegotiation(CYASSL* ssl); CYASSL_API int CyaSSL_Rehandshake(CYASSL* ssl); -#endif /* HAVE_SECURE_RENEGOTIATION */ +#endif + +/* Session Ticket */ +#ifdef HAVE_SESSION_TICKET +#ifndef NO_CYASSL_CLIENT + +CYASSL_API int CyaSSL_UseSessionTicket(CYASSL* ssl); +CYASSL_API int CyaSSL_CTX_UseSessionTicket(CYASSL_CTX* ctx); + +#endif +#endif #define CYASSL_CRL_MONITOR 0x01 /* monitor this dir flag */ #define CYASSL_CRL_START_MON 0x02 /* start monitoring flag */ diff --git a/examples/client/client.c b/examples/client/client.c index fa0a2ff95..a0fc02dcd 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -596,6 +596,10 @@ THREAD_RETURN CYASSL_THREAD client_test(void* args) if (CyaSSL_CTX_UseTruncatedHMAC(ctx) != SSL_SUCCESS) err_sys("UseTruncatedHMAC failed"); #endif +#ifdef HAVE_SESSION_TICKET + if (CyaSSL_CTX_UseSessionTicket(ctx) != SSL_SUCCESS) + err_sys("UseSessionTicket failed"); +#endif if (benchmark) { /* time passed in number of connects give average */ diff --git a/src/internal.c b/src/internal.c index c1321d662..45259945a 100644 --- a/src/internal.c +++ b/src/internal.c @@ -1745,6 +1745,12 @@ int InitSSL(CYASSL* ssl, CYASSL_CTX* ctx) #ifdef HAVE_SECURE_RENEGOTIATION ssl->secure_renegotiation = NULL; #endif +#ifdef HAVE_SESSION_TICKET +#ifndef NO_CYASSL_CLIENT + ssl->candidate_ticket = NULL; + ssl->session_ticket = NULL; +#endif +#endif #endif ssl->rng = NULL; @@ -2001,6 +2007,12 @@ void SSL_ResourceFree(CYASSL* ssl) #ifdef HAVE_TLS_EXTENSIONS TLSX_FreeAll(ssl->extensions); #endif +#ifdef HAVE_SESSION_TICKET +#ifndef NO_CYASSL_CLIENT + TLSX_SessionTicket_Free(ssl->candidate_ticket); + TLSX_SessionTicket_Free(ssl->session_ticket); +#endif +#endif #ifdef HAVE_NETX if (ssl->nxCtx.nxPacket) nx_packet_release(ssl->nxCtx.nxPacket); diff --git a/src/ssl.c b/src/ssl.c index 0f5357fb9..0b24273d9 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -796,6 +796,26 @@ int CyaSSL_Rehandshake(CYASSL* ssl) #endif /* HAVE_SECURE_RENEGOTIATION */ +/* Session Ticket */ +#ifdef HAVE_SESSION_TICKET +#ifndef NO_CYASSL_CLIENT +int CyaSSL_UseSessionTicket(CYASSL* ssl) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + return TLSX_UseSessionTicket(&ssl->extensions, NULL); +} + +int CyaSSL_CTX_UseSessionTicket(CYASSL_CTX* ctx) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; + + return TLSX_UseSessionTicket(&ctx->extensions, NULL); +} +#endif +#endif #ifndef CYASSL_LEANPSK diff --git a/src/tls.c b/src/tls.c index 06d1f53d9..70d34aa8e 100644 --- a/src/tls.c +++ b/src/tls.c @@ -1314,20 +1314,6 @@ int TLSX_UseMaxFragment(TLSX** extensions, byte mfl) #ifdef HAVE_TRUNCATED_HMAC -int TLSX_UseTruncatedHMAC(TLSX** extensions) -{ - int ret = 0; - - if (extensions == NULL) - return BAD_FUNC_ARG; - - if (!TLSX_Find(*extensions, TRUNCATED_HMAC)) - if ((ret = TLSX_Push(extensions, TRUNCATED_HMAC, NULL)) != 0) - return ret; - - return SSL_SUCCESS; -} - static int TLSX_THM_Parse(CYASSL* ssl, byte* input, word16 length, byte isRequest) { @@ -1349,6 +1335,19 @@ static int TLSX_THM_Parse(CYASSL* ssl, byte* input, word16 length, return 0; } +int TLSX_UseTruncatedHMAC(TLSX** extensions) +{ + int ret = 0; + + if (extensions == NULL) + return BAD_FUNC_ARG; + + if ((ret = TLSX_Push(extensions, TRUNCATED_HMAC, NULL)) != 0) + return ret; + + return SSL_SUCCESS; +} + #define THM_PARSE TLSX_THM_Parse #else @@ -1637,9 +1636,11 @@ int TLSX_UseSupportedCurve(TLSX** extensions, word16 name) #define EC_VALIDATE_REQUEST(a, b) #endif /* HAVE_SUPPORTED_CURVES */ + #ifdef HAVE_SECURE_RENEGOTIATION -static byte TLSX_SCR_GetSize(SecureRenegotiation* data, int isRequest) +static byte TLSX_SecureRenegotiation_GetSize(SecureRenegotiation* data, + int isRequest) { byte length = OPAQUE8_LEN; /* empty info length */ @@ -1655,8 +1656,8 @@ static byte TLSX_SCR_GetSize(SecureRenegotiation* data, int isRequest) return length; } -static word16 TLSX_SCR_Write(SecureRenegotiation* data, byte* output, - int isRequest) +static word16 TLSX_SecureRenegotiation_Write(SecureRenegotiation* data, + byte* output, int isRequest) { word16 offset = OPAQUE8_LEN; /* RenegotiationInfo length */ @@ -1677,8 +1678,8 @@ static word16 TLSX_SCR_Write(SecureRenegotiation* data, byte* output, return offset; } -static int TLSX_SCR_Parse(CYASSL* ssl, byte* input, word16 length, - byte isRequest) +static int TLSX_SecureRenegotiation_Parse(CYASSL* ssl, byte* input, + word16 length, byte isRequest) { int ret = SECURE_RENEGOTIATION_E; @@ -1745,9 +1746,9 @@ int TLSX_UseSecureRenegotiation(TLSX** extensions) #define SCR_FREE_ALL(data) XFREE(data, NULL, DYNAMIC_TYPE_TLSX) -#define SCR_GET_SIZE TLSX_SCR_GetSize -#define SCR_WRITE TLSX_SCR_Write -#define SCR_PARSE TLSX_SCR_Parse +#define SCR_GET_SIZE TLSX_SecureRenegotiation_GetSize +#define SCR_WRITE TLSX_SecureRenegotiation_Write +#define SCR_PARSE TLSX_SecureRenegotiation_Parse #else @@ -1758,6 +1759,116 @@ int TLSX_UseSecureRenegotiation(TLSX** extensions) #endif /* HAVE_SECURE_RENEGOTIATION */ +#ifdef HAVE_SESSION_TICKET + +static void TLSX_SessionTicket_ValidateRequest(CYASSL* ssl) +{ + TLSX* extension = TLSX_Find(ssl->extensions, SESSION_TICKET); + SessionTicket* ticket = extension ? extension->data : NULL; + + if (ticket) { + /* TODO validate ticket timeout here! */ + if (ticket->lifetime == 0xfffffff) { + /* send empty ticket on timeout */ + TLSX_UseSessionTicket(&ssl->extensions, NULL); + } + } +} + + +static byte TLSX_SessionTicket_GetSize(SessionTicket* ticket, int isRequest) +{ + return isRequest && ticket ? OPAQUE16_LEN + ticket->size : 0; +} + + +static word16 TLSX_SessionTicket_Write(SessionTicket* ticket, byte* output, + int isRequest) +{ + int offset = 0; /* empty ticket */ + + if (isRequest && ticket) { + c16toa(ticket->size, output + offset); + offset += OPAQUE16_LEN; + + XMEMCPY(output + offset, ticket->data, ticket->size); + offset += ticket->size; + } + + return offset; +} + + +static int TLSX_SessionTicket_Parse(CYASSL* ssl, byte* input, word16 length, + byte isRequest) +{ + if (!isRequest) + return length != 0 ? BUFFER_ERROR : 0; + + /* TODO server side */ + (void)ssl; + (void)input; + + return 0; +} + +CYASSL_LOCAL SessionTicket* TLSX_SessionTicket_Create(word32 lifetime, + byte* data, word16 size) +{ + SessionTicket* ticket = (SessionTicket*)XMALLOC(sizeof(SessionTicket), + NULL, DYNAMIC_TYPE_TLSX); + if (ticket) { + ticket->data = (byte*)XMALLOC(size, NULL, DYNAMIC_TYPE_TLSX); + if (ticket->data == NULL) { + XFREE(ticket, NULL, DYNAMIC_TYPE_TLSX); + return NULL; + } + + XMEMCPY(ticket->data, data, size); + ticket->size = size; + ticket->lifetime = lifetime; + } + + return ticket; +} +CYASSL_LOCAL void TLSX_SessionTicket_Free(SessionTicket* ticket) +{ + if (ticket) { + XFREE(ticket->data, NULL, DYNAMIC_TYPE_TLSX); + XFREE(ticket, NULL, DYNAMIC_TYPE_TLSX); + } +} + +int TLSX_UseSessionTicket(TLSX** extensions, SessionTicket* ticket) +{ + int ret = 0; + + if (extensions == NULL) + return BAD_FUNC_ARG; + + /* If the ticket is NULL, the client will request a new ticket from the + server. Otherwise, the client will use it in the next client hello. */ + if ((ret = TLSX_Push(extensions, SESSION_TICKET, (void*)ticket)) != 0) + return ret; + + return SSL_SUCCESS; +} + +#define STK_VALIDATE_REQUEST TLSX_SessionTicket_ValidateRequest +#define STK_GET_SIZE TLSX_SessionTicket_GetSize +#define STK_WRITE TLSX_SessionTicket_Write +#define STK_PARSE TLSX_SessionTicket_Parse + +#else + +#define STK_VALIDATE_REQUEST(a) +#define STK_GET_SIZE(a, b) 0 +#define STK_WRITE(a, b, c) 0 +#define STK_PARSE(a, b, c, d) 0 + +#endif /* HAVE_SESSION_TICKET */ + + TLSX* TLSX_Find(TLSX* list, TLSX_Type type) { TLSX* extension = list; @@ -1795,6 +1906,10 @@ void TLSX_FreeAll(TLSX* list) case SECURE_RENEGOTIATION: SCR_FREE_ALL(extension->data); break; + + case SESSION_TICKET: + /* Nothing to do. */ + break; } XFREE(extension, 0, DYNAMIC_TYPE_TLSX); @@ -1842,6 +1957,10 @@ static word16 TLSX_GetSize(TLSX* list, byte* semaphore, byte isRequest) case SECURE_RENEGOTIATION: length += SCR_GET_SIZE(extension->data, isRequest); break; + + case SESSION_TICKET: + length += STK_GET_SIZE(extension->data, isRequest); + break; } TURN_ON(semaphore, TLSX_ToSemaphore(extension->type)); @@ -1875,11 +1994,11 @@ static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore, switch (extension->type) { case SERVER_NAME_INDICATION: if (isRequest) - offset += SNI_WRITE((SNI*)extension->data, output + offset); + offset += SNI_WRITE(extension->data, output + offset); break; case MAX_FRAGMENT_LENGTH: - offset += MFL_WRITE((byte*)extension->data, output + offset); + offset += MFL_WRITE(extension->data, output + offset); break; case TRUNCATED_HMAC: @@ -1887,13 +2006,17 @@ static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore, break; case ELLIPTIC_CURVES: - offset += EC_WRITE((EllipticCurve*)extension->data, - output + offset); + offset += EC_WRITE(extension->data, output + offset); break; case SECURE_RENEGOTIATION: - offset += SCR_WRITE((SecureRenegotiation*)extension->data, - output + offset, isRequest); + offset += SCR_WRITE(extension->data, output + offset, + isRequest); + break; + + case SESSION_TICKET: + offset += STK_WRITE(extension->data, output + offset, + isRequest); break; } @@ -1916,6 +2039,7 @@ word16 TLSX_GetRequestSize(CYASSL* ssl) byte semaphore[SEMAPHORE_SIZE] = {0}; EC_VALIDATE_REQUEST(ssl, semaphore); + STK_VALIDATE_REQUEST(ssl); if (ssl->extensions) length += TLSX_GetSize(ssl->extensions, semaphore, 1); @@ -2075,6 +2199,12 @@ int TLSX_Parse(CYASSL* ssl, byte* input, word16 length, byte isRequest, ret = SCR_PARSE(ssl, input + offset, size, isRequest); break; + case SESSION_TICKET: + CYASSL_MSG("Session Ticket extension received"); + + ret = STK_PARSE(ssl, input + offset, size, isRequest); + break; + case HELLO_EXT_SIG_ALGO: if (isRequest) { /* do not mess with offset inside the switch! */