diff --git a/cyassl/ctaocrypt/types.h b/cyassl/ctaocrypt/types.h index 4a5f66694..c385145ae 100644 --- a/cyassl/ctaocrypt/types.h +++ b/cyassl/ctaocrypt/types.h @@ -218,7 +218,8 @@ enum { DYNAMIC_TYPE_ALTNAME = 29, DYNAMIC_TYPE_SUITES = 30, DYNAMIC_TYPE_CIPHER = 31, - DYNAMIC_TYPE_RNG = 32 + DYNAMIC_TYPE_RNG = 32, + DYNAMIC_TYPE_DTLS_POOL = 33 }; /* stack protection */ diff --git a/cyassl/internal.h b/cyassl/internal.h index a6af3e2fa..3eb684c4b 100644 --- a/cyassl/internal.h +++ b/cyassl/internal.h @@ -398,6 +398,7 @@ enum Misc { DTLS_RECORD_EXTRA = 8, /* diff from normal */ DTLS_HANDSHAKE_SEQ_SZ = 2, /* handshake header sequence number */ DTLS_HANDSHAKE_FRAG_SZ = 3, /* fragment offset and length are 24 bit */ + DTLS_POOL_SZ = 5, /* buffers to hold in the retry pool */ FINISHED_LABEL_SZ = 15, /* TLS finished label size */ TLS_FINISHED_SZ = 12, /* TLS has a shorter size */ @@ -445,6 +446,7 @@ enum Misc { CLIENT_HELLO_FIRST = 35, /* Protocol + RAN_LEN + sizeof(id_len) */ MAX_SUITE_NAME = 48, /* maximum length of cipher suite string */ DEFAULT_TIMEOUT = 500, /* default resumption timeout in seconds */ + DTLS_DEFAULT_TIMEOUT = 1, /* default timeout for DTLS receive */ MAX_PSK_ID_LEN = 128, /* max psk identity/hint supported */ MAX_PSK_KEY_LEN = 64, /* max psk key supported */ @@ -1210,6 +1212,13 @@ typedef struct DtlsRecordLayerHeader { } DtlsRecordLayerHeader; +typedef struct DtlsPool { + buffer buf[DTLS_POOL_SZ]; + int used; + byte pool[MAX_MTU*DTLS_POOL_SZ]; +} DtlsPool; + + /* CyaSSL ssl type */ struct CYASSL { CYASSL_CTX* ctx; @@ -1274,6 +1283,7 @@ struct CYASSL { #endif #ifdef CYASSL_DTLS int dtls_timeout; + DtlsPool* dtls_pool; #endif #ifdef CYASSL_CALLBACKS HandShakeInfo handShakeInfo; /* info saved during handshake */ @@ -1479,6 +1489,12 @@ CYASSL_LOCAL void BuildTlsFinished(CYASSL* ssl, Hashes* hashes, #endif #endif /* NO_CYASSL_SERVER */ +#ifdef CYASSL_DTLS + CYASSL_LOCAL int DtlsPoolInit(CYASSL*); + CYASSL_LOCAL void DtlsPoolSave(CYASSL*, const byte*, int); + CYASSL_LOCAL int DtlsPoolSend(CYASSL*); + CYASSL_LOCAL void DtlsPoolReset(CYASSL*); +#endif /* CYASSL_DTLS */ #ifndef NO_TLS diff --git a/cyassl/ssl.h b/cyassl/ssl.h index 0ccc4dd4a..f492def8c 100644 --- a/cyassl/ssl.h +++ b/cyassl/ssl.h @@ -216,6 +216,10 @@ CYASSL_API long CyaSSL_CTX_set_session_cache_mode(CYASSL_CTX*, long); CYASSL_API int CyaSSL_CTX_set_cipher_list(CYASSL_CTX*, const char*); CYASSL_API int CyaSSL_set_cipher_list(CYASSL*, const char*); +/* Nonblocking DTLS helper functions */ +CYASSL_API int CyaSSL_dtls_get_current_timeout(CYASSL* ssl); +CYASSL_API int CyaSSL_dtls_got_timeout(CYASSL* ssl); + CYASSL_API int CyaSSL_ERR_GET_REASON(int err); CYASSL_API char* CyaSSL_ERR_error_string(unsigned long,char*); CYASSL_API void CyaSSL_ERR_error_string_n(unsigned long e, char* buf, diff --git a/examples/server/server.c b/examples/server/server.c index e16f74b50..2df2d99a5 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -292,6 +292,7 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) #endif #ifdef NON_BLOCKING + CyaSSL_using_nonblock(ssl); tcp_set_nonblocking(&clientfd); NonBlockingSSL_Accept(ssl); #else diff --git a/src/internal.c b/src/internal.c index 3ab2a1324..901515b42 100644 --- a/src/internal.c +++ b/src/internal.c @@ -981,7 +981,8 @@ int InitSSL(CYASSL* ssl, CYASSL_CTX* ctx) ssl->keys.dtls_peer_epoch = 0; ssl->keys.dtls_expected_peer_epoch = 0; ssl->arrays.cookieSz = 0; - ssl->dtls_timeout = 2; + ssl->dtls_timeout = DTLS_DEFAULT_TIMEOUT; + ssl->dtls_pool = NULL; #endif ssl->keys.encryptionOn = 0; /* initially off */ ssl->keys.decryptedCur = 0; /* initially off */ @@ -1135,6 +1136,8 @@ void SSL_ResourceFree(CYASSL* ssl) #ifdef CYASSL_DTLS if (ssl->buffers.dtlsHandshake.buffer != NULL) XFREE(ssl->buffers.dtlsHandshake.buffer, ssl->heap, DYNAMIC_TYPE_NONE); + if (ssl->dtls_pool != NULL) + XFREE(ssl->dtls_pool, ssl->heap, DYNAMIC_TYPE_NONE); #endif #if defined(OPENSSL_EXTRA) || defined(GOAHEAD_WS) XFREE(ssl->peerCert.derCert.buffer, ssl->heap, DYNAMIC_TYPE_CERT); @@ -1172,6 +1175,14 @@ void FreeHandshakeResources(CYASSL* ssl) XFREE(ssl->rng, ssl->heap, DYNAMIC_TYPE_RNG); ssl->rng = NULL; } + +#ifdef CYASSL_DTLS + /* DTLS_POOL */ + if (ssl->options.dtls && ssl->dtls_pool != NULL) { + XFREE(ssl->dtls_pool, ssl->heap, DYNAMIC_TYPE_DTLS_POOL); + ssl->dtls_pool = NULL; + } +#endif } @@ -1183,6 +1194,87 @@ void FreeSSL(CYASSL* ssl) } +#ifdef CYASSL_DTLS + +int DtlsPoolInit(CYASSL* ssl) +{ + if (ssl->dtls_pool == NULL) { + DtlsPool *pool = (DtlsPool*)XMALLOC(sizeof(DtlsPool), + ssl->heap, DYNAMIC_TYPE_DTLS_POOL); + if (pool == NULL) { + CYASSL_MSG("DTLS Buffer Pool Memory error"); + return MEMORY_E; + } + else { + int i; + + for (i = 0; i < DTLS_POOL_SZ; i++) { + pool->buf[i].length = 0; + pool->buf[i].buffer = pool->pool + (MAX_MTU * i); + } + pool->used = 0; + ssl->dtls_pool = pool; + } + } + return 0; +} + + +void DtlsPoolSave(CYASSL* ssl, const byte *src, int sz) +{ + DtlsPool *pool = ssl->dtls_pool; + if (pool != NULL && pool->used < DTLS_POOL_SZ) { + buffer *buf = &pool->buf[pool->used]; + XMEMCPY(buf->buffer, src, sz); + buf->length = (word32)sz; + pool->used++; + } +} + + +void DtlsPoolReset(CYASSL* ssl) +{ + if (ssl->dtls_pool != NULL) { + ssl->dtls_pool->used = 0; + ssl->dtls_timeout = DTLS_DEFAULT_TIMEOUT; + } +} + + +int DtlsPoolSend(CYASSL* ssl) +{ + DtlsPool *pool = ssl->dtls_pool; + + if (pool != NULL && pool->used > 0) { + int i; + for (i = 0; i < pool->used; i++) { + int sendResult; + buffer* buf = &pool->buf[i]; + DtlsRecordLayerHeader* dtls = (DtlsRecordLayerHeader*)buf->buffer; + + if (dtls->type == change_cipher_spec) { + ssl->keys.dtls_epoch++; + ssl->keys.dtls_sequence_number = 0; + } + c16toa(ssl->keys.dtls_epoch, dtls->epoch); + c32to48(ssl->keys.dtls_sequence_number++, dtls->sequence_number); + + XMEMCPY(ssl->buffers.outputBuffer.buffer, buf->buffer, buf->length); + ssl->buffers.outputBuffer.idx = 0; + ssl->buffers.outputBuffer.length = buf->length; + + sendResult = SendBuffered(ssl); + if (sendResult < 0) { + return sendResult; + } + } + } + return 0; +} + +#endif + + ProtocolVersion MakeSSLv3(void) { ProtocolVersion pv; @@ -1438,9 +1530,11 @@ retry: ssl->options.isClosed = 1; return -1; +#ifdef CYASSL_DTLS case IO_ERR_TIMEOUT: - /* XXX More than retry. Need to resend. */ + DtlsPoolSend(ssl); goto retry; +#endif default: return recvd; @@ -3014,6 +3108,7 @@ int ProcessReply(CYASSL* ssl) #ifdef CYASSL_DTLS if (ssl->options.dtls) { + DtlsPoolReset(ssl); ssl->keys.dtls_expected_peer_epoch++; ssl->keys.dtls_expected_peer_sequence_number = 0; } @@ -3120,6 +3215,11 @@ int SendChangeCipher(CYASSL* ssl) output[idx] = 1; /* turn it on */ + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + DtlsPoolSave(ssl, output, sendSz); + } + #endif #ifdef CYASSL_CALLBACKS if (ssl->hsInfoOn) AddPacketName("ChangeCipher", &ssl->handShakeInfo); if (ssl->toInfoOn) @@ -3318,8 +3418,14 @@ static int BuildMessage(CYASSL* ssl, byte* output, const byte* input, int inSz, XMEMCPY(output + idx, input, inSz); idx += inSz; - if (type == handshake) + if (type == handshake) { +#ifdef CYASSL_DTLS + if (ssl->options.dtls) { + DtlsPoolSave(ssl, output, headerSz+inSz); + } +#endif HashOutput(ssl, output, headerSz + inSz, ivSz); + } if (ssl->specs.cipher_type != aead) { ssl->hmac(ssl, output+idx, output + headerSz + ivSz, inSz, type, 0); idx += digestSz; @@ -3389,6 +3495,11 @@ int SendFinished(CYASSL* ssl) else BuildFinished(ssl, &ssl->verifyHashes, client); } + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + DtlsPoolSave(ssl, output, sendSz); + } + #endif #ifdef CYASSL_CALLBACKS if (ssl->hsInfoOn) AddPacketName("Finished", &ssl->handShakeInfo); @@ -3467,6 +3578,11 @@ int SendCertificate(CYASSL* ssl) i += ssl->buffers.certChain.length; */ } } + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + DtlsPoolSave(ssl, output, sendSz); + } + #endif HashOutput(ssl, output, sendSz, 0); #ifdef CYASSL_CALLBACKS if (ssl->hsInfoOn) AddPacketName("Certificate", &ssl->handShakeInfo); @@ -3536,6 +3652,11 @@ int SendCertificateRequest(CYASSL* ssl) /* if add more to output, adjust i i += REQ_HEADER_SZ; */ + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + DtlsPoolSave(ssl, output, sendSz); + } + #endif HashOutput(ssl, output, sendSz, 0); #ifdef CYASSL_CALLBACKS @@ -4797,6 +4918,11 @@ int SetCipherList(Suites* s, const char* list) output[idx++] = ecc_dsa_sa_algo; } + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + DtlsPoolSave(ssl, output, sendSz); + } + #endif HashOutput(ssl, output, sendSz, 0); ssl->options.clientState = CLIENT_HELLO_COMPLETE; @@ -4824,6 +4950,11 @@ int SetCipherList(Suites* s, const char* list) if (ssl->hsInfoOn) AddPacketName("HelloVerifyRequest", &ssl->handShakeInfo); if (ssl->toInfoOn) AddLateName("HelloVerifyRequest", &ssl->timeoutInfo); +#endif +#ifdef CYASSL_DTLS + if (ssl->options.dtls) { + DtlsPoolReset(ssl); + } #endif XMEMCPY(&pv, input + *inOutIdx, sizeof(pv)); *inOutIdx += sizeof(pv); @@ -4937,7 +5068,11 @@ int SetCipherList(Suites* s, const char* list) ssl->options.resuming = 0; /* server denied resumption try */ } } - + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + DtlsPoolReset(ssl); + } + #endif return SetCipherSpecs(ssl); } @@ -5391,7 +5526,11 @@ int SetCipherList(Suites* s, const char* list) XMEMCPY(output + idx, encSecret, encSz); /* if add more to output, adjust idx idx += encSz; */ - + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + DtlsPoolSave(ssl, output, sendSz); + } + #endif HashOutput(ssl, output, sendSz, 0); #ifdef CYASSL_CALLBACKS @@ -5527,8 +5666,10 @@ int SetCipherList(Suites* s, const char* list) sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + length + extraSz + VERIFY_HEADER; #ifdef CYASSL_DTLS - if (ssl->options.dtls) + if (ssl->options.dtls) { sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + DtlsPoolSave(ssl, output, sendSz); + } #endif HashOutput(ssl, output, sendSz, 0); } @@ -5631,6 +5772,11 @@ int SetCipherList(Suites* s, const char* list) output[idx++] = NO_COMPRESSION; ssl->buffers.outputBuffer.length += sendSz; + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + DtlsPoolSave(ssl, output, sendSz); + } + #endif HashOutput(ssl, output, sendSz, 0); #ifdef CYASSL_CALLBACKS @@ -6091,6 +6237,11 @@ int SetCipherList(Suites* s, const char* list) } } + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + DtlsPoolSave(ssl, output, sendSz); + } + #endif HashOutput(ssl, output, sendSz, 0); #ifdef CYASSL_CALLBACKS @@ -6943,6 +7094,11 @@ int SetCipherList(Suites* s, const char* list) AddHeaders(output, 0, server_hello_done, ssl); + #ifdef CYASSL_DTLS + if (ssl->options.dtls) { + DtlsPoolSave(ssl, output, sendSz); + } + #endif HashOutput(ssl, output, sendSz, 0); #ifdef CYASSL_CALLBACKS if (ssl->hsInfoOn) diff --git a/src/io.c b/src/io.c index 30f38622e..e66e1e355 100644 --- a/src/io.c +++ b/src/io.c @@ -143,7 +143,7 @@ int EmbedReceive(CYASSL *ssl, char *buf, int sz, void *ctx) #ifdef CYASSL_DTLS if (ssl->options.dtls && !ssl->options.usingNonblock && ssl->dtls_timeout != 0) { - #if USE_WINDOWS_API + #ifdef USE_WINDOWS_API DWORD timeout = ssl->dtls_timeout; #else struct timeval timeout = {ssl->dtls_timeout, 0}; diff --git a/src/ssl.c b/src/ssl.c index 867fc9ff3..6a796229b 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -2219,19 +2219,30 @@ int CyaSSL_dtls_get_current_timeout(CYASSL* ssl) #ifdef CYASSL_DTLS return ssl->dtls_timeout; #else - return 0; + return SSL_NOT_IMPLEMENTED; #endif } -void CyaSSL_dtls_got_timeout(CYASSL* ssl) +int CyaSSL_dtls_got_timeout(CYASSL* ssl) { + int result = SSL_NOT_IMPLEMENTED; (void)ssl; #ifdef CYASSL_DTLS - if (ssl->dtls_timeout < 64) + if (ssl->dtls_timeout < 64) { ssl->dtls_timeout *= 2; + if (DtlsPoolSend(ssl) < 0) + result = SSL_FATAL_ERROR; + else + result = SSL_SUCCESS; + } + else { + result = SSL_FATAL_ERROR; + } #endif + + return result; } @@ -2285,6 +2296,12 @@ void CyaSSL_dtls_got_timeout(CYASSL* ssl) ssl->options.dtls = 1; ssl->options.tls = 1; ssl->options.tls1_1 = 1; + + if (DtlsPoolInit(ssl) != 0) { + ssl->error = MEMORY_ERROR; + CYASSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } } #endif @@ -2535,6 +2552,12 @@ void CyaSSL_dtls_got_timeout(CYASSL* ssl) ssl->options.dtls = 1; ssl->options.tls = 1; ssl->options.tls1_1 = 1; + + if (DtlsPoolInit(ssl) != 0) { + ssl->error = MEMORY_ERROR; + CYASSL_ERROR(ssl->error); + return SSL_FATAL_ERROR; + } } #endif