diff --git a/openssl-0.9.8b-cve-2007-3108.patch b/openssl-0.9.8b-cve-2007-3108.patch index 81fa59e..9a3829a 100644 --- a/openssl-0.9.8b-cve-2007-3108.patch +++ b/openssl-0.9.8b-cve-2007-3108.patch @@ -336,7 +336,7 @@ diff -up openssl-0.9.8b/crypto/bn/bn_mont.c.no-branch openssl-0.9.8b/crypto/bn/b r->neg=a->neg^n->neg; np=n->d; -@@ -228,37 +228,56 @@ int BN_from_montgomery(BIGNUM *ret, cons +@@ -228,37 +228,58 @@ int BN_from_montgomery(BIGNUM *ret, cons } bn_correct_top(r); @@ -413,10 +413,12 @@ diff -up openssl-0.9.8b/crypto/bn/bn_mont.c.no-branch openssl-0.9.8b/crypto/bn/b -#endif + for (ri+=4; iN,ctx)) goto err; if (!BN_add(t2,a,t1)) goto err; if (!BN_rshift(ret,t2,mont->ri)) goto err; diff --git a/openssl-0.9.8b-cve-2007-4995.patch b/openssl-0.9.8b-cve-2007-4995.patch new file mode 100644 index 0000000..1dd4baf --- /dev/null +++ b/openssl-0.9.8b-cve-2007-4995.patch @@ -0,0 +1,1429 @@ +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; zlength; 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 + #include + #include ++#include + + 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' && is3->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]); diff --git a/openssl-0.9.8b-cve-2007-5135.patch b/openssl-0.9.8b-cve-2007-5135.patch new file mode 100644 index 0000000..49e2fff --- /dev/null +++ b/openssl-0.9.8b-cve-2007-5135.patch @@ -0,0 +1,45 @@ +Possible one byte buffer overflow in SSL_get_shared_ciphers. +CVE-2007-5135 +diff -up openssl-0.9.8b/ssl/ssl_lib.c.orig openssl-0.9.8b/ssl/ssl_lib.c +--- openssl-0.9.8b/ssl/ssl_lib.c.orig 2007-10-08 10:20:42.000000000 +0200 ++++ openssl-0.9.8b/ssl/ssl_lib.c 2007-10-08 17:32:29.000000000 +0200 +@@ -1201,7 +1201,6 @@ int SSL_set_cipher_list(SSL *s,const cha + char *SSL_get_shared_ciphers(const SSL *s,char *buf,int len) + { + char *p; +- const char *cp; + STACK_OF(SSL_CIPHER) *sk; + SSL_CIPHER *c; + int i; +@@ -1214,20 +1213,21 @@ char *SSL_get_shared_ciphers(const SSL * + sk=s->session->ciphers; + for (i=0; iname; *cp; ) ++ n=strlen(c->name); ++ if (n+1 > len) + { +- if (len-- <= 0) +- { +- *p='\0'; +- return(buf); +- } +- else +- *(p++)= *(cp++); ++ if (p != buf) ++ --p; ++ *p='\0'; ++ return buf; + } ++ strcpy(p,c->name); ++ p+=n; + *(p++)=':'; ++ len-=n+1; + } + p[-1]='\0'; + return(buf); diff --git a/openssl.spec b/openssl.spec index 31d3921..1c3190d 100644 --- a/openssl.spec +++ b/openssl.spec @@ -21,7 +21,7 @@ Summary: The OpenSSL toolkit Name: openssl Version: 0.9.8b -Release: 14%{?dist} +Release: 15%{?dist} Source: openssl-%{version}-usa.tar.bz2 Source1: hobble-openssl Source2: Makefile.certificate @@ -66,6 +66,8 @@ Patch63: openssl-0.9.8b-x509-add-dir.patch Patch64: openssl-0.9.8b-test-use-localhost.patch Patch65: openssl-0.9.8b-cve-2007-3108.patch Patch66: openssl-0.9.7a-ssl-strict-matching.patch +Patch67: openssl-0.9.8b-cve-2007-4995.patch +Patch68: openssl-0.9.8b-cve-2007-5135.patch License: OpenSSL Group: System Environment/Libraries @@ -142,6 +144,8 @@ from other formats to the formats used by the OpenSSL toolkit. %patch64 -p1 -b .use-localhost %patch65 -p1 -b .no-branch %patch66 -p1 -b .strict-matching +%patch67 -p1 -b .dtls-fixes +%patch68 -p1 -b .shciphers # Modify the various perl scripts to reference perl in the right location. perl util/perlpath.pl `dirname %{__perl}` @@ -382,6 +386,10 @@ rm -rf $RPM_BUILD_ROOT/%{_bindir}/openssl_fips_fingerprint %postun -p /sbin/ldconfig %changelog +* Fri Oct 12 2007 Tomas Mraz 0.9.8b-15 +- fix CVE-2007-5135 - off-by-one in SSL_get_shared_ciphers (#309801) +- fix CVE-2007-4995 - out of order DTLS fragments buffer overflow (#321191) + * Fri Aug 3 2007 Tomas Mraz 0.9.8b-14 - use localhost in testsuite, hopefully fixes slow build in koji - CVE-2007-3108 - fix side channel attack on private keys (#250577)