aboutsummaryrefslogtreecommitdiffstats
path: root/ssl
diff options
context:
space:
mode:
authorSimon L. B. Nielsen <simon@FreeBSD.org>2010-02-28 18:49:43 +0000
committerSimon L. B. Nielsen <simon@FreeBSD.org>2010-02-28 18:49:43 +0000
commitf7a1b4761cf3f798e1b42d703d38221b47ce1eec (patch)
tree21770f10e7f26d05fc9b0fa96a7b6d7b107552c5 /ssl
parentf0c2a617dfb432d01bc5a716eb18dae12e6b45e3 (diff)
downloadsrc-f7a1b4761cf3f798e1b42d703d38221b47ce1eec.tar.gz
src-f7a1b4761cf3f798e1b42d703d38221b47ce1eec.zip
Import OpenSSL 0.9.8m.vendor/openssl/0.9.8m
Notes
Notes: svn path=/vendor-crypto/openssl/dist/; revision=204477 svn path=/vendor-crypto/openssl/0.9.8m/; revision=204478; tag=vendor/openssl/0.9.8m
Diffstat (limited to 'ssl')
-rw-r--r--ssl/Makefile25
-rw-r--r--ssl/d1_both.c242
-rw-r--r--ssl/d1_clnt.c104
-rw-r--r--ssl/d1_enc.c2
-rw-r--r--ssl/d1_lib.c199
-rw-r--r--ssl/d1_pkt.c225
-rw-r--r--ssl/d1_srvr.c228
-rw-r--r--ssl/dtls1.h52
-rw-r--r--ssl/kssl.c5
-rw-r--r--ssl/s23_clnt.c5
-rw-r--r--ssl/s23_srvr.c9
-rw-r--r--ssl/s2_srvr.c2
-rw-r--r--ssl/s3_both.c127
-rw-r--r--ssl/s3_clnt.c59
-rw-r--r--ssl/s3_lib.c17
-rw-r--r--ssl/s3_pkt.c57
-rw-r--r--ssl/s3_srvr.c84
-rw-r--r--ssl/ssl.h49
-rw-r--r--ssl/ssl3.h9
-rw-r--r--ssl/ssl_algs.c3
-rw-r--r--ssl/ssl_asn1.c65
-rw-r--r--ssl/ssl_cert.c7
-rw-r--r--ssl/ssl_ciph.c3
-rw-r--r--ssl/ssl_err.c16
-rw-r--r--ssl/ssl_lib.c60
-rw-r--r--ssl/ssl_locl.h27
-rw-r--r--ssl/ssl_rsa.c2
-rw-r--r--ssl/ssl_sess.c7
-rw-r--r--ssl/ssl_stat.c11
-rw-r--r--ssl/ssl_txt.c8
-rw-r--r--ssl/t1_enc.c6
-rw-r--r--ssl/t1_lib.c156
-rw-r--r--ssl/t1_reneg.c292
-rw-r--r--ssl/tls1.h7
34 files changed, 1761 insertions, 409 deletions
diff --git a/ssl/Makefile b/ssl/Makefile
index 46c06597fa4c..5ac350745a19 100644
--- a/ssl/Makefile
+++ b/ssl/Makefile
@@ -30,7 +30,7 @@ LIBSRC= \
ssl_lib.c ssl_err2.c ssl_cert.c ssl_sess.c \
ssl_ciph.c ssl_stat.c ssl_rsa.c \
ssl_asn1.c ssl_txt.c ssl_algs.c \
- bio_ssl.c ssl_err.c kssl.c
+ bio_ssl.c ssl_err.c kssl.c t1_reneg.c
LIBOBJ= \
s2_meth.o s2_srvr.o s2_clnt.o s2_lib.o s2_enc.o s2_pkt.o \
s3_meth.o s3_srvr.o s3_clnt.o s3_lib.o s3_enc.o s3_pkt.o s3_both.o \
@@ -41,7 +41,7 @@ LIBOBJ= \
ssl_lib.o ssl_err2.o ssl_cert.o ssl_sess.o \
ssl_ciph.o ssl_stat.o ssl_rsa.o \
ssl_asn1.o ssl_txt.o ssl_algs.o \
- bio_ssl.o ssl_err.o kssl.o
+ bio_ssl.o ssl_err.o kssl.o t1_reneg.o
SRC= $(LIBSRC)
@@ -994,6 +994,27 @@ t1_meth.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
t1_meth.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
t1_meth.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h ssl_locl.h
t1_meth.o: t1_meth.c
+t1_reneg.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
+t1_reneg.o: ../include/openssl/bn.h ../include/openssl/buffer.h
+t1_reneg.o: ../include/openssl/comp.h ../include/openssl/crypto.h
+t1_reneg.o: ../include/openssl/dsa.h ../include/openssl/dtls1.h
+t1_reneg.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
+t1_reneg.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
+t1_reneg.o: ../include/openssl/err.h ../include/openssl/evp.h
+t1_reneg.o: ../include/openssl/fips.h ../include/openssl/hmac.h
+t1_reneg.o: ../include/openssl/kssl.h ../include/openssl/lhash.h
+t1_reneg.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
+t1_reneg.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
+t1_reneg.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
+t1_reneg.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
+t1_reneg.o: ../include/openssl/pq_compat.h ../include/openssl/pqueue.h
+t1_reneg.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
+t1_reneg.o: ../include/openssl/sha.h ../include/openssl/ssl.h
+t1_reneg.o: ../include/openssl/ssl2.h ../include/openssl/ssl23.h
+t1_reneg.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
+t1_reneg.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
+t1_reneg.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h ssl_locl.h
+t1_reneg.o: t1_reneg.c
t1_srvr.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
t1_srvr.o: ../include/openssl/bn.h ../include/openssl/buffer.h
t1_srvr.o: ../include/openssl/comp.h ../include/openssl/crypto.h
diff --git a/ssl/d1_both.c b/ssl/d1_both.c
index 017719210613..0a5c08d71395 100644
--- a/ssl/d1_both.c
+++ b/ssl/d1_both.c
@@ -136,7 +136,6 @@ static unsigned char *dtls1_write_message_header(SSL *s,
static void dtls1_set_message_header_int(SSL *s, unsigned char mt,
unsigned long len, unsigned short seq_num, unsigned long frag_off,
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);
@@ -178,7 +177,7 @@ int dtls1_do_write(SSL *s, int type)
{
int ret;
int curr_mtu;
- unsigned int len, frag_off;
+ unsigned int len, frag_off, mac_size, blocksize;
/* AHA! Figure out the MTU, and stick to the right size */
if ( ! (SSL_get_options(s) & SSL_OP_NO_QUERY_MTU))
@@ -226,11 +225,22 @@ int dtls1_do_write(SSL *s, int type)
OPENSSL_assert(s->init_num ==
(int)s->d1->w_msg_hdr.msg_len + DTLS1_HM_HEADER_LENGTH);
+ if (s->write_hash)
+ mac_size = EVP_MD_size(s->write_hash);
+ else
+ mac_size = 0;
+
+ if (s->enc_write_ctx &&
+ (EVP_CIPHER_mode( s->enc_write_ctx->cipher) & EVP_CIPH_CBC_MODE))
+ blocksize = 2 * EVP_CIPHER_block_size(s->enc_write_ctx->cipher);
+ else
+ blocksize = 0;
+
frag_off = 0;
while( s->init_num)
{
curr_mtu = s->d1->mtu - BIO_wpending(SSL_get_wbio(s)) -
- DTLS1_RT_HEADER_LENGTH;
+ DTLS1_RT_HEADER_LENGTH - mac_size - blocksize;
if ( curr_mtu <= DTLS1_HM_HEADER_LENGTH)
{
@@ -238,7 +248,8 @@ int dtls1_do_write(SSL *s, int type)
ret = BIO_flush(SSL_get_wbio(s));
if ( ret <= 0)
return ret;
- curr_mtu = s->d1->mtu - DTLS1_RT_HEADER_LENGTH;
+ curr_mtu = s->d1->mtu - DTLS1_RT_HEADER_LENGTH -
+ mac_size - blocksize;
}
if ( s->init_num > curr_mtu)
@@ -280,7 +291,7 @@ int dtls1_do_write(SSL *s, int type)
* retransmit
*/
if ( BIO_ctrl(SSL_get_wbio(s),
- BIO_CTRL_DGRAM_MTU_EXCEEDED, 0, NULL))
+ BIO_CTRL_DGRAM_MTU_EXCEEDED, 0, NULL) > 0 )
s->d1->mtu = BIO_ctrl(SSL_get_wbio(s),
BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
else
@@ -569,9 +580,13 @@ dtls1_process_out_of_seq_message(SSL *s, struct hm_header_st* msg_hdr, int *ok)
pq_64bit_free(&seq64);
/* Discard the message if sequence number was already there, is
- * too far in the future or the fragment is already in the queue */
+ * too far in the future, already in the queue or if we received
+ * a FINISHED before the SERVER_HELLO, which then must be a stale
+ * retransmit.
+ */
if (msg_hdr->seq <= s->d1->handshake_read_seq ||
- msg_hdr->seq > s->d1->handshake_read_seq + 10 || item != NULL)
+ msg_hdr->seq > s->d1->handshake_read_seq + 10 || item != NULL ||
+ (s->d1->handshake_read_seq == 0 && msg_hdr->type == SSL3_MT_FINISHED))
{
unsigned char devnull [256];
@@ -750,6 +765,24 @@ int dtls1_send_finished(SSL *s, int a, int b, const char *sender, int slen)
p+=i;
l=i;
+ /* Copy the finished so we can use it for
+ * renegotiation checks
+ */
+ if(s->type == SSL_ST_CONNECT)
+ {
+ OPENSSL_assert(i <= EVP_MAX_MD_SIZE);
+ memcpy(s->s3->previous_client_finished,
+ s->s3->tmp.finish_md, i);
+ s->s3->previous_client_finished_len=i;
+ }
+ else
+ {
+ OPENSSL_assert(i <= EVP_MAX_MD_SIZE);
+ memcpy(s->s3->previous_server_finished,
+ s->s3->tmp.finish_md, i);
+ s->s3->previous_server_finished_len=i;
+ }
+
#ifdef OPENSSL_SYS_WIN16
/* MSVC 1.5 does not clear the top bytes of the word unless
* I do this.
@@ -812,14 +845,30 @@ int dtls1_send_change_cipher_spec(SSL *s, int a, int b)
return(dtls1_do_write(s,SSL3_RT_CHANGE_CIPHER_SPEC));
}
+static int dtls1_add_cert_to_buf(BUF_MEM *buf, unsigned long *l, X509 *x)
+ {
+ int n;
+ unsigned char *p;
+
+ n=i2d_X509(x,NULL);
+ if (!BUF_MEM_grow_clean(buf,(int)(n+(*l)+3)))
+ {
+ SSLerr(SSL_F_DTLS1_ADD_CERT_TO_BUF,ERR_R_BUF_LIB);
+ return 0;
+ }
+ p=(unsigned char *)&(buf->data[*l]);
+ l2n3(n,p);
+ i2d_X509(x,&p);
+ *l+=n+3;
+
+ return 1;
+ }
unsigned long dtls1_output_cert_chain(SSL *s, X509 *x)
{
unsigned char *p;
- int n,i;
+ int i;
unsigned long l= 3 + DTLS1_HM_HEADER_LENGTH;
BUF_MEM *buf;
- X509_STORE_CTX xs_ctx;
- X509_OBJECT obj;
/* TLSv1 sends a chain with nothing in it, instead of an alert */
buf=s->init_buf;
@@ -830,54 +879,33 @@ unsigned long dtls1_output_cert_chain(SSL *s, X509 *x)
}
if (x != NULL)
{
- if(!X509_STORE_CTX_init(&xs_ctx,s->ctx->cert_store,NULL,NULL))
- {
- SSLerr(SSL_F_DTLS1_OUTPUT_CERT_CHAIN,ERR_R_X509_LIB);
- return(0);
- }
-
- for (;;)
- {
- n=i2d_X509(x,NULL);
- if (!BUF_MEM_grow_clean(buf,(int)(n+l+3)))
- {
- SSLerr(SSL_F_DTLS1_OUTPUT_CERT_CHAIN,ERR_R_BUF_LIB);
- return(0);
- }
- p=(unsigned char *)&(buf->data[l]);
- l2n3(n,p);
- i2d_X509(x,&p);
- l+=n+3;
- if (X509_NAME_cmp(X509_get_subject_name(x),
- X509_get_issuer_name(x)) == 0) break;
-
- i=X509_STORE_get_by_subject(&xs_ctx,X509_LU_X509,
- X509_get_issuer_name(x),&obj);
- if (i <= 0) break;
- x=obj.data.x509;
- /* Count is one too high since the X509_STORE_get uped the
- * ref count */
- X509_free(x);
- }
-
- X509_STORE_CTX_cleanup(&xs_ctx);
- }
-
+ X509_STORE_CTX xs_ctx;
+
+ if (!X509_STORE_CTX_init(&xs_ctx,s->ctx->cert_store,x,NULL))
+ {
+ SSLerr(SSL_F_DTLS1_OUTPUT_CERT_CHAIN,ERR_R_X509_LIB);
+ return(0);
+ }
+
+ X509_verify_cert(&xs_ctx);
+ for (i=0; i < sk_X509_num(xs_ctx.chain); i++)
+ {
+ x = sk_X509_value(xs_ctx.chain, i);
+
+ if (!dtls1_add_cert_to_buf(buf, &l, x))
+ {
+ X509_STORE_CTX_cleanup(&xs_ctx);
+ return 0;
+ }
+ }
+ X509_STORE_CTX_cleanup(&xs_ctx);
+ }
/* Thawte special :-) */
- if (s->ctx->extra_certs != NULL)
for (i=0; i<sk_X509_num(s->ctx->extra_certs); i++)
{
x=sk_X509_value(s->ctx->extra_certs,i);
- n=i2d_X509(x,NULL);
- if (!BUF_MEM_grow_clean(buf,(int)(n+l+3)))
- {
- SSLerr(SSL_F_DTLS1_OUTPUT_CERT_CHAIN,ERR_R_BUF_LIB);
- return(0);
- }
- p=(unsigned char *)&(buf->data[l]);
- l2n3(n,p);
- i2d_X509(x,&p);
- l+=n+3;
+ if (!dtls1_add_cert_to_buf(buf, &l, x))
+ return 0;
}
l-= (3 + DTLS1_HM_HEADER_LENGTH);
@@ -894,18 +922,13 @@ unsigned long dtls1_output_cert_chain(SSL *s, X509 *x)
int dtls1_read_failed(SSL *s, int code)
{
- DTLS1_STATE *state;
- BIO *bio;
- int send_alert = 0;
-
if ( code > 0)
{
fprintf( stderr, "invalid state reached %s:%d", __FILE__, __LINE__);
return 1;
}
- bio = SSL_get_rbio(s);
- if ( ! BIO_dgram_recv_timedout(bio))
+ if (!dtls1_is_timer_expired(s))
{
/* not a timeout, none of our business,
let higher layers handle this. in fact it's probably an error */
@@ -918,23 +941,6 @@ int dtls1_read_failed(SSL *s, int code)
return code;
}
- state = s->d1;
- state->timeout.num_alerts++;
- if ( state->timeout.num_alerts > DTLS1_TMO_ALERT_COUNT)
- {
- /* fail the connection, enough alerts have been sent */
- SSLerr(SSL_F_DTLS1_READ_FAILED,SSL_R_READ_TIMEOUT_EXPIRED);
- return 0;
- }
-
- state->timeout.read_timeouts++;
- if ( state->timeout.read_timeouts > DTLS1_TMO_READ_COUNT)
- {
- send_alert = 1;
- state->timeout.read_timeouts = 1;
- }
-
-
#if 0 /* for now, each alert contains only one record number */
item = pqueue_peek(state->rcvd_records);
if ( item )
@@ -945,16 +951,29 @@ int dtls1_read_failed(SSL *s, int code)
#endif
#if 0 /* no more alert sending, just retransmit the last set of messages */
- if ( send_alert)
- ssl3_send_alert(s,SSL3_AL_WARNING,
- DTLS1_AD_MISSING_HANDSHAKE_MESSAGE);
+ if ( state->timeout.read_timeouts >= DTLS1_TMO_READ_COUNT)
+ ssl3_send_alert(s,SSL3_AL_WARNING,
+ DTLS1_AD_MISSING_HANDSHAKE_MESSAGE);
#endif
- return dtls1_retransmit_buffered_messages(s) ;
+ return dtls1_handle_timeout(s);
}
+int
+dtls1_get_queue_priority(unsigned short seq, int is_ccs)
+ {
+ /* The index of the retransmission queue actually is the message sequence number,
+ * since the queue only contains messages of a single handshake. However, the
+ * ChangeCipherSpec has no message sequence number and so using only the sequence
+ * will result in the CCS and Finished having the same index. To prevent this,
+ * the sequence number is multiplied by 2. In case of a CCS 1 is subtracted.
+ * This does not only differ CSS and Finished, it also maintains the order of the
+ * index (important for priority queues) and fits in the unsigned short variable.
+ */
+ return seq * 2 - is_ccs;
+ }
-static int
+int
dtls1_retransmit_buffered_messages(SSL *s)
{
pqueue sent = s->d1->sent_messages;
@@ -968,8 +987,9 @@ dtls1_retransmit_buffered_messages(SSL *s)
for ( item = pqueue_next(&iter); item != NULL; item = pqueue_next(&iter))
{
frag = (hm_fragment *)item->data;
- if ( dtls1_retransmit_message(s, frag->msg_header.seq, 0, &found) <= 0 &&
- found)
+ if ( dtls1_retransmit_message(s,
+ (unsigned short)dtls1_get_queue_priority(frag->msg_header.seq, frag->msg_header.is_ccs),
+ 0, &found) <= 0 && found)
{
fprintf(stderr, "dtls1_retransmit_message() failed\n");
return -1;
@@ -985,7 +1005,6 @@ dtls1_buffer_message(SSL *s, int is_ccs)
pitem *item;
hm_fragment *frag;
PQ_64BIT seq64;
- unsigned int epoch = s->d1->w_epoch;
/* this function is called immediately after a message has
* been serialized */
@@ -999,7 +1018,6 @@ dtls1_buffer_message(SSL *s, int is_ccs)
{
OPENSSL_assert(s->d1->w_msg_hdr.msg_len +
DTLS1_CCS_HEADER_LENGTH <= (unsigned int)s->init_num);
- epoch++;
}
else
{
@@ -1014,9 +1032,19 @@ dtls1_buffer_message(SSL *s, int is_ccs)
frag->msg_header.frag_len = s->d1->w_msg_hdr.msg_len;
frag->msg_header.is_ccs = is_ccs;
+ /* save current state*/
+ frag->msg_header.saved_retransmit_state.enc_write_ctx = s->enc_write_ctx;
+ frag->msg_header.saved_retransmit_state.write_hash = s->write_hash;
+ frag->msg_header.saved_retransmit_state.compress = s->compress;
+ frag->msg_header.saved_retransmit_state.session = s->session;
+ frag->msg_header.saved_retransmit_state.epoch = s->d1->w_epoch;
+
pq_64bit_init(&seq64);
- pq_64bit_assign_word(&seq64, epoch<<16 | frag->msg_header.seq);
+ pq_64bit_assign_word(&seq64,
+ dtls1_get_queue_priority(frag->msg_header.seq,
+ frag->msg_header.is_ccs));
+
item = pitem_new(seq64, frag);
pq_64bit_free(&seq64);
if ( item == NULL)
@@ -1045,6 +1073,8 @@ dtls1_retransmit_message(SSL *s, unsigned short seq, unsigned long frag_off,
hm_fragment *frag ;
unsigned long header_length;
PQ_64BIT seq64;
+ struct dtls1_retransmit_state saved_state;
+ unsigned char save_write_sequence[8];
/*
OPENSSL_assert(s->init_num == 0);
@@ -1080,9 +1110,45 @@ dtls1_retransmit_message(SSL *s, unsigned short seq, unsigned long frag_off,
frag->msg_header.msg_len, frag->msg_header.seq, 0,
frag->msg_header.frag_len);
+ /* save current state */
+ saved_state.enc_write_ctx = s->enc_write_ctx;
+ saved_state.write_hash = s->write_hash;
+ saved_state.compress = s->compress;
+ saved_state.session = s->session;
+ saved_state.epoch = s->d1->w_epoch;
+ saved_state.epoch = s->d1->w_epoch;
+
s->d1->retransmitting = 1;
+
+ /* restore state in which the message was originally sent */
+ s->enc_write_ctx = frag->msg_header.saved_retransmit_state.enc_write_ctx;
+ s->write_hash = frag->msg_header.saved_retransmit_state.write_hash;
+ s->compress = frag->msg_header.saved_retransmit_state.compress;
+ s->session = frag->msg_header.saved_retransmit_state.session;
+ s->d1->w_epoch = frag->msg_header.saved_retransmit_state.epoch;
+
+ if (frag->msg_header.saved_retransmit_state.epoch == saved_state.epoch - 1)
+ {
+ memcpy(save_write_sequence, s->s3->write_sequence, sizeof(s->s3->write_sequence));
+ memcpy(s->s3->write_sequence, s->d1->last_write_sequence, sizeof(s->s3->write_sequence));
+ }
+
ret = dtls1_do_write(s, frag->msg_header.is_ccs ?
- SSL3_RT_CHANGE_CIPHER_SPEC : SSL3_RT_HANDSHAKE);
+ SSL3_RT_CHANGE_CIPHER_SPEC : SSL3_RT_HANDSHAKE);
+
+ /* restore current state */
+ s->enc_write_ctx = saved_state.enc_write_ctx;
+ s->write_hash = saved_state.write_hash;
+ s->compress = saved_state.compress;
+ s->session = saved_state.session;
+ s->d1->w_epoch = saved_state.epoch;
+
+ if (frag->msg_header.saved_retransmit_state.epoch == saved_state.epoch - 1)
+ {
+ memcpy(s->d1->last_write_sequence, s->s3->write_sequence, sizeof(s->s3->write_sequence));
+ memcpy(s->s3->write_sequence, save_write_sequence, sizeof(s->s3->write_sequence));
+ }
+
s->d1->retransmitting = 0;
(void)BIO_flush(SSL_get_wbio(s));
diff --git a/ssl/d1_clnt.c b/ssl/d1_clnt.c
index 49c6760d19a7..223d11627948 100644
--- a/ssl/d1_clnt.c
+++ b/ssl/d1_clnt.c
@@ -130,7 +130,7 @@ static int dtls1_get_hello_verify(SSL *s);
static SSL_METHOD *dtls1_get_client_method(int ver)
{
- if (ver == DTLS1_VERSION)
+ if (ver == DTLS1_VERSION || ver == DTLS1_BAD_VER)
return(DTLSv1_client_method());
else
return(NULL);
@@ -145,7 +145,6 @@ int dtls1_connect(SSL *s)
{
BUF_MEM *buf=NULL;
unsigned long Time=(unsigned long)time(NULL),l;
- long num1;
void (*cb)(const SSL *ssl,int type,int val)=NULL;
int ret= -1;
int new_state,state,skip=0;;
@@ -181,7 +180,8 @@ int dtls1_connect(SSL *s)
s->server=0;
if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1);
- if ((s->version & 0xff00 ) != (DTLS1_VERSION & 0xff00))
+ if ((s->version & 0xff00 ) != (DTLS1_VERSION & 0xff00) &&
+ (s->version & 0xff00 ) != (DTLS1_BAD_VER & 0xff00))
{
SSLerr(SSL_F_DTLS1_CONNECT, ERR_R_INTERNAL_ERROR);
ret = -1;
@@ -219,6 +219,8 @@ int dtls1_connect(SSL *s)
s->init_num=0;
/* mark client_random uninitialized */
memset(s->s3->client_random,0,sizeof(s->s3->client_random));
+ s->d1->send_cookie = 0;
+ s->hit = 0;
break;
case SSL3_ST_CW_CLNT_HELLO_A:
@@ -229,6 +231,7 @@ int dtls1_connect(SSL *s)
/* every DTLS ClientHello resets Finished MAC */
ssl3_init_finished_mac(s);
+ dtls1_start_timer(s);
ret=dtls1_client_hello(s);
if (ret <= 0) goto end;
@@ -254,6 +257,7 @@ int dtls1_connect(SSL *s)
if (ret <= 0) goto end;
else
{
+ dtls1_stop_timer(s);
if (s->hit)
s->state=SSL3_ST_CR_FINISHED_A;
else
@@ -268,6 +272,7 @@ int dtls1_connect(SSL *s)
ret = dtls1_get_hello_verify(s);
if ( ret <= 0)
goto end;
+ dtls1_stop_timer(s);
if ( s->d1->send_cookie) /* start again, with a cookie */
s->state=SSL3_ST_CW_CLNT_HELLO_A;
else
@@ -277,15 +282,43 @@ int dtls1_connect(SSL *s)
case SSL3_ST_CR_CERT_A:
case SSL3_ST_CR_CERT_B:
+#ifndef OPENSSL_NO_TLSEXT
+ ret=ssl3_check_finished(s);
+ if (ret <= 0) goto end;
+ if (ret == 2)
+ {
+ s->hit = 1;
+ if (s->tlsext_ticket_expected)
+ s->state=SSL3_ST_CR_SESSION_TICKET_A;
+ else
+ s->state=SSL3_ST_CR_FINISHED_A;
+ s->init_num=0;
+ break;
+ }
+#endif
/* Check if it is anon DH */
if (!(s->s3->tmp.new_cipher->algorithms & SSL_aNULL))
{
ret=ssl3_get_server_certificate(s);
if (ret <= 0) goto end;
+#ifndef OPENSSL_NO_TLSEXT
+ if (s->tlsext_status_expected)
+ s->state=SSL3_ST_CR_CERT_STATUS_A;
+ else
+ s->state=SSL3_ST_CR_KEY_EXCH_A;
+ }
+ else
+ {
+ skip = 1;
+ s->state=SSL3_ST_CR_KEY_EXCH_A;
+ }
+#else
}
else
skip=1;
+
s->state=SSL3_ST_CR_KEY_EXCH_A;
+#endif
s->init_num=0;
break;
@@ -329,6 +362,7 @@ int dtls1_connect(SSL *s)
case SSL3_ST_CW_CERT_B:
case SSL3_ST_CW_CERT_C:
case SSL3_ST_CW_CERT_D:
+ dtls1_start_timer(s);
ret=dtls1_send_client_certificate(s);
if (ret <= 0) goto end;
s->state=SSL3_ST_CW_KEY_EXCH_A;
@@ -337,6 +371,7 @@ int dtls1_connect(SSL *s)
case SSL3_ST_CW_KEY_EXCH_A:
case SSL3_ST_CW_KEY_EXCH_B:
+ dtls1_start_timer(s);
ret=dtls1_send_client_key_exchange(s);
if (ret <= 0) goto end;
l=s->s3->tmp.new_cipher->algorithms;
@@ -359,6 +394,7 @@ int dtls1_connect(SSL *s)
case SSL3_ST_CW_CERT_VRFY_A:
case SSL3_ST_CW_CERT_VRFY_B:
+ dtls1_start_timer(s);
ret=dtls1_send_client_verify(s);
if (ret <= 0) goto end;
s->state=SSL3_ST_CW_CHANGE_A;
@@ -368,6 +404,7 @@ int dtls1_connect(SSL *s)
case SSL3_ST_CW_CHANGE_A:
case SSL3_ST_CW_CHANGE_B:
+ dtls1_start_timer(s);
ret=dtls1_send_change_cipher_spec(s,
SSL3_ST_CW_CHANGE_A,SSL3_ST_CW_CHANGE_B);
if (ret <= 0) goto end;
@@ -402,6 +439,7 @@ int dtls1_connect(SSL *s)
case SSL3_ST_CW_FINISHED_A:
case SSL3_ST_CW_FINISHED_B:
+ dtls1_start_timer(s);
ret=dtls1_send_finished(s,
SSL3_ST_CW_FINISHED_A,SSL3_ST_CW_FINISHED_B,
s->method->ssl3_enc->client_finished_label,
@@ -423,20 +461,44 @@ int dtls1_connect(SSL *s)
}
else
{
+#ifndef OPENSSL_NO_TLSEXT
+ /* Allow NewSessionTicket if ticket expected */
+ if (s->tlsext_ticket_expected)
+ s->s3->tmp.next_state=SSL3_ST_CR_SESSION_TICKET_A;
+ else
+#endif
+
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;
+#ifndef OPENSSL_NO_TLSEXT
+ case SSL3_ST_CR_SESSION_TICKET_A:
+ case SSL3_ST_CR_SESSION_TICKET_B:
+ ret=ssl3_get_new_session_ticket(s);
+ if (ret <= 0) goto end;
+ s->state=SSL3_ST_CR_FINISHED_A;
+ s->init_num=0;
+ break;
+
+ case SSL3_ST_CR_CERT_STATUS_A:
+ case SSL3_ST_CR_CERT_STATUS_B:
+ ret=ssl3_get_cert_status(s);
+ if (ret <= 0) goto end;
+ s->state=SSL3_ST_CR_KEY_EXCH_A;
+ s->init_num=0;
+ break;
+#endif
+
case SSL3_ST_CR_FINISHED_A:
case SSL3_ST_CR_FINISHED_B:
-
+ s->d1->change_cipher_spec_ok = 1;
ret=ssl3_get_finished(s,SSL3_ST_CR_FINISHED_A,
SSL3_ST_CR_FINISHED_B);
if (ret <= 0) goto end;
+ dtls1_stop_timer(s);
if (s->hit)
s->state=SSL3_ST_CW_CHANGE_A;
@@ -446,16 +508,13 @@ int dtls1_connect(SSL *s)
break;
case SSL3_ST_CW_FLUSH:
- /* number of bytes to be flushed */
- num1=BIO_ctrl(s->wbio,BIO_CTRL_INFO,0,NULL);
- if (num1 > 0)
+ s->rwstate=SSL_WRITING;
+ if (BIO_flush(s->wbio) <= 0)
{
- s->rwstate=SSL_WRITING;
- num1=BIO_flush(s->wbio);
- if (num1 <= 0) { ret= -1; goto end; }
- s->rwstate=SSL_NOTHING;
+ ret= -1;
+ goto end;
}
-
+ s->rwstate=SSL_NOTHING;
s->state=s->s3->tmp.next_state;
break;
@@ -492,6 +551,7 @@ int dtls1_connect(SSL *s)
/* done with handshaking */
s->d1->handshake_read_seq = 0;
+ s->d1->next_handshake_write_seq = 0;
goto end;
/* break; */
@@ -541,8 +601,14 @@ int dtls1_client_hello(SSL *s)
buf=(unsigned char *)s->init_buf->data;
if (s->state == SSL3_ST_CW_CLNT_HELLO_A)
{
+ SSL_SESSION *sess = s->session;
if ((s->session == NULL) ||
(s->session->ssl_version != s->version) ||
+#ifdef OPENSSL_NO_TLSEXT
+ !sess->session_id_length ||
+#else
+ (!sess->session_id_length && !sess->tlsext_tick) ||
+#endif
(s->session->not_resumable))
{
if (!ssl_get_new_session(s,0))
@@ -621,7 +687,15 @@ int dtls1_client_hello(SSL *s)
*(p++)=comp->id;
}
*(p++)=0; /* Add the NULL method */
-
+
+#ifndef OPENSSL_NO_TLSEXT
+ if ((p = ssl_add_clienthello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL)
+ {
+ SSLerr(SSL_F_DTLS1_CLIENT_HELLO,ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+#endif
+
l=(p-d);
d=buf;
diff --git a/ssl/d1_enc.c b/ssl/d1_enc.c
index cf3332e4e43d..3dfa5adba3f9 100644
--- a/ssl/d1_enc.c
+++ b/ssl/d1_enc.c
@@ -151,7 +151,7 @@ int dtls1_enc(SSL *s, int send)
__FILE__, __LINE__);
else if ( EVP_CIPHER_block_size(ds->cipher) > 1)
{
- if (!RAND_bytes(rec->input, EVP_CIPHER_block_size(ds->cipher)))
+ if (RAND_bytes(rec->input, EVP_CIPHER_block_size(ds->cipher)) <= 0)
return -1;
}
}
diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c
index 3568e97a8771..63bfbacc8216 100644
--- a/ssl/d1_lib.c
+++ b/ssl/d1_lib.c
@@ -58,10 +58,17 @@
*/
#include <stdio.h>
+#define USE_SOCKETS
#include <openssl/objects.h>
#include "ssl_locl.h"
+#if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VMS)
+#include <sys/timeb.h>
+#endif
+
+static void get_current_time(struct timeval *t);
const char dtls1_version_str[]="DTLSv1" OPENSSL_VERSION_PTEXT;
+int dtls1_listen(SSL *s, struct sockaddr *client);
SSL3_ENC_METHOD DTLSv1_enc_data={
dtls1_enc,
@@ -114,6 +121,7 @@ int dtls1_new(SSL *s)
d1->processed_rcds.q=pqueue_new();
d1->buffered_messages = pqueue_new();
d1->sent_messages=pqueue_new();
+ d1->buffered_app_data.q=pqueue_new();
if ( s->server)
{
@@ -121,12 +129,13 @@ int dtls1_new(SSL *s)
}
if( ! d1->unprocessed_rcds.q || ! d1->processed_rcds.q
- || ! d1->buffered_messages || ! d1->sent_messages)
+ || ! d1->buffered_messages || ! d1->sent_messages || ! d1->buffered_app_data.q)
{
if ( d1->unprocessed_rcds.q) pqueue_free(d1->unprocessed_rcds.q);
if ( d1->processed_rcds.q) pqueue_free(d1->processed_rcds.q);
if ( d1->buffered_messages) pqueue_free(d1->buffered_messages);
if ( d1->sent_messages) pqueue_free(d1->sent_messages);
+ if ( d1->buffered_app_data.q) pqueue_free(d1->buffered_app_data.q);
OPENSSL_free(d1);
return (0);
}
@@ -175,6 +184,15 @@ void dtls1_free(SSL *s)
}
pqueue_free(s->d1->sent_messages);
+ while ( (item = pqueue_pop(s->d1->buffered_app_data.q)) != NULL)
+ {
+ frag = (hm_fragment *)item->data;
+ OPENSSL_free(frag->fragment);
+ OPENSSL_free(frag);
+ pitem_free(item);
+ }
+ pqueue_free(s->d1->buffered_app_data.q);
+
pq_64bit_free(&(s->d1->bitmap.map));
pq_64bit_free(&(s->d1->bitmap.max_seq_num));
@@ -187,7 +205,36 @@ void dtls1_free(SSL *s)
void dtls1_clear(SSL *s)
{
ssl3_clear(s);
- s->version=DTLS1_VERSION;
+ if (s->options & SSL_OP_CISCO_ANYCONNECT)
+ s->version=DTLS1_BAD_VER;
+ else
+ s->version=DTLS1_VERSION;
+ }
+
+long dtls1_ctrl(SSL *s, int cmd, long larg, void *parg)
+ {
+ int ret=0;
+
+ switch (cmd)
+ {
+ case DTLS_CTRL_GET_TIMEOUT:
+ if (dtls1_get_timeout(s, (struct timeval*) parg) != NULL)
+ {
+ ret = 1;
+ }
+ break;
+ case DTLS_CTRL_HANDLE_TIMEOUT:
+ ret = dtls1_handle_timeout(s);
+ break;
+ case DTLS_CTRL_LISTEN:
+ ret = dtls1_listen(s, parg);
+ break;
+
+ default:
+ ret = ssl3_ctrl(s, cmd, larg, parg);
+ break;
+ }
+ return(ret);
}
/*
@@ -209,3 +256,151 @@ SSL_CIPHER *dtls1_get_cipher(unsigned int u)
return ciph;
}
+
+void dtls1_start_timer(SSL *s)
+ {
+ /* If timer is not set, initialize duration with 1 second */
+ if (s->d1->next_timeout.tv_sec == 0 && s->d1->next_timeout.tv_usec == 0)
+ {
+ s->d1->timeout_duration = 1;
+ }
+
+ /* Set timeout to current time */
+ get_current_time(&(s->d1->next_timeout));
+
+ /* Add duration to current time */
+ s->d1->next_timeout.tv_sec += s->d1->timeout_duration;
+ BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0, &(s->d1->next_timeout));
+ }
+
+struct timeval* dtls1_get_timeout(SSL *s, struct timeval* timeleft)
+ {
+ struct timeval timenow;
+
+ /* If no timeout is set, just return NULL */
+ if (s->d1->next_timeout.tv_sec == 0 && s->d1->next_timeout.tv_usec == 0)
+ {
+ return NULL;
+ }
+
+ /* Get current time */
+ get_current_time(&timenow);
+
+ /* If timer already expired, set remaining time to 0 */
+ if (s->d1->next_timeout.tv_sec < timenow.tv_sec ||
+ (s->d1->next_timeout.tv_sec == timenow.tv_sec &&
+ s->d1->next_timeout.tv_usec <= timenow.tv_usec))
+ {
+ memset(timeleft, 0, sizeof(struct timeval));
+ return timeleft;
+ }
+
+ /* Calculate time left until timer expires */
+ memcpy(timeleft, &(s->d1->next_timeout), sizeof(struct timeval));
+ timeleft->tv_sec -= timenow.tv_sec;
+ timeleft->tv_usec -= timenow.tv_usec;
+ if (timeleft->tv_usec < 0)
+ {
+ timeleft->tv_sec--;
+ timeleft->tv_usec += 1000000;
+ }
+
+ return timeleft;
+ }
+
+int dtls1_is_timer_expired(SSL *s)
+ {
+ struct timeval timeleft;
+
+ /* Get time left until timeout, return false if no timer running */
+ if (dtls1_get_timeout(s, &timeleft) == NULL)
+ {
+ return 0;
+ }
+
+ /* Return false if timer is not expired yet */
+ if (timeleft.tv_sec > 0 || timeleft.tv_usec > 0)
+ {
+ return 0;
+ }
+
+ /* Timer expired, so return true */
+ return 1;
+ }
+
+void dtls1_double_timeout(SSL *s)
+ {
+ s->d1->timeout_duration *= 2;
+ if (s->d1->timeout_duration > 60)
+ s->d1->timeout_duration = 60;
+ dtls1_start_timer(s);
+ }
+
+void dtls1_stop_timer(SSL *s)
+ {
+ /* Reset everything */
+ memset(&(s->d1->next_timeout), 0, sizeof(struct timeval));
+ s->d1->timeout_duration = 1;
+ BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0, &(s->d1->next_timeout));
+ }
+
+int dtls1_handle_timeout(SSL *s)
+ {
+ DTLS1_STATE *state;
+
+ /* if no timer is expired, don't do anything */
+ if (!dtls1_is_timer_expired(s))
+ {
+ return 0;
+ }
+
+ dtls1_double_timeout(s);
+ state = s->d1;
+ state->timeout.num_alerts++;
+ if ( state->timeout.num_alerts > DTLS1_TMO_ALERT_COUNT)
+ {
+ /* fail the connection, enough alerts have been sent */
+ SSLerr(SSL_F_DTLS1_HANDLE_TIMEOUT,SSL_R_READ_TIMEOUT_EXPIRED);
+ return 0;
+ }
+
+ state->timeout.read_timeouts++;
+ if ( state->timeout.read_timeouts > DTLS1_TMO_READ_COUNT)
+ {
+ state->timeout.read_timeouts = 1;
+ }
+
+ dtls1_start_timer(s);
+ return dtls1_retransmit_buffered_messages(s);
+ }
+
+static void get_current_time(struct timeval *t)
+{
+#ifdef OPENSSL_SYS_WIN32
+ struct _timeb tb;
+ _ftime(&tb);
+ t->tv_sec = (long)tb.time;
+ t->tv_usec = (long)tb.millitm * 1000;
+#elif defined(OPENSSL_SYS_VMS)
+ struct timeb tb;
+ ftime(&tb);
+ t->tv_sec = (long)tb.time;
+ t->tv_usec = (long)tb.millitm * 1000;
+#else
+ gettimeofday(t, NULL);
+#endif
+}
+
+int dtls1_listen(SSL *s, struct sockaddr *client)
+ {
+ int ret;
+
+ SSL_set_options(s, SSL_OP_COOKIE_EXCHANGE);
+ s->d1->listen = 1;
+
+ ret = SSL_accept(s);
+ if (ret <= 0) return ret;
+
+ (void) BIO_dgram_get_peer(SSL_get_rbio(s), client);
+ return 1;
+ }
diff --git a/ssl/d1_pkt.c b/ssl/d1_pkt.c
index 4ae9be54ae60..ca2d73f02ef5 100644
--- a/ssl/d1_pkt.c
+++ b/ssl/d1_pkt.c
@@ -134,7 +134,7 @@ static int dtls1_record_needs_buffering(SSL *s, SSL3_RECORD *rr,
unsigned short *priority, unsigned long *offset);
#endif
static int dtls1_buffer_record(SSL *s, record_pqueue *q,
- PQ_64BIT priority);
+ PQ_64BIT *priority);
static int dtls1_process_record(SSL *s);
#if PQ_64BIT_IS_INTEGER
static PQ_64BIT bytes_to_long_long(unsigned char *bytes, PQ_64BIT *num);
@@ -162,7 +162,7 @@ dtls1_copy_record(SSL *s, pitem *item)
static int
-dtls1_buffer_record(SSL *s, record_pqueue *queue, PQ_64BIT priority)
+dtls1_buffer_record(SSL *s, record_pqueue *queue, PQ_64BIT *priority)
{
DTLS1_RECORD_DATA *rdata;
pitem *item;
@@ -172,7 +172,7 @@ dtls1_buffer_record(SSL *s, record_pqueue *queue, PQ_64BIT priority)
return 0;
rdata = OPENSSL_malloc(sizeof(DTLS1_RECORD_DATA));
- item = pitem_new(priority, rdata);
+ item = pitem_new(*priority, rdata);
if (rdata == NULL || item == NULL)
{
if (rdata != NULL) OPENSSL_free(rdata);
@@ -267,7 +267,7 @@ dtls1_process_buffered_records(SSL *s)
if ( ! dtls1_process_record(s))
return(0);
dtls1_buffer_record(s, &(s->d1->processed_rcds),
- s->s3->rrec.seq_num);
+ &s->s3->rrec.seq_num);
}
}
@@ -486,11 +486,11 @@ err:
/* used only by dtls1_read_bytes */
int dtls1_get_record(SSL *s)
{
- int ssl_major,ssl_minor,al;
+ int ssl_major,ssl_minor;
int i,n;
SSL3_RECORD *rr;
SSL_SESSION *sess;
- unsigned char *p;
+ unsigned char *p = NULL;
unsigned short version;
DTLS1_BITMAP *bitmap;
unsigned int is_next_epoch;
@@ -517,7 +517,12 @@ again:
/* read timeout is handled by dtls1_read_bytes */
if (n <= 0) return(n); /* error or non-blocking */
- OPENSSL_assert(s->packet_length == DTLS1_RT_HEADER_LENGTH);
+ /* this packet contained a partial record, dump it */
+ if (s->packet_length != DTLS1_RT_HEADER_LENGTH)
+ {
+ s->packet_length = 0;
+ goto again;
+ }
s->rstate=SSL_ST_READ_BODY;
@@ -542,27 +547,28 @@ again:
{
if (version != s->version && version != DTLS1_BAD_VER)
{
- SSLerr(SSL_F_DTLS1_GET_RECORD,SSL_R_WRONG_VERSION_NUMBER);
- /* Send back error using their
- * version number :-) */
- s->version=version;
- al=SSL_AD_PROTOCOL_VERSION;
- goto f_err;
+ /* unexpected version, silently discard */
+ rr->length = 0;
+ s->packet_length = 0;
+ goto again;
}
}
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;
+ /* wrong version, silently discard record */
+ rr->length = 0;
+ s->packet_length = 0;
+ goto again;
}
if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH)
{
- al=SSL_AD_RECORD_OVERFLOW;
- SSLerr(SSL_F_DTLS1_GET_RECORD,SSL_R_PACKET_LENGTH_TOO_LONG);
- goto f_err;
+ /* record too long, silently discard it */
+ rr->length = 0;
+ s->packet_length = 0;
+ goto again;
}
s->client_version = version;
@@ -581,6 +587,7 @@ again:
/* this packet contained a partial record, dump it */
if ( n != i)
{
+ rr->length = 0;
s->packet_length = 0;
goto again;
}
@@ -594,12 +601,20 @@ again:
bitmap = dtls1_get_bitmap(s, rr, &is_next_epoch);
if ( bitmap == NULL)
{
+ rr->length = 0;
s->packet_length = 0; /* dump this record */
goto again; /* get another record */
}
- /* check whether this is a repeat, or aged record */
- if ( ! dtls1_record_replay_check(s, bitmap, &(rr->seq_num)))
+ /* Check whether this is a repeat, or aged record.
+ * Don't check if we're listening and this message is
+ * a ClientHello. They can look as if they're replayed,
+ * since they arrive from different connections and
+ * would be dropped unnecessarily.
+ */
+ if (!(s->d1->listen && rr->type == SSL3_RT_HANDSHAKE &&
+ *p == SSL3_MT_CLIENT_HELLO) &&
+ ! dtls1_record_replay_check(s, bitmap, &(rr->seq_num)))
{
rr->length = 0;
s->packet_length=0; /* dump this record */
@@ -616,7 +631,8 @@ again:
if (is_next_epoch)
{
dtls1_record_bitmap_update(s, bitmap);
- dtls1_buffer_record(s, &(s->d1->unprocessed_rcds), rr->seq_num);
+ dtls1_buffer_record(s, &(s->d1->unprocessed_rcds), &rr->seq_num);
+ rr->length = 0;
s->packet_length = 0;
goto again;
}
@@ -627,10 +643,6 @@ again:
dtls1_clear_timeouts(s); /* done waiting */
return(1);
-f_err:
- ssl3_send_alert(s,SSL3_AL_FATAL,al);
-err:
- return(0);
}
/* Return up to 'len' payload bytes received in 'type' records.
@@ -707,6 +719,27 @@ start:
* s->s3->rrec.length, - number of bytes. */
rr = &(s->s3->rrec);
+ /* We are not handshaking and have no data yet,
+ * so process data buffered during the last handshake
+ * in advance, if any.
+ */
+ if (s->state == SSL_ST_OK && rr->length == 0)
+ {
+ pitem *item;
+ item = pqueue_pop(s->d1->buffered_app_data.q);
+ if (item)
+ {
+ dtls1_copy_record(s, item);
+
+ OPENSSL_free(item->data);
+ pitem_free(item);
+ }
+ }
+
+ /* Check for timeout */
+ if (dtls1_handle_timeout(s) > 0)
+ goto start;
+
/* get new packet if necessary */
if ((rr->length == 0) || (s->rstate == SSL_ST_READ_BODY))
{
@@ -728,9 +761,14 @@ start:
* reset by ssl3_get_finished */
&& (rr->type != SSL3_RT_HANDSHAKE))
{
- al=SSL_AD_UNEXPECTED_MESSAGE;
- SSLerr(SSL_F_DTLS1_READ_BYTES,SSL_R_DATA_BETWEEN_CCS_AND_FINISHED);
- goto err;
+ /* We now have application data between CCS and Finished.
+ * Most likely the packets were reordered on their way, so
+ * buffer the application data for later processing rather
+ * than dropping the connection.
+ */
+ dtls1_buffer_record(s, &(s->d1->buffered_app_data), 0);
+ rr->length = 0;
+ goto start;
}
/* If the other end has shut down, throw anything we read away
@@ -800,15 +838,28 @@ start:
dest = s->d1->alert_fragment;
dest_len = &s->d1->alert_fragment_len;
}
- /* 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;
- }
+ /* else it's a CCS message, or application data or wrong */
+ else if (rr->type != SSL3_RT_CHANGE_CIPHER_SPEC)
+ {
+ /* Application data while renegotiating
+ * is allowed. Try again reading.
+ */
+ if (rr->type == SSL3_RT_APPLICATION_DATA)
+ {
+ BIO *bio;
+ s->s3->in_read_app_data=2;
+ bio=SSL_get_rbio(s);
+ s->rwstate=SSL_READING;
+ BIO_clear_retry_flags(bio);
+ BIO_set_retry_read(bio);
+ return(-1);
+ }
+ /* 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)
{
@@ -946,7 +997,9 @@ start:
n2s(p, seq);
n2l3(p, frag_off);
- dtls1_retransmit_message(s, seq, frag_off, &found);
+ dtls1_retransmit_message(s,
+ dtls1_get_queue_priority(frag->msg_header.seq, 0),
+ frag_off, &found);
if ( ! found && SSL_in_init(s))
{
/* fprintf( stderr,"in init = %d\n", SSL_in_init(s)); */
@@ -991,15 +1044,17 @@ start:
if (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC)
{
struct ccs_header_st ccs_hdr;
+ unsigned int ccs_hdr_len = DTLS1_CCS_HEADER_LENGTH;
dtls1_get_ccs_header(rr->data, &ccs_hdr);
/* '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))
+ if (s->client_version == DTLS1_BAD_VER || s->version == DTLS1_BAD_VER)
+ ccs_hdr_len = 3;
+
+ if ((rr->length != ccs_hdr_len) || (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);
@@ -1012,6 +1067,16 @@ start:
s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC,
rr->data, 1, s, s->msg_callback_arg);
+ /* We can't process a CCS now, because previous handshake
+ * messages are still missing, so just drop it.
+ */
+ if (!s->d1->change_cipher_spec_ok)
+ {
+ goto start;
+ }
+
+ s->d1->change_cipher_spec_ok = 0;
+
s->s3->change_cipher_spec=1;
if (!ssl3_do_change_cipher_spec(s))
goto err;
@@ -1039,6 +1104,16 @@ start:
goto start;
}
+ /* If we are server, we may have a repeated FINISHED of the
+ * client here, then retransmit our CCS and FINISHED.
+ */
+ if (msg_hdr.type == SSL3_MT_FINISHED)
+ {
+ dtls1_retransmit_buffered_messages(s);
+ rr->length = 0;
+ goto start;
+ }
+
if (((s->state&SSL_ST_MASK) == SSL_ST_OK) &&
!(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS))
{
@@ -1145,7 +1220,6 @@ err:
int
dtls1_write_app_data_bytes(SSL *s, int type, const void *buf_, int len)
{
- unsigned int n,tot;
int i;
if (SSL_in_init(s) && !s->in_handshake)
@@ -1159,31 +1233,14 @@ dtls1_write_app_data_bytes(SSL *s, int type, const void *buf_, int len)
}
}
- tot = s->s3->wnum;
- n = len - tot;
-
- while( n)
+ if (len > SSL3_RT_MAX_PLAIN_LENGTH)
{
- /* dtls1_write_bytes sends one record at a time, sized according to
- * the currently known MTU */
- i = dtls1_write_bytes(s, type, buf_, len);
- if (i <= 0) return i;
-
- if ((i == (int)n) ||
- (type == SSL3_RT_APPLICATION_DATA &&
- (s->mode & SSL_MODE_ENABLE_PARTIAL_WRITE)))
- {
- /* next chunk of data should get another prepended empty fragment
- * in ciphersuites with known-IV weakness: */
- s->s3->empty_fragment_done = 0;
- return tot+i;
- }
-
- tot += i;
- n-=i;
+ SSLerr(SSL_F_DTLS1_WRITE_APP_DATA_BYTES,SSL_R_DTLS_MESSAGE_TOO_BIG);
+ return -1;
}
- return tot;
+ i = dtls1_write_bytes(s, type, buf_, len);
+ return i;
}
@@ -1224,46 +1281,13 @@ have_handshake_fragment(SSL *s, int type, unsigned char *buf,
/* Call this to write data in records of type 'type'
* It will return <= 0 if not all data has been sent or non-blocking IO.
*/
-int dtls1_write_bytes(SSL *s, int type, const void *buf_, int len)
+int dtls1_write_bytes(SSL *s, int type, const void *buf, int len)
{
- const unsigned char *buf=buf_;
- unsigned int tot,n,nw;
int i;
- unsigned int mtu;
+ OPENSSL_assert(len <= SSL3_RT_MAX_PLAIN_LENGTH);
s->rwstate=SSL_NOTHING;
- tot=s->s3->wnum;
-
- n=(len-tot);
-
- /* handshake layer figures out MTU for itself, but data records
- * are also sent through this interface, so need to figure out MTU */
-#if 0
- mtu = BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_GET_MTU, 0, NULL);
- mtu += DTLS1_HM_HEADER_LENGTH; /* HM already inserted */
-#endif
- mtu = s->d1->mtu;
-
- if (mtu > SSL3_RT_MAX_PLAIN_LENGTH)
- mtu = SSL3_RT_MAX_PLAIN_LENGTH;
-
- if (n > mtu)
- nw=mtu;
- else
- nw=n;
-
- i=do_dtls1_write(s, type, &(buf[tot]), nw, 0);
- if (i <= 0)
- {
- s->s3->wnum=tot;
- return i;
- }
-
- if ( (int)s->s3->wnum + i == len)
- s->s3->wnum = 0;
- else
- s->s3->wnum += i;
-
+ i=do_dtls1_write(s, type, buf, len, 0);
return i;
}
@@ -1315,7 +1339,7 @@ int do_dtls1_write(SSL *s, int type, const unsigned char *buf, unsigned int len,
#if 0
/* 'create_empty_fragment' is true only when this function calls itself */
if (!clear && !create_empty_fragment && !s->s3->empty_fragment_done
- && SSL_version(s) != DTLS1_VERSION)
+ && SSL_version(s) != DTLS1_VERSION && SSL_version(s) != DTLS1_BAD_VER)
{
/* countermeasure against known-IV weakness in CBC ciphersuites
* (see http://www.openssl.org/~bodo/tls-cbc.txt)
@@ -1762,6 +1786,7 @@ dtls1_reset_seq_numbers(SSL *s, int rw)
else
{
seq = s->s3->write_sequence;
+ memcpy(s->d1->last_write_sequence, seq, sizeof(s->s3->write_sequence));
s->d1->w_epoch++;
}
diff --git a/ssl/d1_srvr.c b/ssl/d1_srvr.c
index 0bbf8ae7f311..5b313664dd12 100644
--- a/ssl/d1_srvr.c
+++ b/ssl/d1_srvr.c
@@ -146,7 +146,6 @@ int dtls1_accept(SSL *s)
BUF_MEM *buf;
unsigned long l,Time=(unsigned long)time(NULL);
void (*cb)(const SSL *ssl,int type,int val)=NULL;
- long num1;
int ret= -1;
int new_state,state,skip=0;
@@ -236,17 +235,13 @@ int dtls1_accept(SSL *s)
s->state=SSL3_ST_SW_HELLO_REQ_A;
}
- if ( (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE))
- s->d1->send_cookie = 1;
- else
- s->d1->send_cookie = 0;
-
break;
case SSL3_ST_SW_HELLO_REQ_A:
case SSL3_ST_SW_HELLO_REQ_B:
s->shutdown=0;
+ dtls1_start_timer(s);
ret=dtls1_send_hello_request(s);
if (ret <= 0) goto end;
s->s3->tmp.next_state=SSL3_ST_SW_HELLO_REQ_C;
@@ -267,22 +262,31 @@ int dtls1_accept(SSL *s)
s->shutdown=0;
ret=ssl3_get_client_hello(s);
if (ret <= 0) goto end;
- s->new_session = 2;
+ dtls1_stop_timer(s);
- if ( s->d1->send_cookie)
+ if (ret == 1 && (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE))
s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A;
else
s->state = SSL3_ST_SW_SRVR_HELLO_A;
s->init_num=0;
+
+ /* If we're just listening, stop here */
+ if (s->d1->listen && s->state == SSL3_ST_SW_SRVR_HELLO_A)
+ {
+ ret = 2;
+ s->d1->listen = 0;
+ goto end;
+ }
+
break;
case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A:
case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B:
+ dtls1_start_timer(s);
ret = dtls1_send_hello_verify_request(s);
if ( ret <= 0) goto end;
- s->d1->send_cookie = 0;
s->state=SSL3_ST_SW_FLUSH;
s->s3->tmp.next_state=SSL3_ST_SR_CLNT_HELLO_A;
@@ -293,11 +297,23 @@ int dtls1_accept(SSL *s)
case SSL3_ST_SW_SRVR_HELLO_A:
case SSL3_ST_SW_SRVR_HELLO_B:
+ s->new_session = 2;
+ dtls1_start_timer(s);
ret=dtls1_send_server_hello(s);
if (ret <= 0) goto end;
+#ifndef OPENSSL_NO_TLSEXT
if (s->hit)
- s->state=SSL3_ST_SW_CHANGE_A;
+ {
+ if (s->tlsext_ticket_expected)
+ s->state=SSL3_ST_SW_SESSION_TICKET_A;
+ else
+ s->state=SSL3_ST_SW_CHANGE_A;
+ }
+#else
+ if (s->hit)
+ s->state=SSL3_ST_SW_CHANGE_A;
+#endif
else
s->state=SSL3_ST_SW_CERT_A;
s->init_num=0;
@@ -308,12 +324,27 @@ int dtls1_accept(SSL *s)
/* Check if it is anon DH */
if (!(s->s3->tmp.new_cipher->algorithms & SSL_aNULL))
{
+ dtls1_start_timer(s);
ret=dtls1_send_server_certificate(s);
if (ret <= 0) goto end;
+#ifndef OPENSSL_NO_TLSEXT
+ if (s->tlsext_status_expected)
+ s->state=SSL3_ST_SW_CERT_STATUS_A;
+ else
+ s->state=SSL3_ST_SW_KEY_EXCH_A;
+ }
+ else
+ {
+ skip = 1;
+ s->state=SSL3_ST_SW_KEY_EXCH_A;
+ }
+#else
}
else
skip=1;
+
s->state=SSL3_ST_SW_KEY_EXCH_A;
+#endif
s->init_num=0;
break;
@@ -349,6 +380,7 @@ int dtls1_accept(SSL *s)
)
)
{
+ dtls1_start_timer(s);
ret=dtls1_send_server_key_exchange(s);
if (ret <= 0) goto end;
}
@@ -385,6 +417,7 @@ int dtls1_accept(SSL *s)
else
{
s->s3->tmp.cert_request=1;
+ dtls1_start_timer(s);
ret=dtls1_send_certificate_request(s);
if (ret <= 0) goto end;
#ifndef NETSCAPE_HANG_BUG
@@ -399,6 +432,7 @@ int dtls1_accept(SSL *s)
case SSL3_ST_SW_SRVR_DONE_A:
case SSL3_ST_SW_SRVR_DONE_B:
+ dtls1_start_timer(s);
ret=dtls1_send_server_done(s);
if (ret <= 0) goto end;
s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;
@@ -407,16 +441,13 @@ int dtls1_accept(SSL *s)
break;
case SSL3_ST_SW_FLUSH:
- /* number of bytes to be flushed */
- num1=BIO_ctrl(s->wbio,BIO_CTRL_INFO,0,NULL);
- if (num1 > 0)
+ s->rwstate=SSL_WRITING;
+ if (BIO_flush(s->wbio) <= 0)
{
- s->rwstate=SSL_WRITING;
- num1=BIO_flush(s->wbio);
- if (num1 <= 0) { ret= -1; goto end; }
- s->rwstate=SSL_NOTHING;
+ ret= -1;
+ goto end;
}
-
+ s->rwstate=SSL_NOTHING;
s->state=s->s3->tmp.next_state;
break;
@@ -426,6 +457,7 @@ int dtls1_accept(SSL *s)
ret = ssl3_check_client_hello(s);
if (ret <= 0)
goto end;
+ dtls1_stop_timer(s);
if (ret == 2)
s->state = SSL3_ST_SR_CLNT_HELLO_C;
else {
@@ -433,6 +465,7 @@ int dtls1_accept(SSL *s)
* have not asked for it :-) */
ret=ssl3_get_client_certificate(s);
if (ret <= 0) goto end;
+ dtls1_stop_timer(s);
s->init_num=0;
s->state=SSL3_ST_SR_KEY_EXCH_A;
}
@@ -442,6 +475,7 @@ int dtls1_accept(SSL *s)
case SSL3_ST_SR_KEY_EXCH_B:
ret=ssl3_get_client_key_exchange(s);
if (ret <= 0) goto end;
+ dtls1_stop_timer(s);
s->state=SSL3_ST_SR_CERT_VRFY_A;
s->init_num=0;
@@ -459,9 +493,11 @@ int dtls1_accept(SSL *s)
case SSL3_ST_SR_CERT_VRFY_A:
case SSL3_ST_SR_CERT_VRFY_B:
+ s->d1->change_cipher_spec_ok = 1;
/* we should decide if we expected this one */
ret=ssl3_get_cert_verify(s);
if (ret <= 0) goto end;
+ dtls1_stop_timer(s);
s->state=SSL3_ST_SR_FINISHED_A;
s->init_num=0;
@@ -469,16 +505,41 @@ int dtls1_accept(SSL *s)
case SSL3_ST_SR_FINISHED_A:
case SSL3_ST_SR_FINISHED_B:
+ s->d1->change_cipher_spec_ok = 1;
ret=ssl3_get_finished(s,SSL3_ST_SR_FINISHED_A,
SSL3_ST_SR_FINISHED_B);
if (ret <= 0) goto end;
+ dtls1_stop_timer(s);
if (s->hit)
s->state=SSL_ST_OK;
+#ifndef OPENSSL_NO_TLSEXT
+ else if (s->tlsext_ticket_expected)
+ s->state=SSL3_ST_SW_SESSION_TICKET_A;
+#endif
else
s->state=SSL3_ST_SW_CHANGE_A;
s->init_num=0;
break;
+#ifndef OPENSSL_NO_TLSEXT
+ case SSL3_ST_SW_SESSION_TICKET_A:
+ case SSL3_ST_SW_SESSION_TICKET_B:
+ ret=dtls1_send_newsession_ticket(s);
+ if (ret <= 0) goto end;
+ s->state=SSL3_ST_SW_CHANGE_A;
+ s->init_num=0;
+ break;
+
+ case SSL3_ST_SW_CERT_STATUS_A:
+ case SSL3_ST_SW_CERT_STATUS_B:
+ ret=ssl3_send_cert_status(s);
+ if (ret <= 0) goto end;
+ s->state=SSL3_ST_SW_KEY_EXCH_A;
+ s->init_num=0;
+ break;
+
+#endif
+
case SSL3_ST_SW_CHANGE_A:
case SSL3_ST_SW_CHANGE_B:
@@ -554,6 +615,7 @@ int dtls1_accept(SSL *s)
s->d1->handshake_read_seq = 0;
/* next message is server hello */
s->d1->handshake_write_seq = 0;
+ s->d1->next_handshake_write_seq = 0;
goto end;
/* break; */
@@ -631,15 +693,13 @@ int dtls1_send_hello_verify_request(SSL *s)
*(p++) = s->version >> 8,
*(p++) = s->version & 0xFF;
- if (s->ctx->app_gen_cookie_cb != NULL &&
- s->ctx->app_gen_cookie_cb(s, s->d1->cookie,
- &(s->d1->cookie_len)) == 0)
+ if (s->ctx->app_gen_cookie_cb == NULL ||
+ s->ctx->app_gen_cookie_cb(s, s->d1->cookie,
+ &(s->d1->cookie_len)) == 0)
{
SSLerr(SSL_F_DTLS1_SEND_HELLO_VERIFY_REQUEST,ERR_R_INTERNAL_ERROR);
return 0;
}
- /* 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);
@@ -713,6 +773,8 @@ int dtls1_send_server_hello(SSL *s)
p+=sl;
/* put the cipher */
+ if (s->s3->tmp.new_cipher == NULL)
+ return -1;
i=ssl3_put_cipher_by_char(s->s3->tmp.new_cipher,p);
p+=i;
@@ -726,6 +788,14 @@ int dtls1_send_server_hello(SSL *s)
*(p++)=s->s3->tmp.new_compression->id;
#endif
+#ifndef OPENSSL_NO_TLSEXT
+ if ((p = ssl_add_serverhello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL)
+ {
+ SSLerr(SSL_F_DTLS1_SEND_SERVER_HELLO,ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+#endif
+
/* do the header */
l=(p-d);
d=buf;
@@ -1145,3 +1215,115 @@ int dtls1_send_server_certificate(SSL *s)
/* SSL3_ST_SW_CERT_B */
return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
}
+
+#ifndef OPENSSL_NO_TLSEXT
+int dtls1_send_newsession_ticket(SSL *s)
+ {
+ if (s->state == SSL3_ST_SW_SESSION_TICKET_A)
+ {
+ unsigned char *p, *senc, *macstart;
+ int len, slen;
+ unsigned int hlen, msg_len;
+ EVP_CIPHER_CTX ctx;
+ HMAC_CTX hctx;
+ SSL_CTX *tctx = s->initial_ctx;
+ unsigned char iv[EVP_MAX_IV_LENGTH];
+ unsigned char key_name[16];
+
+ /* get session encoding length */
+ slen = i2d_SSL_SESSION(s->session, NULL);
+ /* Some length values are 16 bits, so forget it if session is
+ * too long
+ */
+ if (slen > 0xFF00)
+ return -1;
+ /* Grow buffer if need be: the length calculation is as
+ * follows 12 (DTLS handshake message header) +
+ * 4 (ticket lifetime hint) + 2 (ticket length) +
+ * 16 (key name) + max_iv_len (iv length) +
+ * session_length + max_enc_block_size (max encrypted session
+ * length) + max_md_size (HMAC).
+ */
+ if (!BUF_MEM_grow(s->init_buf,
+ DTLS1_HM_HEADER_LENGTH + 22 + EVP_MAX_IV_LENGTH +
+ EVP_MAX_BLOCK_LENGTH + EVP_MAX_MD_SIZE + slen))
+ return -1;
+ senc = OPENSSL_malloc(slen);
+ if (!senc)
+ return -1;
+ p = senc;
+ i2d_SSL_SESSION(s->session, &p);
+
+ p=(unsigned char *)&(s->init_buf->data[DTLS1_HM_HEADER_LENGTH]);
+ EVP_CIPHER_CTX_init(&ctx);
+ HMAC_CTX_init(&hctx);
+ /* Initialize HMAC and cipher contexts. If callback present
+ * it does all the work otherwise use generated values
+ * from parent ctx.
+ */
+ if (tctx->tlsext_ticket_key_cb)
+ {
+ if (tctx->tlsext_ticket_key_cb(s, key_name, iv, &ctx,
+ &hctx, 1) < 0)
+ {
+ OPENSSL_free(senc);
+ return -1;
+ }
+ }
+ else
+ {
+ RAND_pseudo_bytes(iv, 16);
+ EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL,
+ tctx->tlsext_tick_aes_key, iv);
+ HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16,
+ tlsext_tick_md(), NULL);
+ memcpy(key_name, tctx->tlsext_tick_key_name, 16);
+ }
+ l2n(s->session->tlsext_tick_lifetime_hint, p);
+ /* Skip ticket length for now */
+ p += 2;
+ /* Output key name */
+ macstart = p;
+ memcpy(p, key_name, 16);
+ p += 16;
+ /* output IV */
+ memcpy(p, iv, EVP_CIPHER_CTX_iv_length(&ctx));
+ p += EVP_CIPHER_CTX_iv_length(&ctx);
+ /* Encrypt session data */
+ EVP_EncryptUpdate(&ctx, p, &len, senc, slen);
+ p += len;
+ EVP_EncryptFinal(&ctx, p, &len);
+ p += len;
+ EVP_CIPHER_CTX_cleanup(&ctx);
+
+ HMAC_Update(&hctx, macstart, p - macstart);
+ HMAC_Final(&hctx, p, &hlen);
+ HMAC_CTX_cleanup(&hctx);
+
+ p += hlen;
+ /* Now write out lengths: p points to end of data written */
+ /* Total length */
+ len = p - (unsigned char *)(s->init_buf->data);
+ /* Ticket length */
+ p=(unsigned char *)&(s->init_buf->data[DTLS1_HM_HEADER_LENGTH]) + 4;
+ s2n(len - DTLS1_HM_HEADER_LENGTH - 6, p);
+
+ /* number of bytes to write */
+ s->init_num= len;
+ s->state=SSL3_ST_SW_SESSION_TICKET_B;
+ s->init_off=0;
+ OPENSSL_free(senc);
+
+ /* 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_NEWSESSION_TICKET, msg_len, 0, msg_len);
+
+ /* buffer the message to handle re-xmits */
+ dtls1_buffer_message(s, 0);
+ }
+
+ /* SSL3_ST_SW_SESSION_TICKET_B */
+ return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
+ }
+#endif
diff --git a/ssl/dtls1.h b/ssl/dtls1.h
index f159d3711026..a8ce51ac3e34 100644
--- a/ssl/dtls1.h
+++ b/ssl/dtls1.h
@@ -62,6 +62,18 @@
#include <openssl/buffer.h>
#include <openssl/pqueue.h>
+#ifdef OPENSSL_SYS_VMS
+#include <resource.h>
+#include <sys/timeb.h>
+#endif
+#ifdef OPENSSL_SYS_WIN32
+/* Needed for struct timeval */
+#include <winsock.h>
+#elif defined(OPENSSL_SYS_NETWARE) && !defined(_WINSOCK2API_)
+#include <sys/timeval.h>
+#else
+#include <sys/time.h>
+#endif
#ifdef __cplusplus
extern "C" {
@@ -76,7 +88,7 @@ extern "C" {
#endif
/* lengths of messages */
-#define DTLS1_COOKIE_LENGTH 32
+#define DTLS1_COOKIE_LENGTH 256
#define DTLS1_RT_HEADER_LENGTH 13
@@ -101,6 +113,19 @@ typedef struct dtls1_bitmap_st
PQ_64BIT max_seq_num; /* max record number seen so far */
} DTLS1_BITMAP;
+struct dtls1_retransmit_state
+ {
+ EVP_CIPHER_CTX *enc_write_ctx; /* cryptographic state */
+ const EVP_MD *write_hash; /* used for mac generation */
+#ifndef OPENSSL_NO_COMP
+ COMP_CTX *compress; /* compression */
+#else
+ char *compress;
+#endif
+ SSL_SESSION *session;
+ unsigned short epoch;
+ };
+
struct hm_header_st
{
unsigned char type;
@@ -109,6 +134,7 @@ struct hm_header_st
unsigned long frag_off;
unsigned long frag_len;
unsigned int is_ccs;
+ struct dtls1_retransmit_state saved_retransmit_state;
};
struct ccs_header_st
@@ -168,6 +194,9 @@ typedef struct dtls1_state_st
unsigned short handshake_read_seq;
+ /* save last sequence number for retransmissions */
+ unsigned char last_write_sequence[8];
+
/* Received handshake records (processed and unprocessed) */
record_pqueue unprocessed_rcds;
record_pqueue processed_rcds;
@@ -178,13 +207,29 @@ typedef struct dtls1_state_st
/* Buffered (sent) handshake records */
pqueue sent_messages;
- unsigned int mtu; /* max wire packet size */
+ /* Buffered application records.
+ * Only for records between CCS and Finished
+ * to prevent either protocol violation or
+ * unnecessary message loss.
+ */
+ record_pqueue buffered_app_data;
+
+ /* Is set when listening for new connections with dtls1_listen() */
+ unsigned int listen;
+
+ unsigned int mtu; /* max DTLS packet size */
struct hm_header_st w_msg_hdr;
struct hm_header_st r_msg_hdr;
struct dtls1_timeout_st timeout;
-
+
+ /* Indicates when the last handshake msg sent will timeout */
+ struct timeval next_timeout;
+
+ /* Timeout duration */
+ unsigned short timeout_duration;
+
/* storage for Alert/Handshake protocol data received but not
* yet processed by ssl3_read_bytes: */
unsigned char alert_fragment[DTLS1_AL_HEADER_LENGTH];
@@ -193,6 +238,7 @@ typedef struct dtls1_state_st
unsigned int handshake_fragment_len;
unsigned int retransmitting;
+ unsigned int change_cipher_spec_ok;
} DTLS1_STATE;
diff --git a/ssl/kssl.c b/ssl/kssl.c
index 019030ae3c4f..73401c92a3e9 100644
--- a/ssl/kssl.c
+++ b/ssl/kssl.c
@@ -68,11 +68,6 @@
#include <openssl/opensslconf.h>
-#define _XOPEN_SOURCE 500 /* glibc2 needs this to declare strptime() */
-#include <time.h>
-#if 0 /* experimental */
-#undef _XOPEN_SOURCE /* To avoid clashes with anything else... */
-#endif
#include <string.h>
#define KRB5_PRIVATE 1
diff --git a/ssl/s23_clnt.c b/ssl/s23_clnt.c
index bc918170e102..de0238935a2f 100644
--- a/ssl/s23_clnt.c
+++ b/ssl/s23_clnt.c
@@ -202,11 +202,14 @@ static int ssl23_client_hello(SSL *s)
{
unsigned char *buf;
unsigned char *p,*d;
- int i,j,ch_len;
+ int i,ch_len;
unsigned long Time,l;
int ssl2_compat;
int version = 0, version_major, version_minor;
+#ifndef OPENSSL_NO_COMP
+ int j;
SSL_COMP *comp;
+#endif
int ret;
ssl2_compat = (s->options & SSL_OP_NO_SSLv2) ? 0 : 1;
diff --git a/ssl/s23_srvr.c b/ssl/s23_srvr.c
index ba06e7ae2eb9..be05911e96a2 100644
--- a/ssl/s23_srvr.c
+++ b/ssl/s23_srvr.c
@@ -315,7 +315,7 @@ int ssl23_get_client_hello(SSL *s)
(p[1] == SSL3_VERSION_MAJOR) &&
(p[5] == SSL3_MT_CLIENT_HELLO) &&
((p[3] == 0 && p[4] < 5 /* silly record length? */)
- || (p[9] == p[1])))
+ || (p[9] >= p[1])))
{
/*
* SSLv3 or tls1 header
@@ -339,6 +339,13 @@ int ssl23_get_client_hello(SSL *s)
v[1] = TLS1_VERSION_MINOR;
#endif
}
+ /* if major version number > 3 set minor to a value
+ * which will use the highest version 3 we support.
+ * If TLS 2.0 ever appears we will need to revise
+ * this....
+ */
+ else if (p[9] > SSL3_VERSION_MAJOR)
+ v[1]=0xff;
else
v[1]=p[10]; /* minor version according to client_version */
if (v[1] >= TLS1_VERSION_MINOR)
diff --git a/ssl/s2_srvr.c b/ssl/s2_srvr.c
index 50d55e6bf14c..01d62fad1165 100644
--- a/ssl/s2_srvr.c
+++ b/ssl/s2_srvr.c
@@ -267,7 +267,7 @@ int ssl2_accept(SSL *s)
case SSL2_ST_SEND_SERVER_VERIFY_C:
/* get the number of bytes to write */
num1=BIO_ctrl(s->wbio,BIO_CTRL_INFO,0,NULL);
- if (num1 != 0)
+ if (num1 > 0)
{
s->rwstate=SSL_WRITING;
num1=BIO_flush(s->wbio);
diff --git a/ssl/s3_both.c b/ssl/s3_both.c
index 2ecfbb77cb17..7f462250c7a2 100644
--- a/ssl/s3_both.c
+++ b/ssl/s3_both.c
@@ -168,6 +168,23 @@ int ssl3_send_finished(SSL *s, int a, int b, const char *sender, int slen)
p+=i;
l=i;
+ /* Copy the finished so we can use it for
+ renegotiation checks */
+ if(s->type == SSL_ST_CONNECT)
+ {
+ OPENSSL_assert(i <= EVP_MAX_MD_SIZE);
+ memcpy(s->s3->previous_client_finished,
+ s->s3->tmp.finish_md, i);
+ s->s3->previous_client_finished_len=i;
+ }
+ else
+ {
+ OPENSSL_assert(i <= EVP_MAX_MD_SIZE);
+ memcpy(s->s3->previous_server_finished,
+ s->s3->tmp.finish_md, i);
+ s->s3->previous_server_finished_len=i;
+ }
+
#ifdef OPENSSL_SYS_WIN16
/* MSVC 1.5 does not clear the top bytes of the word unless
* I do this.
@@ -232,6 +249,23 @@ int ssl3_get_finished(SSL *s, int a, int b)
goto f_err;
}
+ /* Copy the finished so we can use it for
+ renegotiation checks */
+ if(s->type == SSL_ST_ACCEPT)
+ {
+ OPENSSL_assert(i <= EVP_MAX_MD_SIZE);
+ memcpy(s->s3->previous_client_finished,
+ s->s3->tmp.peer_finish_md, i);
+ s->s3->previous_client_finished_len=i;
+ }
+ else
+ {
+ OPENSSL_assert(i <= EVP_MAX_MD_SIZE);
+ memcpy(s->s3->previous_server_finished,
+ s->s3->tmp.peer_finish_md, i);
+ s->s3->previous_server_finished_len=i;
+ }
+
return(1);
f_err:
ssl3_send_alert(s,SSL3_AL_FATAL,al);
@@ -264,15 +298,31 @@ int ssl3_send_change_cipher_spec(SSL *s, int a, int b)
return(ssl3_do_write(s,SSL3_RT_CHANGE_CIPHER_SPEC));
}
+static int ssl3_add_cert_to_buf(BUF_MEM *buf, unsigned long *l, X509 *x)
+ {
+ int n;
+ unsigned char *p;
+
+ n=i2d_X509(x,NULL);
+ if (!BUF_MEM_grow_clean(buf,(int)(n+(*l)+3)))
+ {
+ SSLerr(SSL_F_SSL3_ADD_CERT_TO_BUF,ERR_R_BUF_LIB);
+ return(-1);
+ }
+ p=(unsigned char *)&(buf->data[*l]);
+ l2n3(n,p);
+ i2d_X509(x,&p);
+ *l+=n+3;
+
+ return(0);
+ }
+
unsigned long ssl3_output_cert_chain(SSL *s, X509 *x)
{
unsigned char *p;
- int n,i;
+ int i;
unsigned long l=7;
BUF_MEM *buf;
- X509_STORE_CTX xs_ctx;
- X509_OBJECT obj;
-
int no_chain;
if ((s->mode & SSL_MODE_NO_AUTO_CHAIN) || s->ctx->extra_certs)
@@ -289,58 +339,40 @@ unsigned long ssl3_output_cert_chain(SSL *s, X509 *x)
}
if (x != NULL)
{
- if(!no_chain && !X509_STORE_CTX_init(&xs_ctx,s->ctx->cert_store,NULL,NULL))
+ if (no_chain)
{
- SSLerr(SSL_F_SSL3_OUTPUT_CERT_CHAIN,ERR_R_X509_LIB);
- return(0);
+ if (ssl3_add_cert_to_buf(buf, &l, x))
+ return(0);
}
-
- for (;;)
+ else
{
- n=i2d_X509(x,NULL);
- if (!BUF_MEM_grow_clean(buf,(int)(n+l+3)))
+ X509_STORE_CTX xs_ctx;
+
+ if (!X509_STORE_CTX_init(&xs_ctx,s->ctx->cert_store,x,NULL))
{
- SSLerr(SSL_F_SSL3_OUTPUT_CERT_CHAIN,ERR_R_BUF_LIB);
+ SSLerr(SSL_F_SSL3_OUTPUT_CERT_CHAIN,ERR_R_X509_LIB);
return(0);
}
- p=(unsigned char *)&(buf->data[l]);
- l2n3(n,p);
- i2d_X509(x,&p);
- l+=n+3;
-
- if (no_chain)
- break;
-
- if (X509_NAME_cmp(X509_get_subject_name(x),
- X509_get_issuer_name(x)) == 0) break;
-
- i=X509_STORE_get_by_subject(&xs_ctx,X509_LU_X509,
- X509_get_issuer_name(x),&obj);
- if (i <= 0) break;
- x=obj.data.x509;
- /* Count is one too high since the X509_STORE_get uped the
- * ref count */
- X509_free(x);
- }
- if (!no_chain)
+ X509_verify_cert(&xs_ctx);
+ for (i=0; i < sk_X509_num(xs_ctx.chain); i++)
+ {
+ x = sk_X509_value(xs_ctx.chain, i);
+
+ if (ssl3_add_cert_to_buf(buf, &l, x))
+ {
+ X509_STORE_CTX_cleanup(&xs_ctx);
+ return 0;
+ }
+ }
X509_STORE_CTX_cleanup(&xs_ctx);
+ }
}
-
/* Thawte special :-) */
- if (s->ctx->extra_certs != NULL)
for (i=0; i<sk_X509_num(s->ctx->extra_certs); i++)
{
x=sk_X509_value(s->ctx->extra_certs,i);
- n=i2d_X509(x,NULL);
- if (!BUF_MEM_grow_clean(buf,(int)(n+l+3)))
- {
- SSLerr(SSL_F_SSL3_OUTPUT_CERT_CHAIN,ERR_R_BUF_LIB);
+ if (ssl3_add_cert_to_buf(buf, &l, x))
return(0);
- }
- p=(unsigned char *)&(buf->data[l]);
- l2n3(n,p);
- i2d_X509(x,&p);
- l+=n+3;
}
l-=7;
@@ -589,9 +621,14 @@ int ssl_verify_alarm_type(long type)
int ssl3_setup_buffers(SSL *s)
{
unsigned char *p;
- unsigned int extra;
+ unsigned int extra,headerlen;
size_t len;
+ if (SSL_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER)
+ headerlen = DTLS1_RT_HEADER_LENGTH;
+ else
+ headerlen = SSL3_RT_HEADER_LENGTH;
+
if (s->s3->rbuf.buf == NULL)
{
if (s->options & SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER)
@@ -608,7 +645,7 @@ int ssl3_setup_buffers(SSL *s)
if (s->s3->wbuf.buf == NULL)
{
len = SSL3_RT_MAX_PACKET_SIZE;
- len += SSL3_RT_HEADER_LENGTH + 256; /* extra space for empty fragment */
+ len += headerlen + 256; /* extra space for empty fragment */
if ((p=OPENSSL_malloc(len)) == NULL)
goto err;
s->s3->wbuf.buf = p;
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index 50308487aa57..e5138b6e5eee 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -144,9 +144,6 @@
static SSL_METHOD *ssl3_get_client_method(int ver);
static int ca_dn_cmp(const X509_NAME * const *a,const X509_NAME * const *b);
-#ifndef OPENSSL_NO_TLSEXT
-static int ssl3_check_finished(SSL *s);
-#endif
#ifndef OPENSSL_NO_ECDH
static int curve_id2nid(int curve_id);
@@ -170,7 +167,6 @@ int ssl3_connect(SSL *s)
{
BUF_MEM *buf=NULL;
unsigned long Time=(unsigned long)time(NULL),l;
- long num1;
void (*cb)(const SSL *ssl,int type,int val)=NULL;
int ret= -1;
int new_state,state,skip=0;
@@ -499,16 +495,13 @@ int ssl3_connect(SSL *s)
break;
case SSL3_ST_CW_FLUSH:
- /* number of bytes to be flushed */
- num1=BIO_ctrl(s->wbio,BIO_CTRL_INFO,0,NULL);
- if (num1 > 0)
+ s->rwstate=SSL_WRITING;
+ if (BIO_flush(s->wbio) <= 0)
{
- s->rwstate=SSL_WRITING;
- num1=BIO_flush(s->wbio);
- if (num1 <= 0) { ret= -1; goto end; }
- s->rwstate=SSL_NOTHING;
+ ret= -1;
+ goto end;
}
-
+ s->rwstate=SSL_NOTHING;
s->state=s->s3->tmp.next_state;
break;
@@ -594,9 +587,15 @@ int ssl3_client_hello(SSL *s)
buf=(unsigned char *)s->init_buf->data;
if (s->state == SSL3_ST_CW_CLNT_HELLO_A)
{
- if ((s->session == NULL) ||
- (s->session->ssl_version != s->version) ||
- (s->session->not_resumable))
+ SSL_SESSION *sess = s->session;
+ if ((sess == NULL) ||
+ (sess->ssl_version != s->version) ||
+#ifdef OPENSSL_NO_TLSEXT
+ !sess->session_id_length ||
+#else
+ (!sess->session_id_length && !sess->tlsext_tick) ||
+#endif
+ (sess->not_resumable))
{
if (!ssl_get_new_session(s,0))
goto err;
@@ -708,7 +707,7 @@ int ssl3_get_server_hello(SSL *s)
if (!ok) return((int)n);
- if ( SSL_version(s) == DTLS1_VERSION)
+ if ( SSL_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER)
{
if ( s->s3->tmp.message_type == DTLS1_MT_HELLO_VERIFY_REQUEST)
{
@@ -855,7 +854,7 @@ int ssl3_get_server_hello(SSL *s)
#endif
#ifndef OPENSSL_NO_TLSEXT
/* TLS extensions*/
- if (s->version > SSL3_VERSION)
+ if (s->version >= SSL3_VERSION)
{
if (!ssl_parse_serverhello_tlsext(s,&p,d,n, &al))
{
@@ -1715,6 +1714,7 @@ int ssl3_get_new_session_ticket(SSL *s)
SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH);
goto f_err;
}
+
p=d=(unsigned char *)s->init_msg;
n2l(p, s->session->tlsext_tick_lifetime_hint);
n2s(p, ticklen);
@@ -1738,7 +1738,28 @@ int ssl3_get_new_session_ticket(SSL *s)
}
memcpy(s->session->tlsext_tick, p, ticklen);
s->session->tlsext_ticklen = ticklen;
-
+ /* There are two ways to detect a resumed ticket sesion.
+ * One is to set an appropriate session ID and then the server
+ * must return a match in ServerHello. This allows the normal
+ * client session ID matching to work and we know much
+ * earlier that the ticket has been accepted.
+ *
+ * The other way is to set zero length session ID when the
+ * ticket is presented and rely on the handshake to determine
+ * session resumption.
+ *
+ * We choose the former approach because this fits in with
+ * assumptions elsewhere in OpenSSL. The session ID is set
+ * to the SHA256 (or SHA1 is SHA256 is disabled) hash of the
+ * ticket.
+ */
+ EVP_Digest(p, ticklen,
+ s->session->session_id, &s->session->session_id_length,
+#ifndef OPENSSL_NO_SHA256
+ EVP_sha256(), NULL);
+#else
+ EVP_sha1(), NULL);
+#endif
ret=1;
return(ret);
f_err:
@@ -2697,7 +2718,7 @@ static int curve_id2nid(int curve_id)
*/
#ifndef OPENSSL_NO_TLSEXT
-static int ssl3_check_finished(SSL *s)
+int ssl3_check_finished(SSL *s)
{
int ok;
long n;
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 8916a0b1b3c7..8fa4ab02c367 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -2458,6 +2458,7 @@ int ssl3_get_req_cert_type(SSL *s, unsigned char *p)
int ssl3_shutdown(SSL *s)
{
+ int ret;
/* Don't do anything much if we have not done the handshake or
* we don't want to send messages :-) */
@@ -2475,18 +2476,32 @@ int ssl3_shutdown(SSL *s)
#endif
/* our shutdown alert has been sent now, and if it still needs
* to be written, s->s3->alert_dispatch will be true */
+ if (s->s3->alert_dispatch)
+ return(-1); /* return WANT_WRITE */
}
else if (s->s3->alert_dispatch)
{
/* resend it if not sent */
#if 1
- s->method->ssl_dispatch_alert(s);
+ ret=s->method->ssl_dispatch_alert(s);
+ if(ret == -1)
+ {
+ /* we only get to return -1 here the 2nd/Nth
+ * invocation, we must have already signalled
+ * return 0 upon a previous invoation,
+ * return WANT_WRITE */
+ return(ret);
+ }
#endif
}
else if (!(s->shutdown & SSL_RECEIVED_SHUTDOWN))
{
/* If we are waiting for a close from our peer, we are closed */
s->method->ssl_read_bytes(s,0,NULL,0,0);
+ if(!(s->shutdown & SSL_RECEIVED_SHUTDOWN))
+ {
+ return(-1); /* return WANT_READ */
+ }
}
if ((s->shutdown == (SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN)) &&
diff --git a/ssl/s3_pkt.c b/ssl/s3_pkt.c
index 9476dcddf6e9..a2ba5748d5eb 100644
--- a/ssl/s3_pkt.c
+++ b/ssl/s3_pkt.c
@@ -141,9 +141,10 @@ int ssl3_read_n(SSL *s, int n, int max, int extend)
/* ... now we can act as if 'extend' was set */
}
- /* extend reads should not span multiple packets for DTLS */
- if ( SSL_version(s) == DTLS1_VERSION &&
- extend)
+ /* For DTLS/UDP reads should not span multiple packets
+ * because the read operation returns the whole packet
+ * at once (as long as it fits into the buffer). */
+ if (SSL_version(s) == DTLS1_VERSION)
{
if ( s->s3->rbuf.left > 0 && n > s->s3->rbuf.left)
n = s->s3->rbuf.left;
@@ -209,6 +210,14 @@ int ssl3_read_n(SSL *s, int n, int max, int extend)
return(i);
}
newb+=i;
+ /* reads should *never* span multiple packets for DTLS because
+ * the underlying transport protocol is message oriented as opposed
+ * to byte oriented as in the TLS case. */
+ if (SSL_version(s) == DTLS1_VERSION)
+ {
+ if (n > newb)
+ n = newb; /* makes the while condition false */
+ }
}
/* done reading, now the book-keeping */
@@ -1020,7 +1029,25 @@ start:
* now try again to obtain the (application) data we were asked for */
goto start;
}
-
+ /* If we are a server and get a client hello when renegotiation isn't
+ * allowed send back a no renegotiation alert and carry on.
+ * WARNING: experimental code, needs reviewing (steve)
+ */
+ if (s->server &&
+ SSL_is_init_finished(s) &&
+ !s->s3->send_connection_binding &&
+ (s->version > SSL3_VERSION) &&
+ (s->s3->handshake_fragment_len >= 4) &&
+ (s->s3->handshake_fragment[0] == SSL3_MT_CLIENT_HELLO) &&
+ (s->session != NULL) && (s->session->cipher != NULL) &&
+ !(s->ctx->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
+
+ {
+ /*s->s3->handshake_fragment_len = 0;*/
+ rr->length = 0;
+ ssl3_send_alert(s,SSL3_AL_WARNING, SSL_AD_NO_RENEGOTIATION);
+ goto start;
+ }
if (s->s3->alert_fragment_len >= 2)
{
int alert_level = s->s3->alert_fragment[0];
@@ -1050,6 +1077,21 @@ start:
s->shutdown |= SSL_RECEIVED_SHUTDOWN;
return(0);
}
+ /* This is a warning but we receive it if we requested
+ * renegotiation and the peer denied it. Terminate with
+ * a fatal alert because if application tried to
+ * renegotiatie it presumably had a good reason and
+ * expects it to succeed.
+ *
+ * In future we might have a renegotiation where we
+ * don't care if the peer refused it where we carry on.
+ */
+ else if (alert_descr == SSL_AD_NO_RENEGOTIATION)
+ {
+ al = SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_NO_RENEGOTIATION);
+ goto f_err;
+ }
}
else if (alert_level == 2) /* fatal */
{
@@ -1268,13 +1310,13 @@ int ssl3_do_change_cipher_spec(SSL *s)
return(1);
}
-void ssl3_send_alert(SSL *s, int level, int desc)
+int ssl3_send_alert(SSL *s, int level, int desc)
{
/* Map tls/ssl alert value to correct one */
desc=s->method->ssl3_enc->alert_value(desc);
if (s->version == SSL3_VERSION && desc == SSL_AD_PROTOCOL_VERSION)
desc = SSL_AD_HANDSHAKE_FAILURE; /* SSL 3.0 does not have protocol_version alerts */
- if (desc < 0) return;
+ if (desc < 0) return -1;
/* If a fatal one, remove from cache */
if ((level == 2) && (s->session != NULL))
SSL_CTX_remove_session(s->ctx,s->session);
@@ -1283,9 +1325,10 @@ void ssl3_send_alert(SSL *s, int level, int desc)
s->s3->send_alert[0]=level;
s->s3->send_alert[1]=desc;
if (s->s3->wbuf.left == 0) /* data still being written out? */
- s->method->ssl_dispatch_alert(s);
+ return s->method->ssl_dispatch_alert(s);
/* else data is still being written out, we will get written
* some time in the future */
+ return -1;
}
int ssl3_dispatch_alert(SSL *s)
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index 80b45eb86ff1..e696450d6569 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -166,7 +166,6 @@ int ssl3_accept(SSL *s)
BUF_MEM *buf;
unsigned long l,Time=(unsigned long)time(NULL);
void (*cb)(const SSL *ssl,int type,int val)=NULL;
- long num1;
int ret= -1;
int new_state,state,skip=0;
@@ -248,6 +247,18 @@ int ssl3_accept(SSL *s)
s->state=SSL3_ST_SR_CLNT_HELLO_A;
s->ctx->stats.sess_accept++;
}
+ else if (!s->s3->send_connection_binding &&
+ !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
+ {
+ /* Server attempting to renegotiate with
+ * client that doesn't support secure
+ * renegotiation.
+ */
+ SSLerr(SSL_F_SSL3_ACCEPT, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
+ ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE);
+ ret = -1;
+ goto end;
+ }
else
{
/* s->state == SSL_ST_RENEGOTIATE,
@@ -435,15 +446,24 @@ int ssl3_accept(SSL *s)
break;
case SSL3_ST_SW_FLUSH:
- /* number of bytes to be flushed */
- num1=BIO_ctrl(s->wbio,BIO_CTRL_INFO,0,NULL);
- if (num1 > 0)
+
+ /* This code originally checked to see if
+ * any data was pending using BIO_CTRL_INFO
+ * and then flushed. This caused problems
+ * as documented in PR#1939. The proposed
+ * fix doesn't completely resolve this issue
+ * as buggy implementations of BIO_CTRL_PENDING
+ * still exist. So instead we just flush
+ * unconditionally.
+ */
+
+ s->rwstate=SSL_WRITING;
+ if (BIO_flush(s->wbio) <= 0)
{
- s->rwstate=SSL_WRITING;
- num1=BIO_flush(s->wbio);
- if (num1 <= 0) { ret= -1; goto end; }
- s->rwstate=SSL_NOTHING;
+ ret= -1;
+ goto end;
}
+ s->rwstate=SSL_NOTHING;
s->state=s->s3->tmp.next_state;
break;
@@ -758,6 +778,21 @@ int ssl3_get_client_hello(SSL *s)
goto f_err;
}
+ /* If we require cookies and this ClientHello doesn't
+ * contain one, just return since we do not want to
+ * allocate any memory yet. So check cookie length...
+ */
+ if (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE)
+ {
+ unsigned int session_length, cookie_length;
+
+ session_length = *(p + SSL3_RANDOM_SIZE);
+ cookie_length = *(p + SSL3_RANDOM_SIZE + session_length + 1);
+
+ if (cookie_length == 0)
+ return 1;
+ }
+
/* load the client random */
memcpy(s->s3->client_random,p,SSL3_RANDOM_SIZE);
p+=SSL3_RANDOM_SIZE;
@@ -797,23 +832,11 @@ int ssl3_get_client_hello(SSL *s)
p+=j;
- if (s->version == DTLS1_VERSION)
+ if (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER)
{
/* cookie stuff */
cookie_len = *(p++);
- if ( (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) &&
- s->d1->send_cookie == 0)
- {
- /* HelloVerifyMessage has already been sent */
- if ( cookie_len != s->d1->cookie_len)
- {
- al = SSL_AD_HANDSHAKE_FAILURE;
- SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_COOKIE_MISMATCH);
- goto f_err;
- }
- }
-
/*
* The ClientHello may contain a cookie even if the
* HelloVerify message has not been sent--make sure that it
@@ -828,7 +851,7 @@ int ssl3_get_client_hello(SSL *s)
}
/* verify the cookie if appropriate option is set. */
- if ( (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) &&
+ if ((SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) &&
cookie_len > 0)
{
memcpy(s->d1->rcvd_cookie, p, cookie_len);
@@ -853,6 +876,8 @@ int ssl3_get_client_hello(SSL *s)
SSL_R_COOKIE_MISMATCH);
goto f_err;
}
+
+ ret = 2;
}
p += cookie_len;
@@ -952,7 +977,7 @@ int ssl3_get_client_hello(SSL *s)
#ifndef OPENSSL_NO_TLSEXT
/* TLS extensions*/
- if (s->version > SSL3_VERSION)
+ if (s->version >= SSL3_VERSION)
{
if (!ssl_parse_clienthello_tlsext(s,&p,d,n, &al))
{
@@ -1087,7 +1112,7 @@ int ssl3_get_client_hello(SSL *s)
* s->tmp.new_cipher - the new cipher to use.
*/
- ret=1;
+ if (ret < 0) ret=1;
if (0)
{
f_err:
@@ -2711,6 +2736,7 @@ int ssl3_send_newsession_ticket(SSL *s)
unsigned int hlen;
EVP_CIPHER_CTX ctx;
HMAC_CTX hctx;
+ SSL_CTX *tctx = s->initial_ctx;
unsigned char iv[EVP_MAX_IV_LENGTH];
unsigned char key_name[16];
@@ -2749,9 +2775,9 @@ int ssl3_send_newsession_ticket(SSL *s)
* it does all the work otherwise use generated values
* from parent ctx.
*/
- if (s->ctx->tlsext_ticket_key_cb)
+ if (tctx->tlsext_ticket_key_cb)
{
- if (s->ctx->tlsext_ticket_key_cb(s, key_name, iv, &ctx,
+ if (tctx->tlsext_ticket_key_cb(s, key_name, iv, &ctx,
&hctx, 1) < 0)
{
OPENSSL_free(senc);
@@ -2762,10 +2788,10 @@ int ssl3_send_newsession_ticket(SSL *s)
{
RAND_pseudo_bytes(iv, 16);
EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL,
- s->ctx->tlsext_tick_aes_key, iv);
- HMAC_Init_ex(&hctx, s->ctx->tlsext_tick_hmac_key, 16,
+ tctx->tlsext_tick_aes_key, iv);
+ HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16,
tlsext_tick_md(), NULL);
- memcpy(key_name, s->ctx->tlsext_tick_key_name, 16);
+ memcpy(key_name, tctx->tlsext_tick_key_name, 16);
}
l2n(s->session->tlsext_tick_lifetime_hint, p);
/* Skip ticket length for now */
diff --git a/ssl/ssl.h b/ssl/ssl.h
index ff8a128d3c2d..7d4e46e9163a 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -485,6 +485,8 @@ typedef struct ssl_session_st
#define SSL_OP_MICROSOFT_SESS_ID_BUG 0x00000001L
#define SSL_OP_NETSCAPE_CHALLENGE_BUG 0x00000002L
+/* Allow initial connection to servers that don't support RI */
+#define SSL_OP_LEGACY_SERVER_CONNECT 0x00000004L
#define SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG 0x00000008L
#define SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG 0x00000010L
#define SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER 0x00000020L
@@ -510,9 +512,13 @@ typedef struct ssl_session_st
#define SSL_OP_COOKIE_EXCHANGE 0x00002000L
/* Don't use RFC4507 ticket extension */
#define SSL_OP_NO_TICKET 0x00004000L
+/* Use Cisco's "speshul" version of DTLS_BAD_VER (as client) */
+#define SSL_OP_CISCO_ANYCONNECT 0x00008000L
/* As server, disallow session resumption on renegotiation */
#define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION 0x00010000L
+/* Permit unsafe legacy renegotiation */
+#define SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0x00040000L
/* If set, always create a new key when using tmp_ecdh parameters */
#define SSL_OP_SINGLE_ECDH_USE 0x00080000L
/* If set, always create a new key when using tmp_dh parameters */
@@ -561,17 +567,25 @@ typedef struct ssl_session_st
#define SSL_CTX_set_options(ctx,op) \
SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,(op),NULL)
+#define SSL_CTX_clear_options(ctx,op) \
+ SSL_CTX_ctrl((ctx),SSL_CTRL_CLEAR_OPTIONS,(op),NULL)
#define SSL_CTX_get_options(ctx) \
SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,0,NULL)
#define SSL_set_options(ssl,op) \
SSL_ctrl((ssl),SSL_CTRL_OPTIONS,(op),NULL)
+#define SSL_clear_options(ssl,op) \
+ SSL_ctrl((ssl),SSL_CTRL_CLEAR_OPTIONS,(op),NULL)
#define SSL_get_options(ssl) \
SSL_ctrl((ssl),SSL_CTRL_OPTIONS,0,NULL)
#define SSL_CTX_set_mode(ctx,op) \
SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,(op),NULL)
+#define SSL_CTX_clear_mode(ctx,op) \
+ SSL_CTX_ctrl((ctx),SSL_CTRL_CLEAR_MODE,(op),NULL)
#define SSL_CTX_get_mode(ctx) \
SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,0,NULL)
+#define SSL_clear_mode(ssl,op) \
+ SSL_ctrl((ssl),SSL_CTRL_CLEAR_MODE,(op),NULL)
#define SSL_set_mode(ssl,op) \
SSL_ctrl((ssl),SSL_CTRL_MODE,(op),NULL)
#define SSL_get_mode(ssl) \
@@ -579,6 +593,8 @@ typedef struct ssl_session_st
#define SSL_set_mtu(ssl, mtu) \
SSL_ctrl((ssl),SSL_CTRL_SET_MTU,(mtu),NULL)
+#define SSL_get_secure_renegotiation_support(ssl) \
+ SSL_ctrl((ssl), SSL_CTRL_GET_RI_SUPPORT, 0, NULL)
void SSL_CTX_set_msg_callback(SSL_CTX *ctx, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg));
void SSL_set_msg_callback(SSL *ssl, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg));
@@ -1269,6 +1285,21 @@ size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count);
#define SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB 72
#endif
+#define DTLS_CTRL_GET_TIMEOUT 73
+#define DTLS_CTRL_HANDLE_TIMEOUT 74
+#define DTLS_CTRL_LISTEN 75
+
+#define SSL_CTRL_GET_RI_SUPPORT 76
+#define SSL_CTRL_CLEAR_OPTIONS 77
+#define SSL_CTRL_CLEAR_MODE 78
+
+#define DTLSv1_get_timeout(ssl, arg) \
+ SSL_ctrl(ssl,DTLS_CTRL_GET_TIMEOUT,0, (void *)arg)
+#define DTLSv1_handle_timeout(ssl) \
+ SSL_ctrl(ssl,DTLS_CTRL_HANDLE_TIMEOUT,0, NULL)
+#define DTLSv1_listen(ssl, peer) \
+ SSL_ctrl(ssl,DTLS_CTRL_LISTEN,0, (void *)peer)
+
#define SSL_session_reused(ssl) \
SSL_ctrl((ssl),SSL_CTRL_GET_SESSION_REUSED,0,NULL)
#define SSL_num_renegotiations(ssl) \
@@ -1519,7 +1550,7 @@ long SSL_get_default_timeout(const SSL *s);
int SSL_library_init(void );
-char *SSL_CIPHER_description(SSL_CIPHER *,char *buf,int size);
+char *SSL_CIPHER_description(const SSL_CIPHER *,char *buf,int size);
STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *sk);
SSL *SSL_dup(SSL *ssl);
@@ -1649,6 +1680,7 @@ void ERR_load_SSL_strings(void);
#define SSL_F_DO_DTLS1_WRITE 245
#define SSL_F_DO_SSL3_WRITE 104
#define SSL_F_DTLS1_ACCEPT 246
+#define SSL_F_DTLS1_ADD_CERT_TO_BUF 280
#define SSL_F_DTLS1_BUFFER_RECORD 247
#define SSL_F_DTLS1_CLIENT_HELLO 248
#define SSL_F_DTLS1_CONNECT 249
@@ -1657,6 +1689,7 @@ void ERR_load_SSL_strings(void);
#define SSL_F_DTLS1_GET_MESSAGE 252
#define SSL_F_DTLS1_GET_MESSAGE_FRAGMENT 253
#define SSL_F_DTLS1_GET_RECORD 254
+#define SSL_F_DTLS1_HANDLE_TIMEOUT 282
#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
@@ -1702,6 +1735,7 @@ void ERR_load_SSL_strings(void);
#define SSL_F_SSL2_SET_CERTIFICATE 126
#define SSL_F_SSL2_WRITE 127
#define SSL_F_SSL3_ACCEPT 128
+#define SSL_F_SSL3_ADD_CERT_TO_BUF 281
#define SSL_F_SSL3_CALLBACK_CTRL 233
#define SSL_F_SSL3_CHANGE_CIPHER_STATE 129
#define SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM 130
@@ -1742,9 +1776,11 @@ void ERR_load_SSL_strings(void);
#define SSL_F_SSL3_SETUP_KEY_BLOCK 157
#define SSL_F_SSL3_WRITE_BYTES 158
#define SSL_F_SSL3_WRITE_PENDING 159
+#define SSL_F_SSL_ADD_CLIENTHELLO_RENEGOTIATE_EXT 285
#define SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT 272
#define SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK 215
#define SSL_F_SSL_ADD_FILE_CERT_SUBJECTS_TO_STACK 216
+#define SSL_F_SSL_ADD_SERVERHELLO_RENEGOTIATE_EXT 286
#define SSL_F_SSL_ADD_SERVERHELLO_TLSEXT 273
#define SSL_F_SSL_BAD_METHOD 160
#define SSL_F_SSL_BYTES_TO_CIPHER_LIST 161
@@ -1786,6 +1822,10 @@ void ERR_load_SSL_strings(void);
#define SSL_F_SSL_INIT_WBIO_BUFFER 184
#define SSL_F_SSL_LOAD_CLIENT_CA_FILE 185
#define SSL_F_SSL_NEW 186
+#define SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT 287
+#define SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT 290
+#define SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT 289
+#define SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT 291
#define SSL_F_SSL_PEEK 270
#define SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT 275
#define SSL_F_SSL_PREPARE_SERVERHELLO_TLSEXT 276
@@ -1885,6 +1925,7 @@ void ERR_load_SSL_strings(void);
#define SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC 281
#define SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG 148
#define SSL_R_DIGEST_CHECK_FAILED 149
+#define SSL_R_DTLS_MESSAGE_TOO_BIG 318
#define SSL_R_DUPLICATE_COMPRESSION_ID 309
#define SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER 310
#define SSL_R_ENCRYPTED_LENGTH_TOO_LONG 150
@@ -1952,6 +1993,7 @@ void ERR_load_SSL_strings(void);
#define SSL_R_NO_PRIVATE_KEY_ASSIGNED 190
#define SSL_R_NO_PROTOCOLS_AVAILABLE 191
#define SSL_R_NO_PUBLICKEY 192
+#define SSL_R_NO_RENEGOTIATION 319
#define SSL_R_NO_SHARED_CIPHER 193
#define SSL_R_NO_VERIFY_CALLBACK 194
#define SSL_R_NULL_SSL_CTX 195
@@ -1979,10 +2021,14 @@ void ERR_load_SSL_strings(void);
#define SSL_R_RECORD_LENGTH_MISMATCH 213
#define SSL_R_RECORD_TOO_LARGE 214
#define SSL_R_RECORD_TOO_SMALL 298
+#define SSL_R_RENEGOTIATE_EXT_TOO_LONG 320
+#define SSL_R_RENEGOTIATION_ENCODING_ERR 321
+#define SSL_R_RENEGOTIATION_MISMATCH 322
#define SSL_R_REQUIRED_CIPHER_MISSING 215
#define SSL_R_REUSE_CERT_LENGTH_NOT_ZERO 216
#define SSL_R_REUSE_CERT_TYPE_NOT_ZERO 217
#define SSL_R_REUSE_CIPHER_LIST_NOT_ZERO 218
+#define SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING 324
#define SSL_R_SERVERHELLO_TLSEXT 224
#define SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED 277
#define SSL_R_SHORT_READ 219
@@ -2052,6 +2098,7 @@ void ERR_load_SSL_strings(void);
#define SSL_R_UNKNOWN_REMOTE_ERROR_TYPE 253
#define SSL_R_UNKNOWN_SSL_VERSION 254
#define SSL_R_UNKNOWN_STATE 255
+#define SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED 323
#define SSL_R_UNSUPPORTED_CIPHER 256
#define SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM 257
#define SSL_R_UNSUPPORTED_ELLIPTIC_CURVE 315
diff --git a/ssl/ssl3.h b/ssl/ssl3.h
index 4b1e2e983477..2f579c253bc8 100644
--- a/ssl/ssl3.h
+++ b/ssl/ssl3.h
@@ -129,6 +129,9 @@
extern "C" {
#endif
+/* Signalling cipher suite value: from draft-ietf-tls-renegotiation-03.txt */
+#define SSL3_CK_SCSV 0x030000FF
+
#define SSL3_CK_RSA_NULL_MD5 0x03000001
#define SSL3_CK_RSA_NULL_SHA 0x03000002
#define SSL3_CK_RSA_RC4_40_MD5 0x03000003
@@ -440,6 +443,12 @@ typedef struct ssl3_state_st
int cert_request;
} tmp;
+ /* Connection binding to prevent renegotiation attacks */
+ unsigned char previous_client_finished[EVP_MAX_MD_SIZE];
+ unsigned char previous_client_finished_len;
+ unsigned char previous_server_finished[EVP_MAX_MD_SIZE];
+ unsigned char previous_server_finished_len;
+ int send_connection_binding; /* TODOEKR */
} SSL3_STATE;
diff --git a/ssl/ssl_algs.c b/ssl/ssl_algs.c
index 4717c0e6e1de..2d9077e30337 100644
--- a/ssl/ssl_algs.c
+++ b/ssl/ssl_algs.c
@@ -92,9 +92,6 @@ int SSL_library_init(void)
EVP_add_cipher(EVP_seed_cbc());
#endif
-#ifndef OPENSSL_NO_MD2
- EVP_add_digest(EVP_md2());
-#endif
#ifndef OPENSSL_NO_MD5
EVP_add_digest(EVP_md5());
EVP_add_digest_alias(SN_md5,"ssl2-md5");
diff --git a/ssl/ssl_asn1.c b/ssl/ssl_asn1.c
index 0f9a3489dd02..d82e47a14eb6 100644
--- a/ssl/ssl_asn1.c
+++ b/ssl/ssl_asn1.c
@@ -68,6 +68,7 @@ typedef struct ssl_session_asn1_st
ASN1_INTEGER version;
ASN1_INTEGER ssl_version;
ASN1_OCTET_STRING cipher;
+ ASN1_OCTET_STRING comp_id;
ASN1_OCTET_STRING master_key;
ASN1_OCTET_STRING session_id;
ASN1_OCTET_STRING session_id_context;
@@ -95,6 +96,10 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
int v6=0,v9=0,v10=0;
unsigned char ibuf6[LSIZE2];
#endif
+#ifndef OPENSSL_NO_COMP
+ int v11=0;
+ unsigned char cbuf;
+#endif
long l;
SSL_SESSION_ASN1 a;
M_ASN1_I2D_vars(in);
@@ -138,6 +143,16 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
buf[1]=((unsigned char)(l ))&0xff;
}
+#ifndef OPENSSL_NO_COMP
+ if (in->compress_meth)
+ {
+ cbuf = (unsigned char)in->compress_meth;
+ a.comp_id.length = 1;
+ a.comp_id.type = V_ASN1_OCTET_STRING;
+ a.comp_id.data = &cbuf;
+ }
+#endif
+
a.master_key.length=in->master_key_length;
a.master_key.type=V_ASN1_OCTET_STRING;
a.master_key.data=in->master_key;
@@ -199,12 +214,6 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
a.tlsext_tick.length= in->tlsext_ticklen;
a.tlsext_tick.type=V_ASN1_OCTET_STRING;
a.tlsext_tick.data=(unsigned char *)in->tlsext_tick;
- /* If we have a ticket set session ID to empty because
- * it will be bogus. If liftime hint is -1 treat as a special
- * case because the session is being used as a container
- */
- if (in->tlsext_ticklen && (in->tlsext_tick_lifetime_hint != -1))
- a.session_id.length=0;
}
if (in->tlsext_tick_lifetime_hint > 0)
{
@@ -242,6 +251,10 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
M_ASN1_I2D_len_EXP_opt(&(a.tlsext_tick), i2d_ASN1_OCTET_STRING,10,v10);
if (in->tlsext_hostname)
M_ASN1_I2D_len_EXP_opt(&(a.tlsext_hostname), i2d_ASN1_OCTET_STRING,6,v6);
+#ifndef OPENSSL_NO_COMP
+ if (in->compress_meth)
+ M_ASN1_I2D_len_EXP_opt(&(a.comp_id), i2d_ASN1_OCTET_STRING,11,v11);
+#endif
#endif /* OPENSSL_NO_TLSEXT */
M_ASN1_I2D_seq_total();
@@ -274,6 +287,10 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp)
if (in->tlsext_tick)
M_ASN1_I2D_put_EXP_opt(&(a.tlsext_tick), i2d_ASN1_OCTET_STRING,10,v10);
#endif /* OPENSSL_NO_TLSEXT */
+#ifndef OPENSSL_NO_COMP
+ if (in->compress_meth)
+ M_ASN1_I2D_put_EXP_opt(&(a.comp_id), i2d_ASN1_OCTET_STRING,11,v11);
+#endif
M_ASN1_I2D_finish();
}
@@ -317,7 +334,7 @@ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp,
((unsigned long)os.data[1]<< 8L)|
(unsigned long)os.data[2];
}
- else if ((ssl_version>>8) == SSL3_VERSION_MAJOR)
+ else if ((ssl_version>>8) >= SSL3_VERSION_MAJOR)
{
if (os.length != 2)
{
@@ -330,15 +347,15 @@ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp,
}
else
{
- SSLerr(SSL_F_D2I_SSL_SESSION,SSL_R_UNKNOWN_SSL_VERSION);
- return(NULL);
+ c.error=SSL_R_UNKNOWN_SSL_VERSION;
+ goto err;
}
ret->cipher=NULL;
ret->cipher_id=id;
M_ASN1_D2I_get_x(ASN1_OCTET_STRING,osp,d2i_ASN1_OCTET_STRING);
- if ((ssl_version>>8) == SSL3_VERSION_MAJOR)
+ if ((ssl_version>>8) >= SSL3_VERSION_MAJOR)
i=SSL3_MAX_SSL_SESSION_ID_LENGTH;
else /* if (ssl_version>>8 == SSL2_VERSION_MAJOR) */
i=SSL2_MAX_SSL_SESSION_ID_LENGTH;
@@ -422,8 +439,8 @@ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp,
{
if (os.length > SSL_MAX_SID_CTX_LENGTH)
{
- ret->sid_ctx_length=os.length;
- SSLerr(SSL_F_D2I_SSL_SESSION,SSL_R_BAD_LENGTH);
+ c.error=SSL_R_BAD_LENGTH;
+ goto err;
}
else
{
@@ -478,23 +495,21 @@ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp,
ret->tlsext_ticklen = os.length;
os.data = NULL;
os.length = 0;
-#if 0
- /* There are two ways to detect a resumed ticket sesion.
- * One is to set a random session ID and then the server
- * must return a match in ServerHello. This allows the normal
- * client session ID matching to work.
- */
- if (ret->session_id_length == 0)
- {
- ret->session_id_length=SSL3_MAX_SSL_SESSION_ID_LENGTH;
- RAND_pseudo_bytes(ret->session_id,
- ret->session_id_length);
- }
-#endif
}
else
ret->tlsext_tick=NULL;
#endif /* OPENSSL_NO_TLSEXT */
+#ifndef OPENSSL_NO_COMP
+ os.length=0;
+ os.data=NULL;
+ M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,11);
+ if (os.data)
+ {
+ ret->compress_meth = os.data[0];
+ OPENSSL_free(os.data);
+ os.data = NULL;
+ }
+#endif
M_ASN1_D2I_Finish(a,SSL_SESSION_free,SSL_F_D2I_SSL_SESSION);
}
diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c
index a32b2d444645..16fda5d8bffe 100644
--- a/ssl/ssl_cert.c
+++ b/ssl/ssl_cert.c
@@ -500,9 +500,6 @@ int ssl_verify_cert_chain(SSL *s,STACK_OF(X509) *sk)
SSLerr(SSL_F_SSL_VERIFY_CERT_CHAIN,ERR_R_X509_LIB);
return(0);
}
- if (s->param)
- X509_VERIFY_PARAM_inherit(X509_STORE_CTX_get0_param(&ctx),
- s->param);
#if 0
if (SSL_get_verify_depth(s) >= 0)
X509_STORE_CTX_set_depth(&ctx, SSL_get_verify_depth(s));
@@ -516,6 +513,10 @@ int ssl_verify_cert_chain(SSL *s,STACK_OF(X509) *sk)
X509_STORE_CTX_set_default(&ctx,
s->server ? "ssl_client" : "ssl_server");
+ /* Anything non-default in "param" should overwrite anything in the
+ * ctx.
+ */
+ X509_VERIFY_PARAM_set1(X509_STORE_CTX_get0_param(&ctx), s->param);
if (s->verify_callback)
X509_STORE_CTX_set_verify_cb(&ctx, s->verify_callback);
diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c
index 52f91cfe6095..5e2d436da39a 100644
--- a/ssl/ssl_ciph.c
+++ b/ssl/ssl_ciph.c
@@ -1091,10 +1091,11 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method,
*cipher_list_by_id = tmp_cipher_list;
(void)sk_SSL_CIPHER_set_cmp_func(*cipher_list_by_id,ssl_cipher_ptr_id_cmp);
+ sk_SSL_CIPHER_sort(*cipher_list_by_id);
return(cipherstack);
}
-char *SSL_CIPHER_description(SSL_CIPHER *cipher, char *buf, int len)
+char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, int len)
{
int is_export,pkl,kl;
const char *ver,*exp_str;
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index 24a994fe01bf..7eb52026e78a 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -78,6 +78,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
{ERR_FUNC(SSL_F_DO_DTLS1_WRITE), "DO_DTLS1_WRITE"},
{ERR_FUNC(SSL_F_DO_SSL3_WRITE), "DO_SSL3_WRITE"},
{ERR_FUNC(SSL_F_DTLS1_ACCEPT), "DTLS1_ACCEPT"},
+{ERR_FUNC(SSL_F_DTLS1_ADD_CERT_TO_BUF), "DTLS1_ADD_CERT_TO_BUF"},
{ERR_FUNC(SSL_F_DTLS1_BUFFER_RECORD), "DTLS1_BUFFER_RECORD"},
{ERR_FUNC(SSL_F_DTLS1_CLIENT_HELLO), "DTLS1_CLIENT_HELLO"},
{ERR_FUNC(SSL_F_DTLS1_CONNECT), "DTLS1_CONNECT"},
@@ -86,6 +87,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
{ERR_FUNC(SSL_F_DTLS1_GET_MESSAGE), "DTLS1_GET_MESSAGE"},
{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_HANDLE_TIMEOUT), "DTLS1_HANDLE_TIMEOUT"},
{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"},
@@ -131,6 +133,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
{ERR_FUNC(SSL_F_SSL2_SET_CERTIFICATE), "SSL2_SET_CERTIFICATE"},
{ERR_FUNC(SSL_F_SSL2_WRITE), "SSL2_WRITE"},
{ERR_FUNC(SSL_F_SSL3_ACCEPT), "SSL3_ACCEPT"},
+{ERR_FUNC(SSL_F_SSL3_ADD_CERT_TO_BUF), "SSL3_ADD_CERT_TO_BUF"},
{ERR_FUNC(SSL_F_SSL3_CALLBACK_CTRL), "SSL3_CALLBACK_CTRL"},
{ERR_FUNC(SSL_F_SSL3_CHANGE_CIPHER_STATE), "SSL3_CHANGE_CIPHER_STATE"},
{ERR_FUNC(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM), "SSL3_CHECK_CERT_AND_ALGORITHM"},
@@ -171,9 +174,11 @@ static ERR_STRING_DATA SSL_str_functs[]=
{ERR_FUNC(SSL_F_SSL3_SETUP_KEY_BLOCK), "SSL3_SETUP_KEY_BLOCK"},
{ERR_FUNC(SSL_F_SSL3_WRITE_BYTES), "SSL3_WRITE_BYTES"},
{ERR_FUNC(SSL_F_SSL3_WRITE_PENDING), "SSL3_WRITE_PENDING"},
+{ERR_FUNC(SSL_F_SSL_ADD_CLIENTHELLO_RENEGOTIATE_EXT), "SSL_ADD_CLIENTHELLO_RENEGOTIATE_EXT"},
{ERR_FUNC(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT), "SSL_ADD_CLIENTHELLO_TLSEXT"},
{ERR_FUNC(SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK), "SSL_add_dir_cert_subjects_to_stack"},
{ERR_FUNC(SSL_F_SSL_ADD_FILE_CERT_SUBJECTS_TO_STACK), "SSL_add_file_cert_subjects_to_stack"},
+{ERR_FUNC(SSL_F_SSL_ADD_SERVERHELLO_RENEGOTIATE_EXT), "SSL_ADD_SERVERHELLO_RENEGOTIATE_EXT"},
{ERR_FUNC(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT), "SSL_ADD_SERVERHELLO_TLSEXT"},
{ERR_FUNC(SSL_F_SSL_BAD_METHOD), "SSL_BAD_METHOD"},
{ERR_FUNC(SSL_F_SSL_BYTES_TO_CIPHER_LIST), "SSL_BYTES_TO_CIPHER_LIST"},
@@ -215,6 +220,10 @@ static ERR_STRING_DATA SSL_str_functs[]=
{ERR_FUNC(SSL_F_SSL_INIT_WBIO_BUFFER), "SSL_INIT_WBIO_BUFFER"},
{ERR_FUNC(SSL_F_SSL_LOAD_CLIENT_CA_FILE), "SSL_load_client_CA_file"},
{ERR_FUNC(SSL_F_SSL_NEW), "SSL_new"},
+{ERR_FUNC(SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT), "SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT"},
+{ERR_FUNC(SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT), "SSL_PARSE_CLIENTHELLO_TLSEXT"},
+{ERR_FUNC(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT), "SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT"},
+{ERR_FUNC(SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT), "SSL_PARSE_SERVERHELLO_TLSEXT"},
{ERR_FUNC(SSL_F_SSL_PEEK), "SSL_peek"},
{ERR_FUNC(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT), "SSL_PREPARE_CLIENTHELLO_TLSEXT"},
{ERR_FUNC(SSL_F_SSL_PREPARE_SERVERHELLO_TLSEXT), "SSL_PREPARE_SERVERHELLO_TLSEXT"},
@@ -317,6 +326,7 @@ static ERR_STRING_DATA SSL_str_reasons[]=
{ERR_REASON(SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC),"decryption failed or bad record mac"},
{ERR_REASON(SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG),"dh public value length is wrong"},
{ERR_REASON(SSL_R_DIGEST_CHECK_FAILED) ,"digest check failed"},
+{ERR_REASON(SSL_R_DTLS_MESSAGE_TOO_BIG) ,"dtls message too big"},
{ERR_REASON(SSL_R_DUPLICATE_COMPRESSION_ID),"duplicate compression id"},
{ERR_REASON(SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER),"ecgroup too large for cipher"},
{ERR_REASON(SSL_R_ENCRYPTED_LENGTH_TOO_LONG),"encrypted length too long"},
@@ -384,6 +394,7 @@ static ERR_STRING_DATA SSL_str_reasons[]=
{ERR_REASON(SSL_R_NO_PRIVATE_KEY_ASSIGNED),"no private key assigned"},
{ERR_REASON(SSL_R_NO_PROTOCOLS_AVAILABLE),"no protocols available"},
{ERR_REASON(SSL_R_NO_PUBLICKEY) ,"no publickey"},
+{ERR_REASON(SSL_R_NO_RENEGOTIATION) ,"no renegotiation"},
{ERR_REASON(SSL_R_NO_SHARED_CIPHER) ,"no shared cipher"},
{ERR_REASON(SSL_R_NO_VERIFY_CALLBACK) ,"no verify callback"},
{ERR_REASON(SSL_R_NULL_SSL_CTX) ,"null ssl ctx"},
@@ -411,10 +422,14 @@ static ERR_STRING_DATA SSL_str_reasons[]=
{ERR_REASON(SSL_R_RECORD_LENGTH_MISMATCH),"record length mismatch"},
{ERR_REASON(SSL_R_RECORD_TOO_LARGE) ,"record too large"},
{ERR_REASON(SSL_R_RECORD_TOO_SMALL) ,"record too small"},
+{ERR_REASON(SSL_R_RENEGOTIATE_EXT_TOO_LONG),"renegotiate ext too long"},
+{ERR_REASON(SSL_R_RENEGOTIATION_ENCODING_ERR),"renegotiation encoding err"},
+{ERR_REASON(SSL_R_RENEGOTIATION_MISMATCH),"renegotiation mismatch"},
{ERR_REASON(SSL_R_REQUIRED_CIPHER_MISSING),"required cipher missing"},
{ERR_REASON(SSL_R_REUSE_CERT_LENGTH_NOT_ZERO),"reuse cert length not zero"},
{ERR_REASON(SSL_R_REUSE_CERT_TYPE_NOT_ZERO),"reuse cert type not zero"},
{ERR_REASON(SSL_R_REUSE_CIPHER_LIST_NOT_ZERO),"reuse cipher list not zero"},
+{ERR_REASON(SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING),"scsv received when renegotiating"},
{ERR_REASON(SSL_R_SERVERHELLO_TLSEXT) ,"serverhello tlsext"},
{ERR_REASON(SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED),"session id context uninitialized"},
{ERR_REASON(SSL_R_SHORT_READ) ,"short read"},
@@ -484,6 +499,7 @@ static ERR_STRING_DATA SSL_str_reasons[]=
{ERR_REASON(SSL_R_UNKNOWN_REMOTE_ERROR_TYPE),"unknown remote error type"},
{ERR_REASON(SSL_R_UNKNOWN_SSL_VERSION) ,"unknown ssl version"},
{ERR_REASON(SSL_R_UNKNOWN_STATE) ,"unknown state"},
+{ERR_REASON(SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED),"unsafe legacy renegotiation disabled"},
{ERR_REASON(SSL_R_UNSUPPORTED_CIPHER) ,"unsupported cipher"},
{ERR_REASON(SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM),"unsupported compression algorithm"},
{ERR_REASON(SSL_R_UNSUPPORTED_ELLIPTIC_CURVE),"unsupported elliptic curve"},
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 893abff1f475..15650da5e720 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -508,7 +508,6 @@ void SSL_free(SSL *s)
if (s->cert != NULL) ssl_cert_free(s->cert);
/* Free up if allocated */
- if (s->ctx) SSL_CTX_free(s->ctx);
#ifndef OPENSSL_NO_TLSEXT
if (s->tlsext_hostname)
OPENSSL_free(s->tlsext_hostname);
@@ -526,6 +525,8 @@ void SSL_free(SSL *s)
if (s->method != NULL) s->method->ssl_free(s);
+ if (s->ctx) SSL_CTX_free(s->ctx);
+
#ifndef OPENSSL_NO_KRB5
if (s->kssl_ctx != NULL)
kssl_ctx_free(s->kssl_ctx);
@@ -986,8 +987,12 @@ long SSL_ctrl(SSL *s,int cmd,long larg,void *parg)
case SSL_CTRL_OPTIONS:
return(s->options|=larg);
+ case SSL_CTRL_CLEAR_OPTIONS:
+ return(s->options&=~larg);
case SSL_CTRL_MODE:
return(s->mode|=larg);
+ case SSL_CTRL_CLEAR_MODE:
+ return(s->mode &=~larg);
case SSL_CTRL_GET_MAX_CERT_LIST:
return(s->max_cert_list);
case SSL_CTRL_SET_MAX_CERT_LIST:
@@ -995,12 +1000,17 @@ long SSL_ctrl(SSL *s,int cmd,long larg,void *parg)
s->max_cert_list=larg;
return(l);
case SSL_CTRL_SET_MTU:
- if (SSL_version(s) == DTLS1_VERSION)
+ if (SSL_version(s) == DTLS1_VERSION ||
+ SSL_version(s) == DTLS1_BAD_VER)
{
s->d1->mtu = larg;
return larg;
}
return 0;
+ case SSL_CTRL_GET_RI_SUPPORT:
+ if (s->s3)
+ return s->s3->send_connection_binding;
+ else return 0;
default:
return(s->method->ssl_ctrl(s,cmd,larg,parg));
}
@@ -1087,8 +1097,12 @@ long SSL_CTX_ctrl(SSL_CTX *ctx,int cmd,long larg,void *parg)
return(ctx->stats.sess_cache_full);
case SSL_CTRL_OPTIONS:
return(ctx->options|=larg);
+ case SSL_CTRL_CLEAR_OPTIONS:
+ return(ctx->options&=~larg);
case SSL_CTRL_MODE:
return(ctx->mode|=larg);
+ case SSL_CTRL_CLEAR_MODE:
+ return(ctx->mode&=~larg);
default:
return(ctx->method->ssl_ctx_ctrl(ctx,cmd,larg,parg));
}
@@ -1285,6 +1299,22 @@ int ssl_cipher_list_to_bytes(SSL *s,STACK_OF(SSL_CIPHER) *sk,unsigned char *p,
j = put_cb ? put_cb(c,p) : ssl_put_cipher_by_char(s,c,p);
p+=j;
}
+ /* If p == q, no ciphers and caller indicates an error. Otherwise
+ * add SCSV if not renegotiating.
+ */
+ if (p != q && !s->new_session)
+ {
+ static SSL_CIPHER scsv =
+ {
+ 0, NULL, SSL3_CK_SCSV, 0, 0, 0, 0, 0, 0, 0,
+ };
+ j = put_cb ? put_cb(&scsv,p) : ssl_put_cipher_by_char(s,&scsv,p);
+ p+=j;
+#ifdef OPENSSL_RI_DEBUG
+ fprintf(stderr, "SCSV sent by client\n");
+#endif
+ }
+
return(p-q);
}
@@ -1294,6 +1324,8 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s,unsigned char *p,int num,
SSL_CIPHER *c;
STACK_OF(SSL_CIPHER) *sk;
int i,n;
+ if (s->s3)
+ s->s3->send_connection_binding = 0;
n=ssl_put_cipher_by_char(s,NULL,NULL);
if ((num%n) != 0)
@@ -1311,6 +1343,26 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s,unsigned char *p,int num,
for (i=0; i<num; i+=n)
{
+ /* Check for SCSV */
+ if (s->s3 && (n != 3 || !p[0]) &&
+ (p[n-2] == ((SSL3_CK_SCSV >> 8) & 0xff)) &&
+ (p[n-1] == (SSL3_CK_SCSV & 0xff)))
+ {
+ /* SCSV fatal if renegotiating */
+ if (s->new_session)
+ {
+ SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST,SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING);
+ ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE);
+ goto err;
+ }
+ s->s3->send_connection_binding = 1;
+ p += n;
+#ifdef OPENSSL_RI_DEBUG
+ fprintf(stderr, "SCSV received by server\n");
+#endif
+ continue;
+ }
+
c=ssl_get_cipher_by_char(s,p);
p+=n;
if (c != NULL)
@@ -1546,6 +1598,10 @@ SSL_CTX *SSL_CTX_new(SSL_METHOD *meth)
}
#endif
#endif
+ /* Default is to connect to non-RI servers. When RI is more widely
+ * deployed might change this.
+ */
+ ret->options |= SSL_OP_LEGACY_SERVER_CONNECT;
return(ret);
err:
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index ed4ddbbae6c3..e305db43ff8d 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -694,7 +694,7 @@ SSL_METHOD *func_name(void) \
dtls1_read_bytes, \
dtls1_write_app_data_bytes, \
dtls1_dispatch_alert, \
- ssl3_ctrl, \
+ dtls1_ctrl, \
ssl3_ctx_ctrl, \
ssl3_get_cipher_by_char, \
ssl3_put_cipher_by_char, \
@@ -789,7 +789,7 @@ int ssl3_send_change_cipher_spec(SSL *s,int state_a,int state_b);
int ssl3_change_cipher_state(SSL *s,int which);
void ssl3_cleanup_key_block(SSL *s);
int ssl3_do_write(SSL *s,int type);
-void ssl3_send_alert(SSL *s,int level, int desc);
+int ssl3_send_alert(SSL *s,int level, int desc);
int ssl3_generate_master_secret(SSL *s, unsigned char *out,
unsigned char *p, int len);
int ssl3_get_req_cert_type(SSL *s,unsigned char *p);
@@ -862,13 +862,21 @@ int dtls1_read_failed(SSL *s, int code);
int dtls1_buffer_message(SSL *s, int ccs);
int dtls1_retransmit_message(SSL *s, unsigned short seq,
unsigned long frag_off, int *found);
+int dtls1_get_queue_priority(unsigned short seq, int is_ccs);
+int dtls1_retransmit_buffered_messages(SSL *s);
void dtls1_clear_record_buffer(SSL *s);
void dtls1_get_message_header(unsigned char *data, struct hm_header_st *msg_hdr);
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);
+struct timeval* dtls1_get_timeout(SSL *s, struct timeval* timeleft);
+int dtls1_handle_timeout(SSL *s);
SSL_CIPHER *dtls1_get_cipher(unsigned int u);
-
+void dtls1_start_timer(SSL *s);
+void dtls1_stop_timer(SSL *s);
+int dtls1_is_timer_expired(SSL *s);
+void dtls1_double_timeout(SSL *s);
+int dtls1_send_newsession_ticket(SSL *s);
/* some client-only functions */
@@ -885,6 +893,9 @@ int ssl3_send_client_key_exchange(SSL *s);
int ssl3_get_key_exchange(SSL *s);
int ssl3_get_server_certificate(SSL *s);
int ssl3_check_cert_and_algorithm(SSL *s);
+#ifndef OPENSSL_NO_TLSEXT
+int ssl3_check_finished(SSL *s);
+#endif
int dtls1_client_hello(SSL *s);
int dtls1_send_client_certificate(SSL *s);
@@ -968,6 +979,7 @@ int ssl_prepare_clienthello_tlsext(SSL *s);
int ssl_prepare_serverhello_tlsext(SSL *s);
int ssl_check_clienthello_tlsext(SSL *s);
int ssl_check_serverhello_tlsext(SSL *s);
+
#ifdef OPENSSL_NO_SHA256
#define tlsext_tick_md EVP_sha1
#else
@@ -977,6 +989,15 @@ int tls1_process_ticket(SSL *s, unsigned char *session_id, int len,
const unsigned char *limit, SSL_SESSION **ret);
EVP_MD_CTX* ssl_replace_hash(EVP_MD_CTX **hash,const EVP_MD *md) ;
void ssl_clear_hash_ctx(EVP_MD_CTX **hash);
+
+int ssl_add_serverhello_renegotiate_ext(SSL *s, unsigned char *p, int *len,
+ int maxlen);
+int ssl_parse_serverhello_renegotiate_ext(SSL *s, unsigned char *d, int len,
+ int *al);
+int ssl_add_clienthello_renegotiate_ext(SSL *s, unsigned char *p, int *len,
+ int maxlen);
+int ssl_parse_clienthello_renegotiate_ext(SSL *s, unsigned char *d, int len,
+ int *al);
#endif
#endif
diff --git a/ssl/ssl_rsa.c b/ssl/ssl_rsa.c
index 27113eba5088..c0960b5712b8 100644
--- a/ssl/ssl_rsa.c
+++ b/ssl/ssl_rsa.c
@@ -723,7 +723,7 @@ int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file)
goto end;
}
- x=PEM_read_bio_X509(in,NULL,ctx->default_passwd_callback,ctx->default_passwd_callback_userdata);
+ x=PEM_read_bio_X509_AUX(in,NULL,ctx->default_passwd_callback,ctx->default_passwd_callback_userdata);
if (x == NULL)
{
SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE,ERR_R_PEM_LIB);
diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c
index 8391d62212ad..e7802e1d9e4b 100644
--- a/ssl/ssl_sess.c
+++ b/ssl/ssl_sess.c
@@ -211,6 +211,11 @@ int ssl_get_new_session(SSL *s, int session)
ss->ssl_version=TLS1_VERSION;
ss->session_id_length=SSL3_SSL_SESSION_ID_LENGTH;
}
+ else if (s->version == DTLS1_BAD_VER)
+ {
+ ss->ssl_version=DTLS1_BAD_VER;
+ ss->session_id_length=SSL3_SSL_SESSION_ID_LENGTH;
+ }
else if (s->version == DTLS1_VERSION)
{
ss->ssl_version=DTLS1_VERSION;
@@ -418,7 +423,7 @@ int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len,
p=buf;
l=ret->cipher_id;
l2n(l,p);
- if ((ret->ssl_version>>8) == SSL3_VERSION_MAJOR)
+ if ((ret->ssl_version>>8) >= SSL3_VERSION_MAJOR)
ret->cipher=ssl_get_cipher_by_char(s,&(buf[2]));
else
ret->cipher=ssl_get_cipher_by_char(s,&(buf[1]));
diff --git a/ssl/ssl_stat.c b/ssl/ssl_stat.c
index 73b02509d448..e7509f030315 100644
--- a/ssl/ssl_stat.c
+++ b/ssl/ssl_stat.c
@@ -198,6 +198,12 @@ case SSL23_ST_SR_CLNT_HELLO_A: str="SSLv2/v3 read client hello A"; break;
case SSL23_ST_SR_CLNT_HELLO_B: str="SSLv2/v3 read client hello B"; break;
#endif
+/* DTLS */
+case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A: str="DTLS1 read hello verify request A"; break;
+case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B: str="DTLS1 read hello verify request B"; break;
+case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A: str="DTLS1 write hello verify request A"; break;
+case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B: str="DTLS1 write hello verify request B"; break;
+
default: str="unknown state"; break;
}
return(str);
@@ -345,6 +351,11 @@ case SSL23_ST_CR_SRVR_HELLO_B: str="23RSHA"; break;
case SSL23_ST_SR_CLNT_HELLO_A: str="23RCHA"; break;
case SSL23_ST_SR_CLNT_HELLO_B: str="23RCHB"; break;
#endif
+/* DTLS */
+case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A: str="DRCHVA"; break;
+case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B: str="DRCHVB"; break;
+case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A: str="DWCHVA"; break;
+case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B: str="DWCHVB"; break;
default: str="UNKWN "; break;
}
diff --git a/ssl/ssl_txt.c b/ssl/ssl_txt.c
index 06b86750fdb5..81c136169870 100644
--- a/ssl/ssl_txt.c
+++ b/ssl/ssl_txt.c
@@ -91,6 +91,10 @@ int SSL_SESSION_print(BIO *bp, const SSL_SESSION *x)
s="SSLv3";
else if (x->ssl_version == TLS1_VERSION)
s="TLSv1";
+ else if (x->ssl_version == DTLS1_VERSION)
+ s="DTLSv1";
+ else if (x->ssl_version == DTLS1_BAD_VER)
+ s="DTLSv1-bad";
else
s="unknown";
if (BIO_printf(bp," Protocol : %s\n",s) <= 0) goto err;
@@ -174,11 +178,11 @@ int SSL_SESSION_print(BIO *bp, const SSL_SESSION *x)
ssl_cipher_get_evp(x,NULL,NULL,&comp);
if (comp == NULL)
{
- if (BIO_printf(bp,"\n Compression: %d",x->compress_meth) <= 0) goto err;
+ if (BIO_printf(bp,"\n Compression: %d",x->compress_meth) <= 0) goto err;
}
else
{
- if (BIO_printf(bp,"\n Compression: %d (%s)", comp->id,comp->method->name) <= 0) goto err;
+ if (BIO_printf(bp,"\n Compression: %d (%s)", comp->id,comp->method->name) <= 0) goto err;
}
}
#endif
diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c
index 7cb3e29a41b8..dab6e4485b78 100644
--- a/ssl/t1_enc.c
+++ b/ssl/t1_enc.c
@@ -765,10 +765,10 @@ int tls1_mac(SSL *ssl, unsigned char *md, int send)
HMAC_CTX_init(&hmac);
HMAC_Init_ex(&hmac,mac_sec,EVP_MD_size(hash),hash,NULL);
- if (ssl->version == DTLS1_VERSION && ssl->client_version != DTLS1_BAD_VER)
+ if (ssl->version == DTLS1_BAD_VER ||
+ (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);
@@ -793,7 +793,7 @@ 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 && SSL_version(ssl) != DTLS1_BAD_VER)
{
for (i=7; i>=0; i--)
{
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 9ce726996d9d..8b5311277015 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -133,6 +133,11 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
int extdatalen=0;
unsigned char *ret = p;
+ /* don't add extensions for SSLv3 unless doing secure renegotiation */
+ if (s->client_version == SSL3_VERSION
+ && !s->s3->send_connection_binding)
+ return p;
+
ret+=2;
if (ret>=limit) return NULL; /* this really never occurs, but ... */
@@ -169,11 +174,37 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
ret+=size_str;
}
-
+
+ /* Add RI if renegotiating */
+ if (s->new_session)
+ {
+ int el;
+
+ if(!ssl_add_clienthello_renegotiate_ext(s, 0, &el, 0))
+ {
+ SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+ return NULL;
+ }
+
+ if((limit - p - 4 - el) < 0) return NULL;
+
+ s2n(TLSEXT_TYPE_renegotiate,ret);
+ s2n(el,ret);
+
+ if(!ssl_add_clienthello_renegotiate_ext(s, ret, &el, el))
+ {
+ SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+ return NULL;
+ }
+
+ ret += el;
+ }
+
+
if (!(SSL_get_options(s) & SSL_OP_NO_TICKET))
{
int ticklen;
- if (s->session && s->session->tlsext_tick)
+ if (!s->new_session && s->session && s->session->tlsext_tick)
ticklen = s->session->tlsext_ticklen;
else
ticklen = 0;
@@ -191,7 +222,8 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
}
}
- if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp)
+ if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp &&
+ s->version != DTLS1_VERSION)
{
int i;
long extlen, idlen, itmp;
@@ -251,6 +283,10 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
int extdatalen=0;
unsigned char *ret = p;
+ /* don't add extensions for SSLv3, unless doing secure renegotiation */
+ if (s->version == SSL3_VERSION && !s->s3->send_connection_binding)
+ return p;
+
ret+=2;
if (ret>=limit) return NULL; /* this really never occurs, but ... */
@@ -261,6 +297,30 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
s2n(TLSEXT_TYPE_server_name,ret);
s2n(0,ret);
}
+
+ if(s->s3->send_connection_binding)
+ {
+ int el;
+
+ if(!ssl_add_serverhello_renegotiate_ext(s, 0, &el, 0))
+ {
+ SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+ return NULL;
+ }
+
+ if((limit - p - 4 - el) < 0) return NULL;
+
+ s2n(TLSEXT_TYPE_renegotiate,ret);
+ s2n(el,ret);
+
+ if(!ssl_add_serverhello_renegotiate_ext(s, ret, &el, el))
+ {
+ SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+ return NULL;
+ }
+
+ ret += el;
+ }
if (s->tlsext_ticket_expected
&& !(SSL_get_options(s) & SSL_OP_NO_TICKET))
@@ -290,15 +350,18 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
unsigned short size;
unsigned short len;
unsigned char *data = *p;
+ int renegotiate_seen = 0;
+
s->servername_done = 0;
s->tlsext_status_type = -1;
if (data >= (d+n-2))
- return 1;
+ goto ri_check;
+
n2s(data,len);
if (data > (d+n-len))
- return 1;
+ goto ri_check;
while (data <= (d+n-4))
{
@@ -306,7 +369,7 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
n2s(data,size);
if (data+size > (d+n))
- return 1;
+ goto ri_check;
if (s->tlsext_debug_cb)
s->tlsext_debug_cb(s, 0, type, data, size,
@@ -407,8 +470,14 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
}
}
- else if (type == TLSEXT_TYPE_status_request
- && s->ctx->tlsext_status_cb)
+ else if (type == TLSEXT_TYPE_renegotiate)
+ {
+ if(!ssl_parse_clienthello_renegotiate_ext(s, data, size, al))
+ return 0;
+ renegotiate_seen = 1;
+ }
+ else if (type == TLSEXT_TYPE_status_request &&
+ s->version != DTLS1_VERSION && s->ctx->tlsext_status_cb)
{
if (size < 5)
@@ -507,12 +576,26 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
else
s->tlsext_status_type = -1;
}
+
/* session ticket processed earlier */
data+=size;
}
-
*p = data;
+
+ ri_check:
+
+ /* Need RI if renegotiating */
+
+ if (!renegotiate_seen && s->new_session &&
+ !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
+ {
+ *al = SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT,
+ SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
+ return 0;
+ }
+
return 1;
}
@@ -522,11 +605,11 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
unsigned short size;
unsigned short len;
unsigned char *data = *p;
-
int tlsext_servername = 0;
+ int renegotiate_seen = 0;
if (data >= (d+n-2))
- return 1;
+ goto ri_check;
n2s(data,len);
@@ -536,7 +619,7 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
n2s(data,size);
if (data+size > (d+n))
- return 1;
+ goto ri_check;
if (s->tlsext_debug_cb)
s->tlsext_debug_cb(s, 1, type, data, size,
@@ -561,7 +644,8 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
}
s->tlsext_ticket_expected = 1;
}
- else if (type == TLSEXT_TYPE_status_request)
+ else if (type == TLSEXT_TYPE_status_request &&
+ s->version != DTLS1_VERSION)
{
/* MUST be empty and only sent if we've requested
* a status request message.
@@ -574,7 +658,12 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
/* Set flag to expect CertificateStatus message */
s->tlsext_status_expected = 1;
}
-
+ else if (type == TLSEXT_TYPE_renegotiate)
+ {
+ if(!ssl_parse_serverhello_renegotiate_ext(s, data, size, al))
+ return 0;
+ renegotiate_seen = 1;
+ }
data+=size;
}
@@ -606,6 +695,26 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
}
*p = data;
+
+ ri_check:
+
+ /* Determine if we need to see RI. Strictly speaking if we want to
+ * avoid an attack we should *always* see RI even on initial server
+ * hello because the client doesn't see any renegotiation during an
+ * attack. However this would mean we could not connect to any server
+ * which doesn't support RI so for the immediate future tolerate RI
+ * absence on initial connect only.
+ */
+ if (!renegotiate_seen
+ && !(s->options & SSL_OP_LEGACY_SERVER_CONNECT)
+ && !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
+ {
+ *al = SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT,
+ SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
+ return 0;
+ }
+
return 1;
}
@@ -745,6 +854,14 @@ int tls1_process_ticket(SSL *s, unsigned char *session_id, int len,
return 1;
if (p >= limit)
return -1;
+ /* Skip past DTLS cookie */
+ if (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER)
+ {
+ i = *(p++);
+ p+= i;
+ if (p >= limit)
+ return -1;
+ }
/* Skip past cipher list */
n2s(p, i);
p+= i;
@@ -795,16 +912,17 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen,
unsigned char tick_hmac[EVP_MAX_MD_SIZE];
HMAC_CTX hctx;
EVP_CIPHER_CTX ctx;
+ SSL_CTX *tctx = s->initial_ctx;
/* Need at least keyname + iv + some encrypted data */
if (eticklen < 48)
goto tickerr;
/* Initialize session ticket encryption and HMAC contexts */
HMAC_CTX_init(&hctx);
EVP_CIPHER_CTX_init(&ctx);
- if (s->ctx->tlsext_ticket_key_cb)
+ if (tctx->tlsext_ticket_key_cb)
{
unsigned char *nctick = (unsigned char *)etick;
- int rv = s->ctx->tlsext_ticket_key_cb(s, nctick, nctick + 16,
+ int rv = tctx->tlsext_ticket_key_cb(s, nctick, nctick + 16,
&ctx, &hctx, 0);
if (rv < 0)
return -1;
@@ -816,12 +934,12 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen,
else
{
/* Check key name matches */
- if (memcmp(etick, s->ctx->tlsext_tick_key_name, 16))
+ if (memcmp(etick, tctx->tlsext_tick_key_name, 16))
goto tickerr;
- HMAC_Init_ex(&hctx, s->ctx->tlsext_tick_hmac_key, 16,
+ HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16,
tlsext_tick_md(), NULL);
EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL,
- s->ctx->tlsext_tick_aes_key, etick + 16);
+ tctx->tlsext_tick_aes_key, etick + 16);
}
/* Attempt to process session ticket, first conduct sanity and
* integrity checks on ticket.
diff --git a/ssl/t1_reneg.c b/ssl/t1_reneg.c
new file mode 100644
index 000000000000..9c2cc3c712a2
--- /dev/null
+++ b/ssl/t1_reneg.c
@@ -0,0 +1,292 @@
+/* ssl/t1_reneg.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2009 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+#include <stdio.h>
+#include <openssl/objects.h>
+#include "ssl_locl.h"
+
+/* Add the client's renegotiation binding */
+int ssl_add_clienthello_renegotiate_ext(SSL *s, unsigned char *p, int *len,
+ int maxlen)
+ {
+ if(p)
+ {
+ if((s->s3->previous_client_finished_len+1) > maxlen)
+ {
+ SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATE_EXT_TOO_LONG);
+ return 0;
+ }
+
+ /* Length byte */
+ *p = s->s3->previous_client_finished_len;
+ p++;
+
+ memcpy(p, s->s3->previous_client_finished,
+ s->s3->previous_client_finished_len);
+#ifdef OPENSSL_RI_DEBUG
+ fprintf(stderr, "%s RI extension sent by client\n",
+ s->s3->previous_client_finished_len ? "Non-empty" : "Empty");
+#endif
+ }
+
+ *len=s->s3->previous_client_finished_len + 1;
+
+
+ return 1;
+ }
+
+/* Parse the client's renegotiation binding and abort if it's not
+ right */
+int ssl_parse_clienthello_renegotiate_ext(SSL *s, unsigned char *d, int len,
+ int *al)
+ {
+ int ilen;
+
+ /* Parse the length byte */
+ if(len < 1)
+ {
+ SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_ENCODING_ERR);
+ *al=SSL_AD_ILLEGAL_PARAMETER;
+ return 0;
+ }
+ ilen = *d;
+ d++;
+
+ /* Consistency check */
+ if((ilen+1) != len)
+ {
+ SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_ENCODING_ERR);
+ *al=SSL_AD_ILLEGAL_PARAMETER;
+ return 0;
+ }
+
+ /* Check that the extension matches */
+ if(ilen != s->s3->previous_client_finished_len)
+ {
+ SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_MISMATCH);
+ *al=SSL_AD_HANDSHAKE_FAILURE;
+ return 0;
+ }
+
+ if(memcmp(d, s->s3->previous_client_finished,
+ s->s3->previous_client_finished_len))
+ {
+ SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_MISMATCH);
+ *al=SSL_AD_HANDSHAKE_FAILURE;
+ return 0;
+ }
+#ifdef OPENSSL_RI_DEBUG
+ fprintf(stderr, "%s RI extension received by server\n",
+ ilen ? "Non-empty" : "Empty");
+#endif
+
+ s->s3->send_connection_binding=1;
+
+ return 1;
+ }
+
+/* Add the server's renegotiation binding */
+int ssl_add_serverhello_renegotiate_ext(SSL *s, unsigned char *p, int *len,
+ int maxlen)
+ {
+ if(p)
+ {
+ if((s->s3->previous_client_finished_len +
+ s->s3->previous_server_finished_len + 1) > maxlen)
+ {
+ SSLerr(SSL_F_SSL_ADD_SERVERHELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATE_EXT_TOO_LONG);
+ return 0;
+ }
+
+ /* Length byte */
+ *p = s->s3->previous_client_finished_len + s->s3->previous_server_finished_len;
+ p++;
+
+ memcpy(p, s->s3->previous_client_finished,
+ s->s3->previous_client_finished_len);
+ p += s->s3->previous_client_finished_len;
+
+ memcpy(p, s->s3->previous_server_finished,
+ s->s3->previous_server_finished_len);
+#ifdef OPENSSL_RI_DEBUG
+ fprintf(stderr, "%s RI extension sent by server\n",
+ s->s3->previous_client_finished_len ? "Non-empty" : "Empty");
+#endif
+ }
+
+ *len=s->s3->previous_client_finished_len
+ + s->s3->previous_server_finished_len + 1;
+
+ return 1;
+ }
+
+/* Parse the server's renegotiation binding and abort if it's not
+ right */
+int ssl_parse_serverhello_renegotiate_ext(SSL *s, unsigned char *d, int len,
+ int *al)
+ {
+ int expected_len=s->s3->previous_client_finished_len
+ + s->s3->previous_server_finished_len;
+ int ilen;
+
+ /* Check for logic errors */
+ OPENSSL_assert(!expected_len || s->s3->previous_client_finished_len);
+ OPENSSL_assert(!expected_len || s->s3->previous_server_finished_len);
+
+ /* Parse the length byte */
+ if(len < 1)
+ {
+ SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_ENCODING_ERR);
+ *al=SSL_AD_ILLEGAL_PARAMETER;
+ return 0;
+ }
+ ilen = *d;
+ d++;
+
+ /* Consistency check */
+ if(ilen+1 != len)
+ {
+ SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_ENCODING_ERR);
+ *al=SSL_AD_ILLEGAL_PARAMETER;
+ return 0;
+ }
+
+ /* Check that the extension matches */
+ if(ilen != expected_len)
+ {
+ SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_MISMATCH);
+ *al=SSL_AD_HANDSHAKE_FAILURE;
+ return 0;
+ }
+
+ if(memcmp(d, s->s3->previous_client_finished,
+ s->s3->previous_client_finished_len))
+ {
+ SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_MISMATCH);
+ *al=SSL_AD_HANDSHAKE_FAILURE;
+ return 0;
+ }
+ d += s->s3->previous_client_finished_len;
+
+ if(memcmp(d, s->s3->previous_server_finished,
+ s->s3->previous_server_finished_len))
+ {
+ SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_MISMATCH);
+ *al=SSL_AD_ILLEGAL_PARAMETER;
+ return 0;
+ }
+#ifdef OPENSSL_RI_DEBUG
+ fprintf(stderr, "%s RI extension received by client\n",
+ ilen ? "Non-empty" : "Empty");
+#endif
+ s->s3->send_connection_binding=1;
+
+ return 1;
+ }
diff --git a/ssl/tls1.h b/ssl/tls1.h
index 2d1d293e1a43..afe4807fa900 100644
--- a/ssl/tls1.h
+++ b/ssl/tls1.h
@@ -115,6 +115,9 @@ extern "C" {
#define TLSEXT_TYPE_ec_point_formats 11
#define TLSEXT_TYPE_session_ticket 35
+/* Temporary extension type */
+#define TLSEXT_TYPE_renegotiate 0xff01
+
/* NameType value from RFC 3546 */
#define TLSEXT_NAMETYPE_host_name 0
/* status request value from RFC 3546 */
@@ -169,9 +172,9 @@ SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_CB,(void (*)(void))cb)
SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG,0, (void *)arg)
#define SSL_CTX_get_tlsext_ticket_keys(ctx, keys, keylen) \
- SSL_CTX_ctrl((ctx),SSL_CTRL_GET_TLXEXT_TICKET_KEYS,(keylen),(keys))
+ SSL_CTX_ctrl((ctx),SSL_CTRL_GET_TLSEXT_TICKET_KEYS,(keylen),(keys))
#define SSL_CTX_set_tlsext_ticket_keys(ctx, keys, keylen) \
- SSL_CTX_ctrl((ctx),SSL_CTRL_SET_TLXEXT_TICKET_KEYS,(keylen),(keys))
+ SSL_CTX_ctrl((ctx),SSL_CTRL_SET_TLSEXT_TICKET_KEYS,(keylen),(keys))
#define SSL_CTX_set_tlsext_status_cb(ssl, cb) \
SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB,(void (*)(void))cb)