873b8d554b
- fix CVE-2007-4995 - out of order DTLS fragments buffer overflow (#321191) - add alpha sub-archs (#296031)
1430 lines
43 KiB
Diff
1430 lines
43 KiB
Diff
Fix DTLS implementation to be RFC 4347 compliant. This makes the new client
|
|
incompatible with the old openssl DTLS servers. However the older openssl client
|
|
will still be able to connect to the new server code. This change also
|
|
resolves buffer overrun when out-of-order fragments are received during
|
|
the handshake.
|
|
CVE-2007-4995
|
|
diff -up openssl-0.9.8b/ssl/dtls1.h.dtls-fixes openssl-0.9.8b/ssl/dtls1.h
|
|
--- openssl-0.9.8b/ssl/dtls1.h.dtls-fixes 2007-10-08 17:55:22.000000000 +0200
|
|
+++ openssl-0.9.8b/ssl/dtls1.h 2007-10-08 17:55:22.000000000 +0200
|
|
@@ -67,9 +67,8 @@
|
|
extern "C" {
|
|
#endif
|
|
|
|
-#define DTLS1_VERSION 0x0100
|
|
-#define DTLS1_VERSION_MAJOR 0x01
|
|
-#define DTLS1_VERSION_MINOR 0x00
|
|
+#define DTLS1_VERSION 0xFEFF
|
|
+#define DTLS1_BAD_VER 0x0100
|
|
|
|
#define DTLS1_AD_MISSING_HANDSHAKE_MESSAGE 110
|
|
|
|
@@ -83,7 +82,7 @@ extern "C" {
|
|
#define DTLS1_HM_BAD_FRAGMENT -2
|
|
#define DTLS1_HM_FRAGMENT_RETRY -3
|
|
|
|
-#define DTLS1_CCS_HEADER_LENGTH 3
|
|
+#define DTLS1_CCS_HEADER_LENGTH 1
|
|
|
|
#define DTLS1_AL_HEADER_LENGTH 7
|
|
|
|
diff -up openssl-0.9.8b/ssl/d1_lib.c.dtls-fixes openssl-0.9.8b/ssl/d1_lib.c
|
|
--- openssl-0.9.8b/ssl/d1_lib.c.dtls-fixes 2005-08-08 21:26:35.000000000 +0200
|
|
+++ openssl-0.9.8b/ssl/d1_lib.c 2007-10-08 17:55:22.000000000 +0200
|
|
@@ -188,3 +188,23 @@ void dtls1_clear(SSL *s)
|
|
ssl3_clear(s);
|
|
s->version=DTLS1_VERSION;
|
|
}
|
|
+
|
|
+/*
|
|
+ * 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;
|
|
+ }
|
|
diff -up openssl-0.9.8b/ssl/d1_srvr.c.dtls-fixes openssl-0.9.8b/ssl/d1_srvr.c
|
|
--- openssl-0.9.8b/ssl/d1_srvr.c.dtls-fixes 2005-12-05 18:32:19.000000000 +0100
|
|
+++ openssl-0.9.8b/ssl/d1_srvr.c 2007-10-10 14:21:49.000000000 +0200
|
|
@@ -285,6 +285,10 @@ int dtls1_accept(SSL *s)
|
|
s->d1->send_cookie = 0;
|
|
s->state=SSL3_ST_SW_FLUSH;
|
|
s->s3->tmp.next_state=SSL3_ST_SR_CLNT_HELLO_A;
|
|
+
|
|
+ /* HelloVerifyRequests resets Finished MAC */
|
|
+ if (s->client_version != DTLS1_BAD_VER)
|
|
+ ssl3_init_finished_mac(s);
|
|
break;
|
|
|
|
case SSL3_ST_SW_SRVR_HELLO_A:
|
|
@@ -620,10 +624,13 @@ int dtls1_send_hello_verify_request(SSL
|
|
buf = (unsigned char *)s->init_buf->data;
|
|
|
|
msg = p = &(buf[DTLS1_HM_HEADER_LENGTH]);
|
|
- *(p++) = s->version >> 8;
|
|
- *(p++) = s->version & 0xFF;
|
|
+ if (s->client_version == DTLS1_BAD_VER)
|
|
+ *(p++) = DTLS1_BAD_VER>>8,
|
|
+ *(p++) = DTLS1_BAD_VER&0xff;
|
|
+ else
|
|
+ *(p++) = s->version >> 8,
|
|
+ *(p++) = s->version & 0xFF;
|
|
|
|
- *(p++) = (unsigned char) s->d1->cookie_len;
|
|
if ( s->ctx->app_gen_cookie_cb != NULL &&
|
|
s->ctx->app_gen_cookie_cb(s, s->d1->cookie,
|
|
&(s->d1->cookie_len)) == 0)
|
|
@@ -634,6 +641,7 @@ int dtls1_send_hello_verify_request(SSL
|
|
/* else the cookie is assumed to have
|
|
* been initialized by the application */
|
|
|
|
+ *(p++) = (unsigned char) s->d1->cookie_len;
|
|
memcpy(p, s->d1->cookie, s->d1->cookie_len);
|
|
p += s->d1->cookie_len;
|
|
msg_len = p - msg;
|
|
@@ -672,8 +680,12 @@ int dtls1_send_server_hello(SSL *s)
|
|
/* Do the message type and length last */
|
|
d=p= &(buf[DTLS1_HM_HEADER_LENGTH]);
|
|
|
|
- *(p++)=s->version>>8;
|
|
- *(p++)=s->version&0xff;
|
|
+ if (s->client_version == DTLS1_BAD_VER)
|
|
+ *(p++)=DTLS1_BAD_VER>>8,
|
|
+ *(p++)=DTLS1_BAD_VER&0xff;
|
|
+ else
|
|
+ *(p++)=s->version>>8,
|
|
+ *(p++)=s->version&0xff;
|
|
|
|
/* Random stuff */
|
|
memcpy(p,s->s3->server_random,SSL3_RANDOM_SIZE);
|
|
@@ -1009,6 +1021,7 @@ int dtls1_send_certificate_request(SSL *
|
|
STACK_OF(X509_NAME) *sk=NULL;
|
|
X509_NAME *name;
|
|
BUF_MEM *buf;
|
|
+ unsigned int msg_len;
|
|
|
|
if (s->state == SSL3_ST_SW_CERT_REQ_A)
|
|
{
|
|
@@ -1086,6 +1099,10 @@ int dtls1_send_certificate_request(SSL *
|
|
#endif
|
|
|
|
/* XDTLS: set message header ? */
|
|
+ msg_len = s->init_num - DTLS1_HM_HEADER_LENGTH;
|
|
+ dtls1_set_message_header(s, (void *)s->init_buf->data,
|
|
+ SSL3_MT_CERTIFICATE_REQUEST, msg_len, 0, msg_len);
|
|
+
|
|
/* buffer the message to handle re-xmits */
|
|
dtls1_buffer_message(s, 0);
|
|
|
|
diff -up openssl-0.9.8b/ssl/s3_srvr.c.dtls-fixes openssl-0.9.8b/ssl/s3_srvr.c
|
|
--- openssl-0.9.8b/ssl/s3_srvr.c.dtls-fixes 2007-10-08 17:55:22.000000000 +0200
|
|
+++ openssl-0.9.8b/ssl/s3_srvr.c 2007-10-08 17:55:22.000000000 +0200
|
|
@@ -679,9 +679,9 @@ int ssl3_get_client_hello(SSL *s)
|
|
*/
|
|
if (s->state == SSL3_ST_SR_CLNT_HELLO_A)
|
|
{
|
|
- s->first_packet=1;
|
|
s->state=SSL3_ST_SR_CLNT_HELLO_B;
|
|
}
|
|
+ s->first_packet=1;
|
|
n=s->method->ssl_get_message(s,
|
|
SSL3_ST_SR_CLNT_HELLO_B,
|
|
SSL3_ST_SR_CLNT_HELLO_C,
|
|
@@ -690,6 +690,7 @@ int ssl3_get_client_hello(SSL *s)
|
|
&ok);
|
|
|
|
if (!ok) return((int)n);
|
|
+ s->first_packet=0;
|
|
d=p=(unsigned char *)s->init_msg;
|
|
|
|
/* use version from inside client hello, not from record header
|
|
@@ -697,7 +698,8 @@ int ssl3_get_client_hello(SSL *s)
|
|
s->client_version=(((int)p[0])<<8)|(int)p[1];
|
|
p+=2;
|
|
|
|
- if (s->client_version < s->version)
|
|
+ if ((s->version == DTLS1_VERSION && s->client_version > s->version) ||
|
|
+ (s->version != DTLS1_VERSION && s->client_version < s->version))
|
|
{
|
|
SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_WRONG_VERSION_NUMBER);
|
|
if ((s->client_version>>8) == SSL3_VERSION_MAJOR)
|
|
@@ -748,7 +750,7 @@ int ssl3_get_client_hello(SSL *s)
|
|
|
|
p+=j;
|
|
|
|
- if (SSL_version(s) == DTLS1_VERSION)
|
|
+ if (s->version == DTLS1_VERSION)
|
|
{
|
|
/* cookie stuff */
|
|
cookie_len = *(p++);
|
|
@@ -1709,8 +1711,9 @@ int ssl3_get_client_key_exchange(SSL *s)
|
|
rsa=pkey->pkey.rsa;
|
|
}
|
|
|
|
- /* TLS */
|
|
- if (s->version > SSL3_VERSION)
|
|
+ /* TLS and [incidentally] DTLS, including pre-0.9.8f */
|
|
+ if (s->version > SSL3_VERSION &&
|
|
+ s->client_version != DTLS1_BAD_VER)
|
|
{
|
|
n2s(p,i);
|
|
if (n != i+2)
|
|
diff -up openssl-0.9.8b/ssl/ssl_locl.h.dtls-fixes openssl-0.9.8b/ssl/ssl_locl.h
|
|
--- openssl-0.9.8b/ssl/ssl_locl.h.dtls-fixes 2007-10-08 17:55:22.000000000 +0200
|
|
+++ openssl-0.9.8b/ssl/ssl_locl.h 2007-10-08 17:55:22.000000000 +0200
|
|
@@ -677,7 +677,7 @@ SSL_METHOD *func_name(void) \
|
|
ssl3_put_cipher_by_char, \
|
|
ssl3_pending, \
|
|
ssl3_num_ciphers, \
|
|
- ssl3_get_cipher, \
|
|
+ dtls1_get_cipher, \
|
|
s_get_meth, \
|
|
dtls1_default_timeout, \
|
|
&DTLSv1_enc_data, \
|
|
@@ -842,6 +842,8 @@ void dtls1_get_message_header(unsigned c
|
|
void dtls1_get_ccs_header(unsigned char *data, struct ccs_header_st *ccs_hdr);
|
|
void dtls1_reset_seq_numbers(SSL *s, int rw);
|
|
long dtls1_default_timeout(void);
|
|
+SSL_CIPHER *dtls1_get_cipher(unsigned int u);
|
|
+
|
|
|
|
|
|
/* some client-only functions */
|
|
diff -up openssl-0.9.8b/ssl/t1_enc.c.dtls-fixes openssl-0.9.8b/ssl/t1_enc.c
|
|
--- openssl-0.9.8b/ssl/t1_enc.c.dtls-fixes 2007-10-08 17:55:22.000000000 +0200
|
|
+++ openssl-0.9.8b/ssl/t1_enc.c 2007-10-10 14:24:52.000000000 +0200
|
|
@@ -737,15 +737,35 @@ int tls1_mac(SSL *ssl, unsigned char *md
|
|
md_size=EVP_MD_size(hash);
|
|
|
|
buf[0]=rec->type;
|
|
- buf[1]=TLS1_VERSION_MAJOR;
|
|
- buf[2]=TLS1_VERSION_MINOR;
|
|
+ if (ssl->version == DTLS1_VERSION && ssl->client_version == DTLS1_BAD_VER)
|
|
+ {
|
|
+ buf[1]=TLS1_VERSION_MAJOR;
|
|
+ buf[2]=TLS1_VERSION_MINOR;
|
|
+ }
|
|
+ else {
|
|
+ buf[1]=(unsigned char)(ssl->version>>8);
|
|
+ buf[2]=(unsigned char)(ssl->version);
|
|
+ }
|
|
+
|
|
buf[3]=rec->length>>8;
|
|
buf[4]=rec->length&0xff;
|
|
|
|
/* I should fix this up TLS TLS TLS TLS TLS XXXXXXXX */
|
|
HMAC_CTX_init(&hmac);
|
|
HMAC_Init_ex(&hmac,mac_sec,EVP_MD_size(hash),hash,NULL);
|
|
- HMAC_Update(&hmac,seq,8);
|
|
+
|
|
+ if (ssl->version == DTLS1_VERSION && ssl->client_version != DTLS1_BAD_VER)
|
|
+ {
|
|
+ unsigned char dtlsseq[8],*p=dtlsseq;
|
|
+
|
|
+ s2n(send?ssl->d1->w_epoch:ssl->d1->r_epoch, p);
|
|
+ memcpy (p,&seq[2],6);
|
|
+
|
|
+ HMAC_Update(&hmac,dtlsseq,8);
|
|
+ }
|
|
+ else
|
|
+ HMAC_Update(&hmac,seq,8);
|
|
+
|
|
HMAC_Update(&hmac,buf,5);
|
|
HMAC_Update(&hmac,rec->input,rec->length);
|
|
HMAC_Final(&hmac,md,&md_size);
|
|
@@ -762,8 +782,8 @@ printf("rec=");
|
|
{unsigned int z; for (z=0; z<rec->length; z++) printf("%02X ",buf[z]); printf("\n"); }
|
|
#endif
|
|
|
|
- if ( SSL_version(ssl) != DTLS1_VERSION)
|
|
- {
|
|
+ if ( SSL_version(ssl) != DTLS1_VERSION)
|
|
+ {
|
|
for (i=7; i>=0; i--)
|
|
{
|
|
++seq[i];
|
|
diff -up openssl-0.9.8b/ssl/ssl.h.dtls-fixes openssl-0.9.8b/ssl/ssl.h
|
|
--- openssl-0.9.8b/ssl/ssl.h.dtls-fixes 2007-10-08 17:55:22.000000000 +0200
|
|
+++ openssl-0.9.8b/ssl/ssl.h 2007-10-08 17:55:22.000000000 +0200
|
|
@@ -315,7 +315,7 @@ extern "C" {
|
|
/* The following cipher list is used by default.
|
|
* It also is substituted when an application-defined cipher list string
|
|
* starts with 'DEFAULT'. */
|
|
-#define SSL_DEFAULT_CIPHER_LIST "ALL:!ADH:+RC4:@STRENGTH" /* low priority for RC4 */
|
|
+#define SSL_DEFAULT_CIPHER_LIST "AES:ALL:!aNULL:!eNULL:+RC4:@STRENGTH" /* low priority for RC4 */
|
|
|
|
/* Used in SSL_set_shutdown()/SSL_get_shutdown(); */
|
|
#define SSL_SENT_SHUTDOWN 1
|
|
@@ -1551,6 +1551,7 @@ void ERR_load_SSL_strings(void);
|
|
#define SSL_F_DTLS1_GET_MESSAGE_FRAGMENT 253
|
|
#define SSL_F_DTLS1_GET_RECORD 254
|
|
#define SSL_F_DTLS1_OUTPUT_CERT_CHAIN 255
|
|
+#define SSL_F_DTLS1_PREPROCESS_FRAGMENT 277
|
|
#define SSL_F_DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE 256
|
|
#define SSL_F_DTLS1_PROCESS_RECORD 257
|
|
#define SSL_F_DTLS1_READ_BYTES 258
|
|
diff -up openssl-0.9.8b/ssl/d1_pkt.c.dtls-fixes openssl-0.9.8b/ssl/d1_pkt.c
|
|
--- openssl-0.9.8b/ssl/d1_pkt.c.dtls-fixes 2006-02-08 20:16:32.000000000 +0100
|
|
+++ openssl-0.9.8b/ssl/d1_pkt.c 2007-10-08 17:55:22.000000000 +0200
|
|
@@ -120,6 +120,7 @@
|
|
#include <openssl/evp.h>
|
|
#include <openssl/buffer.h>
|
|
#include <openssl/pqueue.h>
|
|
+#include <openssl/rand.h>
|
|
|
|
static int have_handshake_fragment(SSL *s, int type, unsigned char *buf,
|
|
int len, int peek);
|
|
@@ -486,9 +487,9 @@ int dtls1_get_record(SSL *s)
|
|
SSL3_RECORD *rr;
|
|
SSL_SESSION *sess;
|
|
unsigned char *p;
|
|
- short version;
|
|
+ unsigned short version;
|
|
DTLS1_BITMAP *bitmap;
|
|
- unsigned int is_next_epoch;
|
|
+ unsigned int is_next_epoch;
|
|
|
|
rr= &(s->s3->rrec);
|
|
sess=s->session;
|
|
@@ -524,7 +525,7 @@ again:
|
|
ssl_minor= *(p++);
|
|
version=(ssl_major<<8)|ssl_minor;
|
|
|
|
- /* sequence number is 64 bits, with top 2 bytes = epoch */
|
|
+ /* sequence number is 64 bits, with top 2 bytes = epoch */
|
|
n2s(p,rr->epoch);
|
|
|
|
memcpy(&(s->s3->read_sequence[2]), p, 6);
|
|
@@ -533,13 +534,9 @@ again:
|
|
n2s(p,rr->length);
|
|
|
|
/* Lets check version */
|
|
- if (s->first_packet)
|
|
+ if (!s->first_packet)
|
|
{
|
|
- s->first_packet=0;
|
|
- }
|
|
- else
|
|
- {
|
|
- if (version != s->version)
|
|
+ if (version != s->version && version != DTLS1_BAD_VER)
|
|
{
|
|
SSLerr(SSL_F_DTLS1_GET_RECORD,SSL_R_WRONG_VERSION_NUMBER);
|
|
/* Send back error using their
|
|
@@ -550,7 +547,8 @@ again:
|
|
}
|
|
}
|
|
|
|
- if ((version & 0xff00) != (DTLS1_VERSION & 0xff00))
|
|
+ if ((version & 0xff00) != (DTLS1_VERSION & 0xff00) &&
|
|
+ (version & 0xff00) != (DTLS1_BAD_VER & 0xff00))
|
|
{
|
|
SSLerr(SSL_F_DTLS1_GET_RECORD,SSL_R_WRONG_VERSION_NUMBER);
|
|
goto err;
|
|
@@ -796,8 +794,14 @@ start:
|
|
dest = s->d1->alert_fragment;
|
|
dest_len = &s->d1->alert_fragment_len;
|
|
}
|
|
- else /* else it's a CCS message */
|
|
- OPENSSL_assert(rr->type == SSL3_RT_CHANGE_CIPHER_SPEC);
|
|
+ /* else it's a CCS message, or it's wrong */
|
|
+ else if (rr->type != SSL3_RT_CHANGE_CIPHER_SPEC)
|
|
+ {
|
|
+ /* Not certain if this is the right error handling */
|
|
+ al=SSL_AD_UNEXPECTED_MESSAGE;
|
|
+ SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_UNEXPECTED_RECORD);
|
|
+ goto f_err;
|
|
+ }
|
|
|
|
|
|
if (dest_maxlen > 0)
|
|
@@ -971,47 +975,40 @@ start:
|
|
}
|
|
|
|
if (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC)
|
|
- {
|
|
- struct ccs_header_st ccs_hdr;
|
|
+ {
|
|
+ struct ccs_header_st ccs_hdr;
|
|
|
|
dtls1_get_ccs_header(rr->data, &ccs_hdr);
|
|
|
|
- if ( ccs_hdr.seq == s->d1->handshake_read_seq)
|
|
+ /* 'Change Cipher Spec' is just a single byte, so we know
|
|
+ * exactly what the record payload has to look like */
|
|
+ /* XDTLS: check that epoch is consistent */
|
|
+ if ( (s->client_version == DTLS1_BAD_VER && rr->length != 3) ||
|
|
+ (s->client_version != DTLS1_BAD_VER && rr->length != DTLS1_CCS_HEADER_LENGTH) ||
|
|
+ (rr->off != 0) || (rr->data[0] != SSL3_MT_CCS))
|
|
{
|
|
- /* 'Change Cipher Spec' is just a single byte, so we know
|
|
- * exactly what the record payload has to look like */
|
|
- /* XDTLS: check that epoch is consistent */
|
|
- if ( (rr->length != DTLS1_CCS_HEADER_LENGTH) ||
|
|
- (rr->off != 0) || (rr->data[0] != SSL3_MT_CCS))
|
|
- {
|
|
- i=SSL_AD_ILLEGAL_PARAMETER;
|
|
- SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_BAD_CHANGE_CIPHER_SPEC);
|
|
- goto err;
|
|
- }
|
|
-
|
|
- rr->length=0;
|
|
-
|
|
- if (s->msg_callback)
|
|
- s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC,
|
|
- rr->data, 1, s, s->msg_callback_arg);
|
|
-
|
|
- s->s3->change_cipher_spec=1;
|
|
- if (!ssl3_do_change_cipher_spec(s))
|
|
- goto err;
|
|
-
|
|
- /* do this whenever CCS is processed */
|
|
- dtls1_reset_seq_numbers(s, SSL3_CC_READ);
|
|
-
|
|
- /* handshake read seq is reset upon handshake completion */
|
|
- s->d1->handshake_read_seq++;
|
|
-
|
|
- goto start;
|
|
- }
|
|
- else
|
|
- {
|
|
- rr->length = 0;
|
|
- goto start;
|
|
+ i=SSL_AD_ILLEGAL_PARAMETER;
|
|
+ SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_BAD_CHANGE_CIPHER_SPEC);
|
|
+ goto err;
|
|
}
|
|
+
|
|
+ rr->length=0;
|
|
+
|
|
+ if (s->msg_callback)
|
|
+ s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC,
|
|
+ rr->data, 1, s, s->msg_callback_arg);
|
|
+
|
|
+ s->s3->change_cipher_spec=1;
|
|
+ if (!ssl3_do_change_cipher_spec(s))
|
|
+ goto err;
|
|
+
|
|
+ /* do this whenever CCS is processed */
|
|
+ dtls1_reset_seq_numbers(s, SSL3_CC_READ);
|
|
+
|
|
+ /* handshake read seq is reset upon handshake completion */
|
|
+ s->d1->handshake_read_seq++;
|
|
+
|
|
+ goto start;
|
|
}
|
|
|
|
/* Unexpected handshake message (Client Hello, or protocol violation) */
|
|
@@ -1339,8 +1336,12 @@ int do_dtls1_write(SSL *s, int type, con
|
|
*(p++)=type&0xff;
|
|
wr->type=type;
|
|
|
|
- *(p++)=(s->version>>8);
|
|
- *(p++)=s->version&0xff;
|
|
+ if (s->client_version == DTLS1_BAD_VER)
|
|
+ *(p++) = DTLS1_BAD_VER>>8,
|
|
+ *(p++) = DTLS1_BAD_VER&0xff;
|
|
+ else
|
|
+ *(p++)=(s->version>>8),
|
|
+ *(p++)=s->version&0xff;
|
|
|
|
/* field where we are to write out packet epoch, seq num and len */
|
|
pseq=p;
|
|
@@ -1395,8 +1396,14 @@ int do_dtls1_write(SSL *s, int type, con
|
|
|
|
|
|
/* ssl3_enc can only have an error on read */
|
|
- wr->length += bs; /* bs != 0 in case of CBC. The enc fn provides
|
|
- * the randomness */
|
|
+ if (bs) /* bs != 0 in case of CBC */
|
|
+ {
|
|
+ RAND_pseudo_bytes(p,bs);
|
|
+ /* master IV and last CBC residue stand for
|
|
+ * the rest of randomness */
|
|
+ wr->length += bs;
|
|
+ }
|
|
+
|
|
s->method->ssl3_enc->enc(s,1);
|
|
|
|
/* record length after mac and block padding */
|
|
diff -up openssl-0.9.8b/ssl/ssl_err.c.dtls-fixes openssl-0.9.8b/ssl/ssl_err.c
|
|
--- openssl-0.9.8b/ssl/ssl_err.c.dtls-fixes 2006-01-08 22:52:46.000000000 +0100
|
|
+++ openssl-0.9.8b/ssl/ssl_err.c 2007-10-08 17:55:22.000000000 +0200
|
|
@@ -87,6 +87,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
|
|
{ERR_FUNC(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT), "DTLS1_GET_MESSAGE_FRAGMENT"},
|
|
{ERR_FUNC(SSL_F_DTLS1_GET_RECORD), "DTLS1_GET_RECORD"},
|
|
{ERR_FUNC(SSL_F_DTLS1_OUTPUT_CERT_CHAIN), "DTLS1_OUTPUT_CERT_CHAIN"},
|
|
+{ERR_FUNC(SSL_F_DTLS1_PREPROCESS_FRAGMENT), "DTLS1_PREPROCESS_FRAGMENT"},
|
|
{ERR_FUNC(SSL_F_DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE), "DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE"},
|
|
{ERR_FUNC(SSL_F_DTLS1_PROCESS_RECORD), "DTLS1_PROCESS_RECORD"},
|
|
{ERR_FUNC(SSL_F_DTLS1_READ_BYTES), "DTLS1_READ_BYTES"},
|
|
diff -up openssl-0.9.8b/ssl/s3_pkt.c.dtls-fixes openssl-0.9.8b/ssl/s3_pkt.c
|
|
--- openssl-0.9.8b/ssl/s3_pkt.c.dtls-fixes 2005-10-01 01:38:20.000000000 +0200
|
|
+++ openssl-0.9.8b/ssl/s3_pkt.c 2007-10-08 17:55:22.000000000 +0200
|
|
@@ -277,11 +277,7 @@ again:
|
|
n2s(p,rr->length);
|
|
|
|
/* Lets check version */
|
|
- if (s->first_packet)
|
|
- {
|
|
- s->first_packet=0;
|
|
- }
|
|
- else
|
|
+ if (!s->first_packet)
|
|
{
|
|
if (version != s->version)
|
|
{
|
|
diff -up openssl-0.9.8b/ssl/s23_srvr.c.dtls-fixes openssl-0.9.8b/ssl/s23_srvr.c
|
|
--- openssl-0.9.8b/ssl/s23_srvr.c.dtls-fixes 2005-12-05 18:32:19.000000000 +0100
|
|
+++ openssl-0.9.8b/ssl/s23_srvr.c 2007-10-08 17:55:22.000000000 +0200
|
|
@@ -565,7 +565,6 @@ int ssl23_get_client_hello(SSL *s)
|
|
s->init_num=0;
|
|
|
|
if (buf != buf_space) OPENSSL_free(buf);
|
|
- s->first_packet=1;
|
|
return(SSL_accept(s));
|
|
err:
|
|
if (buf != buf_space) OPENSSL_free(buf);
|
|
diff -up openssl-0.9.8b/ssl/s23_clnt.c.dtls-fixes openssl-0.9.8b/ssl/s23_clnt.c
|
|
--- openssl-0.9.8b/ssl/s23_clnt.c.dtls-fixes 2005-12-05 18:32:19.000000000 +0100
|
|
+++ openssl-0.9.8b/ssl/s23_clnt.c 2007-10-08 17:55:22.000000000 +0200
|
|
@@ -574,7 +574,6 @@ static int ssl23_get_server_hello(SSL *s
|
|
if (!ssl_get_new_session(s,0))
|
|
goto err;
|
|
|
|
- s->first_packet=1;
|
|
return(SSL_connect(s));
|
|
err:
|
|
return(-1);
|
|
diff -up openssl-0.9.8b/ssl/s3_lib.c.dtls-fixes openssl-0.9.8b/ssl/s3_lib.c
|
|
--- openssl-0.9.8b/ssl/s3_lib.c.dtls-fixes 2006-01-15 08:14:38.000000000 +0100
|
|
+++ openssl-0.9.8b/ssl/s3_lib.c 2007-10-08 17:55:22.000000000 +0200
|
|
@@ -903,7 +903,8 @@ OPENSSL_GLOBAL SSL_CIPHER ssl3_ciphers[]
|
|
},
|
|
|
|
#if TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES
|
|
- /* New TLS Export CipherSuites */
|
|
+ /* New TLS Export CipherSuites from expired ID */
|
|
+#if 0
|
|
/* Cipher 60 */
|
|
{
|
|
1,
|
|
@@ -930,6 +931,7 @@ OPENSSL_GLOBAL SSL_CIPHER ssl3_ciphers[]
|
|
SSL_ALL_CIPHERS,
|
|
SSL_ALL_STRENGTHS,
|
|
},
|
|
+#endif
|
|
/* Cipher 62 */
|
|
{
|
|
1,
|
|
diff -up openssl-0.9.8b/ssl/s2_lib.c.dtls-fixes openssl-0.9.8b/ssl/s2_lib.c
|
|
--- openssl-0.9.8b/ssl/s2_lib.c.dtls-fixes 2005-08-27 14:05:23.000000000 +0200
|
|
+++ openssl-0.9.8b/ssl/s2_lib.c 2007-10-08 17:55:22.000000000 +0200
|
|
@@ -178,7 +178,7 @@ OPENSSL_GLOBAL SSL_CIPHER ssl2_ciphers[]
|
|
SSL_ALL_STRENGTHS,
|
|
},
|
|
/* RC4_64_WITH_MD5 */
|
|
-#if 1
|
|
+#if 0
|
|
{
|
|
1,
|
|
SSL2_TXT_RC4_64_WITH_MD5,
|
|
diff -up openssl-0.9.8b/ssl/d1_both.c.dtls-fixes openssl-0.9.8b/ssl/d1_both.c
|
|
--- openssl-0.9.8b/ssl/d1_both.c.dtls-fixes 2005-08-29 01:20:52.000000000 +0200
|
|
+++ openssl-0.9.8b/ssl/d1_both.c 2007-10-08 17:55:22.000000000 +0200
|
|
@@ -138,38 +138,40 @@ static void dtls1_set_message_header_int
|
|
unsigned long frag_len);
|
|
static int dtls1_retransmit_buffered_messages(SSL *s);
|
|
static long dtls1_get_message_fragment(SSL *s, int st1, int stn,
|
|
- long max, int *ok);
|
|
-static void dtls1_process_handshake_fragment(SSL *s, int frag_len);
|
|
+ long max, int *ok);
|
|
|
|
static hm_fragment *
|
|
dtls1_hm_fragment_new(unsigned long frag_len)
|
|
- {
|
|
- hm_fragment *frag = NULL;
|
|
- unsigned char *buf = NULL;
|
|
+ {
|
|
+ hm_fragment *frag = NULL;
|
|
+ unsigned char *buf = NULL;
|
|
|
|
- frag = (hm_fragment *)OPENSSL_malloc(sizeof(hm_fragment));
|
|
- if ( frag == NULL)
|
|
- return NULL;
|
|
+ frag = (hm_fragment *)OPENSSL_malloc(sizeof(hm_fragment));
|
|
+ if ( frag == NULL)
|
|
+ return NULL;
|
|
|
|
- buf = (unsigned char *)OPENSSL_malloc(frag_len
|
|
- + DTLS1_HM_HEADER_LENGTH);
|
|
- if ( buf == NULL)
|
|
- {
|
|
- OPENSSL_free(frag);
|
|
- return NULL;
|
|
- }
|
|
-
|
|
- frag->fragment = buf;
|
|
+ if (frag_len)
|
|
+ {
|
|
+ buf = (unsigned char *)OPENSSL_malloc(frag_len);
|
|
+ if ( buf == NULL)
|
|
+ {
|
|
+ OPENSSL_free(frag);
|
|
+ return NULL;
|
|
+ }
|
|
+ }
|
|
|
|
- return frag;
|
|
- }
|
|
+ /* zero length fragment gets zero frag->fragment */
|
|
+ frag->fragment = buf;
|
|
+
|
|
+ return frag;
|
|
+ }
|
|
|
|
static void
|
|
dtls1_hm_fragment_free(hm_fragment *frag)
|
|
- {
|
|
- OPENSSL_free(frag->fragment);
|
|
- OPENSSL_free(frag);
|
|
- }
|
|
+ {
|
|
+ if (frag->fragment) OPENSSL_free(frag->fragment);
|
|
+ OPENSSL_free(frag);
|
|
+ }
|
|
|
|
/* send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or SSL3_RT_CHANGE_CIPHER_SPEC) */
|
|
int dtls1_do_write(SSL *s, int type)
|
|
@@ -180,7 +182,7 @@ int dtls1_do_write(SSL *s, int type)
|
|
|
|
/* AHA! Figure out the MTU, and stick to the right size */
|
|
if ( ! (SSL_get_options(s) & SSL_OP_NO_QUERY_MTU))
|
|
- {
|
|
+ {
|
|
s->d1->mtu =
|
|
BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
|
|
|
|
@@ -207,7 +209,7 @@ int dtls1_do_write(SSL *s, int type)
|
|
mtu = curr_mtu;
|
|
else if ( ( ret = BIO_flush(SSL_get_wbio(s))) <= 0)
|
|
return ret;
|
|
-
|
|
+
|
|
if ( BIO_wpending(SSL_get_wbio(s)) + s->init_num >= mtu)
|
|
{
|
|
ret = BIO_flush(SSL_get_wbio(s));
|
|
@@ -254,11 +256,11 @@ int dtls1_do_write(SSL *s, int type)
|
|
s->init_off -= DTLS1_HM_HEADER_LENGTH;
|
|
s->init_num += DTLS1_HM_HEADER_LENGTH;
|
|
|
|
- /* write atleast DTLS1_HM_HEADER_LENGTH bytes */
|
|
+ /* write atleast DTLS1_HM_HEADER_LENGTH bytes */
|
|
if ( len <= DTLS1_HM_HEADER_LENGTH)
|
|
len += DTLS1_HM_HEADER_LENGTH;
|
|
}
|
|
-
|
|
+
|
|
dtls1_fix_message_header(s, frag_off,
|
|
len - DTLS1_HM_HEADER_LENGTH);
|
|
|
|
@@ -286,18 +288,40 @@ int dtls1_do_write(SSL *s, int type)
|
|
}
|
|
else
|
|
{
|
|
-
|
|
+
|
|
/* bad if this assert fails, only part of the handshake
|
|
* message got sent. but why would this happen? */
|
|
- OPENSSL_assert(len == (unsigned int)ret);
|
|
-
|
|
+ OPENSSL_assert(len == (unsigned int)ret);
|
|
+
|
|
if (type == SSL3_RT_HANDSHAKE && ! s->d1->retransmitting)
|
|
+ {
|
|
/* should not be done for 'Hello Request's, but in that case
|
|
* we'll ignore the result anyway */
|
|
- ssl3_finish_mac(s,
|
|
- (unsigned char *)&s->init_buf->data[s->init_off +
|
|
- DTLS1_HM_HEADER_LENGTH], ret - DTLS1_HM_HEADER_LENGTH);
|
|
-
|
|
+ unsigned char *p = &s->init_buf->data[s->init_off];
|
|
+ const struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
|
|
+ int len;
|
|
+
|
|
+ if (frag_off == 0 && s->client_version != DTLS1_BAD_VER)
|
|
+ {
|
|
+ /* reconstruct message header is if it
|
|
+ * is being sent in single fragment */
|
|
+ *p++ = msg_hdr->type;
|
|
+ l2n3(msg_hdr->msg_len,p);
|
|
+ s2n (msg_hdr->seq,p);
|
|
+ l2n3(0,p);
|
|
+ l2n3(msg_hdr->msg_len,p);
|
|
+ p -= DTLS1_HM_HEADER_LENGTH;
|
|
+ len = ret;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ p += DTLS1_HM_HEADER_LENGTH;
|
|
+ len = ret - DTLS1_HM_HEADER_LENGTH;
|
|
+ }
|
|
+
|
|
+ ssl3_finish_mac(s, p, len);
|
|
+ }
|
|
+
|
|
if (ret == s->init_num)
|
|
{
|
|
if (s->msg_callback)
|
|
@@ -307,7 +331,7 @@ int dtls1_do_write(SSL *s, int type)
|
|
|
|
s->init_off = 0; /* done writing this message */
|
|
s->init_num = 0;
|
|
-
|
|
+
|
|
return(1);
|
|
}
|
|
s->init_off+=ret;
|
|
@@ -327,6 +351,7 @@ int dtls1_do_write(SSL *s, int type)
|
|
long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok)
|
|
{
|
|
int i, al;
|
|
+ struct hm_header_st *msg_hdr;
|
|
|
|
/* s3->tmp is used to store messages that are unexpected, caused
|
|
* by the absence of an optional handshake message */
|
|
@@ -344,25 +369,56 @@ long dtls1_get_message(SSL *s, int st1,
|
|
s->init_num = (int)s->s3->tmp.message_size;
|
|
return s->init_num;
|
|
}
|
|
-
|
|
+
|
|
+ msg_hdr = &s->d1->r_msg_hdr;
|
|
do
|
|
{
|
|
- if ( s->d1->r_msg_hdr.frag_off == 0)
|
|
+ if ( msg_hdr->frag_off == 0)
|
|
{
|
|
/* s->d1->r_message_header.msg_len = 0; */
|
|
- memset(&(s->d1->r_msg_hdr), 0x00, sizeof(struct hm_header_st));
|
|
+ memset(msg_hdr, 0x00, sizeof(struct hm_header_st));
|
|
}
|
|
|
|
i = dtls1_get_message_fragment(s, st1, stn, max, ok);
|
|
if ( i == DTLS1_HM_BAD_FRAGMENT ||
|
|
- i == DTLS1_HM_FRAGMENT_RETRY) /* bad fragment received */
|
|
+ i == DTLS1_HM_FRAGMENT_RETRY) /* bad fragment received */
|
|
continue;
|
|
else if ( i <= 0 && !*ok)
|
|
return i;
|
|
|
|
- if (s->d1->r_msg_hdr.msg_len == (unsigned int)s->init_num - DTLS1_HM_HEADER_LENGTH)
|
|
+ /* Note that s->init_sum is used as a counter summing
|
|
+ * up fragments' lengths: as soon as they sum up to
|
|
+ * handshake packet length, we assume we have got all
|
|
+ * the fragments. Overlapping fragments would cause
|
|
+ * premature termination, so we don't expect overlaps.
|
|
+ * Well, handling overlaps would require something more
|
|
+ * drastic. Indeed, as it is now there is no way to
|
|
+ * tell if out-of-order fragment from the middle was
|
|
+ * the last. '>=' is the best/least we can do to control
|
|
+ * the potential damage caused by malformed overlaps. */
|
|
+ if ((unsigned int)s->init_num >= msg_hdr->msg_len)
|
|
{
|
|
- memset(&(s->d1->r_msg_hdr), 0x00, sizeof(struct hm_header_st));
|
|
+ unsigned char *p = s->init_buf->data;
|
|
+ unsigned long msg_len = msg_hdr->msg_len;
|
|
+
|
|
+ /* reconstruct message header as if it was
|
|
+ * sent in single fragment */
|
|
+ *(p++) = msg_hdr->type;
|
|
+ l2n3(msg_len,p);
|
|
+ s2n (msg_hdr->seq,p);
|
|
+ l2n3(0,p);
|
|
+ l2n3(msg_len,p);
|
|
+ if (s->client_version != DTLS1_BAD_VER)
|
|
+ p -= DTLS1_HM_HEADER_LENGTH,
|
|
+ msg_len += DTLS1_HM_HEADER_LENGTH;
|
|
+
|
|
+ ssl3_finish_mac(s, p, msg_len);
|
|
+ if (s->msg_callback)
|
|
+ s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
|
|
+ p, msg_len,
|
|
+ s, s->msg_callback_arg);
|
|
+
|
|
+ memset(msg_hdr, 0x00, sizeof(struct hm_header_st));
|
|
|
|
s->d1->handshake_read_seq++;
|
|
/* we just read a handshake message from the other side:
|
|
@@ -379,11 +435,11 @@ long dtls1_get_message(SSL *s, int st1,
|
|
* first data segment, but is there a better way? */
|
|
dtls1_clear_record_buffer(s);
|
|
|
|
- s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
|
|
- return s->init_num - DTLS1_HM_HEADER_LENGTH;
|
|
+ s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
|
|
+ return s->init_num;
|
|
}
|
|
else
|
|
- s->d1->r_msg_hdr.frag_off = i;
|
|
+ msg_hdr->frag_off = i;
|
|
} while(1) ;
|
|
|
|
f_err:
|
|
@@ -393,161 +449,183 @@ f_err:
|
|
}
|
|
|
|
|
|
-static int
|
|
-dtls1_retrieve_buffered_fragment(SSL *s, unsigned long *copied)
|
|
- {
|
|
- /* (0) check whether the desired fragment is available
|
|
- * if so:
|
|
- * (1) copy over the fragment to s->init_buf->data[]
|
|
- * (2) update s->init_num
|
|
- */
|
|
- pitem *item;
|
|
- hm_fragment *frag;
|
|
- unsigned long overlap;
|
|
- unsigned char *p;
|
|
-
|
|
- item = pqueue_peek(s->d1->buffered_messages);
|
|
- if ( item == NULL)
|
|
- return 0;
|
|
+static int dtls1_preprocess_fragment(SSL *s,struct hm_header_st *msg_hdr,int max)
|
|
+ {
|
|
+ size_t frag_off,frag_len,msg_len;
|
|
|
|
- frag = (hm_fragment *)item->data;
|
|
-
|
|
- if ( s->d1->handshake_read_seq == frag->msg_header.seq &&
|
|
- frag->msg_header.frag_off <= (unsigned int)s->init_num - DTLS1_HM_HEADER_LENGTH)
|
|
- {
|
|
- pqueue_pop(s->d1->buffered_messages);
|
|
- overlap = s->init_num - DTLS1_HM_HEADER_LENGTH
|
|
- - frag->msg_header.frag_off;
|
|
-
|
|
- p = frag->fragment;
|
|
-
|
|
- memcpy(&s->init_buf->data[s->init_num],
|
|
- p + DTLS1_HM_HEADER_LENGTH + overlap,
|
|
- frag->msg_header.frag_len - overlap);
|
|
-
|
|
- OPENSSL_free(frag->fragment);
|
|
- OPENSSL_free(frag);
|
|
- pitem_free(item);
|
|
+ msg_len = msg_hdr->msg_len;
|
|
+ frag_off = msg_hdr->frag_off;
|
|
+ frag_len = msg_hdr->frag_len;
|
|
|
|
- *copied = frag->msg_header.frag_len - overlap;
|
|
- return *copied;
|
|
- }
|
|
- else
|
|
- return 0;
|
|
- }
|
|
+ /* sanity checking */
|
|
+ if ( (frag_off+frag_len) > msg_len)
|
|
+ {
|
|
+ SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE);
|
|
+ return SSL_AD_ILLEGAL_PARAMETER;
|
|
+ }
|
|
|
|
+ if ( (frag_off+frag_len) > (unsigned long)max)
|
|
+ {
|
|
+ SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE);
|
|
+ return SSL_AD_ILLEGAL_PARAMETER;
|
|
+ }
|
|
|
|
-static int
|
|
-dtls1_buffer_handshake_fragment(SSL *s, struct hm_header_st* msg_hdr)
|
|
-{
|
|
- hm_fragment *frag = NULL;
|
|
- pitem *item = NULL;
|
|
- PQ_64BIT seq64;
|
|
+ if ( s->d1->r_msg_hdr.frag_off == 0) /* first fragment */
|
|
+ {
|
|
+ /* msg_len is limited to 2^24, but is effectively checked
|
|
+ * against max above */
|
|
+ if (!BUF_MEM_grow_clean(s->init_buf,(int)msg_len+DTLS1_HM_HEADER_LENGTH))
|
|
+ {
|
|
+ SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT,ERR_R_BUF_LIB);
|
|
+ return SSL_AD_INTERNAL_ERROR;
|
|
+ }
|
|
|
|
- frag = dtls1_hm_fragment_new(msg_hdr->frag_len);
|
|
- if ( frag == NULL)
|
|
- goto err;
|
|
+ s->s3->tmp.message_size = msg_len;
|
|
+ s->d1->r_msg_hdr.msg_len = msg_len;
|
|
+ s->s3->tmp.message_type = msg_hdr->type;
|
|
+ s->d1->r_msg_hdr.type = msg_hdr->type;
|
|
+ s->d1->r_msg_hdr.seq = msg_hdr->seq;
|
|
+ }
|
|
+ else if (msg_len != s->d1->r_msg_hdr.msg_len)
|
|
+ {
|
|
+ /* They must be playing with us! BTW, failure to enforce
|
|
+ * upper limit would open possibility for buffer overrun. */
|
|
+ SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE);
|
|
+ return SSL_AD_ILLEGAL_PARAMETER;
|
|
+ }
|
|
|
|
- memcpy(frag->fragment, &(s->init_buf->data[s->init_num]),
|
|
- msg_hdr->frag_len + DTLS1_HM_HEADER_LENGTH);
|
|
+ return 0; /* no error */
|
|
+ }
|
|
|
|
- memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr));
|
|
|
|
- pq_64bit_init(&seq64);
|
|
- pq_64bit_assign_word(&seq64, msg_hdr->seq);
|
|
+static int
|
|
+dtls1_retrieve_buffered_fragment(SSL *s, long max, int *ok)
|
|
+ {
|
|
+ /* (0) check whether the desired fragment is available
|
|
+ * if so:
|
|
+ * (1) copy over the fragment to s->init_buf->data[]
|
|
+ * (2) update s->init_num
|
|
+ */
|
|
+ pitem *item;
|
|
+ hm_fragment *frag;
|
|
+ int al;
|
|
|
|
- item = pitem_new(seq64, frag);
|
|
- if ( item == NULL)
|
|
- goto err;
|
|
+ *ok = 0;
|
|
+ item = pqueue_peek(s->d1->buffered_messages);
|
|
+ if ( item == NULL)
|
|
+ return 0;
|
|
|
|
- pq_64bit_free(&seq64);
|
|
+ frag = (hm_fragment *)item->data;
|
|
|
|
- pqueue_insert(s->d1->buffered_messages, item);
|
|
- return 1;
|
|
+ if ( s->d1->handshake_read_seq == frag->msg_header.seq)
|
|
+ {
|
|
+ pqueue_pop(s->d1->buffered_messages);
|
|
|
|
-err:
|
|
- if ( frag != NULL) dtls1_hm_fragment_free(frag);
|
|
- if ( item != NULL) OPENSSL_free(item);
|
|
- return 0;
|
|
-}
|
|
+ al=dtls1_preprocess_fragment(s,&frag->msg_header,max);
|
|
|
|
+ if (al==0) /* no alert */
|
|
+ {
|
|
+ unsigned char *p = s->init_buf->data+DTLS1_HM_HEADER_LENGTH;
|
|
+ memcpy(&p[frag->msg_header.frag_off],
|
|
+ frag->fragment,frag->msg_header.frag_len);
|
|
+ }
|
|
|
|
-static void
|
|
-dtls1_process_handshake_fragment(SSL *s, int frag_len)
|
|
- {
|
|
- unsigned char *p;
|
|
+ dtls1_hm_fragment_free(frag);
|
|
+ pitem_free(item);
|
|
|
|
- p = (unsigned char *)s->init_buf->data;
|
|
+ if (al==0)
|
|
+ {
|
|
+ *ok = 1;
|
|
+ return frag->msg_header.frag_len;
|
|
+ }
|
|
|
|
- ssl3_finish_mac(s, &p[s->init_num - frag_len], frag_len);
|
|
- }
|
|
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
|
|
+ s->init_num = 0;
|
|
+ *ok = 0;
|
|
+ return -1;
|
|
+ }
|
|
+ else
|
|
+ return 0;
|
|
+ }
|
|
|
|
|
|
static int
|
|
-dtls1_process_out_of_seq_message(SSL *s, struct hm_header_st *msg_hdr, int *ok)
|
|
- {
|
|
- int i;
|
|
- unsigned char *p;
|
|
-
|
|
- /* make sure there's enough room to read this fragment */
|
|
- if ( (int)msg_hdr->frag_len && !BUF_MEM_grow_clean(s->init_buf,
|
|
- (int)msg_hdr->frag_len + DTLS1_HM_HEADER_LENGTH + s->init_num))
|
|
- {
|
|
- SSLerr(SSL_F_DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE,ERR_R_BUF_LIB);
|
|
- goto err;
|
|
- }
|
|
+dtls1_process_out_of_seq_message(SSL *s, struct hm_header_st* msg_hdr, int *ok)
|
|
+{
|
|
+ int i=-1;
|
|
+ hm_fragment *frag = NULL;
|
|
+ pitem *item = NULL;
|
|
+ PQ_64BIT seq64;
|
|
+ unsigned long frag_len = msg_hdr->frag_len;
|
|
|
|
- p = (unsigned char *)s->init_buf->data;
|
|
+ if ((msg_hdr->frag_off+frag_len) > msg_hdr->msg_len)
|
|
+ goto err;
|
|
|
|
- /* read the body of the fragment (header has already been read */
|
|
- if ( msg_hdr->frag_len > 0)
|
|
+ if (msg_hdr->seq <= s->d1->handshake_read_seq)
|
|
{
|
|
- i=s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
|
|
- &p[s->init_num],
|
|
- msg_hdr->frag_len,0);
|
|
- if (i <= 0)
|
|
+ unsigned char devnull [256];
|
|
+
|
|
+ while (frag_len)
|
|
{
|
|
- *ok = 0;
|
|
- return i;
|
|
+ i = s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
|
|
+ devnull,
|
|
+ frag_len>sizeof(devnull)?sizeof(devnull):frag_len,0);
|
|
+ if (i<=0) goto err;
|
|
+ frag_len -= i;
|
|
}
|
|
}
|
|
|
|
- if ( msg_hdr->seq > s->d1->handshake_read_seq)
|
|
- dtls1_buffer_handshake_fragment(s, msg_hdr);
|
|
- else
|
|
- OPENSSL_assert(msg_hdr->seq < s->d1->handshake_read_seq);
|
|
+ frag = dtls1_hm_fragment_new(frag_len);
|
|
+ if ( frag == NULL)
|
|
+ goto err;
|
|
+
|
|
+ memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr));
|
|
+
|
|
+ if (frag_len)
|
|
+ {
|
|
+ /* read the body of the fragment (header has already been read */
|
|
+ i = s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
|
|
+ frag->fragment,frag_len,0);
|
|
+ if (i<=0 || i!=frag_len)
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ pq_64bit_init(&seq64);
|
|
+ pq_64bit_assign_word(&seq64, msg_hdr->seq);
|
|
+
|
|
+ item = pitem_new(seq64, frag);
|
|
+ pq_64bit_free(&seq64);
|
|
+ if ( item == NULL)
|
|
+ goto err;
|
|
+
|
|
+ pqueue_insert(s->d1->buffered_messages, item);
|
|
+ return DTLS1_HM_FRAGMENT_RETRY;
|
|
|
|
- return DTLS1_HM_FRAGMENT_RETRY;
|
|
err:
|
|
- *ok = 0;
|
|
- return -1;
|
|
- }
|
|
+ if ( frag != NULL) dtls1_hm_fragment_free(frag);
|
|
+ if ( item != NULL) OPENSSL_free(item);
|
|
+ *ok = 0;
|
|
+ return i;
|
|
+ }
|
|
|
|
|
|
static long
|
|
dtls1_get_message_fragment(SSL *s, int st1, int stn, long max, int *ok)
|
|
{
|
|
- unsigned char *p;
|
|
+ unsigned char wire[DTLS1_HM_HEADER_LENGTH];
|
|
unsigned long l, frag_off, frag_len;
|
|
int i,al;
|
|
struct hm_header_st msg_hdr;
|
|
- unsigned long overlap;
|
|
-
|
|
- /* see if we have the required fragment already */
|
|
- if (dtls1_retrieve_buffered_fragment(s, &l))
|
|
- {
|
|
- /* compute MAC, remove fragment headers */
|
|
- dtls1_process_handshake_fragment(s, l);
|
|
- s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
|
|
- s->state = stn;
|
|
- return 1;
|
|
- }
|
|
|
|
- /* get a handshake fragment from the record layer */
|
|
- p = (unsigned char *)s->init_buf->data;
|
|
+ /* see if we have the required fragment already */
|
|
+ if ((frag_len = dtls1_retrieve_buffered_fragment(s,max,ok)) || *ok)
|
|
+ {
|
|
+ if (*ok) s->init_num += frag_len;
|
|
+ return frag_len;
|
|
+ }
|
|
|
|
- /* read handshake message header */
|
|
- i=s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,&p[s->init_num],
|
|
+ /* read handshake message header */
|
|
+ i=s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,wire,
|
|
DTLS1_HM_HEADER_LENGTH, 0);
|
|
if (i <= 0) /* nbio, or an error */
|
|
{
|
|
@@ -555,130 +633,61 @@ dtls1_get_message_fragment(SSL *s, int s
|
|
*ok = 0;
|
|
return i;
|
|
}
|
|
-
|
|
OPENSSL_assert(i == DTLS1_HM_HEADER_LENGTH);
|
|
|
|
- p += s->init_num;
|
|
- /* parse the message fragment header */
|
|
-
|
|
- dtls1_get_message_header(p, &msg_hdr);
|
|
+ /* parse the message fragment header */
|
|
+ dtls1_get_message_header(wire, &msg_hdr);
|
|
|
|
- /*
|
|
- * if this is a future (or stale) message it gets buffered
|
|
- * (or dropped)--no further processing at this time
|
|
- */
|
|
- if ( msg_hdr.seq != s->d1->handshake_read_seq)
|
|
- return dtls1_process_out_of_seq_message(s, &msg_hdr, ok);
|
|
+ /*
|
|
+ * if this is a future (or stale) message it gets buffered
|
|
+ * (or dropped)--no further processing at this time
|
|
+ */
|
|
+ if ( msg_hdr.seq != s->d1->handshake_read_seq)
|
|
+ return dtls1_process_out_of_seq_message(s, &msg_hdr, ok);
|
|
|
|
- l = msg_hdr.msg_len;
|
|
- frag_off = msg_hdr.frag_off;
|
|
+ l = msg_hdr.msg_len;
|
|
+ frag_off = msg_hdr.frag_off;
|
|
frag_len = msg_hdr.frag_len;
|
|
|
|
- /* sanity checking */
|
|
- if ( frag_off + frag_len > l)
|
|
- {
|
|
- al=SSL_AD_ILLEGAL_PARAMETER;
|
|
- SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE);
|
|
- goto f_err;
|
|
- }
|
|
-
|
|
if (!s->server && s->d1->r_msg_hdr.frag_off == 0 &&
|
|
- p[0] == SSL3_MT_HELLO_REQUEST)
|
|
- {
|
|
- /* The server may always send 'Hello Request' messages --
|
|
- * we are doing a handshake anyway now, so ignore them
|
|
- * if their format is correct. Does not count for
|
|
- * 'Finished' MAC. */
|
|
- if (p[1] == 0 && p[2] == 0 &&p[3] == 0)
|
|
- {
|
|
- if (s->msg_callback)
|
|
- s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
|
|
- p, DTLS1_HM_HEADER_LENGTH, s,
|
|
- s->msg_callback_arg);
|
|
-
|
|
- s->init_num = 0;
|
|
- return dtls1_get_message_fragment(s, st1, stn,
|
|
- max, ok);
|
|
- }
|
|
- else /* Incorrectly formated Hello request */
|
|
- {
|
|
- al=SSL_AD_UNEXPECTED_MESSAGE;
|
|
- SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,SSL_R_UNEXPECTED_MESSAGE);
|
|
- goto f_err;
|
|
- }
|
|
- }
|
|
-
|
|
- /* XDTLS: do a sanity check on the fragment */
|
|
-
|
|
- s->init_num += i;
|
|
-
|
|
- if ( s->d1->r_msg_hdr.frag_off == 0) /* first fragment */
|
|
+ wire[0] == SSL3_MT_HELLO_REQUEST)
|
|
{
|
|
- /* BUF_MEM_grow takes an 'int' parameter */
|
|
- if (l > (INT_MAX-DTLS1_HM_HEADER_LENGTH))
|
|
+ /* The server may always send 'Hello Request' messages --
|
|
+ * we are doing a handshake anyway now, so ignore them
|
|
+ * if their format is correct. Does not count for
|
|
+ * 'Finished' MAC. */
|
|
+ if (wire[1] == 0 && wire[2] == 0 && wire[3] == 0)
|
|
{
|
|
- al=SSL_AD_ILLEGAL_PARAMETER;
|
|
- SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE);
|
|
- goto f_err;
|
|
- }
|
|
- if (l && !BUF_MEM_grow_clean(s->init_buf,(int)l
|
|
- + DTLS1_HM_HEADER_LENGTH))
|
|
- {
|
|
- SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,ERR_R_BUF_LIB);
|
|
- goto err;
|
|
+ if (s->msg_callback)
|
|
+ s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
|
|
+ wire, DTLS1_HM_HEADER_LENGTH, s,
|
|
+ s->msg_callback_arg);
|
|
+
|
|
+ s->init_num = 0;
|
|
+ return dtls1_get_message_fragment(s, st1, stn,
|
|
+ max, ok);
|
|
}
|
|
- /* Only do this test when we're reading the expected message.
|
|
- * Stale messages will be dropped and future messages will be buffered */
|
|
- if ( l > (unsigned long)max)
|
|
+ else /* Incorrectly formated Hello request */
|
|
{
|
|
- al=SSL_AD_ILLEGAL_PARAMETER;
|
|
- SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE);
|
|
+ al=SSL_AD_UNEXPECTED_MESSAGE;
|
|
+ SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,SSL_R_UNEXPECTED_MESSAGE);
|
|
goto f_err;
|
|
}
|
|
-
|
|
- s->s3->tmp.message_size=l;
|
|
}
|
|
|
|
- if ( frag_len > (unsigned long)max)
|
|
- {
|
|
- al=SSL_AD_ILLEGAL_PARAMETER;
|
|
- SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE);
|
|
- goto f_err;
|
|
- }
|
|
- if ( frag_len + s->init_num > (INT_MAX - DTLS1_HM_HEADER_LENGTH))
|
|
- {
|
|
- al=SSL_AD_ILLEGAL_PARAMETER;
|
|
- SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,SSL_R_EXCESSIVE_MESSAGE_SIZE);
|
|
- goto f_err;
|
|
- }
|
|
-
|
|
- if ( frag_len & !BUF_MEM_grow_clean(s->init_buf, (int)frag_len
|
|
- + DTLS1_HM_HEADER_LENGTH + s->init_num))
|
|
- {
|
|
- SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT,ERR_R_BUF_LIB);
|
|
- goto err;
|
|
- }
|
|
-
|
|
- if ( s->d1->r_msg_hdr.frag_off == 0)
|
|
- {
|
|
- s->s3->tmp.message_type = msg_hdr.type;
|
|
- s->d1->r_msg_hdr.type = msg_hdr.type;
|
|
- s->d1->r_msg_hdr.msg_len = l;
|
|
- /* s->d1->r_msg_hdr.seq = seq_num; */
|
|
- }
|
|
+ if ((al=dtls1_preprocess_fragment(s,&msg_hdr,max)))
|
|
+ goto f_err;
|
|
|
|
/* XDTLS: ressurect this when restart is in place */
|
|
s->state=stn;
|
|
-
|
|
- /* next state (stn) */
|
|
- p = (unsigned char *)s->init_buf->data;
|
|
|
|
if ( frag_len > 0)
|
|
{
|
|
+ unsigned char *p=s->init_buf->data+DTLS1_HM_HEADER_LENGTH;
|
|
+
|
|
i=s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
|
|
- &p[s->init_num],
|
|
- frag_len,0);
|
|
- /* XDTLS: fix this--message fragments cannot span multiple packets */
|
|
+ &p[frag_off],frag_len,0);
|
|
+ /* XDTLS: fix this--message fragments cannot span multiple packets */
|
|
if (i <= 0)
|
|
{
|
|
s->rwstate=SSL_READING;
|
|
@@ -689,70 +698,23 @@ dtls1_get_message_fragment(SSL *s, int s
|
|
else
|
|
i = 0;
|
|
|
|
- /* XDTLS: an incorrectly formatted fragment should cause the
|
|
- * handshake to fail */
|
|
+ /* XDTLS: an incorrectly formatted fragment should cause the
|
|
+ * handshake to fail */
|
|
OPENSSL_assert(i == (int)frag_len);
|
|
|
|
-#if 0
|
|
- /* Successfully read a fragment.
|
|
- * It may be (1) out of order, or
|
|
- * (2) it's a repeat, in which case we dump it
|
|
- * (3) the one we are expecting next (maybe with overlap)
|
|
- * If it is next one, it may overlap with previously read bytes
|
|
- */
|
|
+ *ok = 1;
|
|
|
|
- /* case (1): buffer the future fragment
|
|
- * (we can treat fragments from a future message the same
|
|
- * as future fragments from the message being currently read, since
|
|
- * they are sematically simply out of order.
|
|
- */
|
|
- if ( msg_hdr.seq > s->d1->handshake_read_seq ||
|
|
- frag_off > s->init_num - DTLS1_HM_HEADER_LENGTH)
|
|
- {
|
|
- dtls1_buffer_handshake_fragment(s, &msg_hdr);
|
|
- return DTLS1_HM_FRAGMENT_RETRY;
|
|
- }
|
|
-
|
|
- /* case (2): drop the entire fragment, and try again */
|
|
- if ( msg_hdr.seq < s->d1->handshake_read_seq ||
|
|
- frag_off + frag_len < s->init_num - DTLS1_HM_HEADER_LENGTH)
|
|
- {
|
|
- s->init_num -= DTLS1_HM_HEADER_LENGTH;
|
|
- return DTLS1_HM_FRAGMENT_RETRY;
|
|
- }
|
|
-#endif
|
|
-
|
|
- /* case (3): received a immediately useful fragment. Determine the
|
|
- * possible overlap and copy the fragment.
|
|
- */
|
|
- overlap = (s->init_num - DTLS1_HM_HEADER_LENGTH) - frag_off;
|
|
-
|
|
- /* retain the header for the first fragment */
|
|
- if ( s->init_num > DTLS1_HM_HEADER_LENGTH)
|
|
- {
|
|
- memmove(&(s->init_buf->data[s->init_num]),
|
|
- &(s->init_buf->data[s->init_num + DTLS1_HM_HEADER_LENGTH + overlap]),
|
|
- frag_len - overlap);
|
|
-
|
|
- s->init_num += frag_len - overlap;
|
|
- }
|
|
- else
|
|
- s->init_num += frag_len;
|
|
-
|
|
- dtls1_process_handshake_fragment(s, frag_len - overlap);
|
|
-
|
|
- if (s->msg_callback)
|
|
- s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->init_buf->data,
|
|
- (size_t)s->init_num, s,
|
|
- s->msg_callback_arg);
|
|
- *ok=1;
|
|
-
|
|
- return s->init_num;
|
|
+ /* Note that s->init_num is *not* used as current offset in
|
|
+ * s->init_buf->data, but as a counter summing up fragments'
|
|
+ * lengths: as soon as they sum up to handshake packet
|
|
+ * length, we assume we have got all the fragments. */
|
|
+ s->init_num += frag_len;
|
|
+ return frag_len;
|
|
|
|
f_err:
|
|
ssl3_send_alert(s,SSL3_AL_FATAL,al);
|
|
- s->init_num = 0;
|
|
-err:
|
|
+ s->init_num = 0;
|
|
+
|
|
*ok=0;
|
|
return(-1);
|
|
}
|
|
@@ -790,7 +752,7 @@ int dtls1_send_finished(SSL *s, int a, i
|
|
|
|
/* buffer the message to handle re-xmits */
|
|
dtls1_buffer_message(s, 0);
|
|
-
|
|
+
|
|
s->state=b;
|
|
}
|
|
|
|
@@ -816,9 +778,14 @@ int dtls1_send_change_cipher_spec(SSL *s
|
|
*p++=SSL3_MT_CCS;
|
|
s->d1->handshake_write_seq = s->d1->next_handshake_write_seq;
|
|
s->d1->next_handshake_write_seq++;
|
|
- s2n(s->d1->handshake_write_seq,p);
|
|
-
|
|
s->init_num=DTLS1_CCS_HEADER_LENGTH;
|
|
+
|
|
+ if (s->client_version == DTLS1_BAD_VER)
|
|
+ {
|
|
+ s2n(s->d1->handshake_write_seq,p);
|
|
+ s->init_num+=2;
|
|
+ }
|
|
+
|
|
s->init_off=0;
|
|
|
|
dtls1_set_message_header_int(s, SSL3_MT_CCS, 0,
|
|
@@ -1056,7 +1023,7 @@ dtls1_buffer_message(SSL *s, int is_ccs)
|
|
if ( is_ccs)
|
|
{
|
|
OPENSSL_assert(s->d1->w_msg_hdr.msg_len +
|
|
- DTLS1_CCS_HEADER_LENGTH == (unsigned int)s->init_num);
|
|
+ DTLS1_CCS_HEADER_LENGTH <= (unsigned int)s->init_num);
|
|
}
|
|
else
|
|
{
|
|
@@ -1259,5 +1226,4 @@ dtls1_get_ccs_header(unsigned char *data
|
|
memset(ccs_hdr, 0x00, sizeof(struct ccs_header_st));
|
|
|
|
ccs_hdr->type = *(data++);
|
|
- n2s(data, ccs_hdr->seq);
|
|
}
|
|
diff -up openssl-0.9.8b/ssl/d1_clnt.c.dtls-fixes openssl-0.9.8b/ssl/d1_clnt.c
|
|
--- openssl-0.9.8b/ssl/d1_clnt.c.dtls-fixes 2005-12-05 18:32:19.000000000 +0100
|
|
+++ openssl-0.9.8b/ssl/d1_clnt.c 2007-10-08 17:55:22.000000000 +0200
|
|
@@ -214,17 +214,21 @@ int dtls1_connect(SSL *s)
|
|
|
|
/* don't push the buffering BIO quite yet */
|
|
|
|
- ssl3_init_finished_mac(s);
|
|
-
|
|
s->state=SSL3_ST_CW_CLNT_HELLO_A;
|
|
s->ctx->stats.sess_connect++;
|
|
s->init_num=0;
|
|
+ /* mark client_random uninitialized */
|
|
+ memset(s->s3->client_random,0,sizeof(s->s3->client_random));
|
|
break;
|
|
|
|
case SSL3_ST_CW_CLNT_HELLO_A:
|
|
case SSL3_ST_CW_CLNT_HELLO_B:
|
|
|
|
s->shutdown=0;
|
|
+
|
|
+ /* every DTLS ClientHello resets Finished MAC */
|
|
+ ssl3_init_finished_mac(s);
|
|
+
|
|
ret=dtls1_client_hello(s);
|
|
if (ret <= 0) goto end;
|
|
|
|
@@ -422,6 +426,9 @@ int dtls1_connect(SSL *s)
|
|
s->s3->tmp.next_state=SSL3_ST_CR_FINISHED_A;
|
|
}
|
|
s->init_num=0;
|
|
+ /* mark client_random uninitialized */
|
|
+ memset (s->s3->client_random,0,sizeof(s->s3->client_random));
|
|
+
|
|
break;
|
|
|
|
case SSL3_ST_CR_FINISHED_A:
|
|
@@ -544,9 +551,15 @@ int dtls1_client_hello(SSL *s)
|
|
/* else use the pre-loaded session */
|
|
|
|
p=s->s3->client_random;
|
|
- Time=(unsigned long)time(NULL); /* Time */
|
|
- l2n(Time,p);
|
|
- RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-sizeof(Time));
|
|
+ /* if client_random is initialized, reuse it, we are
|
|
+ * required to use same upon reply to HelloVerify */
|
|
+ for (i=0;p[i]=='\0' && i<sizeof(s->s3->client_random);i++) ;
|
|
+ if (i==sizeof(s->s3->client_random))
|
|
+ {
|
|
+ Time=(unsigned long)time(NULL); /* Time */
|
|
+ l2n(Time,p);
|
|
+ RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4);
|
|
+ }
|
|
|
|
/* Do the message type and length last */
|
|
d=p= &(buf[DTLS1_HM_HEADER_LENGTH]);
|