diff --git a/src/internal.c b/src/internal.c index ab2ec279e..a50bb8cac 100755 --- a/src/internal.c +++ b/src/internal.c @@ -2652,6 +2652,7 @@ void SSL_ResourceFree(WOLFSSL* ssl) #if defined(KEEP_PEER_CERT) || defined(GOAHEAD_WS) FreeX509(&ssl->peerCert); #endif + #ifdef HAVE_SESSION_TICKET if (ssl->session.isDynamic) { XFREE(ssl->session.ticket, ssl->heap, DYNAMIC_TYPE_SESSION_TICK); @@ -2797,6 +2798,7 @@ void FreeHandshakeResources(WOLFSSL* ssl) #ifdef HAVE_QSH QSH_FreeAll(ssl); #endif + #ifdef HAVE_SESSION_TICKET if (ssl->session.isDynamic) { XFREE(ssl->session.ticket, ssl->heap, DYNAMIC_TYPE_SESSION_TICK); @@ -15966,7 +15968,7 @@ int DoSessionTicket(WOLFSSL* ssl, if (ssl->options.resuming) { /* let's try */ int ret = -1; WOLFSSL_SESSION* session = GetSession(ssl, - ssl->arrays->masterSecret); + ssl->arrays->masterSecret, 1); #ifdef HAVE_SESSION_TICKET if (ssl->options.useTicket == 1) { session = &ssl->session; @@ -15981,9 +15983,6 @@ int DoSessionTicket(WOLFSSL* ssl, WOLFSSL_MSG("Unsupported cipher suite, OldClientHello"); return UNSUPPORTED_SUITE; } - #ifdef SESSION_CERTS - ssl->session = *session; /* restore session certs. */ - #endif ret = wc_RNG_GenerateBlock(ssl->rng, ssl->arrays->serverRandom, RAN_LEN); @@ -16361,7 +16360,7 @@ int DoSessionTicket(WOLFSSL* ssl, if (ssl->options.resuming) { int ret = -1; WOLFSSL_SESSION* session = GetSession(ssl, - ssl->arrays->masterSecret); + ssl->arrays->masterSecret, 1); #ifdef HAVE_SESSION_TICKET if (ssl->options.useTicket == 1) { session = &ssl->session; @@ -16377,9 +16376,6 @@ int DoSessionTicket(WOLFSSL* ssl, WOLFSSL_MSG("Unsupported cipher suite, ClientHello"); return UNSUPPORTED_SUITE; } - #ifdef SESSION_CERTS - ssl->session = *session; /* restore session certs. */ - #endif ret = wc_RNG_GenerateBlock(ssl->rng, ssl->arrays->serverRandom, RAN_LEN); diff --git a/src/sniffer.c b/src/sniffer.c index 4a9f18570..3194183ae 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -1560,7 +1560,7 @@ static int ProcessServerHello(const byte* input, int* sslBytes, if (doResume ) { int ret = 0; SSL_SESSION* resume = GetSession(session->sslServer, - session->sslServer->arrays->masterSecret); + session->sslServer->arrays->masterSecret, 0); if (resume == NULL) { SetError(BAD_SESSION_RESUME_STR, error, session, FATAL_ERROR_STATE); return -1; @@ -1825,7 +1825,7 @@ static int ProcessFinished(const byte* input, int size, int* sslBytes, if (ret == 0 && session->flags.cached == 0) { if (session->sslServer->options.haveSessionId) { - WOLFSSL_SESSION* sess = GetSession(session->sslServer, NULL); + WOLFSSL_SESSION* sess = GetSession(session->sslServer, NULL, 0); if (sess == NULL) AddSession(session->sslServer); /* don't re add */ session->flags.cached = 1; diff --git a/src/ssl.c b/src/ssl.c index d120f4bae..0c8a7c201 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -1265,29 +1265,34 @@ WOLFSSL_API int wolfSSL_set_SessionTicket(WOLFSSL* ssl, byte* buf, word32 bufSz) if (ssl == NULL || (buf == NULL && bufSz > 0)) return BAD_FUNC_ARG; - /* Ticket will fit into static ticket */ - if(bufSz <= SESSION_TICKET_LEN) { - if (ssl->session.isDynamic) { - XFREE(ssl->session.ticket, ssl->heap, DYNAMIC_TYPE_SESSION_TICK); - ssl->session.isDynamic = 0; - } + if (bufSz > 0) { + /* Ticket will fit into static ticket */ + if(bufSz <= SESSION_TICKET_LEN) { + if (ssl->session.isDynamic) { + XFREE(ssl->session.ticket, ssl->heap, DYNAMIC_TYPE_SESSION_TICK); + ssl->session.isDynamic = 0; + } - ssl->session.ticket = ssl->session.staticTicket; - ssl->session.ticketLen = (word16)bufSz; - XMEMCPY(ssl->session.ticket, buf, bufSz); - } else { /* Ticket requires dynamic ticket storage */ - /*Not big enough space, need to alloc */ - if (!(ssl->session.ticketLen >= bufSz)) { - if(ssl->session.isDynamic) - XFREE(ssl->session.ticket); - ssl->session.ticket = XMALLOC(bufSz, ssl->heap, DYNAMIC_TYPE_TICK); - if(!ssl->session.ticket) - return MEMORY_ERROR; - ssl->session.isDynamic = 1; + ssl->session.ticket = ssl->session.staticTicket; + ssl->session.ticketLen = (word16)bufSz; + XMEMCPY(ssl->session.ticket, buf, bufSz); + } else { /* Ticket requires dynamic ticket storage */ + /*Not big enough space, need to alloc */ + if (!(ssl->session.ticketLen >= bufSz)) { + if(ssl->session.isDynamic) + XFREE(ssl->session.ticket, ssl->heap, + DYNAMIC_TYPE_SESSION_TICK); + ssl->session.ticket = XMALLOC(bufSz, ssl->heap, + DYNAMIC_TYPE_SESSION_TICK); + if(!ssl->session.ticket) + return MEMORY_ERROR; + ssl->session.isDynamic = 1; + } + XMEMCPY(ssl->session.ticket, buf, bufSz); } - XMEMCPY(ssl->session.ticket, buf, bufSz); - ssl->session.ticketLen = bufSz; } + ssl->session.ticketLen = (word16)bufSz; + return SSL_SUCCESS; } @@ -5201,7 +5206,7 @@ WOLFSSL_SESSION* wolfSSL_get_session(WOLFSSL* ssl) { WOLFSSL_ENTER("SSL_get_session"); if (ssl) - return GetSession(ssl, 0); + return GetSession(ssl, 0, 0); return NULL; } @@ -6949,7 +6954,8 @@ WOLFSSL_SESSION* GetSessionClient(WOLFSSL* ssl, const byte* id, int len) #endif /* NO_CLIENT_CACHE */ -WOLFSSL_SESSION* GetSession(WOLFSSL* ssl, byte* masterSecret) +WOLFSSL_SESSION* GetSession(WOLFSSL* ssl, byte* masterSecret, + byte restoreSessionCerts) { WOLFSSL_SESSION* ret = 0; const byte* id = NULL; @@ -6958,6 +6964,8 @@ WOLFSSL_SESSION* GetSession(WOLFSSL* ssl, byte* masterSecret) int count; int error = 0; + (void) restoreSessionCerts; + if (ssl->options.sessionCacheOff) return NULL; @@ -7005,6 +7013,17 @@ WOLFSSL_SESSION* GetSession(WOLFSSL* ssl, byte* masterSecret) ret = current; if (masterSecret) XMEMCPY(masterSecret, current->masterSecret, SECRET_LEN); +#ifdef SESSION_CERTS + /* If set, we should copy the session certs from the ssl object + * to the session we are returning so we can resume */ + if (restoreSessionCerts) { + ret->chain = ssl->session.chain; + ret->version = ssl->session.version; + ret->cipherSuite0 = ssl->session.cipherSuite0; + ret->cipherSuite = ssl->session.cipherSuite; + } +#endif /* SESSION_CERTS */ + } else { WOLFSSL_MSG("Session timed out"); } @@ -7020,13 +7039,92 @@ WOLFSSL_SESSION* GetSession(WOLFSSL* ssl, byte* masterSecret) } +int GetDeepCopySession(WOLFSSL* ssl, WOLFSSL_SESSION* copyFrom) +{ + int ticketLen; + int doDynamicCopy; + WOLFSSL_SESSION* copyInto = &ssl->session; + void* tmpBuff = NULL; + int ret = SSL_SUCCESS; + + (void)ticketLen; + (void)doDynamicCopy; + (void)tmpBuff; + + if (!ssl || !copyFrom) + return BAD_FUNC_ARG; + + if (LockMutex(&session_mutex) != 0) + return BAD_MUTEX_E; + +#ifdef HAVE_SESSION_TICKET + /* Free old dynamic ticket if we had one to avoid leak */ + if (copyInto->isDynamic) { + XFREE(copyInto->ticket, ssl->heap, DYNAMIC_TYPE_SESS_TICK); + copyInto->ticket = copyInto->staticTicket; + copyInto->isDynamic = 0; + } + /* Size of ticket to alloc if needed; Use later for alloc outside lock */ + if (copyFrom) { + doDynamicCopy = 1; + ticketLen = copyFrom->ticketLen; + } +#endif + + *copyInto = *copyFrom; + if (UnLockMutex(&session_mutex) != 0) { + return BAD_MUTEX_E; + } + +#ifdef HAVE_SESSION_TICKET + /* If doing dynamic copy, need to alloc outside lock, then inside a lock + * confirm the size still matches and memcpy */ + if (doDynamicCopy) { + tmpBuff = XMALLOC(ticketLen, ssl->heap, DYNAMIC_TYPE_SESSION_TICK); + if (!tmpBuff) + return MEMORY_ERROR; + + if (LockMutex(&session_mutex) != 0) { + XFREE(tmpBuff, ssl->heap, DYNAMIC_TYPE_SESS_TICK); + return BAD_MUTEX_E; + } + + if (ticketLen != copyFrom->ticketLen) { + /* Another thread modified the ssl-> session ticket during alloc. + * Treat as error, as ticket different than when copy requested */ + ret = VAR_STATE_CHANGE_E; + } + + if (ret == SSL_SUCCESS) { + copyInto->ticket = tmpBuff; + XMEMCPY(copyInto->ticket, copyFrom->ticket, ticketLen); + } + } + + if (UnLockMutex(&session_mutex) != 0) { + if (ret == SSL_SUCCESS) + ret = BAD_MUTEX_E; + } + + if (ret != SSL_SUCCESS) { + /* cleanup */ + if (tmpBuff) + XFREE(tmpBuff, ssl->heap, DYNAMIC_TYPE_SESS_TICK); + copyInto->ticket = copyInto->staticTicket; + copyInto->isDynamic = 0; + } +#endif /* HAVE_SESSION_TICKET */ + return ret; +} + + int SetSession(WOLFSSL* ssl, WOLFSSL_SESSION* session) { if (ssl->options.sessionCacheOff) return SSL_FAILURE; if (LowResTimer() < (session->bornOn + session->timeout)) { - ssl->session = *session; + GetDeepCopySession(ssl, session); ssl->options.resuming = 1; #ifdef SESSION_CERTS @@ -7034,7 +7132,6 @@ int SetSession(WOLFSSL* ssl, WOLFSSL_SESSION* session) ssl->options.cipherSuite0 = session->cipherSuite0; ssl->options.cipherSuite = session->cipherSuite; #endif - return SSL_SUCCESS; } return SSL_FAILURE; /* session timed out */ @@ -7397,10 +7494,12 @@ int wolfSSL_get_session_stats(word32* active, word32* total, word32* peak, #else /* NO_SESSION_CACHE */ /* No session cache version */ -WOLFSSL_SESSION* GetSession(WOLFSSL* ssl, byte* masterSecret) +WOLFSSL_SESSION* GetSession(WOLFSSL* ssl, byte* masterSecret, + byte restoreSessionCerts) { (void)ssl; (void)masterSecret; + (void)restoreSessionCerts; return NULL; } diff --git a/wolfcrypt/src/error.c b/wolfcrypt/src/error.c index 5ad5d77a5..c3f252d90 100644 --- a/wolfcrypt/src/error.c +++ b/wolfcrypt/src/error.c @@ -101,6 +101,9 @@ const char* wc_GetErrorString(int error) case MEMORY_E : return "out of memory error"; + case VAR_STATE_CHANGE_E : + return "Variable state modified by different thread"; + case RSA_WRONG_TYPE_E : return "RSA wrong block type for RSA function"; diff --git a/wolfssl/internal.h b/wolfssl/internal.h index b7e66a86d..4f8d47e4b 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2164,11 +2164,11 @@ struct WOLFSSL_X509_CHAIN { /* wolfSSL session type */ struct WOLFSSL_SESSION { - word32 bornOn; /* create time in seconds */ - word32 timeout; /* timeout in seconds */ - byte sessionID[ID_LEN]; /* id for protocol */ - byte sessionIDSz; - byte masterSecret[SECRET_LEN]; /* stored secret */ + word32 bornOn; /* create time in seconds */ + word32 timeout; /* timeout in seconds */ + byte sessionID[ID_LEN]; /* id for protocol */ + byte sessionIDSz; + byte masterSecret[SECRET_LEN]; /* stored secret */ #ifdef SESSION_CERTS WOLFSSL_X509_CHAIN chain; /* peer cert chain, static */ ProtocolVersion version; /* which version was used */ @@ -2176,23 +2176,23 @@ struct WOLFSSL_SESSION { byte cipherSuite; /* 2nd byte, actual suite */ #endif #ifndef NO_CLIENT_CACHE - word16 idLen; /* serverID length */ - byte serverID[SERVER_ID_LEN]; /* for easier client lookup */ + word16 idLen; /* serverID length */ + byte serverID[SERVER_ID_LEN]; /* for easier client lookup */ #endif #ifdef HAVE_SESSION_TICKET - byte* ticket; - word16 ticketLen; - byte staticTicket[SESSION_TICKET_LEN]; - byte isDynamic; + byte* ticket; + word16 ticketLen; + byte staticTicket[SESSION_TICKET_LEN]; + byte isDynamic; #endif #ifdef HAVE_STUNNEL - void* ex_data[MAX_EX_DATA]; + void* ex_data[MAX_EX_DATA]; #endif }; WOLFSSL_LOCAL -WOLFSSL_SESSION* GetSession(WOLFSSL*, byte*); +WOLFSSL_SESSION* GetSession(WOLFSSL*, byte*, byte); WOLFSSL_LOCAL int SetSession(WOLFSSL*, WOLFSSL_SESSION*); diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 72434bd63..8e6c5cc82 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -287,6 +287,7 @@ WOLFSSL_API void wolfSSL_set_quiet_shutdown(WOLFSSL*, int); WOLFSSL_API int wolfSSL_get_error(WOLFSSL*, int); WOLFSSL_API int wolfSSL_get_alert_history(WOLFSSL*, WOLFSSL_ALERT_HISTORY *); +WOLFSSL_API int GetDeepCopySession(WOLFSSL*, WOLFSSL_SESSION*); WOLFSSL_API int wolfSSL_set_session(WOLFSSL* ssl,WOLFSSL_SESSION* session); WOLFSSL_API long wolfSSL_SSL_SESSION_set_timeout(WOLFSSL_SESSION* session, long t); WOLFSSL_API WOLFSSL_SESSION* wolfSSL_get_session(WOLFSSL* ssl); diff --git a/wolfssl/wolfcrypt/error-crypt.h b/wolfssl/wolfcrypt/error-crypt.h index fe1aef3e5..91c229f18 100644 --- a/wolfssl/wolfcrypt/error-crypt.h +++ b/wolfssl/wolfcrypt/error-crypt.h @@ -59,6 +59,8 @@ enum { MP_ZERO_E = -121, /* got a mp zero result, not expected */ MEMORY_E = -125, /* out of memory error */ + VAR_STATE_CHANGE_E = -126, /* var state modified by different thread */ + RSA_WRONG_TYPE_E = -130, /* RSA wrong block type for RSA function */ RSA_BUFFER_E = -131, /* RSA buffer error, output too small or