X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=ssl%2Fd1_lib.c;h=183717624c3a403e186cfb00d3ea2b6045210a9c;hb=c21a427a149774c0e14600062d04646da0c7a3f0;hp=d774521aaff9f751ee85075302c0fed5b37a14de;hpb=36d16f8ee0845d932e250286e8e236580470e35b;p=oweals%2Fopenssl.git diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c index d774521aaf..183717624c 100644 --- a/ssl/d1_lib.c +++ b/ssl/d1_lib.c @@ -58,14 +58,18 @@ */ #include +#define USE_SOCKETS #include #include "ssl_locl.h" -const char *dtls1_version_str="DTLSv1" OPENSSL_VERSION_PTEXT; +#if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VMS) +#include +#endif -static long dtls1_default_timeout(void); +static void get_current_time(struct timeval *t); +const char dtls1_version_str[]="DTLSv1" OPENSSL_VERSION_PTEXT; -static SSL3_ENC_METHOD DTLSv1_enc_data={ +SSL3_ENC_METHOD DTLSv1_enc_data={ dtls1_enc, tls1_mac, tls1_setup_key_block, @@ -79,49 +83,17 @@ static SSL3_ENC_METHOD DTLSv1_enc_data={ tls1_alert_code, }; -static SSL_METHOD DTLSv1_data= { - DTLS1_VERSION, - dtls1_new, - dtls1_clear, - dtls1_free, - ssl_undefined_function, - ssl_undefined_function, - ssl3_read, - ssl3_peek, - ssl3_write, - ssl3_shutdown, - ssl3_renegotiate, - ssl3_renegotiate_check, - dtls1_get_message, - dtls1_read_bytes, - dtls1_write_app_data_bytes, - dtls1_dispatch_alert, - ssl3_ctrl, - ssl3_ctx_ctrl, - ssl3_get_cipher_by_char, - ssl3_put_cipher_by_char, - ssl3_pending, - ssl3_num_ciphers, - ssl3_get_cipher, - ssl_bad_method, - dtls1_default_timeout, - &DTLSv1_enc_data, - ssl_undefined_void_function, - ssl3_callback_ctrl, - ssl3_ctx_callback_ctrl, - }; - -static long dtls1_default_timeout(void) +long dtls1_default_timeout(void) { /* 2 hours, the 24 hours mentioned in the DTLSv1 spec * is way too long for http, the cache would over fill */ return(60*60*2); } -SSL_METHOD *dtlsv1_base_method(void) - { - return(&DTLSv1_data); - } +IMPLEMENT_dtls1_meth_func(dtlsv1_base_method, + ssl_undefined_function, + ssl_undefined_function, + ssl_bad_method) int dtls1_new(SSL *s) { @@ -132,11 +104,23 @@ int dtls1_new(SSL *s) memset(d1,0, sizeof *d1); /* d1->handshake_epoch=0; */ +#if defined(OPENSSL_SYS_VMS) || defined(VMS_TEST) + d1->bitmap.length=64; +#else d1->bitmap.length=sizeof(d1->bitmap.map) * 8; +#endif + pq_64bit_init(&(d1->bitmap.map)); + pq_64bit_init(&(d1->bitmap.max_seq_num)); + + d1->next_bitmap.length = d1->bitmap.length; + pq_64bit_init(&(d1->next_bitmap.map)); + pq_64bit_init(&(d1->next_bitmap.max_seq_num)); + d1->unprocessed_rcds.q=pqueue_new(); - d1->processed_rcds.q=pqueue_new(); - d1->buffered_messages = pqueue_new(); + d1->processed_rcds.q=pqueue_new(); + d1->buffered_messages = pqueue_new(); d1->sent_messages=pqueue_new(); + d1->buffered_app_data.q=pqueue_new(); if ( s->server) { @@ -144,12 +128,13 @@ int dtls1_new(SSL *s) } if( ! d1->unprocessed_rcds.q || ! d1->processed_rcds.q - || ! d1->buffered_messages || ! d1->sent_messages) + || ! d1->buffered_messages || ! d1->sent_messages || ! d1->buffered_app_data.q) { if ( d1->unprocessed_rcds.q) pqueue_free(d1->unprocessed_rcds.q); if ( d1->processed_rcds.q) pqueue_free(d1->processed_rcds.q); if ( d1->buffered_messages) pqueue_free(d1->buffered_messages); if ( d1->sent_messages) pqueue_free(d1->sent_messages); + if ( d1->buffered_app_data.q) pqueue_free(d1->buffered_app_data.q); OPENSSL_free(d1); return (0); } @@ -198,11 +183,206 @@ void dtls1_free(SSL *s) } pqueue_free(s->d1->sent_messages); + while ( (item = pqueue_pop(s->d1->buffered_app_data.q)) != NULL) + { + frag = (hm_fragment *)item->data; + OPENSSL_free(frag->fragment); + OPENSSL_free(frag); + pitem_free(item); + } + pqueue_free(s->d1->buffered_app_data.q); + + pq_64bit_free(&(s->d1->bitmap.map)); + pq_64bit_free(&(s->d1->bitmap.max_seq_num)); + + pq_64bit_free(&(s->d1->next_bitmap.map)); + pq_64bit_free(&(s->d1->next_bitmap.max_seq_num)); + OPENSSL_free(s->d1); } void dtls1_clear(SSL *s) { ssl3_clear(s); - s->version=DTLS1_VERSION; + if (s->options & SSL_OP_CISCO_ANYCONNECT) + s->version=DTLS1_BAD_VER; + else + s->version=DTLS1_VERSION; + } + +long dtls1_ctrl(SSL *s, int cmd, long larg, void *parg) + { + int ret=0; + + switch (cmd) + { + case DTLS_CTRL_GET_TIMEOUT: + if (dtls1_get_timeout(s, (struct timeval*) parg) != NULL) + { + ret = 1; + } + break; + case DTLS_CTRL_HANDLE_TIMEOUT: + ret = dtls1_handle_timeout(s); + break; + + default: + ret = ssl3_ctrl(s, cmd, larg, parg); + break; + } + return(ret); + } + +/* + * As it's impossible to use stream ciphers in "datagram" mode, this + * simple filter is designed to disengage them in DTLS. Unfortunately + * there is no universal way to identify stream SSL_CIPHER, so we have + * to explicitly list their SSL_* codes. Currently RC4 is the only one + * available, but if new ones emerge, they will have to be added... + */ +SSL_CIPHER *dtls1_get_cipher(unsigned int u) + { + SSL_CIPHER *ciph = ssl3_get_cipher(u); + + if (ciph != NULL) + { + if ((ciph->algorithms&SSL_ENC_MASK) == SSL_RC4) + return NULL; + } + + return ciph; + } + +void dtls1_start_timer(SSL *s) + { + /* If timer is not set, initialize duration with 1 second */ + if (s->d1->next_timeout.tv_sec == 0 && s->d1->next_timeout.tv_usec == 0) + { + s->d1->timeout_duration = 1; + } + + /* Set timeout to current time */ + get_current_time(&(s->d1->next_timeout)); + + /* Add duration to current time */ + s->d1->next_timeout.tv_sec += s->d1->timeout_duration; + BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0, &(s->d1->next_timeout)); + } + +struct timeval* dtls1_get_timeout(SSL *s, struct timeval* timeleft) + { + struct timeval timenow; + + /* If no timeout is set, just return NULL */ + if (s->d1->next_timeout.tv_sec == 0 && s->d1->next_timeout.tv_usec == 0) + { + return NULL; + } + + /* Get current time */ + get_current_time(&timenow); + + /* If timer already expired, set remaining time to 0 */ + if (s->d1->next_timeout.tv_sec < timenow.tv_sec || + (s->d1->next_timeout.tv_sec == timenow.tv_sec && + s->d1->next_timeout.tv_usec <= timenow.tv_usec)) + { + memset(timeleft, 0, sizeof(struct timeval)); + return timeleft; + } + + /* Calculate time left until timer expires */ + memcpy(timeleft, &(s->d1->next_timeout), sizeof(struct timeval)); + timeleft->tv_sec -= timenow.tv_sec; + timeleft->tv_usec -= timenow.tv_usec; + if (timeleft->tv_usec < 0) + { + timeleft->tv_sec--; + timeleft->tv_usec += 1000000; + } + + return timeleft; } + +int dtls1_is_timer_expired(SSL *s) + { + struct timeval timeleft; + + /* Get time left until timeout, return false if no timer running */ + if (dtls1_get_timeout(s, &timeleft) == NULL) + { + return 0; + } + + /* Return false if timer is not expired yet */ + if (timeleft.tv_sec > 0 || timeleft.tv_usec > 0) + { + return 0; + } + + /* Timer expired, so return true */ + return 1; + } + +void dtls1_double_timeout(SSL *s) + { + s->d1->timeout_duration *= 2; + if (s->d1->timeout_duration > 60) + s->d1->timeout_duration = 60; + dtls1_start_timer(s); + } + +void dtls1_stop_timer(SSL *s) + { + /* Reset everything */ + memset(&(s->d1->next_timeout), 0, sizeof(struct timeval)); + s->d1->timeout_duration = 1; + BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0, &(s->d1->next_timeout)); + } + +int dtls1_handle_timeout(SSL *s) + { + DTLS1_STATE *state; + + /* if no timer is expired, don't do anything */ + if (!dtls1_is_timer_expired(s)) + { + return 0; + } + + dtls1_double_timeout(s); + state = s->d1; + state->timeout.num_alerts++; + if ( state->timeout.num_alerts > DTLS1_TMO_ALERT_COUNT) + { + /* fail the connection, enough alerts have been sent */ + SSLerr(SSL_F_DTLS1_HANDLE_TIMEOUT,SSL_R_READ_TIMEOUT_EXPIRED); + return 0; + } + + state->timeout.read_timeouts++; + if ( state->timeout.read_timeouts > DTLS1_TMO_READ_COUNT) + { + state->timeout.read_timeouts = 1; + } + + dtls1_start_timer(s); + return dtls1_retransmit_buffered_messages(s); + } + +static void get_current_time(struct timeval *t) +{ +#ifdef OPENSSL_SYS_WIN32 + struct _timeb tb; + _ftime(&tb); + t->tv_sec = (long)tb.time; + t->tv_usec = (long)tb.millitm * 1000; +#elif defined(OPENSSL_SYS_VMS) + struct timeb tb; + ftime(&tb); + t->tv_sec = (long)tb.time; + t->tv_usec = (long)tb.millitm * 1000; +#else + gettimeofday(t, NULL); +#endif +}