Summary: upgrading to openssl-0.9.8m and adding new testssl.sh
Testing Summary:
- Passed new android.testssl/testssl.sh
- General testing with BrowserActivity based program
Details:
Expanded detail in README.android about how to build and test openssl
upgrades based on my first experience.
modified: README.android
Significant rework of import_openssl.sh script that does most of
the work of the upgrade. Most of the existing code became the main
and import functions. The newly regenerate code helps regenerate
patch files, building on the fact that import now keeps and
original unmodified read-only source tree for use for patch
generation. Patch generation relies on additions to openssl.config
for defining which patches include which files. Note that
sometimes a file may be patched multiple times, in that case
manual review is still necessary to prune the patch after
auto-regeneration. Other enhancements to import_openssl.sh include
generating android.testssl and printing Makefile defines for
android-config.mk review.
modified: import_openssl.sh
Test support files for openssl/
Add support for building /system/bin/ssltest as test executible for
use by testssl script. Need confirmation that this is the right way
to define such a test binary.
modified: patches/ssl_Android.mk
Driver script that generates user and CA keys and certs on the
device with /system/bin/openssl before running testssl. Based on
openssl/test/testss for generation and openssl/test/Makefile
test_ssl for test execution.
new file: patches/testssl.sh
Note all following android.testssl files are automatically
imported from openssl, although possible with modifications by
import_openssl.sh
testssl script imported from openssl/test that does the bulk of
the testing. Includes new tests patched in for our additions.
new file: android.testssl/testssl
CA and user certificate configuration files from openssl.
Automatically imported from openssl/test/
new file: android.testssl/CAss.cnf
new file: android.testssl/Uss.cnf
certificate and key test file imported from openssl/apps
new file: android.testssl/server2.pem
Actual 0.9.8m upgrade specific bits
Trying to bring ngm's small records support into 0.9.8m. Needs
signoff by ngm although it does pass testing.
modified: patches/small_records.patch
Update openssl.config for 0.9.8m. Expanded lists of undeeded
directories and files for easier update and review, adding new
excludes. Also added new definitions to support "import_openssl.sh
regenerate" for patch updating.
modified: openssl.config
Updated OPENSSL_VERSION to 0.9.8m
modified: openssl.version
Automatically imported/patched files. Seems like it could be
further pruned in by openssl.config UNNEEDED_SOURCES, but extra
stuff doesn't end up impacting device.
modified: apps/...
modified: crypto/...
modified: include/...
modified: ssl/...
Other Android build stuff.
Note for these patches/... is source, .../Android.mk is derived.
Split LOCAL_CFLAGS additions into lines based on openssl/Makefile
source for easier comparison when upgrading. I knowingly left the
lines long and unwrapped for easy vdiff with openssl/Makefile
modified: android-config.mk
Removed local -DOPENSSL_NO_ECDH already in android-config.mk.
modified: patches/apps_Android.mk
Sync up with changes that had crept into derived crypto/Android.mk
modified: patches/crypto_Android.mk
Change-Id: I73204c56cdaccfc45d03a9c8088a6a93003d7ce6
diff --git a/ssl/Android.mk b/ssl/Android.mk
index 75cb8a1..f681718 100644
--- a/ssl/Android.mk
+++ b/ssl/Android.mk
@@ -1,4 +1,10 @@
LOCAL_PATH:= $(call my-dir)
+
+local_c_includes := \
+ external/openssl \
+ external/openssl/include \
+ external/openssl/crypto
+
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
@@ -41,14 +47,28 @@
include $(LOCAL_PATH)/../android-config.mk
-
-LOCAL_C_INCLUDES += \
- external/openssl \
- external/openssl/include \
- external/openssl/crypto
+LOCAL_C_INCLUDES += $(local_c_includes)
LOCAL_SHARED_LIBRARIES += libcrypto
LOCAL_MODULE:= libssl
include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+
+# ssltest
+
+LOCAL_SRC_FILES:=ssltest.c
+
+LOCAL_C_INCLUDES += $(local_c_includes)
+
+LOCAL_SHARED_LIBRARIES := libssl
+
+include $(LOCAL_PATH)/../android-config.mk
+
+LOCAL_MODULE:=ssltest
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_EXECUTABLE)
diff --git a/ssl/Makefile b/ssl/Makefile
index 46c0659..5ac3507 100644
--- a/ssl/Makefile
+++ b/ssl/Makefile
@@ -30,7 +30,7 @@
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 @@
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/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 15a201a..0a5c08d 100644
--- a/ssl/d1_both.c
+++ b/ssl/d1_both.c
@@ -136,7 +136,6 @@
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 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 @@
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 @@
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 @@
* 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
@@ -519,6 +530,7 @@
if ( s->d1->handshake_read_seq == frag->msg_header.seq)
{
+ unsigned long frag_len = frag->msg_header.frag_len;
pqueue_pop(s->d1->buffered_messages);
al=dtls1_preprocess_fragment(s,&frag->msg_header,max);
@@ -536,7 +548,7 @@
if (al==0)
{
*ok = 1;
- return frag->msg_header.frag_len;
+ return frag_len;
}
ssl3_send_alert(s,SSL3_AL_FATAL,al);
@@ -561,7 +573,20 @@
if ((msg_hdr->frag_off+frag_len) > msg_hdr->msg_len)
goto err;
- if (msg_hdr->seq <= s->d1->handshake_read_seq)
+ /* Try to find item in queue, to prevent duplicate entries */
+ pq_64bit_init(&seq64);
+ pq_64bit_assign_word(&seq64, msg_hdr->seq);
+ item = pqueue_find(s->d1->buffered_messages, seq64);
+ pq_64bit_free(&seq64);
+
+ /* Discard the message if sequence number was already there, is
+ * 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 ||
+ (s->d1->handshake_read_seq == 0 && msg_hdr->type == SSL3_MT_FINISHED))
{
unsigned char devnull [256];
@@ -575,30 +600,31 @@
}
}
- frag = dtls1_hm_fragment_new(frag_len);
- if ( frag == NULL)
- goto err;
-
- memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr));
-
if (frag_len)
- {
- /* read the body of the fragment (header has already been read */
+ {
+ frag = dtls1_hm_fragment_new(frag_len);
+ if ( frag == NULL)
+ goto err;
+
+ memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr));
+
+ /* read the body of the fragment (header has already been read) */
i = s->method->ssl_read_bytes(s,SSL3_RT_HANDSHAKE,
frag->fragment,frag_len,0);
if (i<=0 || (unsigned long)i!=frag_len)
goto err;
- }
- pq_64bit_init(&seq64);
- pq_64bit_assign_word(&seq64, msg_hdr->seq);
+ pq_64bit_init(&seq64);
+ pq_64bit_assign_word(&seq64, msg_hdr->seq);
- item = pitem_new(seq64, frag);
- pq_64bit_free(&seq64);
- if ( item == NULL)
- goto err;
+ item = pitem_new(seq64, frag);
+ pq_64bit_free(&seq64);
+ if ( item == NULL)
+ goto err;
- pqueue_insert(s->d1->buffered_messages, item);
+ pqueue_insert(s->d1->buffered_messages, item);
+ }
+
return DTLS1_HM_FRAGMENT_RETRY;
err:
@@ -739,6 +765,24 @@
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.
@@ -801,14 +845,30 @@
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;
@@ -819,54 +879,33 @@
}
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);
- }
+ 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);
- 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);
- }
-
+ 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);
@@ -883,18 +922,13 @@
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 */
@@ -907,23 +941,6 @@
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 )
@@ -934,16 +951,29 @@
#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;
@@ -957,8 +987,9 @@
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;
@@ -974,7 +1005,6 @@
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 */
@@ -988,7 +1018,6 @@
{
OPENSSL_assert(s->d1->w_msg_hdr.msg_len +
DTLS1_CCS_HEADER_LENGTH <= (unsigned int)s->init_num);
- epoch++;
}
else
{
@@ -1003,9 +1032,19 @@
frag->msg_header.frag_len = s->d1->w_msg_hdr.msg_len;
frag->msg_header.is_ccs = is_ccs;
- pq_64bit_init(&seq64);
- pq_64bit_assign_word(&seq64, epoch<<16 | frag->msg_header.seq);
+ /* 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,
+ 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)
@@ -1034,6 +1073,8 @@
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);
@@ -1069,9 +1110,45 @@
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 49c6760..223d116 100644
--- a/ssl/d1_clnt.c
+++ b/ssl/d1_clnt.c
@@ -130,7 +130,7 @@
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 @@
{
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 @@
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 @@
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 @@
/* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
/* done with handshaking */
s->d1->handshake_read_seq = 0;
+ s->d1->next_handshake_write_seq = 0;
goto end;
/* break; */
@@ -541,8 +601,14 @@
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 @@
*(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 cf3332e..3dfa5ad 100644
--- a/ssl/d1_enc.c
+++ b/ssl/d1_enc.c
@@ -151,7 +151,7 @@
__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 3568e97..63bfbac 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 @@
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 @@
}
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 @@
}
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_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 @@
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 7d464b4..bf395d4 100644
--- a/ssl/d1_pkt.c
+++ b/ssl/d1_pkt.c
@@ -134,7 +134,7 @@
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,13 +162,17 @@
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;
+ /* Limit the size of the queue to prevent DOS attacks */
+ if (pqueue_size(queue->q) >= 100)
+ 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);
@@ -263,7 +267,7 @@
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);
}
}
@@ -482,11 +486,11 @@
/* 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;
@@ -513,7 +517,12 @@
/* 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;
@@ -538,27 +547,28 @@
{
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;
}
/* If we receive a valid record larger than the current buffer size,
@@ -592,6 +602,7 @@
/* this packet contained a partial record, dump it */
if ( n != i)
{
+ rr->length = 0;
s->packet_length = 0;
goto again;
}
@@ -605,12 +616,20 @@
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 */
@@ -627,7 +646,8 @@
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;
}
@@ -638,10 +658,6 @@
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.
@@ -718,6 +734,27 @@
* 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))
{
@@ -739,9 +776,14 @@
* 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
@@ -811,15 +853,28 @@
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)
{
@@ -957,7 +1012,9 @@
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)); */
@@ -1002,15 +1059,17 @@
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);
@@ -1023,6 +1082,16 @@
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;
@@ -1050,6 +1119,16 @@
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))
{
@@ -1156,7 +1235,6 @@
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)
@@ -1170,31 +1248,14 @@
}
}
- 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;
}
@@ -1235,56 +1296,13 @@
/* 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;
- unsigned int max_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 (!(SSL_get_mode(s) & SSL_MODE_SMALL_BUFFERS))
- {
- max_mtu = SSL3_RT_MAX_PLAIN_LENGTH;
- }
- else
- {
- max_mtu = SSL3_RT_DEFAULT_PLAIN_LENGTH;
- }
-
- if (mtu > max_mtu)
- mtu = max_mtu;
-
- 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;
}
@@ -1336,7 +1354,7 @@
#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)
@@ -1785,6 +1803,7 @@
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 0bbf8ae..5b31366 100644
--- a/ssl/d1_srvr.c
+++ b/ssl/d1_srvr.c
@@ -146,7 +146,6 @@
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 @@
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 @@
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 @@
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 @@
/* 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 @@
)
)
{
+ dtls1_start_timer(s);
ret=dtls1_send_server_key_exchange(s);
if (ret <= 0) goto end;
}
@@ -385,6 +417,7 @@
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 @@
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 @@
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 @@
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 @@
* 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 @@
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 @@
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 @@
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 @@
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 @@
*(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 @@
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 @@
*(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 @@
/* 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 f159d37..a8ce51a 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 @@
#endif
/* lengths of messages */
-#define DTLS1_COOKIE_LENGTH 32
+#define DTLS1_COOKIE_LENGTH 256
#define DTLS1_RT_HEADER_LENGTH 13
@@ -101,6 +113,19 @@
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 @@
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 @@
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 @@
/* 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 @@
unsigned int handshake_fragment_len;
unsigned int retransmitting;
+ unsigned int change_cipher_spec_ok;
} DTLS1_STATE;
diff --git a/ssl/install.com b/ssl/install.com
index fce8c66..7f56067 100644
--- a/ssl/install.com
+++ b/ssl/install.com
@@ -8,10 +8,19 @@
$ IF P1 .EQS. ""
$ THEN
$ WRITE SYS$OUTPUT "First argument missing."
-$ WRITE SYS$OUTPUT "Should be the directory where you want things installed."
+$ WRITE SYS$OUTPUT -
+ "It should be the directory where you want things installed."
$ EXIT
$ ENDIF
$
+$ IF (F$GETSYI("CPU").LT.128)
+$ THEN
+$ ARCH := VAX
+$ ELSE
+$ ARCH = F$EDIT( F$GETSYI( "ARCH_NAME"), "UPCASE")
+$ IF (ARCH .EQS. "") THEN ARCH = "UNK"
+$ ENDIF
+$
$ ROOT = F$PARSE(P1,"[]A.;0",,,"SYNTAX_ONLY,NO_CONCEAL") - "A.;0"
$ ROOT_DEV = F$PARSE(ROOT,,,"DEVICE","SYNTAX_ONLY")
$ ROOT_DIR = F$PARSE(ROOT,,,"DIRECTORY","SYNTAX_ONLY") -
@@ -19,31 +28,24 @@
$ ROOT = ROOT_DEV + "[" + ROOT_DIR
$
$ DEFINE/NOLOG WRK_SSLROOT 'ROOT'.] /TRANS=CONC
-$ DEFINE/NOLOG WRK_SSLVLIB WRK_SSLROOT:[VAX_LIB]
-$ DEFINE/NOLOG WRK_SSLALIB WRK_SSLROOT:[ALPHA_LIB]
+$ DEFINE/NOLOG WRK_SSLXLIB WRK_SSLROOT:['ARCH'_LIB]
$ DEFINE/NOLOG WRK_SSLINCLUDE WRK_SSLROOT:[INCLUDE]
-$ DEFINE/NOLOG WRK_SSLVEXE WRK_SSLROOT:[VAX_EXE]
-$ DEFINE/NOLOG WRK_SSLAEXE WRK_SSLROOT:[ALPHA_EXE]
+$ DEFINE/NOLOG WRK_SSLXEXE WRK_SSLROOT:['ARCH'_EXE]
$
$ IF F$PARSE("WRK_SSLROOT:[000000]") .EQS. "" THEN -
CREATE/DIR/LOG WRK_SSLROOT:[000000]
-$ IF F$PARSE("WRK_SSLVLIB:") .EQS. "" THEN -
- CREATE/DIR/LOG WRK_SSLVLIB:
-$ IF F$PARSE("WRK_SSLALIB:") .EQS. "" THEN -
- CREATE/DIR/LOG WRK_SSLALIB:
+$ IF F$PARSE("WRK_SSLXLIB:") .EQS. "" THEN -
+ CREATE/DIR/LOG WRK_SSLXLIB:
$ IF F$PARSE("WRK_SSLINCLUDE:") .EQS. "" THEN -
CREATE/DIR/LOG WRK_SSLINCLUDE:
-$ IF F$PARSE("WRK_SSLVEXE:") .EQS. "" THEN -
- CREATE/DIR/LOG WRK_SSLVEXE:
-$ IF F$PARSE("WRK_SSLAEXE:") .EQS. "" THEN -
- CREATE/DIR/LOG WRK_SSLAEXE:
+$ IF F$PARSE("WRK_SSLXEXE:") .EQS. "" THEN -
+ CREATE/DIR/LOG WRK_SSLXEXE:
$
$ EXHEADER := ssl.h,ssl2.h,ssl3.h,ssl23.h,tls1.h,dtls1.h,kssl.h
$ E_EXE := ssl_task
$ LIBS := LIBSSL
$
-$ VEXE_DIR := [-.VAX.EXE.SSL]
-$ AEXE_DIR := [-.AXP.EXE.SSL]
+$ XEXE_DIR := [-.'ARCH'.EXE.SSL]
$
$ COPY 'EXHEADER' WRK_SSLINCLUDE:/LOG
$ SET FILE/PROT=WORLD:RE WRK_SSLINCLUDE:'EXHEADER'
@@ -54,15 +56,10 @@
$ I = I + 1
$ IF E .EQS. "," THEN GOTO LOOP_EXE_END
$ SET NOON
-$ IF F$SEARCH(VEXE_DIR+E+".EXE") .NES. ""
+$ IF F$SEARCH(XEXE_DIR+E+".EXE") .NES. ""
$ THEN
-$ COPY 'VEXE_DIR''E'.EXE WRK_SSLVEXE:'E'.EXE/log
-$ SET FILE/PROT=W:RE WRK_SSLVEXE:'E'.EXE
-$ ENDIF
-$ IF F$SEARCH(AEXE_DIR+E+".EXE") .NES. ""
-$ THEN
-$ COPY 'AEXE_DIR''E'.EXE WRK_SSLAEXE:'E'.EXE/log
-$ SET FILE/PROT=W:RE WRK_SSLAEXE:'E'.EXE
+$ COPY 'XEXE_DIR''E'.EXE WRK_SSLXEXE:'E'.EXE/log
+$ SET FILE/PROT=W:RE WRK_SSLXEXE:'E'.EXE
$ ENDIF
$ SET ON
$ GOTO LOOP_EXE
@@ -74,27 +71,17 @@
$ I = I + 1
$ IF E .EQS. "," THEN GOTO LOOP_LIB_END
$ SET NOON
-$ IF F$SEARCH(VEXE_DIR+E+".OLB") .NES. ""
+$! Object library.
+$ IF F$SEARCH(XEXE_DIR+E+".OLB") .NES. ""
$ THEN
-$ COPY 'VEXE_DIR''E'.OLB WRK_SSLVLIB:'E'.OLB/log
-$ SET FILE/PROT=W:RE WRK_SSLVLIB:'E'.OLB
+$ COPY 'XEXE_DIR''E'.OLB WRK_SSLXLIB:'E'.OLB/log
+$ SET FILE/PROT=W:RE WRK_SSLXLIB:'E'.OLB
$ ENDIF
-$ ! Preparing for the time when we have shareable images
-$ IF F$SEARCH(VEXE_DIR+E+".EXE") .NES. ""
+$! Shareable image.
+$ IF F$SEARCH(XEXE_DIR+E+".EXE") .NES. ""
$ THEN
-$ COPY 'VEXE_DIR''E'.EXE WRK_SSLVLIB:'E'.EXE/log
-$ SET FILE/PROT=W:RE WRK_SSLVLIB:'E'.EXE
-$ ENDIF
-$ IF F$SEARCH(AEXE_DIR+E+".OLB") .NES. ""
-$ THEN
-$ COPY 'AEXE_DIR''E'.OLB WRK_SSLALIB:'E'.OLB/log
-$ SET FILE/PROT=W:RE WRK_SSLALIB:'E'.OLB
-$ ENDIF
-$ ! Preparing for the time when we have shareable images
-$ IF F$SEARCH(AEXE_DIR+E+".EXE") .NES. ""
-$ THEN
-$ COPY 'AEXE_DIR''E'.EXE WRK_SSLALIB:'E'.EXE/log
-$ SET FILE/PROT=W:RE WRK_SSLALIB:'E'.EXE
+$ COPY 'XEXE_DIR''E'.EXE WRK_SSLXLIB:'E'.EXE/log
+$ SET FILE/PROT=W:RE WRK_SSLXLIB:'E'.EXE
$ ENDIF
$ SET ON
$ GOTO LOOP_LIB
diff --git a/ssl/kssl.c b/ssl/kssl.c
index 019030a..73401c9 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 bc91817..de02389 100644
--- a/ssl/s23_clnt.c
+++ b/ssl/s23_clnt.c
@@ -202,11 +202,14 @@
{
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 468251a..42f7de4 100644
--- a/ssl/s23_srvr.c
+++ b/ssl/s23_srvr.c
@@ -315,7 +315,7 @@
(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 @@
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 50d55e6..01d62fa 100644
--- a/ssl/s2_srvr.c
+++ b/ssl/s2_srvr.c
@@ -267,7 +267,7 @@
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 d5bb99c..3f22bfd 100644
--- a/ssl/s3_both.c
+++ b/ssl/s3_both.c
@@ -168,6 +168,23 @@
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 @@
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 @@
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 @@
}
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;
+ 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 (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)
+ 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 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 + 256; /* extra space for empty fragment */
+ else
+ headerlen = SSL3_RT_DEFAULT_WRITE_OVERHEAD;
+
if (s->s3->rbuf.buf == NULL)
{
if (SSL_get_mode(s) & SSL_MODE_SMALL_BUFFERS)
@@ -622,7 +659,7 @@
{
len = SSL3_RT_MAX_PACKET_SIZE;
}
- len += SSL3_RT_DEFAULT_WRITE_OVERHEAD; /* extra space for empty fragment */
+ len += headerlen;
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 95f7c12..5893064 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 @@
{
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;
@@ -521,16 +517,13 @@
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;
@@ -634,9 +627,15 @@
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;
@@ -748,7 +747,7 @@
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)
{
@@ -895,7 +894,7 @@
#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))
{
@@ -1755,6 +1754,7 @@
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);
@@ -1778,7 +1778,28 @@
}
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:
@@ -2737,7 +2758,7 @@
*/
#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 63f1342..2c44bde 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -2458,6 +2458,7 @@
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 @@
#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 e32174d..6fe4004 100644
--- a/ssl/s3_pkt.c
+++ b/ssl/s3_pkt.c
@@ -141,9 +141,10 @@
/* ... 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 @@
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 */
@@ -1044,7 +1053,25 @@
* 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];
@@ -1074,6 +1101,21 @@
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 */
{
@@ -1292,13 +1334,13 @@
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);
@@ -1307,9 +1349,10 @@
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 80b45eb..e696450 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -166,7 +166,6 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
/* 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 @@
SSL_R_COOKIE_MISMATCH);
goto f_err;
}
+
+ ret = 2;
}
p += cookie_len;
@@ -952,7 +977,7 @@
#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 @@
* s->tmp.new_cipher - the new cipher to use.
*/
- ret=1;
+ if (ret < 0) ret=1;
if (0)
{
f_err:
@@ -2711,6 +2736,7 @@
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 @@
* 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 @@
{
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-lib.com b/ssl/ssl-lib.com
index fcd7ff7..85ab2f6 100644
--- a/ssl/ssl-lib.com
+++ b/ssl/ssl-lib.com
@@ -8,11 +8,11 @@
$! Changes by Richard Levitte <richard@levitte.org>
$!
$! This command file compiles and creates the "[.xxx.EXE.SSL]LIBSSL.OLB"
-$! library for OpenSSL. The "xxx" denotes the machine architecture of AXP
-$! or VAX.
+$! library for OpenSSL. The "xxx" denotes the machine architecture of
+$! ALPHA, IA64 or VAX.
$!
$! It is written to detect what type of machine you are compiling on
-$! (i.e. AXP or VAX) and which "C" compiler you have (i.e. VAXC, DECC
+$! (i.e. ALPHA or VAX) and which "C" compiler you have (i.e. VAXC, DECC
$! or GNU C) or you can specify which compiler to use.
$!
$! Specify the following as P1 to build just that part or ALL to just
@@ -48,27 +48,36 @@
$!
$ TCPIP_LIB = ""
$!
-$! Check Which Architecture We Are Using.
+$! Check What Architecture We Are Using.
$!
-$ IF (F$GETSYI("CPU").GE.128)
+$ IF (F$GETSYI("CPU").LT.128)
$ THEN
$!
-$! The Architecture Is AXP.
-$!
-$ ARCH := AXP
-$!
-$! Else...
-$!
-$ ELSE
-$!
$! The Architecture Is VAX.
$!
$ ARCH := VAX
$!
+$! Else...
+$!
+$ ELSE
+$!
+$! The Architecture Is Alpha, IA64 or whatever comes in the future.
+$!
+$ ARCH = F$EDIT( F$GETSYI( "ARCH_NAME"), "UPCASE")
+$ IF (ARCH .EQS. "") THEN ARCH = "UNK"
+$!
$! End The Architecture Check.
$!
$ ENDIF
$!
+$! Define The OBJ Directory.
+$!
+$ OBJ_DIR := SYS$DISK:[-.'ARCH'.OBJ.SSL]
+$!
+$! Define The EXE Directory.
+$!
+$ EXE_DIR := SYS$DISK:[-.'ARCH'.EXE.SSL]
+$!
$! Check To Make Sure We Have Valid Command Line Parameters.
$!
$ GOSUB CHECK_OPTIONS
@@ -81,10 +90,6 @@
$!
$ WRITE SYS$OUTPUT "Compiling On A ",ARCH," Machine."
$!
-$! Define The OBJ Directory.
-$!
-$ OBJ_DIR := SYS$DISK:[-.'ARCH'.OBJ.SSL]
-$!
$! Check To See If The Architecture Specific OBJ Directory Exists.
$!
$ IF (F$PARSE(OBJ_DIR).EQS."")
@@ -98,10 +103,6 @@
$!
$ ENDIF
$!
-$! Define The EXE Directory.
-$!
-$ EXE_DIR := SYS$DISK:[-.'ARCH'.EXE.SSL]
-$!
$! Check To See If The Architecture Specific Directory Exists.
$!
$ IF (F$PARSE(EXE_DIR).EQS."")
@@ -179,7 +180,7 @@
"ssl_lib,ssl_err2,ssl_cert,ssl_sess,"+ -
"ssl_ciph,ssl_stat,ssl_rsa,"+ -
"ssl_asn1,ssl_txt,ssl_algs,"+ -
- "bio_ssl,ssl_err,kssl"
+ "bio_ssl,ssl_err,kssl,t1_reneg"
$!
$! Tell The User That We Are Compiling The Library.
$!
@@ -409,7 +410,7 @@
$ IF (F$SEARCH(OPT_FILE).EQS."")
$ THEN
$!
-$! Figure Out If We Need An AXP Or A VAX Linker Option File.
+$! Figure Out If We Need A non-VAX Or A VAX Linker Option File.
$!
$ IF (ARCH.EQS."VAX")
$ THEN
@@ -429,19 +430,19 @@
$!
$ ELSE
$!
-$! Create The AXP Linker Option File.
+$! Create The non-VAX Linker Option File.
$!
$ CREATE 'OPT_FILE'
$DECK
!
-! Default System Options File For AXP To Link Agianst
+! Default System Options File For non-VAX To Link Agianst
! The Sharable C Runtime Library.
!
SYS$SHARE:CMA$OPEN_LIB_SHR/SHARE
SYS$SHARE:CMA$OPEN_RTL/SHARE
$EOD
$!
-$! End The VAX/AXP DEC C Option File Check.
+$! End The DEC C Option File Check.
$!
$ ENDIF
$!
@@ -547,8 +548,9 @@
$ WRITE SYS$OUTPUT ""
$ WRITE SYS$OUTPUT " Where 'xxx' Stands For:"
$ WRITE SYS$OUTPUT ""
-$ WRITE SYS$OUTPUT " AXP : Alpha Architecture."
-$ WRITE SYS$OUTPUT " VAX : VAX Architecture."
+$ WRITE SYS$OUTPUT " ALPHA : Alpha Architecture."
+$ WRITE SYS$OUTPUT " IA64 : IA64 Architecture."
+$ WRITE SYS$OUTPUT " VAX : VAX Architecture."
$ WRITE SYS$OUTPUT ""
$!
$! Time To EXIT.
@@ -674,7 +676,7 @@
$!
$! Check To See If We Have VAXC Or DECC.
$!
-$ IF (ARCH.EQS."AXP").OR.(F$TRNLNM("DECC$CC_DEFAULT").NES."")
+$ IF (ARCH.NES."VAX").OR.(F$TRNLNM("DECC$CC_DEFAULT").NES."")
$ THEN
$!
$! Looks Like DECC, Set To Use DECC.
@@ -784,7 +786,7 @@
$!
$! Define The Linker Options File Name.
$!
-$ OPT_FILE = "SYS$DISK:[]VAX_DECC_OPTIONS.OPT"
+$ OPT_FILE = "''EXE_DIR'VAX_DECC_OPTIONS.OPT"
$!
$! End DECC Check.
$!
@@ -806,9 +808,9 @@
$! Compile Using VAXC.
$!
$ CC = "CC"
-$ IF ARCH.EQS."AXP"
+$ IF ARCH.NES."VAX"
$ THEN
-$ WRITE SYS$OUTPUT "There is no VAX C on Alpha!"
+$ WRITE SYS$OUTPUT "There is no VAX C on ''ARCH'!"
$ EXIT
$ ENDIF
$ IF F$TRNLNM("DECC$CC_DEFAULT").EQS."/DECC" THEN CC = "CC/VAXC"
@@ -822,7 +824,7 @@
$!
$! Define The Linker Options File Name.
$!
-$ OPT_FILE = "SYS$DISK:[]VAX_VAXC_OPTIONS.OPT"
+$ OPT_FILE = "''EXE_DIR'VAX_VAXC_OPTIONS.OPT"
$!
$! End VAXC Check
$!
@@ -849,7 +851,7 @@
$!
$! Define The Linker Options File Name.
$!
-$ OPT_FILE = "SYS$DISK:[]VAX_GNUC_OPTIONS.OPT"
+$ OPT_FILE = "''EXE_DIR'VAX_GNUC_OPTIONS.OPT"
$!
$! End The GNU C Check.
$!
diff --git a/ssl/ssl.h b/ssl/ssl.h
index 0e0bc6e..c7167f1 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -485,6 +485,8 @@
#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 @@
#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 */
@@ -567,17 +573,25 @@
#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) \
@@ -585,6 +599,8 @@
#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));
@@ -1277,6 +1293,21 @@
#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) \
@@ -1527,7 +1558,7 @@
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);
@@ -1657,6 +1688,7 @@
#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
@@ -1665,6 +1697,7 @@
#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
@@ -1710,6 +1743,7 @@
#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
@@ -1750,9 +1784,11 @@
#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
@@ -1794,6 +1830,10 @@
#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
@@ -1893,6 +1933,7 @@
#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
@@ -1960,6 +2001,7 @@
#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
@@ -1987,10 +2029,14 @@
#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
@@ -2060,6 +2106,7 @@
#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 803e13a..164b5f9 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
@@ -449,6 +452,12 @@
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 4717c0e..2d9077e 100644
--- a/ssl/ssl_algs.c
+++ b/ssl/ssl_algs.c
@@ -92,9 +92,6 @@
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 0f9a348..d82e47a 100644
--- a/ssl/ssl_asn1.c
+++ b/ssl/ssl_asn1.c
@@ -68,6 +68,7 @@
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 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 @@
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 @@
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 @@
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 @@
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 @@
((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 @@
}
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 @@
{
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 @@
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 a32b2d4..16fda5d 100644
--- a/ssl/ssl_cert.c
+++ b/ssl/ssl_cert.c
@@ -500,9 +500,6 @@
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 @@
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 52f91cf..5e2d436 100644
--- a/ssl/ssl_ciph.c
+++ b/ssl/ssl_ciph.c
@@ -1091,10 +1091,11 @@
*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 24a994f..7eb5202 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -78,6 +78,7 @@
{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 @@
{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 @@
{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 @@
{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 @@
{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 @@
{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 @@
{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 @@
{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 @@
{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 4c56e7a..0ba658e 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -508,7 +508,6 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
#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 ed4ddbb..e305db4 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -694,7 +694,7 @@
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_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_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_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_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 @@
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 27113eb..c0960b5 100644
--- a/ssl/ssl_rsa.c
+++ b/ssl/ssl_rsa.c
@@ -723,7 +723,7 @@
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 8391d62..e7802e1 100644
--- a/ssl/ssl_sess.c
+++ b/ssl/ssl_sess.c
@@ -211,6 +211,11 @@
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 @@
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 73b0250..e7509f0 100644
--- a/ssl/ssl_stat.c
+++ b/ssl/ssl_stat.c
@@ -198,6 +198,12 @@
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_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 06b8675..81c1361 100644
--- a/ssl/ssl_txt.c
+++ b/ssl/ssl_txt.c
@@ -91,6 +91,10 @@
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 @@
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 7cb3e29..dab6e44 100644
--- a/ssl/t1_enc.c
+++ b/ssl/t1_enc.c
@@ -765,10 +765,10 @@
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 @@
{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 9ce7269..8b53112 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -133,6 +133,11 @@
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 @@
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 @@
}
}
- 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 @@
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 @@
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 @@
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 @@
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 @@
}
}
- 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 @@
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 @@
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 @@
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 @@
}
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 @@
/* 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 @@
}
*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 @@
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 @@
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 @@
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/tls1.h b/ssl/tls1.h
index 2d1d293..afe4807 100644
--- a/ssl/tls1.h
+++ b/ssl/tls1.h
@@ -115,6 +115,9 @@
#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_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)