Reorganise state machine files
authorMatt Caswell <matt@openssl.org>
Fri, 11 Sep 2015 09:48:59 +0000 (10:48 +0100)
committerMatt Caswell <matt@openssl.org>
Fri, 30 Oct 2015 08:38:18 +0000 (08:38 +0000)
Pull out the state machine into a separate sub directory. Also moved some
functions which were nothing to do with the state machine but were in state
machine files. Pulled all the SSL_METHOD definitions into one place...most
of those files had very little left in them any more.

Reviewed-by: Tim Hudson <tjh@openssl.org>
Reviewed-by: Richard Levitte <levitte@openssl.org>
23 files changed:
crypto/ct/Makefile
ssl/Makefile
ssl/d1_both.c [deleted file]
ssl/d1_clnt.c [deleted file]
ssl/d1_lib.c
ssl/d1_meth.c [deleted file]
ssl/d1_srvr.c [deleted file]
ssl/methods.c [new file with mode: 0644]
ssl/s3_both.c [deleted file]
ssl/s3_clnt.c [deleted file]
ssl/s3_srvr.c [deleted file]
ssl/ssl_locl.h
ssl/statem.c [deleted file]
ssl/statem/statem.c [new file with mode: 0644]
ssl/statem/statem.h [new file with mode: 0644]
ssl/statem/statem_clnt.c [new file with mode: 0644]
ssl/statem/statem_dtls.c [new file with mode: 0644]
ssl/statem/statem_lib.c [new file with mode: 0644]
ssl/statem/statem_srvr.c [new file with mode: 0644]
ssl/t1_clnt.c [deleted file]
ssl/t1_meth.c [deleted file]
ssl/t1_srvr.c [deleted file]
test/Makefile

index 2f55a2d560a2030c546772a81a6b4bb97520fafb..dfb0839c1e5bc8a788adb46360b90306012c496d 100644 (file)
@@ -90,4 +90,5 @@ ct_lib.o: ../../include/openssl/stack.h ../../include/openssl/symhacks.h
 ct_lib.o: ../../include/openssl/tls1.h ../../include/openssl/x509.h
 ct_lib.o: ../../include/openssl/x509_vfy.h ../../ssl/packet_locl.h
 ct_lib.o: ../../ssl/record/record.h ../../ssl/ssl_locl.h
-ct_lib.o: ../include/internal/cryptlib.h ../include/internal/ct_int.h ct_lib.c
+ct_lib.o: ../../ssl/statem/statem.h ../include/internal/cryptlib.h
+ct_lib.o: ../include/internal/ct_int.h ct_lib.c
index 536ddcc20033e8b7d63b8a6dab6d42e14e0b6d6d..9f1fe8d8c2b3cf85f3f8cc69470a5a786de5d063 100644 (file)
@@ -17,33 +17,33 @@ GENERAL=Makefile README ssl-lib.com install.com
 LIB=$(TOP)/libssl.a
 SHARED_LIB= libssl$(SHLIB_EXT)
 LIBSRC=        \
-       s3_srvr.c s3_clnt.c  s3_lib.c  s3_enc.c record/rec_layer_s3.c \
-       s3_both.c s3_cbc.c s3_msg.c \
-       t1_meth.c   t1_srvr.c t1_clnt.c  t1_lib.c  t1_enc.c t1_ext.c \
-       d1_meth.c   d1_srvr.c d1_clnt.c  d1_lib.c  record/rec_layer_d1.c d1_msg.c \
-       d1_both.c d1_srtp.c \
+       statem/statem_srvr.c statem/statem_clnt.c  s3_lib.c  s3_enc.c record/rec_layer_s3.c \
+       statem/statem_lib.c s3_cbc.c s3_msg.c \
+       methods.c   t1_lib.c  t1_enc.c t1_ext.c \
+       d1_lib.c  record/rec_layer_d1.c d1_msg.c \
+       statem/statem_dtls.c d1_srtp.c \
        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 ssl_conf.c \
        bio_ssl.c ssl_err.c t1_reneg.c tls_srp.c t1_trce.c ssl_utst.c \
        record/ssl3_buffer.c record/ssl3_record.c record/dtls1_bitmap.c \
-       statem.c
+       statem/statem.c
 LIBOBJ= \
-       s3_srvr.o  s3_clnt.o  s3_lib.o  s3_enc.o record/rec_layer_s3.o \
-       s3_both.o s3_cbc.o s3_msg.o \
-       t1_meth.o   t1_srvr.o t1_clnt.o  t1_lib.o  t1_enc.o t1_ext.o \
-       d1_meth.o   d1_srvr.o d1_clnt.o  d1_lib.o  record/rec_layer_d1.o d1_msg.o \
-       d1_both.o d1_srtp.o\
+       statem/statem_srvr.o  statem/statem_clnt.o  s3_lib.o  s3_enc.o record/rec_layer_s3.o \
+       statem/statem_lib.o s3_cbc.o s3_msg.o \
+       methods.o   t1_lib.o  t1_enc.o t1_ext.o \
+       d1_lib.o  record/rec_layer_d1.o d1_msg.o \
+       statem/statem_dtls.o d1_srtp.o\
        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 ssl_conf.o \
        bio_ssl.o ssl_err.o t1_reneg.o tls_srp.o t1_trce.o ssl_utst.o \
        record/ssl3_buffer.o record/ssl3_record.o record/dtls1_bitmap.o \
-       statem.o
+       statem/statem.o
 
 SRC= $(LIBSRC)
 
-HEADER=        ssl_locl.h record/record_locl.h record/record.h
+HEADER=        ssl_locl.h record/record_locl.h record/record.h statem/statem.h
 
 ALL=   $(GENERAL) $(SRC) $(HEADER)
 
@@ -93,7 +93,9 @@ clean:
        rm -f $(LIBOBJ) *.obj lib tags core .pure .nfs* *.old *.bak fluff
        rm -f record/*.obj record/lib record/retags record/core \
        record/.pure record/.nfs* record/*.old record/*.bak record/fluff
-
+       rm -f statem/*.obj statem/lib statem/retags statem/core \
+       statem/.pure statem/.nfs* statem/*.old statem/*.bak statem/fluff
+       
 # DO NOT DELETE THIS LINE -- make depend depends on it.
 
 bio_ssl.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
@@ -115,48 +117,7 @@ bio_ssl.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 bio_ssl.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 bio_ssl.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 bio_ssl.o: ../include/openssl/x509_vfy.h bio_ssl.c packet_locl.h
-bio_ssl.o: record/record.h ssl_locl.h
-d1_both.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-d1_both.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-d1_both.o: ../include/openssl/comp.h ../include/openssl/crypto.h
-d1_both.o: ../include/openssl/dsa.h ../include/openssl/dtls1.h
-d1_both.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
-d1_both.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
-d1_both.o: ../include/openssl/err.h ../include/openssl/evp.h
-d1_both.o: ../include/openssl/hmac.h ../include/openssl/lhash.h
-d1_both.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-d1_both.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-d1_both.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-d1_both.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-d1_both.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-d1_both.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-d1_both.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-d1_both.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-d1_both.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-d1_both.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-d1_both.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h d1_both.c
-d1_both.o: packet_locl.h record/record.h ssl_locl.h
-d1_clnt.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-d1_clnt.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-d1_clnt.o: ../include/openssl/comp.h ../include/openssl/crypto.h
-d1_clnt.o: ../include/openssl/dh.h ../include/openssl/dsa.h
-d1_clnt.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-d1_clnt.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-d1_clnt.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-d1_clnt.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-d1_clnt.o: ../include/openssl/lhash.h ../include/openssl/md5.h
-d1_clnt.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-d1_clnt.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-d1_clnt.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-d1_clnt.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-d1_clnt.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-d1_clnt.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-d1_clnt.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-d1_clnt.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-d1_clnt.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-d1_clnt.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-d1_clnt.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h d1_clnt.c
-d1_clnt.o: packet_locl.h record/record.h ssl_locl.h
+bio_ssl.o: record/record.h ssl_locl.h statem/statem.h
 d1_lib.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 d1_lib.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 d1_lib.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -169,34 +130,14 @@ d1_lib.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
 d1_lib.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
 d1_lib.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
 d1_lib.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-d1_lib.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-d1_lib.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-d1_lib.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-d1_lib.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
-d1_lib.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-d1_lib.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-d1_lib.o: ../include/openssl/x509_vfy.h d1_lib.c packet_locl.h record/record.h
-d1_lib.o: ssl_locl.h
-d1_meth.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-d1_meth.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-d1_meth.o: ../include/openssl/comp.h ../include/openssl/crypto.h
-d1_meth.o: ../include/openssl/dsa.h ../include/openssl/dtls1.h
-d1_meth.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
-d1_meth.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
-d1_meth.o: ../include/openssl/err.h ../include/openssl/evp.h
-d1_meth.o: ../include/openssl/hmac.h ../include/openssl/lhash.h
-d1_meth.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-d1_meth.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-d1_meth.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-d1_meth.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-d1_meth.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-d1_meth.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-d1_meth.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-d1_meth.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
-d1_meth.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-d1_meth.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-d1_meth.o: ../include/openssl/x509_vfy.h d1_meth.c packet_locl.h
-d1_meth.o: record/record.h ssl_locl.h
+d1_lib.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
+d1_lib.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
+d1_lib.o: ../include/openssl/sha.h ../include/openssl/srtp.h
+d1_lib.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
+d1_lib.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
+d1_lib.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
+d1_lib.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h d1_lib.c
+d1_lib.o: packet_locl.h record/record.h ssl_locl.h statem/statem.h
 d1_msg.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 d1_msg.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 d1_msg.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -216,7 +157,7 @@ d1_msg.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 d1_msg.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 d1_msg.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 d1_msg.o: ../include/openssl/x509_vfy.h d1_msg.c packet_locl.h record/record.h
-d1_msg.o: ssl_locl.h
+d1_msg.o: ssl_locl.h statem/statem.h
 d1_srtp.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 d1_srtp.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 d1_srtp.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -236,28 +177,27 @@ d1_srtp.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 d1_srtp.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 d1_srtp.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 d1_srtp.o: ../include/openssl/x509_vfy.h d1_srtp.c packet_locl.h
-d1_srtp.o: record/record.h ssl_locl.h
-d1_srvr.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-d1_srvr.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-d1_srvr.o: ../include/openssl/comp.h ../include/openssl/crypto.h
-d1_srvr.o: ../include/openssl/dh.h ../include/openssl/dsa.h
-d1_srvr.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-d1_srvr.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-d1_srvr.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-d1_srvr.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-d1_srvr.o: ../include/openssl/lhash.h ../include/openssl/md5.h
-d1_srvr.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-d1_srvr.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-d1_srvr.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-d1_srvr.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-d1_srvr.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-d1_srvr.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-d1_srvr.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-d1_srvr.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-d1_srvr.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-d1_srvr.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-d1_srvr.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h d1_srvr.c
-d1_srvr.o: packet_locl.h record/record.h ssl_locl.h
+d1_srtp.o: record/record.h ssl_locl.h statem/statem.h
+methods.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
+methods.o: ../include/openssl/bn.h ../include/openssl/buffer.h
+methods.o: ../include/openssl/comp.h ../include/openssl/crypto.h
+methods.o: ../include/openssl/dsa.h ../include/openssl/dtls1.h
+methods.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
+methods.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
+methods.o: ../include/openssl/err.h ../include/openssl/evp.h
+methods.o: ../include/openssl/hmac.h ../include/openssl/lhash.h
+methods.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
+methods.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
+methods.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
+methods.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
+methods.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
+methods.o: ../include/openssl/safestack.h ../include/openssl/sha.h
+methods.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
+methods.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
+methods.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
+methods.o: ../include/openssl/tls1.h ../include/openssl/x509.h
+methods.o: ../include/openssl/x509_vfy.h methods.c packet_locl.h
+methods.o: record/record.h ssl_locl.h statem/statem.h
 record/dtls1_bitmap.o: ../e_os.h ../include/openssl/asn1.h
 record/dtls1_bitmap.o: ../include/openssl/bio.h ../include/openssl/bn.h
 record/dtls1_bitmap.o: ../include/openssl/buffer.h ../include/openssl/comp.h
@@ -280,7 +220,8 @@ record/dtls1_bitmap.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 record/dtls1_bitmap.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 record/dtls1_bitmap.o: ../include/openssl/x509_vfy.h record/../packet_locl.h
 record/dtls1_bitmap.o: record/../record/record.h record/../ssl_locl.h
-record/dtls1_bitmap.o: record/dtls1_bitmap.c record/record_locl.h
+record/dtls1_bitmap.o: record/../statem/statem.h record/dtls1_bitmap.c
+record/dtls1_bitmap.o: record/record_locl.h
 record/rec_layer_d1.o: ../e_os.h ../include/openssl/asn1.h
 record/rec_layer_d1.o: ../include/openssl/bio.h ../include/openssl/bn.h
 record/rec_layer_d1.o: ../include/openssl/buffer.h ../include/openssl/comp.h
@@ -303,8 +244,8 @@ record/rec_layer_d1.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
 record/rec_layer_d1.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
 record/rec_layer_d1.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
 record/rec_layer_d1.o: record/../packet_locl.h record/../record/record.h
-record/rec_layer_d1.o: record/../ssl_locl.h record/rec_layer_d1.c
-record/rec_layer_d1.o: record/record_locl.h
+record/rec_layer_d1.o: record/../ssl_locl.h record/../statem/statem.h
+record/rec_layer_d1.o: record/rec_layer_d1.c record/record_locl.h
 record/rec_layer_s3.o: ../e_os.h ../include/openssl/asn1.h
 record/rec_layer_s3.o: ../include/openssl/bio.h ../include/openssl/bn.h
 record/rec_layer_s3.o: ../include/openssl/buffer.h ../include/openssl/comp.h
@@ -327,8 +268,8 @@ record/rec_layer_s3.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
 record/rec_layer_s3.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
 record/rec_layer_s3.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
 record/rec_layer_s3.o: record/../packet_locl.h record/../record/record.h
-record/rec_layer_s3.o: record/../ssl_locl.h record/rec_layer_s3.c
-record/rec_layer_s3.o: record/record_locl.h
+record/rec_layer_s3.o: record/../ssl_locl.h record/../statem/statem.h
+record/rec_layer_s3.o: record/rec_layer_s3.c record/record_locl.h
 record/ssl3_buffer.o: ../e_os.h ../include/openssl/asn1.h
 record/ssl3_buffer.o: ../include/openssl/bio.h ../include/openssl/bn.h
 record/ssl3_buffer.o: ../include/openssl/buffer.h ../include/openssl/comp.h
@@ -351,7 +292,8 @@ record/ssl3_buffer.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 record/ssl3_buffer.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 record/ssl3_buffer.o: ../include/openssl/x509_vfy.h record/../packet_locl.h
 record/ssl3_buffer.o: record/../record/record.h record/../ssl_locl.h
-record/ssl3_buffer.o: record/record_locl.h record/ssl3_buffer.c
+record/ssl3_buffer.o: record/../statem/statem.h record/record_locl.h
+record/ssl3_buffer.o: record/ssl3_buffer.c
 record/ssl3_record.o: ../e_os.h ../include/internal/constant_time_locl.h
 record/ssl3_record.o: ../include/openssl/asn1.h ../include/openssl/bio.h
 record/ssl3_record.o: ../include/openssl/bn.h ../include/openssl/buffer.h
@@ -374,28 +316,8 @@ record/ssl3_record.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
 record/ssl3_record.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
 record/ssl3_record.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
 record/ssl3_record.o: record/../packet_locl.h record/../record/record.h
-record/ssl3_record.o: record/../ssl_locl.h record/record_locl.h
-record/ssl3_record.o: record/ssl3_record.c
-s3_both.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s3_both.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-s3_both.o: ../include/openssl/comp.h ../include/openssl/crypto.h
-s3_both.o: ../include/openssl/dsa.h ../include/openssl/dtls1.h
-s3_both.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
-s3_both.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
-s3_both.o: ../include/openssl/err.h ../include/openssl/evp.h
-s3_both.o: ../include/openssl/hmac.h ../include/openssl/lhash.h
-s3_both.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s3_both.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s3_both.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s3_both.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s3_both.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-s3_both.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-s3_both.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-s3_both.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-s3_both.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-s3_both.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-s3_both.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
-s3_both.o: packet_locl.h record/record.h s3_both.c ssl_locl.h
+record/ssl3_record.o: record/../ssl_locl.h record/../statem/statem.h
+record/ssl3_record.o: record/record_locl.h record/ssl3_record.c
 s3_cbc.o: ../e_os.h ../include/internal/constant_time_locl.h
 s3_cbc.o: ../include/openssl/asn1.h ../include/openssl/bio.h
 s3_cbc.o: ../include/openssl/bn.h ../include/openssl/buffer.h
@@ -416,29 +338,7 @@ s3_cbc.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
 s3_cbc.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
 s3_cbc.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
 s3_cbc.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h packet_locl.h
-s3_cbc.o: record/record.h s3_cbc.c ssl_locl.h
-s3_clnt.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-s3_clnt.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-s3_clnt.o: ../include/openssl/comp.h ../include/openssl/crypto.h
-s3_clnt.o: ../include/openssl/dh.h ../include/openssl/dsa.h
-s3_clnt.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s3_clnt.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s3_clnt.o: ../include/openssl/ecdsa.h ../include/openssl/engine.h
-s3_clnt.o: ../include/openssl/err.h ../include/openssl/evp.h
-s3_clnt.o: ../include/openssl/hmac.h ../include/openssl/lhash.h
-s3_clnt.o: ../include/openssl/md5.h ../include/openssl/obj_mac.h
-s3_clnt.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
-s3_clnt.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h
-s3_clnt.o: ../include/openssl/pem.h ../include/openssl/pem2.h
-s3_clnt.o: ../include/openssl/pkcs7.h ../include/openssl/pqueue.h
-s3_clnt.o: ../include/openssl/rand.h ../include/openssl/rsa.h
-s3_clnt.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-s3_clnt.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-s3_clnt.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
-s3_clnt.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-s3_clnt.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-s3_clnt.o: ../include/openssl/x509_vfy.h packet_locl.h record/record.h
-s3_clnt.o: s3_clnt.c ssl_locl.h
+s3_cbc.o: record/record.h s3_cbc.c ssl_locl.h statem/statem.h
 s3_enc.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 s3_enc.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 s3_enc.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -458,7 +358,7 @@ s3_enc.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
 s3_enc.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
 s3_enc.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
 s3_enc.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h packet_locl.h
-s3_enc.o: record/record.h s3_enc.c ssl_locl.h
+s3_enc.o: record/record.h s3_enc.c ssl_locl.h statem/statem.h
 s3_lib.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 s3_lib.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 s3_lib.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -479,7 +379,7 @@ s3_lib.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
 s3_lib.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
 s3_lib.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
 s3_lib.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h packet_locl.h
-s3_lib.o: record/record.h s3_lib.c ssl_locl.h
+s3_lib.o: record/record.h s3_lib.c ssl_locl.h statem/statem.h
 s3_msg.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 s3_msg.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 s3_msg.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -499,29 +399,7 @@ s3_msg.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 s3_msg.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 s3_msg.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 s3_msg.o: ../include/openssl/x509_vfy.h packet_locl.h record/record.h s3_msg.c
-s3_msg.o: ssl_locl.h
-s3_srvr.o: ../e_os.h ../include/internal/constant_time_locl.h
-s3_srvr.o: ../include/openssl/asn1.h ../include/openssl/bio.h
-s3_srvr.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-s3_srvr.o: ../include/openssl/comp.h ../include/openssl/crypto.h
-s3_srvr.o: ../include/openssl/dh.h ../include/openssl/dsa.h
-s3_srvr.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
-s3_srvr.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
-s3_srvr.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
-s3_srvr.o: ../include/openssl/evp.h ../include/openssl/hmac.h
-s3_srvr.o: ../include/openssl/lhash.h ../include/openssl/md5.h
-s3_srvr.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-s3_srvr.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-s3_srvr.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-s3_srvr.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-s3_srvr.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-s3_srvr.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-s3_srvr.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-s3_srvr.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-s3_srvr.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-s3_srvr.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-s3_srvr.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
-s3_srvr.o: packet_locl.h record/record.h s3_srvr.c ssl_locl.h
+s3_msg.o: ssl_locl.h statem/statem.h
 ssl_algs.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 ssl_algs.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 ssl_algs.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -541,7 +419,7 @@ ssl_algs.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 ssl_algs.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 ssl_algs.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 ssl_algs.o: ../include/openssl/x509_vfy.h packet_locl.h record/record.h
-ssl_algs.o: ssl_algs.c ssl_locl.h
+ssl_algs.o: ssl_algs.c ssl_locl.h statem/statem.h
 ssl_asn1.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/asn1t.h
 ssl_asn1.o: ../include/openssl/bio.h ../include/openssl/bn.h
 ssl_asn1.o: ../include/openssl/buffer.h ../include/openssl/comp.h
@@ -561,7 +439,7 @@ ssl_asn1.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
 ssl_asn1.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
 ssl_asn1.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
 ssl_asn1.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
-ssl_asn1.o: packet_locl.h record/record.h ssl_asn1.c ssl_locl.h
+ssl_asn1.o: packet_locl.h record/record.h ssl_asn1.c ssl_locl.h statem/statem.h
 ssl_cert.o: ../e_os.h ../include/internal/o_dir.h ../include/openssl/asn1.h
 ssl_cert.o: ../include/openssl/bio.h ../include/openssl/bn.h
 ssl_cert.o: ../include/openssl/buffer.h ../include/openssl/comp.h
@@ -583,7 +461,7 @@ ssl_cert.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
 ssl_cert.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
 ssl_cert.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
 ssl_cert.o: ../include/openssl/x509v3.h packet_locl.h record/record.h
-ssl_cert.o: ssl_cert.c ssl_locl.h
+ssl_cert.o: ssl_cert.c ssl_locl.h statem/statem.h
 ssl_ciph.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 ssl_ciph.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 ssl_ciph.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -603,7 +481,7 @@ ssl_ciph.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
 ssl_ciph.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
 ssl_ciph.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
 ssl_ciph.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
-ssl_ciph.o: packet_locl.h record/record.h ssl_ciph.c ssl_locl.h
+ssl_ciph.o: packet_locl.h record/record.h ssl_ciph.c ssl_locl.h statem/statem.h
 ssl_conf.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 ssl_conf.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 ssl_conf.o: ../include/openssl/comp.h ../include/openssl/conf.h
@@ -624,7 +502,7 @@ ssl_conf.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 ssl_conf.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 ssl_conf.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 ssl_conf.o: ../include/openssl/x509_vfy.h packet_locl.h record/record.h
-ssl_conf.o: ssl_conf.c ssl_locl.h
+ssl_conf.o: ssl_conf.c ssl_locl.h statem/statem.h
 ssl_err.o: ../include/openssl/asn1.h ../include/openssl/bio.h
 ssl_err.o: ../include/openssl/buffer.h ../include/openssl/comp.h
 ssl_err.o: ../include/openssl/crypto.h ../include/openssl/dtls1.h
@@ -681,7 +559,7 @@ ssl_lib.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
 ssl_lib.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
 ssl_lib.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
 ssl_lib.o: ../include/openssl/x509v3.h packet_locl.h record/record.h ssl_lib.c
-ssl_lib.o: ssl_locl.h
+ssl_lib.o: ssl_locl.h statem/statem.h
 ssl_rsa.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 ssl_rsa.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 ssl_rsa.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -701,7 +579,7 @@ ssl_rsa.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 ssl_rsa.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 ssl_rsa.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 ssl_rsa.o: ../include/openssl/x509_vfy.h packet_locl.h record/record.h
-ssl_rsa.o: ssl_locl.h ssl_rsa.c
+ssl_rsa.o: ssl_locl.h ssl_rsa.c statem/statem.h
 ssl_sess.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 ssl_sess.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 ssl_sess.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -722,7 +600,7 @@ ssl_sess.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 ssl_sess.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 ssl_sess.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 ssl_sess.o: ../include/openssl/x509_vfy.h packet_locl.h record/record.h
-ssl_sess.o: ssl_locl.h ssl_sess.c
+ssl_sess.o: ssl_locl.h ssl_sess.c statem/statem.h
 ssl_stat.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 ssl_stat.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 ssl_stat.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -742,7 +620,7 @@ ssl_stat.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 ssl_stat.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 ssl_stat.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 ssl_stat.o: ../include/openssl/x509_vfy.h packet_locl.h record/record.h
-ssl_stat.o: ssl_locl.h ssl_stat.c
+ssl_stat.o: ssl_locl.h ssl_stat.c statem/statem.h
 ssl_txt.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 ssl_txt.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 ssl_txt.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -762,7 +640,7 @@ ssl_txt.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 ssl_txt.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 ssl_txt.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 ssl_txt.o: ../include/openssl/x509_vfy.h packet_locl.h record/record.h
-ssl_txt.o: ssl_locl.h ssl_txt.c
+ssl_txt.o: ssl_locl.h ssl_txt.c statem/statem.h
 ssl_utst.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 ssl_utst.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 ssl_utst.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -782,47 +660,126 @@ ssl_utst.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 ssl_utst.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 ssl_utst.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 ssl_utst.o: ../include/openssl/x509_vfy.h packet_locl.h record/record.h
-ssl_utst.o: ssl_locl.h ssl_utst.c
-statem.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-statem.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-statem.o: ../include/openssl/comp.h ../include/openssl/crypto.h
-statem.o: ../include/openssl/dsa.h ../include/openssl/dtls1.h
-statem.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
-statem.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
-statem.o: ../include/openssl/err.h ../include/openssl/evp.h
-statem.o: ../include/openssl/hmac.h ../include/openssl/lhash.h
-statem.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-statem.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-statem.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-statem.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-statem.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-statem.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-statem.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-statem.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-statem.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-statem.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-statem.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h packet_locl.h
-statem.o: record/record.h ssl_locl.h statem.c
-t1_clnt.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-t1_clnt.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-t1_clnt.o: ../include/openssl/comp.h ../include/openssl/crypto.h
-t1_clnt.o: ../include/openssl/dsa.h ../include/openssl/dtls1.h
-t1_clnt.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
-t1_clnt.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
-t1_clnt.o: ../include/openssl/err.h ../include/openssl/evp.h
-t1_clnt.o: ../include/openssl/hmac.h ../include/openssl/lhash.h
-t1_clnt.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-t1_clnt.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-t1_clnt.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-t1_clnt.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-t1_clnt.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-t1_clnt.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-t1_clnt.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-t1_clnt.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-t1_clnt.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-t1_clnt.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-t1_clnt.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
-t1_clnt.o: packet_locl.h record/record.h ssl_locl.h t1_clnt.c
+ssl_utst.o: ssl_locl.h ssl_utst.c statem/statem.h
+statem/statem.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
+statem/statem.o: ../include/openssl/bn.h ../include/openssl/buffer.h
+statem/statem.o: ../include/openssl/comp.h ../include/openssl/crypto.h
+statem/statem.o: ../include/openssl/dsa.h ../include/openssl/dtls1.h
+statem/statem.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
+statem/statem.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
+statem/statem.o: ../include/openssl/err.h ../include/openssl/evp.h
+statem/statem.o: ../include/openssl/hmac.h ../include/openssl/lhash.h
+statem/statem.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
+statem/statem.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
+statem/statem.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
+statem/statem.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
+statem/statem.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
+statem/statem.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
+statem/statem.o: ../include/openssl/sha.h ../include/openssl/srtp.h
+statem/statem.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
+statem/statem.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
+statem/statem.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
+statem/statem.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
+statem/statem.o: statem/../packet_locl.h statem/../record/record.h
+statem/statem.o: statem/../ssl_locl.h statem/../statem/statem.h statem/statem.c
+statem/statem_clnt.o: ../e_os.h ../include/openssl/asn1.h
+statem/statem_clnt.o: ../include/openssl/bio.h ../include/openssl/bn.h
+statem/statem_clnt.o: ../include/openssl/buffer.h ../include/openssl/comp.h
+statem/statem_clnt.o: ../include/openssl/crypto.h ../include/openssl/dh.h
+statem/statem_clnt.o: ../include/openssl/dsa.h ../include/openssl/dtls1.h
+statem/statem_clnt.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
+statem/statem_clnt.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
+statem/statem_clnt.o: ../include/openssl/engine.h ../include/openssl/err.h
+statem/statem_clnt.o: ../include/openssl/evp.h ../include/openssl/hmac.h
+statem/statem_clnt.o: ../include/openssl/lhash.h ../include/openssl/md5.h
+statem/statem_clnt.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
+statem/statem_clnt.o: ../include/openssl/opensslconf.h
+statem/statem_clnt.o: ../include/openssl/opensslv.h
+statem/statem_clnt.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
+statem/statem_clnt.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
+statem/statem_clnt.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
+statem/statem_clnt.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
+statem/statem_clnt.o: ../include/openssl/sha.h ../include/openssl/srtp.h
+statem/statem_clnt.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
+statem/statem_clnt.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
+statem/statem_clnt.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
+statem/statem_clnt.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
+statem/statem_clnt.o: statem/../packet_locl.h statem/../record/record.h
+statem/statem_clnt.o: statem/../ssl_locl.h statem/../statem/statem.h
+statem/statem_clnt.o: statem/statem_clnt.c
+statem/statem_dtls.o: ../e_os.h ../include/openssl/asn1.h
+statem/statem_dtls.o: ../include/openssl/bio.h ../include/openssl/bn.h
+statem/statem_dtls.o: ../include/openssl/buffer.h ../include/openssl/comp.h
+statem/statem_dtls.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
+statem/statem_dtls.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
+statem/statem_dtls.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
+statem/statem_dtls.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
+statem/statem_dtls.o: ../include/openssl/evp.h ../include/openssl/hmac.h
+statem/statem_dtls.o: ../include/openssl/lhash.h ../include/openssl/obj_mac.h
+statem/statem_dtls.o: ../include/openssl/objects.h
+statem/statem_dtls.o: ../include/openssl/opensslconf.h
+statem/statem_dtls.o: ../include/openssl/opensslv.h
+statem/statem_dtls.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
+statem/statem_dtls.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
+statem/statem_dtls.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
+statem/statem_dtls.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
+statem/statem_dtls.o: ../include/openssl/sha.h ../include/openssl/srtp.h
+statem/statem_dtls.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
+statem/statem_dtls.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
+statem/statem_dtls.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
+statem/statem_dtls.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
+statem/statem_dtls.o: statem/../packet_locl.h statem/../record/record.h
+statem/statem_dtls.o: statem/../ssl_locl.h statem/../statem/statem.h
+statem/statem_dtls.o: statem/statem_dtls.c
+statem/statem_lib.o: ../e_os.h ../include/openssl/asn1.h
+statem/statem_lib.o: ../include/openssl/bio.h ../include/openssl/bn.h
+statem/statem_lib.o: ../include/openssl/buffer.h ../include/openssl/comp.h
+statem/statem_lib.o: ../include/openssl/crypto.h ../include/openssl/dsa.h
+statem/statem_lib.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
+statem/statem_lib.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
+statem/statem_lib.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
+statem/statem_lib.o: ../include/openssl/evp.h ../include/openssl/hmac.h
+statem/statem_lib.o: ../include/openssl/lhash.h ../include/openssl/obj_mac.h
+statem/statem_lib.o: ../include/openssl/objects.h
+statem/statem_lib.o: ../include/openssl/opensslconf.h
+statem/statem_lib.o: ../include/openssl/opensslv.h
+statem/statem_lib.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
+statem/statem_lib.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
+statem/statem_lib.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
+statem/statem_lib.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
+statem/statem_lib.o: ../include/openssl/sha.h ../include/openssl/srtp.h
+statem/statem_lib.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
+statem/statem_lib.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
+statem/statem_lib.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
+statem/statem_lib.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
+statem/statem_lib.o: statem/../packet_locl.h statem/../record/record.h
+statem/statem_lib.o: statem/../ssl_locl.h statem/../statem/statem.h
+statem/statem_lib.o: statem/statem_lib.c
+statem/statem_srvr.o: ../e_os.h ../include/internal/constant_time_locl.h
+statem/statem_srvr.o: ../include/openssl/asn1.h ../include/openssl/bio.h
+statem/statem_srvr.o: ../include/openssl/bn.h ../include/openssl/buffer.h
+statem/statem_srvr.o: ../include/openssl/comp.h ../include/openssl/crypto.h
+statem/statem_srvr.o: ../include/openssl/dh.h ../include/openssl/dsa.h
+statem/statem_srvr.o: ../include/openssl/dtls1.h ../include/openssl/e_os2.h
+statem/statem_srvr.o: ../include/openssl/ec.h ../include/openssl/ecdh.h
+statem/statem_srvr.o: ../include/openssl/ecdsa.h ../include/openssl/err.h
+statem/statem_srvr.o: ../include/openssl/evp.h ../include/openssl/hmac.h
+statem/statem_srvr.o: ../include/openssl/lhash.h ../include/openssl/md5.h
+statem/statem_srvr.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
+statem/statem_srvr.o: ../include/openssl/opensslconf.h
+statem/statem_srvr.o: ../include/openssl/opensslv.h
+statem/statem_srvr.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
+statem/statem_srvr.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
+statem/statem_srvr.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
+statem/statem_srvr.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
+statem/statem_srvr.o: ../include/openssl/sha.h ../include/openssl/srtp.h
+statem/statem_srvr.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
+statem/statem_srvr.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
+statem/statem_srvr.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
+statem/statem_srvr.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
+statem/statem_srvr.o: statem/../packet_locl.h statem/../record/record.h
+statem/statem_srvr.o: statem/../ssl_locl.h statem/../statem/statem.h
+statem/statem_srvr.o: statem/statem_srvr.c
 t1_enc.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 t1_enc.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 t1_enc.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -843,7 +800,7 @@ t1_enc.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 t1_enc.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 t1_enc.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 t1_enc.o: ../include/openssl/x509_vfy.h packet_locl.h record/record.h
-t1_enc.o: ssl_locl.h t1_enc.c
+t1_enc.o: ssl_locl.h statem/statem.h t1_enc.c
 t1_ext.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 t1_ext.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 t1_ext.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -863,7 +820,7 @@ t1_ext.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 t1_ext.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 t1_ext.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 t1_ext.o: ../include/openssl/x509_vfy.h packet_locl.h record/record.h
-t1_ext.o: ssl_locl.h t1_ext.c
+t1_ext.o: ssl_locl.h statem/statem.h t1_ext.c
 t1_lib.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 t1_lib.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 t1_lib.o: ../include/openssl/comp.h ../include/openssl/conf.h
@@ -885,27 +842,7 @@ t1_lib.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 t1_lib.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 t1_lib.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 t1_lib.o: ../include/openssl/x509_vfy.h ../include/openssl/x509v3.h
-t1_lib.o: packet_locl.h record/record.h ssl_locl.h t1_lib.c
-t1_meth.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
-t1_meth.o: ../include/openssl/bn.h ../include/openssl/buffer.h
-t1_meth.o: ../include/openssl/comp.h ../include/openssl/crypto.h
-t1_meth.o: ../include/openssl/dsa.h ../include/openssl/dtls1.h
-t1_meth.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
-t1_meth.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
-t1_meth.o: ../include/openssl/err.h ../include/openssl/evp.h
-t1_meth.o: ../include/openssl/hmac.h ../include/openssl/lhash.h
-t1_meth.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-t1_meth.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-t1_meth.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-t1_meth.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-t1_meth.o: ../include/openssl/pqueue.h ../include/openssl/rsa.h
-t1_meth.o: ../include/openssl/safestack.h ../include/openssl/sha.h
-t1_meth.o: ../include/openssl/srtp.h ../include/openssl/ssl.h
-t1_meth.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
-t1_meth.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
-t1_meth.o: ../include/openssl/tls1.h ../include/openssl/x509.h
-t1_meth.o: ../include/openssl/x509_vfy.h packet_locl.h record/record.h
-t1_meth.o: ssl_locl.h t1_meth.c
+t1_lib.o: packet_locl.h record/record.h ssl_locl.h statem/statem.h t1_lib.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
@@ -925,27 +862,7 @@ t1_reneg.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 t1_reneg.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 t1_reneg.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 t1_reneg.o: ../include/openssl/x509_vfy.h packet_locl.h record/record.h
-t1_reneg.o: ssl_locl.h 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
-t1_srvr.o: ../include/openssl/dsa.h ../include/openssl/dtls1.h
-t1_srvr.o: ../include/openssl/e_os2.h ../include/openssl/ec.h
-t1_srvr.o: ../include/openssl/ecdh.h ../include/openssl/ecdsa.h
-t1_srvr.o: ../include/openssl/err.h ../include/openssl/evp.h
-t1_srvr.o: ../include/openssl/hmac.h ../include/openssl/lhash.h
-t1_srvr.o: ../include/openssl/obj_mac.h ../include/openssl/objects.h
-t1_srvr.o: ../include/openssl/opensslconf.h ../include/openssl/opensslv.h
-t1_srvr.o: ../include/openssl/ossl_typ.h ../include/openssl/pem.h
-t1_srvr.o: ../include/openssl/pem2.h ../include/openssl/pkcs7.h
-t1_srvr.o: ../include/openssl/pqueue.h ../include/openssl/rand.h
-t1_srvr.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
-t1_srvr.o: ../include/openssl/sha.h ../include/openssl/srtp.h
-t1_srvr.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h
-t1_srvr.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
-t1_srvr.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
-t1_srvr.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
-t1_srvr.o: packet_locl.h record/record.h ssl_locl.h t1_srvr.c
+t1_reneg.o: ssl_locl.h statem/statem.h t1_reneg.c
 t1_trce.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 t1_trce.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 t1_trce.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -965,7 +882,7 @@ t1_trce.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 t1_trce.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 t1_trce.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 t1_trce.o: ../include/openssl/x509_vfy.h packet_locl.h record/record.h
-t1_trce.o: ssl_locl.h t1_trce.c
+t1_trce.o: ssl_locl.h statem/statem.h t1_trce.c
 tls_srp.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 tls_srp.o: ../include/openssl/bn.h ../include/openssl/buffer.h
 tls_srp.o: ../include/openssl/comp.h ../include/openssl/crypto.h
@@ -986,4 +903,4 @@ tls_srp.o: ../include/openssl/ssl2.h ../include/openssl/ssl3.h
 tls_srp.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
 tls_srp.o: ../include/openssl/tls1.h ../include/openssl/x509.h
 tls_srp.o: ../include/openssl/x509_vfy.h packet_locl.h record/record.h
-tls_srp.o: ssl_locl.h tls_srp.c
+tls_srp.o: ssl_locl.h statem/statem.h tls_srp.c
diff --git a/ssl/d1_both.c b/ssl/d1_both.c
deleted file mode 100644 (file)
index e20278b..0000000
+++ /dev/null
@@ -1,1517 +0,0 @@
-/* ssl/d1_both.c */
-/*
- * DTLS implementation written by Nagendra Modadugu
- * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
- */
-/* ====================================================================
- * Copyright (c) 1998-2005 The OpenSSL Project.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- *    software must display the following acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- *    endorse or promote products derived from this software without
- *    prior written permission. For written permission, please contact
- *    openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- *    nor may "OpenSSL" appear in their names without prior written
- *    permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- *    acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com).  This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to.  The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *    "This product includes cryptographic software written by
- *     Eric Young (eay@cryptsoft.com)"
- *    The word 'cryptographic' can be left out if the rouines from the library
- *    being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- *    the apps directory (application code) you must include an acknowledgement:
- *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed.  i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#include <limits.h>
-#include <string.h>
-#include <stdio.h>
-#include "ssl_locl.h"
-#include <openssl/buffer.h>
-#include <openssl/rand.h>
-#include <openssl/objects.h>
-#include <openssl/evp.h>
-#include <openssl/x509.h>
-
-#define RSMBLY_BITMASK_SIZE(msg_len) (((msg_len) + 7) / 8)
-
-#define RSMBLY_BITMASK_MARK(bitmask, start, end) { \
-                        if ((end) - (start) <= 8) { \
-                                long ii; \
-                                for (ii = (start); ii < (end); ii++) bitmask[((ii) >> 3)] |= (1 << ((ii) & 7)); \
-                        } else { \
-                                long ii; \
-                                bitmask[((start) >> 3)] |= bitmask_start_values[((start) & 7)]; \
-                                for (ii = (((start) >> 3) + 1); ii < ((((end) - 1)) >> 3); ii++) bitmask[ii] = 0xff; \
-                                bitmask[(((end) - 1) >> 3)] |= bitmask_end_values[((end) & 7)]; \
-                        } }
-
-#define RSMBLY_BITMASK_IS_COMPLETE(bitmask, msg_len, is_complete) { \
-                        long ii; \
-                        OPENSSL_assert((msg_len) > 0); \
-                        is_complete = 1; \
-                        if (bitmask[(((msg_len) - 1) >> 3)] != bitmask_end_values[((msg_len) & 7)]) is_complete = 0; \
-                        if (is_complete) for (ii = (((msg_len) - 1) >> 3) - 1; ii >= 0 ; ii--) \
-                                if (bitmask[ii] != 0xff) { is_complete = 0; break; } }
-
-static unsigned char bitmask_start_values[] =
-    { 0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80 };
-static unsigned char bitmask_end_values[] =
-    { 0xff, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f };
-
-/* XDTLS:  figure out the right values */
-static const unsigned int g_probable_mtu[] = { 1500, 512, 256 };
-
-static void dtls1_fix_message_header(SSL *s, unsigned long frag_off,
-                                     unsigned long frag_len);
-static unsigned char *dtls1_write_message_header(SSL *s, unsigned char *p);
-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 dtls_get_reassembled_message(SSL *s, long *len);
-
-static hm_fragment *dtls1_hm_fragment_new(unsigned long frag_len,
-                                          int reassembly)
-{
-    hm_fragment *frag = NULL;
-    unsigned char *buf = NULL;
-    unsigned char *bitmask = NULL;
-
-    frag = OPENSSL_malloc(sizeof(*frag));
-    if (frag == NULL)
-        return NULL;
-
-    if (frag_len) {
-        buf = OPENSSL_malloc(frag_len);
-        if (buf == NULL) {
-            OPENSSL_free(frag);
-            return NULL;
-        }
-    }
-
-    /* zero length fragment gets zero frag->fragment */
-    frag->fragment = buf;
-
-    /* Initialize reassembly bitmask if necessary */
-    if (reassembly) {
-        bitmask = OPENSSL_zalloc(RSMBLY_BITMASK_SIZE(frag_len));
-        if (bitmask == NULL) {
-            OPENSSL_free(buf);
-            OPENSSL_free(frag);
-            return NULL;
-        }
-    }
-
-    frag->reassembly = bitmask;
-
-    return frag;
-}
-
-void dtls1_hm_fragment_free(hm_fragment *frag)
-{
-    if (!frag)
-        return;
-    if (frag->msg_header.is_ccs) {
-        EVP_CIPHER_CTX_free(frag->msg_header.
-                            saved_retransmit_state.enc_write_ctx);
-        EVP_MD_CTX_destroy(frag->msg_header.
-                           saved_retransmit_state.write_hash);
-    }
-    OPENSSL_free(frag->fragment);
-    OPENSSL_free(frag->reassembly);
-    OPENSSL_free(frag);
-}
-
-static int dtls1_query_mtu(SSL *s)
-{
-    if (s->d1->link_mtu) {
-        s->d1->mtu =
-            s->d1->link_mtu - BIO_dgram_get_mtu_overhead(SSL_get_wbio(s));
-        s->d1->link_mtu = 0;
-    }
-
-    /* AHA!  Figure out the MTU, and stick to the right size */
-    if (s->d1->mtu < dtls1_min_mtu(s)) {
-        if (!(SSL_get_options(s) & SSL_OP_NO_QUERY_MTU)) {
-            s->d1->mtu =
-                BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
-
-            /*
-             * I've seen the kernel return bogus numbers when it doesn't know
-             * (initial write), so just make sure we have a reasonable number
-             */
-            if (s->d1->mtu < dtls1_min_mtu(s)) {
-                /* Set to min mtu */
-                s->d1->mtu = dtls1_min_mtu(s);
-                BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SET_MTU,
-                         s->d1->mtu, NULL);
-            }
-        } else
-            return 0;
-    }
-    return 1;
-}
-
-/*
- * send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or
- * SSL3_RT_CHANGE_CIPHER_SPEC)
- */
-int dtls1_do_write(SSL *s, int type)
-{
-    int ret;
-    unsigned int curr_mtu;
-    int retry = 1;
-    unsigned int len, frag_off, mac_size, blocksize, used_len;
-
-    if (!dtls1_query_mtu(s))
-        return -1;
-
-    OPENSSL_assert(s->d1->mtu >= dtls1_min_mtu(s)); /* should have something
-                                                     * reasonable now */
-
-    if (s->init_off == 0 && type == SSL3_RT_HANDSHAKE)
-        OPENSSL_assert(s->init_num ==
-                       (int)s->d1->w_msg_hdr.msg_len +
-                       DTLS1_HM_HEADER_LENGTH);
-
-    if (s->write_hash) {
-        if (s->enc_write_ctx
-            && ((EVP_CIPHER_CTX_mode(s->enc_write_ctx) == EVP_CIPH_GCM_MODE) ||
-                (EVP_CIPHER_CTX_mode(s->enc_write_ctx) == EVP_CIPH_CCM_MODE)))
-            mac_size = 0;
-        else
-            mac_size = EVP_MD_CTX_size(s->write_hash);
-    } else
-        mac_size = 0;
-
-    if (s->enc_write_ctx &&
-        (EVP_CIPHER_CTX_mode(s->enc_write_ctx) == EVP_CIPH_CBC_MODE))
-        blocksize = 2 * EVP_CIPHER_block_size(s->enc_write_ctx->cipher);
-    else
-        blocksize = 0;
-
-    frag_off = 0;
-    /* s->init_num shouldn't ever be < 0...but just in case */
-    while (s->init_num > 0) {
-        used_len = BIO_wpending(SSL_get_wbio(s)) + DTLS1_RT_HEADER_LENGTH
-            + mac_size + blocksize;
-        if (s->d1->mtu > used_len)
-            curr_mtu = s->d1->mtu - used_len;
-        else
-            curr_mtu = 0;
-
-        if (curr_mtu <= DTLS1_HM_HEADER_LENGTH) {
-            /*
-             * grr.. we could get an error if MTU picked was wrong
-             */
-            ret = BIO_flush(SSL_get_wbio(s));
-            if (ret <= 0)
-                return ret;
-            used_len = DTLS1_RT_HEADER_LENGTH + mac_size + blocksize;
-            if (s->d1->mtu > used_len + DTLS1_HM_HEADER_LENGTH) {
-                curr_mtu = s->d1->mtu - used_len;
-            } else {
-                /* Shouldn't happen */
-                return -1;
-            }
-        }
-
-        /*
-         * We just checked that s->init_num > 0 so this cast should be safe
-         */
-        if (((unsigned int)s->init_num) > curr_mtu)
-            len = curr_mtu;
-        else
-            len = s->init_num;
-
-        /* Shouldn't ever happen */
-        if (len > INT_MAX)
-            len = INT_MAX;
-
-        /*
-         * XDTLS: this function is too long.  split out the CCS part
-         */
-        if (type == SSL3_RT_HANDSHAKE) {
-            if (s->init_off != 0) {
-                OPENSSL_assert(s->init_off > DTLS1_HM_HEADER_LENGTH);
-                s->init_off -= DTLS1_HM_HEADER_LENGTH;
-                s->init_num += DTLS1_HM_HEADER_LENGTH;
-
-                /*
-                 * We just checked that s->init_num > 0 so this cast should
-                 * be safe
-                 */
-                if (((unsigned int)s->init_num) > curr_mtu)
-                    len = curr_mtu;
-                else
-                    len = s->init_num;
-            }
-
-            /* Shouldn't ever happen */
-            if (len > INT_MAX)
-                len = INT_MAX;
-
-            if (len < DTLS1_HM_HEADER_LENGTH) {
-                /*
-                 * len is so small that we really can't do anything sensible
-                 * so fail
-                 */
-                return -1;
-            }
-            dtls1_fix_message_header(s, frag_off,
-                                     len - DTLS1_HM_HEADER_LENGTH);
-
-            dtls1_write_message_header(s,
-                                       (unsigned char *)&s->init_buf->
-                                       data[s->init_off]);
-        }
-
-        ret = dtls1_write_bytes(s, type, &s->init_buf->data[s->init_off],
-                                len);
-        if (ret < 0) {
-            /*
-             * might need to update MTU here, but we don't know which
-             * previous packet caused the failure -- so can't really
-             * retransmit anything.  continue as if everything is fine and
-             * wait for an alert to handle the retransmit
-             */
-            if (retry && BIO_ctrl(SSL_get_wbio(s),
-                                  BIO_CTRL_DGRAM_MTU_EXCEEDED, 0, NULL) > 0) {
-                if (!(SSL_get_options(s) & SSL_OP_NO_QUERY_MTU)) {
-                    if (!dtls1_query_mtu(s))
-                        return -1;
-                    /* Have one more go */
-                    retry = 0;
-                } else
-                    return -1;
-            } else {
-                return (-1);
-            }
-        } else {
-
-            /*
-             * bad if this assert fails, only part of the handshake message
-             * got sent.  but why would this happen?
-             */
-            OPENSSL_assert(len == (unsigned int)ret);
-
-            if (type == SSL3_RT_HANDSHAKE && !s->d1->retransmitting) {
-                /*
-                 * should not be done for 'Hello Request's, but in that case
-                 * we'll ignore the result anyway
-                 */
-                unsigned char *p =
-                    (unsigned char *)&s->init_buf->data[s->init_off];
-                const struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
-                int xlen;
-
-                if (frag_off == 0 && s->version != DTLS1_BAD_VER) {
-                    /*
-                     * reconstruct message header is if it is being sent in
-                     * single fragment
-                     */
-                    *p++ = msg_hdr->type;
-                    l2n3(msg_hdr->msg_len, p);
-                    s2n(msg_hdr->seq, p);
-                    l2n3(0, p);
-                    l2n3(msg_hdr->msg_len, p);
-                    p -= DTLS1_HM_HEADER_LENGTH;
-                    xlen = ret;
-                } else {
-                    p += DTLS1_HM_HEADER_LENGTH;
-                    xlen = ret - DTLS1_HM_HEADER_LENGTH;
-                }
-
-                ssl3_finish_mac(s, p, xlen);
-            }
-
-            if (ret == s->init_num) {
-                if (s->msg_callback)
-                    s->msg_callback(1, s->version, type, s->init_buf->data,
-                                    (size_t)(s->init_off + s->init_num), s,
-                                    s->msg_callback_arg);
-
-                s->init_off = 0; /* done writing this message */
-                s->init_num = 0;
-
-                return (1);
-            }
-            s->init_off += ret;
-            s->init_num -= ret;
-            frag_off += (ret -= DTLS1_HM_HEADER_LENGTH);
-        }
-    }
-    return (0);
-}
-
-int dtls_get_message(SSL *s, int *mt, unsigned long *len)
-{
-    struct hm_header_st *msg_hdr;
-    unsigned char *p;
-    unsigned long msg_len;
-    int ok;
-    long tmplen;
-
-    msg_hdr = &s->d1->r_msg_hdr;
-    memset(msg_hdr, 0, sizeof(*msg_hdr));
-
- again:
-    ok = dtls_get_reassembled_message(s, &tmplen);
-    if (tmplen == DTLS1_HM_BAD_FRAGMENT
-        || tmplen == DTLS1_HM_FRAGMENT_RETRY) {
-        /* bad fragment received */
-        goto again;
-    } else if (tmplen <= 0 && !ok) {
-        return 0;
-    }
-
-    *mt = s->s3->tmp.message_type;
-
-    p = (unsigned char *)s->init_buf->data;
-
-    if (*mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
-        if (s->msg_callback) {
-            s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC,
-                            p, 1, s, s->msg_callback_arg);
-        }
-        /*
-         * This isn't a real handshake message so skip the processing below.
-         */
-        *len = (unsigned long)tmplen;
-        return 1;
-    }
-
-    msg_len = msg_hdr->msg_len;
-
-    /* reconstruct message header */
-    *(p++) = msg_hdr->type;
-    l2n3(msg_len, p);
-    s2n(msg_hdr->seq, p);
-    l2n3(0, p);
-    l2n3(msg_len, p);
-    if (s->version != DTLS1_BAD_VER) {
-        p -= DTLS1_HM_HEADER_LENGTH;
-        msg_len += DTLS1_HM_HEADER_LENGTH;
-    }
-
-    ssl3_finish_mac(s, p, msg_len);
-    if (s->msg_callback)
-        s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
-                        p, msg_len, s, s->msg_callback_arg);
-
-    memset(msg_hdr, 0, sizeof(*msg_hdr));
-
-    s->d1->handshake_read_seq++;
-
-
-    s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
-    *len = s->init_num;
-
-    return 1;
-}
-
-static int dtls1_preprocess_fragment(SSL *s, struct hm_header_st *msg_hdr)
-{
-    size_t frag_off, frag_len, msg_len;
-
-    msg_len = msg_hdr->msg_len;
-    frag_off = msg_hdr->frag_off;
-    frag_len = msg_hdr->frag_len;
-
-    /* sanity checking */
-    if ((frag_off + frag_len) > msg_len) {
-        SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT, SSL_R_EXCESSIVE_MESSAGE_SIZE);
-        return SSL_AD_ILLEGAL_PARAMETER;
-    }
-
-    if (s->d1->r_msg_hdr.frag_off == 0) { /* first fragment */
-        /*
-         * msg_len is limited to 2^24, but is effectively checked against max
-         * above
-         */
-        if (!BUF_MEM_grow_clean
-            (s->init_buf, msg_len + DTLS1_HM_HEADER_LENGTH)) {
-            SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT, ERR_R_BUF_LIB);
-            return SSL_AD_INTERNAL_ERROR;
-        }
-
-        s->s3->tmp.message_size = msg_len;
-        s->d1->r_msg_hdr.msg_len = msg_len;
-        s->s3->tmp.message_type = msg_hdr->type;
-        s->d1->r_msg_hdr.type = msg_hdr->type;
-        s->d1->r_msg_hdr.seq = msg_hdr->seq;
-    } else if (msg_len != s->d1->r_msg_hdr.msg_len) {
-        /*
-         * They must be playing with us! BTW, failure to enforce upper limit
-         * would open possibility for buffer overrun.
-         */
-        SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT, SSL_R_EXCESSIVE_MESSAGE_SIZE);
-        return SSL_AD_ILLEGAL_PARAMETER;
-    }
-
-    return 0;                   /* no error */
-}
-
-static int dtls1_retrieve_buffered_fragment(SSL *s, int *ok)
-{
-    /*-
-     * (0) check whether the desired fragment is available
-     * if so:
-     * (1) copy over the fragment to s->init_buf->data[]
-     * (2) update s->init_num
-     */
-    pitem *item;
-    hm_fragment *frag;
-    int al;
-
-    *ok = 0;
-    item = pqueue_peek(s->d1->buffered_messages);
-    if (item == NULL)
-        return 0;
-
-    frag = (hm_fragment *)item->data;
-
-    /* Don't return if reassembly still in progress */
-    if (frag->reassembly != NULL)
-        return 0;
-
-    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);
-
-        if (al == 0) {          /* no alert */
-            unsigned char *p =
-                (unsigned char *)s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
-            memcpy(&p[frag->msg_header.frag_off], frag->fragment,
-                   frag->msg_header.frag_len);
-        }
-
-        dtls1_hm_fragment_free(frag);
-        pitem_free(item);
-
-        if (al == 0) {
-            *ok = 1;
-            return frag_len;
-        }
-
-        ssl3_send_alert(s, SSL3_AL_FATAL, al);
-        s->init_num = 0;
-        *ok = 0;
-        return -1;
-    } else
-        return 0;
-}
-
-/*
- * dtls1_max_handshake_message_len returns the maximum number of bytes
- * permitted in a DTLS handshake message for |s|. The minimum is 16KB, but
- * may be greater if the maximum certificate list size requires it.
- */
-static unsigned long dtls1_max_handshake_message_len(const SSL *s)
-{
-    unsigned long max_len =
-        DTLS1_HM_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH;
-    if (max_len < (unsigned long)s->max_cert_list)
-        return s->max_cert_list;
-    return max_len;
-}
-
-static int
-dtls1_reassemble_fragment(SSL *s, const struct hm_header_st *msg_hdr, int *ok)
-{
-    hm_fragment *frag = NULL;
-    pitem *item = NULL;
-    int i = -1, is_complete;
-    unsigned char seq64be[8];
-    unsigned long frag_len = msg_hdr->frag_len;
-
-    if ((msg_hdr->frag_off + frag_len) > msg_hdr->msg_len ||
-        msg_hdr->msg_len > dtls1_max_handshake_message_len(s))
-        goto err;
-
-    if (frag_len == 0)
-        return DTLS1_HM_FRAGMENT_RETRY;
-
-    /* Try to find item in queue */
-    memset(seq64be, 0, sizeof(seq64be));
-    seq64be[6] = (unsigned char)(msg_hdr->seq >> 8);
-    seq64be[7] = (unsigned char)msg_hdr->seq;
-    item = pqueue_find(s->d1->buffered_messages, seq64be);
-
-    if (item == NULL) {
-        frag = dtls1_hm_fragment_new(msg_hdr->msg_len, 1);
-        if (frag == NULL)
-            goto err;
-        memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr));
-        frag->msg_header.frag_len = frag->msg_header.msg_len;
-        frag->msg_header.frag_off = 0;
-    } else {
-        frag = (hm_fragment *)item->data;
-        if (frag->msg_header.msg_len != msg_hdr->msg_len) {
-            item = NULL;
-            frag = NULL;
-            goto err;
-        }
-    }
-
-    /*
-     * If message is already reassembled, this must be a retransmit and can
-     * be dropped. In this case item != NULL and so frag does not need to be
-     * freed.
-     */
-    if (frag->reassembly == NULL) {
-        unsigned char devnull[256];
-
-        while (frag_len) {
-            i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL,
-                                          devnull,
-                                          frag_len >
-                                          sizeof(devnull) ? sizeof(devnull) :
-                                          frag_len, 0);
-            if (i <= 0)
-                goto err;
-            frag_len -= i;
-        }
-        return DTLS1_HM_FRAGMENT_RETRY;
-    }
-
-    /* read the body of the fragment (header has already been read */
-    i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL,
-                                  frag->fragment + msg_hdr->frag_off,
-                                  frag_len, 0);
-    if ((unsigned long)i != frag_len)
-        i = -1;
-    if (i <= 0)
-        goto err;
-
-    RSMBLY_BITMASK_MARK(frag->reassembly, (long)msg_hdr->frag_off,
-                        (long)(msg_hdr->frag_off + frag_len));
-
-    RSMBLY_BITMASK_IS_COMPLETE(frag->reassembly, (long)msg_hdr->msg_len,
-                               is_complete);
-
-    if (is_complete) {
-        OPENSSL_free(frag->reassembly);
-        frag->reassembly = NULL;
-    }
-
-    if (item == NULL) {
-        item = pitem_new(seq64be, frag);
-        if (item == NULL) {
-            i = -1;
-            goto err;
-        }
-
-        item = pqueue_insert(s->d1->buffered_messages, item);
-        /*
-         * pqueue_insert fails iff a duplicate item is inserted. However,
-         * |item| cannot be a duplicate. If it were, |pqueue_find|, above,
-         * would have returned it and control would never have reached this
-         * branch.
-         */
-        OPENSSL_assert(item != NULL);
-    }
-
-    return DTLS1_HM_FRAGMENT_RETRY;
-
- err:
-    if (item == NULL)
-        dtls1_hm_fragment_free(frag);
-    *ok = 0;
-    return i;
-}
-
-static int
-dtls1_process_out_of_seq_message(SSL *s, const struct hm_header_st *msg_hdr,
-                                 int *ok)
-{
-    int i = -1;
-    hm_fragment *frag = NULL;
-    pitem *item = NULL;
-    unsigned char seq64be[8];
-    unsigned long frag_len = msg_hdr->frag_len;
-
-    if ((msg_hdr->frag_off + frag_len) > msg_hdr->msg_len)
-        goto err;
-
-    /* Try to find item in queue, to prevent duplicate entries */
-    memset(seq64be, 0, sizeof(seq64be));
-    seq64be[6] = (unsigned char)(msg_hdr->seq >> 8);
-    seq64be[7] = (unsigned char)msg_hdr->seq;
-    item = pqueue_find(s->d1->buffered_messages, seq64be);
-
-    /*
-     * If we already have an entry and this one is a fragment, don't discard
-     * it and rather try to reassemble it.
-     */
-    if (item != NULL && frag_len != msg_hdr->msg_len)
-        item = NULL;
-
-    /*
-     * 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];
-
-        while (frag_len) {
-            i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL,
-                                          devnull,
-                                          frag_len >
-                                          sizeof(devnull) ? sizeof(devnull) :
-                                          frag_len, 0);
-            if (i <= 0)
-                goto err;
-            frag_len -= i;
-        }
-    } else {
-        if (frag_len != msg_hdr->msg_len)
-            return dtls1_reassemble_fragment(s, msg_hdr, ok);
-
-        if (frag_len > dtls1_max_handshake_message_len(s))
-            goto err;
-
-        frag = dtls1_hm_fragment_new(frag_len, 0);
-        if (frag == NULL)
-            goto err;
-
-        memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr));
-
-        if (frag_len) {
-            /*
-             * read the body of the fragment (header has already been read
-             */
-            i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL,
-                                          frag->fragment, frag_len, 0);
-            if ((unsigned long)i != frag_len)
-                i = -1;
-            if (i <= 0)
-                goto err;
-        }
-
-        item = pitem_new(seq64be, frag);
-        if (item == NULL)
-            goto err;
-
-        item = pqueue_insert(s->d1->buffered_messages, item);
-        /*
-         * pqueue_insert fails iff a duplicate item is inserted. However,
-         * |item| cannot be a duplicate. If it were, |pqueue_find|, above,
-         * would have returned it. Then, either |frag_len| !=
-         * |msg_hdr->msg_len| in which case |item| is set to NULL and it will
-         * have been processed with |dtls1_reassemble_fragment|, above, or
-         * the record will have been discarded.
-         */
-        OPENSSL_assert(item != NULL);
-    }
-
-    return DTLS1_HM_FRAGMENT_RETRY;
-
- err:
-    if (item == NULL)
-        dtls1_hm_fragment_free(frag);
-    *ok = 0;
-    return i;
-}
-
-static int dtls_get_reassembled_message(SSL *s, long *len)
-{
-    unsigned char wire[DTLS1_HM_HEADER_LENGTH];
-    unsigned long mlen, frag_off, frag_len;
-    int i, al, recvd_type;
-    struct hm_header_st msg_hdr;
-    int ok;
-
- redo:
-    /* see if we have the required fragment already */
-    if ((frag_len = dtls1_retrieve_buffered_fragment(s, &ok)) || ok) {
-        if (ok)
-            s->init_num = frag_len;
-        *len = frag_len;
-        return ok;
-    }
-
-    /* read handshake message header */
-    i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, &recvd_type, wire,
-                                  DTLS1_HM_HEADER_LENGTH, 0);
-    if (i <= 0) {               /* nbio, or an error */
-        s->rwstate = SSL_READING;
-        *len = i;
-        return 0;
-    }
-    if(recvd_type == SSL3_RT_CHANGE_CIPHER_SPEC) {
-        if (wire[0] != SSL3_MT_CCS) {
-            al = SSL_AD_UNEXPECTED_MESSAGE;
-            SSLerr(SSL_F_DTLS_GET_REASSEMBLED_MESSAGE,
-                   SSL_R_BAD_CHANGE_CIPHER_SPEC);
-            goto f_err;
-        }
-
-        memcpy(s->init_buf->data, wire, i);
-        s->init_num = i - 1;
-        s->init_msg = s->init_buf->data + 1;
-        s->s3->tmp.message_type = SSL3_MT_CHANGE_CIPHER_SPEC;
-        s->s3->tmp.message_size = i - 1;
-        *len = i - 1;
-        return 1;
-    }
-
-    /* Handshake fails if message header is incomplete */
-    if (i != DTLS1_HM_HEADER_LENGTH) {
-        al = SSL_AD_UNEXPECTED_MESSAGE;
-        SSLerr(SSL_F_DTLS_GET_REASSEMBLED_MESSAGE, SSL_R_UNEXPECTED_MESSAGE);
-        goto f_err;
-    }
-
-    /* parse the message fragment header */
-    dtls1_get_message_header(wire, &msg_hdr);
-
-    mlen = msg_hdr.msg_len;
-    frag_off = msg_hdr.frag_off;
-    frag_len = msg_hdr.frag_len;
-
-    /*
-     * We must have at least frag_len bytes left in the record to be read.
-     * Fragments must not span records.
-     */
-    if (frag_len > RECORD_LAYER_get_rrec_length(&s->rlayer)) {
-        al = SSL3_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_DTLS_GET_REASSEMBLED_MESSAGE, SSL_R_BAD_LENGTH);
-        goto f_err;
-    }
-
-    /*
-     * if this is a future (or stale) message it gets buffered
-     * (or dropped)--no further processing at this time
-     * While listening, we accept seq 1 (ClientHello with cookie)
-     * although we're still expecting seq 0 (ClientHello)
-     */
-    if (msg_hdr.seq != s->d1->handshake_read_seq) {
-        *len = dtls1_process_out_of_seq_message(s, &msg_hdr, &ok);
-        return ok;
-    }
-
-    if (frag_len && frag_len < mlen) {
-        *len = dtls1_reassemble_fragment(s, &msg_hdr, &ok);
-        return ok;
-    }
-
-    if (!s->server && s->d1->r_msg_hdr.frag_off == 0 &&
-        wire[0] == SSL3_MT_HELLO_REQUEST) {
-        /*
-         * The server may always send 'Hello Request' messages -- we are
-         * doing a handshake anyway now, so ignore them if their format is
-         * correct. Does not count for 'Finished' MAC.
-         */
-        if (wire[1] == 0 && wire[2] == 0 && wire[3] == 0) {
-            if (s->msg_callback)
-                s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
-                                wire, DTLS1_HM_HEADER_LENGTH, s,
-                                s->msg_callback_arg);
-
-            s->init_num = 0;
-            goto redo;
-        } else {                /* Incorrectly formated Hello request */
-
-            al = SSL_AD_UNEXPECTED_MESSAGE;
-            SSLerr(SSL_F_DTLS_GET_REASSEMBLED_MESSAGE,
-                   SSL_R_UNEXPECTED_MESSAGE);
-            goto f_err;
-        }
-    }
-
-    if ((al = dtls1_preprocess_fragment(s, &msg_hdr)))
-        goto f_err;
-
-    if (frag_len > 0) {
-        unsigned char *p =
-            (unsigned char *)s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
-
-        i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL,
-                                      &p[frag_off], frag_len, 0);
-
-        /*
-         * This shouldn't ever fail due to NBIO because we already checked
-         * that we have enough data in the record
-         */
-        if (i <= 0) {
-            s->rwstate = SSL_READING;
-            *len = i;
-            return 0;
-        }
-    } else
-        i = 0;
-
-    /*
-     * XDTLS: an incorrectly formatted fragment should cause the handshake
-     * to fail
-     */
-    if (i != (int)frag_len) {
-        al = SSL3_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_DTLS_GET_REASSEMBLED_MESSAGE, SSL3_AD_ILLEGAL_PARAMETER);
-        goto f_err;
-    }
-
-    /*
-     * Note that s->init_num is *not* used as current offset in
-     * s->init_buf->data, but as a counter summing up fragments' lengths: as
-     * soon as they sum up to handshake packet length, we assume we have got
-     * all the fragments.
-     */
-    *len = s->init_num = frag_len;
-    return 1;
-
- f_err:
-    ssl3_send_alert(s, SSL3_AL_FATAL, al);
-    s->init_num = 0;
-    *len = -1;
-    return 0;
-}
-
-/*-
- * for these 2 messages, we need to
- * ssl->enc_read_ctx                    re-init
- * ssl->rlayer.read_sequence            zero
- * ssl->s3->read_mac_secret             re-init
- * ssl->session->read_sym_enc           assign
- * ssl->session->read_compression       assign
- * ssl->session->read_hash              assign
- */
-int dtls_construct_change_cipher_spec(SSL *s)
-{
-    unsigned char *p;
-
-    p = (unsigned char *)s->init_buf->data;
-    *p++ = SSL3_MT_CCS;
-    s->d1->handshake_write_seq = s->d1->next_handshake_write_seq;
-    s->init_num = DTLS1_CCS_HEADER_LENGTH;
-
-    if (s->version == DTLS1_BAD_VER) {
-        s->d1->next_handshake_write_seq++;
-        s2n(s->d1->handshake_write_seq, p);
-        s->init_num += 2;
-    }
-
-    s->init_off = 0;
-
-    dtls1_set_message_header_int(s, SSL3_MT_CCS, 0,
-                                 s->d1->handshake_write_seq, 0, 0);
-
-    /* buffer the message to handle re-xmits */
-    if (!dtls1_buffer_message(s, 1)) {
-        SSLerr(SSL_F_DTLS_CONSTRUCT_CHANGE_CIPHER_SPEC, ERR_R_INTERNAL_ERROR);
-        return 0;
-    }
-
-    return 1;
-}
-
-#ifndef OPENSSL_NO_SCTP
-enum WORK_STATE dtls_wait_for_dry(SSL *s)
-{
-    int ret;
-
-    /* read app data until dry event */
-    ret = BIO_dgram_sctp_wait_for_dry(SSL_get_wbio(s));
-    if (ret < 0)
-        return WORK_ERROR;
-
-    if (ret == 0) {
-        s->s3->in_read_app_data = 2;
-        s->rwstate = SSL_READING;
-        BIO_clear_retry_flags(SSL_get_rbio(s));
-        BIO_set_retry_read(SSL_get_rbio(s));
-        return WORK_MORE_A;
-    }
-    return WORK_FINISHED_CONTINUE;
-}
-#endif
-
-int dtls1_read_failed(SSL *s, int code)
-{
-    if (code > 0) {
-        fprintf(stderr, "invalid state reached %s:%d", __FILE__, __LINE__);
-        return 1;
-    }
-
-    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
-         */
-        return code;
-    }
-#ifndef OPENSSL_NO_HEARTBEATS
-    /* done, no need to send a retransmit */
-    if (!SSL_in_init(s) && !s->tlsext_hb_pending)
-#else
-    /* done, no need to send a retransmit */
-    if (!SSL_in_init(s))
-#endif
-    {
-        BIO_set_flags(SSL_get_rbio(s), BIO_FLAGS_READ);
-        return code;
-    }
-
-    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;
-}
-
-int dtls1_retransmit_buffered_messages(SSL *s)
-{
-    pqueue sent = s->d1->sent_messages;
-    piterator iter;
-    pitem *item;
-    hm_fragment *frag;
-    int found = 0;
-
-    iter = pqueue_iterator(sent);
-
-    for (item = pqueue_next(&iter); item != NULL; item = pqueue_next(&iter)) {
-        frag = (hm_fragment *)item->data;
-        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;
-        }
-    }
-
-    return 1;
-}
-
-int dtls1_buffer_message(SSL *s, int is_ccs)
-{
-    pitem *item;
-    hm_fragment *frag;
-    unsigned char seq64be[8];
-
-    /*
-     * this function is called immediately after a message has been
-     * serialized
-     */
-    OPENSSL_assert(s->init_off == 0);
-
-    frag = dtls1_hm_fragment_new(s->init_num, 0);
-    if (!frag)
-        return 0;
-
-    memcpy(frag->fragment, s->init_buf->data, s->init_num);
-
-    if (is_ccs) {
-        /* For DTLS1_BAD_VER the header length is non-standard */
-        OPENSSL_assert(s->d1->w_msg_hdr.msg_len +
-                       ((s->version==DTLS1_BAD_VER)?3:DTLS1_CCS_HEADER_LENGTH)
-                       == (unsigned int)s->init_num);
-    } else {
-        OPENSSL_assert(s->d1->w_msg_hdr.msg_len +
-                       DTLS1_HM_HEADER_LENGTH == (unsigned int)s->init_num);
-    }
-
-    frag->msg_header.msg_len = s->d1->w_msg_hdr.msg_len;
-    frag->msg_header.seq = s->d1->w_msg_hdr.seq;
-    frag->msg_header.type = s->d1->w_msg_hdr.type;
-    frag->msg_header.frag_off = 0;
-    frag->msg_header.frag_len = s->d1->w_msg_hdr.msg_len;
-    frag->msg_header.is_ccs = is_ccs;
-
-    /* save current state */
-    frag->msg_header.saved_retransmit_state.enc_write_ctx = s->enc_write_ctx;
-    frag->msg_header.saved_retransmit_state.write_hash = s->write_hash;
-    frag->msg_header.saved_retransmit_state.compress = s->compress;
-    frag->msg_header.saved_retransmit_state.session = s->session;
-    frag->msg_header.saved_retransmit_state.epoch =
-        DTLS_RECORD_LAYER_get_w_epoch(&s->rlayer);
-
-    memset(seq64be, 0, sizeof(seq64be));
-    seq64be[6] =
-        (unsigned
-         char)(dtls1_get_queue_priority(frag->msg_header.seq,
-                                        frag->msg_header.is_ccs) >> 8);
-    seq64be[7] =
-        (unsigned
-         char)(dtls1_get_queue_priority(frag->msg_header.seq,
-                                        frag->msg_header.is_ccs));
-
-    item = pitem_new(seq64be, frag);
-    if (item == NULL) {
-        dtls1_hm_fragment_free(frag);
-        return 0;
-    }
-
-    pqueue_insert(s->d1->sent_messages, item);
-    return 1;
-}
-
-int
-dtls1_retransmit_message(SSL *s, unsigned short seq, unsigned long frag_off,
-                         int *found)
-{
-    int ret;
-    /* XDTLS: for now assuming that read/writes are blocking */
-    pitem *item;
-    hm_fragment *frag;
-    unsigned long header_length;
-    unsigned char seq64be[8];
-    struct dtls1_retransmit_state saved_state;
-
-    /*-
-      OPENSSL_assert(s->init_num == 0);
-      OPENSSL_assert(s->init_off == 0);
-     */
-
-    /* XDTLS:  the requested message ought to be found, otherwise error */
-    memset(seq64be, 0, sizeof(seq64be));
-    seq64be[6] = (unsigned char)(seq >> 8);
-    seq64be[7] = (unsigned char)seq;
-
-    item = pqueue_find(s->d1->sent_messages, seq64be);
-    if (item == NULL) {
-        fprintf(stderr, "retransmit:  message %d non-existant\n", seq);
-        *found = 0;
-        return 0;
-    }
-
-    *found = 1;
-    frag = (hm_fragment *)item->data;
-
-    if (frag->msg_header.is_ccs)
-        header_length = DTLS1_CCS_HEADER_LENGTH;
-    else
-        header_length = DTLS1_HM_HEADER_LENGTH;
-
-    memcpy(s->init_buf->data, frag->fragment,
-           frag->msg_header.msg_len + header_length);
-    s->init_num = frag->msg_header.msg_len + header_length;
-
-    dtls1_set_message_header_int(s, frag->msg_header.type,
-                                 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 = DTLS_RECORD_LAYER_get_w_epoch(&s->rlayer);
-
-    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;
-    DTLS_RECORD_LAYER_set_saved_w_epoch(&s->rlayer,
-        frag->msg_header.saved_retransmit_state.epoch);
-
-    ret = dtls1_do_write(s, frag->msg_header.is_ccs ?
-                         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;
-    DTLS_RECORD_LAYER_set_saved_w_epoch(&s->rlayer, saved_state.epoch);
-
-    s->d1->retransmitting = 0;
-
-    (void)BIO_flush(SSL_get_wbio(s));
-    return ret;
-}
-
-/* call this function when the buffered messages are no longer needed */
-void dtls1_clear_record_buffer(SSL *s)
-{
-    pitem *item;
-
-    for (item = pqueue_pop(s->d1->sent_messages);
-         item != NULL; item = pqueue_pop(s->d1->sent_messages)) {
-        dtls1_hm_fragment_free((hm_fragment *)item->data);
-        pitem_free(item);
-    }
-}
-
-void dtls1_set_message_header(SSL *s, unsigned char *p,
-                                        unsigned char mt, unsigned long len,
-                                        unsigned long frag_off,
-                                        unsigned long frag_len)
-{
-    if (frag_off == 0) {
-        s->d1->handshake_write_seq = s->d1->next_handshake_write_seq;
-        s->d1->next_handshake_write_seq++;
-    }
-
-    dtls1_set_message_header_int(s, mt, len, s->d1->handshake_write_seq,
-                                 frag_off, frag_len);
-}
-
-/* don't actually do the writing, wait till the MTU has been retrieved */
-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)
-{
-    struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
-
-    msg_hdr->type = mt;
-    msg_hdr->msg_len = len;
-    msg_hdr->seq = seq_num;
-    msg_hdr->frag_off = frag_off;
-    msg_hdr->frag_len = frag_len;
-}
-
-static void
-dtls1_fix_message_header(SSL *s, unsigned long frag_off,
-                         unsigned long frag_len)
-{
-    struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
-
-    msg_hdr->frag_off = frag_off;
-    msg_hdr->frag_len = frag_len;
-}
-
-static unsigned char *dtls1_write_message_header(SSL *s, unsigned char *p)
-{
-    struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
-
-    *p++ = msg_hdr->type;
-    l2n3(msg_hdr->msg_len, p);
-
-    s2n(msg_hdr->seq, p);
-    l2n3(msg_hdr->frag_off, p);
-    l2n3(msg_hdr->frag_len, p);
-
-    return p;
-}
-
-unsigned int dtls1_link_min_mtu(void)
-{
-    return (g_probable_mtu[(sizeof(g_probable_mtu) /
-                            sizeof(g_probable_mtu[0])) - 1]);
-}
-
-unsigned int dtls1_min_mtu(SSL *s)
-{
-    return dtls1_link_min_mtu() - BIO_dgram_get_mtu_overhead(SSL_get_wbio(s));
-}
-
-void
-dtls1_get_message_header(unsigned char *data, struct hm_header_st *msg_hdr)
-{
-    memset(msg_hdr, 0, sizeof(*msg_hdr));
-    msg_hdr->type = *(data++);
-    n2l3(data, msg_hdr->msg_len);
-
-    n2s(data, msg_hdr->seq);
-    n2l3(data, msg_hdr->frag_off);
-    n2l3(data, msg_hdr->frag_len);
-}
-
-int dtls1_shutdown(SSL *s)
-{
-    int ret;
-#ifndef OPENSSL_NO_SCTP
-    BIO *wbio;
-
-    wbio = SSL_get_wbio(s);
-    if (wbio != NULL && BIO_dgram_is_sctp(wbio) &&
-        !(s->shutdown & SSL_SENT_SHUTDOWN)) {
-        ret = BIO_dgram_sctp_wait_for_dry(wbio);
-        if (ret < 0)
-            return -1;
-
-        if (ret == 0)
-            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN, 1,
-                     NULL);
-    }
-#endif
-    ret = ssl3_shutdown(s);
-#ifndef OPENSSL_NO_SCTP
-    BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN, 0, NULL);
-#endif
-    return ret;
-}
-
-#ifndef OPENSSL_NO_HEARTBEATS
-int dtls1_process_heartbeat(SSL *s, unsigned char *p, unsigned int length)
-{
-    unsigned char *pl;
-    unsigned short hbtype;
-    unsigned int payload;
-    unsigned int padding = 16;  /* Use minimum padding */
-
-    if (s->msg_callback)
-        s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT,
-                        p, length, s, s->msg_callback_arg);
-
-    /* Read type and payload length first */
-    if (1 + 2 + 16 > length)
-        return 0;               /* silently discard */
-    if (length > SSL3_RT_MAX_PLAIN_LENGTH)
-        return 0;               /* silently discard per RFC 6520 sec. 4 */
-
-    hbtype = *p++;
-    n2s(p, payload);
-    if (1 + 2 + payload + 16 > length)
-        return 0;               /* silently discard per RFC 6520 sec. 4 */
-    pl = p;
-
-    if (hbtype == TLS1_HB_REQUEST) {
-        unsigned char *buffer, *bp;
-        unsigned int write_length = 1 /* heartbeat type */  +
-            2 /* heartbeat length */  +
-            payload + padding;
-        int r;
-
-        if (write_length > SSL3_RT_MAX_PLAIN_LENGTH)
-            return 0;
-
-        /*
-         * Allocate memory for the response, size is 1 byte message type,
-         * plus 2 bytes payload length, plus payload, plus padding
-         */
-        buffer = OPENSSL_malloc(write_length);
-        if (buffer == NULL)
-            return -1;
-        bp = buffer;
-
-        /* Enter response type, length and copy payload */
-        *bp++ = TLS1_HB_RESPONSE;
-        s2n(payload, bp);
-        memcpy(bp, pl, payload);
-        bp += payload;
-        /* Random padding */
-        if (RAND_bytes(bp, padding) <= 0) {
-            OPENSSL_free(buffer);
-            return -1;
-        }
-
-        r = dtls1_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, write_length);
-
-        if (r >= 0 && s->msg_callback)
-            s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT,
-                            buffer, write_length, s, s->msg_callback_arg);
-
-        OPENSSL_free(buffer);
-
-        if (r < 0)
-            return r;
-    } else if (hbtype == TLS1_HB_RESPONSE) {
-        unsigned int seq;
-
-        /*
-         * We only send sequence numbers (2 bytes unsigned int), and 16
-         * random bytes, so we just try to read the sequence number
-         */
-        n2s(pl, seq);
-
-        if (payload == 18 && seq == s->tlsext_hb_seq) {
-            dtls1_stop_timer(s);
-            s->tlsext_hb_seq++;
-            s->tlsext_hb_pending = 0;
-        }
-    }
-
-    return 0;
-}
-
-int dtls1_heartbeat(SSL *s)
-{
-    unsigned char *buf, *p;
-    int ret = -1;
-    unsigned int payload = 18;  /* Sequence number + random bytes */
-    unsigned int padding = 16;  /* Use minimum padding */
-
-    /* Only send if peer supports and accepts HB requests... */
-    if (!(s->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED) ||
-        s->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_SEND_REQUESTS) {
-        SSLerr(SSL_F_DTLS1_HEARTBEAT, SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT);
-        return -1;
-    }
-
-    /* ...and there is none in flight yet... */
-    if (s->tlsext_hb_pending) {
-        SSLerr(SSL_F_DTLS1_HEARTBEAT, SSL_R_TLS_HEARTBEAT_PENDING);
-        return -1;
-    }
-
-    /* ...and no handshake in progress. */
-    if (SSL_in_init(s) || s->in_handshake) {
-        SSLerr(SSL_F_DTLS1_HEARTBEAT, SSL_R_UNEXPECTED_MESSAGE);
-        return -1;
-    }
-
-    /*
-     * Check if padding is too long, payload and padding must not exceed 2^14
-     * - 3 = 16381 bytes in total.
-     */
-    OPENSSL_assert(payload + padding <= 16381);
-
-    /*-
-     * Create HeartBeat message, we just use a sequence number
-     * as payload to distuingish different messages and add
-     * some random stuff.
-     *  - Message Type, 1 byte
-     *  - Payload Length, 2 bytes (unsigned int)
-     *  - Payload, the sequence number (2 bytes uint)
-     *  - Payload, random bytes (16 bytes uint)
-     *  - Padding
-     */
-    buf = OPENSSL_malloc(1 + 2 + payload + padding);
-    if (buf == NULL) {
-        SSLerr(SSL_F_DTLS1_HEARTBEAT, ERR_R_MALLOC_FAILURE);
-        return -1;
-    }
-    p = buf;
-    /* Message Type */
-    *p++ = TLS1_HB_REQUEST;
-    /* Payload length (18 bytes here) */
-    s2n(payload, p);
-    /* Sequence number */
-    s2n(s->tlsext_hb_seq, p);
-    /* 16 random bytes */
-    if (RAND_bytes(p, 16) <= 0) {
-        SSLerr(SSL_F_DTLS1_HEARTBEAT, ERR_R_INTERNAL_ERROR);
-        goto err;
-    }
-    p += 16;
-    /* Random padding */
-    if (RAND_bytes(p, padding) <= 0) {
-        SSLerr(SSL_F_DTLS1_HEARTBEAT, ERR_R_INTERNAL_ERROR);
-        goto err;
-    }
-
-    ret = dtls1_write_bytes(s, TLS1_RT_HEARTBEAT, buf, 3 + payload + padding);
-    if (ret >= 0) {
-        if (s->msg_callback)
-            s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT,
-                            buf, 3 + payload + padding,
-                            s, s->msg_callback_arg);
-
-        dtls1_start_timer(s);
-        s->tlsext_hb_pending = 1;
-    }
-
- err:
-    OPENSSL_free(buf);
-
-    return ret;
-}
-#endif
diff --git a/ssl/d1_clnt.c b/ssl/d1_clnt.c
deleted file mode 100644 (file)
index d26e39c..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-/* ssl/d1_clnt.c */
-/*
- * DTLS implementation written by Nagendra Modadugu
- * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
- */
-/* ====================================================================
- * Copyright (c) 1999-2007 The OpenSSL Project.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- *    software must display the following acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- *    endorse or promote products derived from this software without
- *    prior written permission. For written permission, please contact
- *    openssl-core@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- *    nor may "OpenSSL" appear in their names without prior written
- *    permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- *    acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com).  This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to.  The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *    "This product includes cryptographic software written by
- *     Eric Young (eay@cryptsoft.com)"
- *    The word 'cryptographic' can be left out if the rouines from the library
- *    being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- *    the apps directory (application code) you must include an acknowledgement:
- *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed.  i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#include <stdio.h>
-#include "ssl_locl.h"
-#include <openssl/buffer.h>
-#include <openssl/rand.h>
-#include <openssl/objects.h>
-#include <openssl/evp.h>
-#include <openssl/md5.h>
-#include <openssl/bn.h>
-#ifndef OPENSSL_NO_DH
-# include <openssl/dh.h>
-#endif
-
-static const SSL_METHOD *dtls1_get_client_method(int ver);
-
-static const SSL_METHOD *dtls1_get_client_method(int ver)
-{
-    if (ver == DTLS1_VERSION || ver == DTLS1_BAD_VER)
-        return (DTLSv1_client_method());
-    else if (ver == DTLS1_2_VERSION)
-        return (DTLSv1_2_client_method());
-    else
-        return (NULL);
-}
-
-IMPLEMENT_dtls1_meth_func(DTLS1_VERSION,
-                          DTLSv1_client_method,
-                          ssl_undefined_function,
-                          dtls1_connect,
-                          dtls1_get_client_method, DTLSv1_enc_data)
-
-    IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION,
-                          DTLSv1_2_client_method,
-                          ssl_undefined_function,
-                          dtls1_connect,
-                          dtls1_get_client_method, DTLSv1_2_enc_data)
-
-    IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION,
-                          DTLS_client_method,
-                          ssl_undefined_function,
-                          dtls1_connect,
-                          dtls1_get_client_method, DTLSv1_2_enc_data)
-
-
-enum MSG_PROCESS_RETURN dtls_process_hello_verify(SSL *s, PACKET *pkt)
-{
-    int al;
-    unsigned int cookie_len;
-    PACKET cookiepkt;
-
-    if (!PACKET_forward(pkt, 2)
-            || !PACKET_get_length_prefixed_1(pkt, &cookiepkt)) {
-        al = SSL_AD_DECODE_ERROR;
-        SSLerr(SSL_F_DTLS_PROCESS_HELLO_VERIFY, SSL_R_LENGTH_MISMATCH);
-        goto f_err;
-    }
-
-    cookie_len = PACKET_remaining(&cookiepkt);
-    if (cookie_len > sizeof(s->d1->cookie)) {
-        al = SSL_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_DTLS_PROCESS_HELLO_VERIFY, SSL_R_LENGTH_TOO_LONG);
-        goto f_err;
-    }
-
-    if (!PACKET_copy_bytes(&cookiepkt, s->d1->cookie, cookie_len)) {
-        al = SSL_AD_DECODE_ERROR;
-        SSLerr(SSL_F_DTLS_PROCESS_HELLO_VERIFY, SSL_R_LENGTH_MISMATCH);
-        goto f_err;
-    }
-    s->d1->cookie_len = cookie_len;
-
-    return MSG_PROCESS_FINISHED_READING;
- f_err:
-    ssl3_send_alert(s, SSL3_AL_FATAL, al);
-    statem_set_error(s);
-    return MSG_PROCESS_ERROR;
-}
index 3bc9fe73626c0f8585eabf609fd4539debc3c187..2f9609affbf7bdcfc9b1b6fe1046ed00b6dc6a9b 100644 (file)
@@ -60,6 +60,7 @@
 #include <stdio.h>
 #define USE_SOCKETS
 #include <openssl/objects.h>
+#include <openssl/rand.h>
 #include "ssl_locl.h"
 
 #if defined(OPENSSL_SYS_VMS)
@@ -77,6 +78,9 @@ static int dtls1_set_handshake_header(SSL *s, int type, unsigned long len);
 static int dtls1_handshake_write(SSL *s);
 int dtls1_listen(SSL *s, struct sockaddr *client);
 
+/* XDTLS:  figure out the right values */
+static const unsigned int g_probable_mtu[] = { 1500, 512, 256 };
+
 const SSL3_ENC_METHOD DTLSv1_enc_data = {
     tls1_enc,
     tls1_mac,
@@ -762,8 +766,8 @@ int dtls1_listen(SSL *s, struct sockaddr *client)
             }
 
             p = &buf[DTLS1_RT_HEADER_LENGTH];
-            msglen = dtls1_raw_hello_verify_request(p + DTLS1_HM_HEADER_LENGTH,
-                                                    cookie, cookielen);
+            msglen = dtls_raw_hello_verify_request(p + DTLS1_HM_HEADER_LENGTH,
+                                                   cookie, cookielen);
 
             *p++ = DTLS1_MT_HELLO_VERIFY_REQUEST;
 
@@ -905,3 +909,236 @@ static int dtls1_handshake_write(SSL *s)
 {
     return dtls1_do_write(s, SSL3_RT_HANDSHAKE);
 }
+
+#ifndef OPENSSL_NO_HEARTBEATS
+int dtls1_process_heartbeat(SSL *s, unsigned char *p, unsigned int length)
+{
+    unsigned char *pl;
+    unsigned short hbtype;
+    unsigned int payload;
+    unsigned int padding = 16;  /* Use minimum padding */
+
+    if (s->msg_callback)
+        s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT,
+                        p, length, s, s->msg_callback_arg);
+
+    /* Read type and payload length first */
+    if (1 + 2 + 16 > length)
+        return 0;               /* silently discard */
+    if (length > SSL3_RT_MAX_PLAIN_LENGTH)
+        return 0;               /* silently discard per RFC 6520 sec. 4 */
+
+    hbtype = *p++;
+    n2s(p, payload);
+    if (1 + 2 + payload + 16 > length)
+        return 0;               /* silently discard per RFC 6520 sec. 4 */
+    pl = p;
+
+    if (hbtype == TLS1_HB_REQUEST) {
+        unsigned char *buffer, *bp;
+        unsigned int write_length = 1 /* heartbeat type */  +
+            2 /* heartbeat length */  +
+            payload + padding;
+        int r;
+
+        if (write_length > SSL3_RT_MAX_PLAIN_LENGTH)
+            return 0;
+
+        /*
+         * Allocate memory for the response, size is 1 byte message type,
+         * plus 2 bytes payload length, plus payload, plus padding
+         */
+        buffer = OPENSSL_malloc(write_length);
+        if (buffer == NULL)
+            return -1;
+        bp = buffer;
+
+        /* Enter response type, length and copy payload */
+        *bp++ = TLS1_HB_RESPONSE;
+        s2n(payload, bp);
+        memcpy(bp, pl, payload);
+        bp += payload;
+        /* Random padding */
+        if (RAND_bytes(bp, padding) <= 0) {
+            OPENSSL_free(buffer);
+            return -1;
+        }
+
+        r = dtls1_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, write_length);
+
+        if (r >= 0 && s->msg_callback)
+            s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT,
+                            buffer, write_length, s, s->msg_callback_arg);
+
+        OPENSSL_free(buffer);
+
+        if (r < 0)
+            return r;
+    } else if (hbtype == TLS1_HB_RESPONSE) {
+        unsigned int seq;
+
+        /*
+         * We only send sequence numbers (2 bytes unsigned int), and 16
+         * random bytes, so we just try to read the sequence number
+         */
+        n2s(pl, seq);
+
+        if (payload == 18 && seq == s->tlsext_hb_seq) {
+            dtls1_stop_timer(s);
+            s->tlsext_hb_seq++;
+            s->tlsext_hb_pending = 0;
+        }
+    }
+
+    return 0;
+}
+
+int dtls1_heartbeat(SSL *s)
+{
+    unsigned char *buf, *p;
+    int ret = -1;
+    unsigned int payload = 18;  /* Sequence number + random bytes */
+    unsigned int padding = 16;  /* Use minimum padding */
+
+    /* Only send if peer supports and accepts HB requests... */
+    if (!(s->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED) ||
+        s->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_SEND_REQUESTS) {
+        SSLerr(SSL_F_DTLS1_HEARTBEAT, SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT);
+        return -1;
+    }
+
+    /* ...and there is none in flight yet... */
+    if (s->tlsext_hb_pending) {
+        SSLerr(SSL_F_DTLS1_HEARTBEAT, SSL_R_TLS_HEARTBEAT_PENDING);
+        return -1;
+    }
+
+    /* ...and no handshake in progress. */
+    if (SSL_in_init(s) || s->in_handshake) {
+        SSLerr(SSL_F_DTLS1_HEARTBEAT, SSL_R_UNEXPECTED_MESSAGE);
+        return -1;
+    }
+
+    /*
+     * Check if padding is too long, payload and padding must not exceed 2^14
+     * - 3 = 16381 bytes in total.
+     */
+    OPENSSL_assert(payload + padding <= 16381);
+
+    /*-
+     * Create HeartBeat message, we just use a sequence number
+     * as payload to distuingish different messages and add
+     * some random stuff.
+     *  - Message Type, 1 byte
+     *  - Payload Length, 2 bytes (unsigned int)
+     *  - Payload, the sequence number (2 bytes uint)
+     *  - Payload, random bytes (16 bytes uint)
+     *  - Padding
+     */
+    buf = OPENSSL_malloc(1 + 2 + payload + padding);
+    if (buf == NULL) {
+        SSLerr(SSL_F_DTLS1_HEARTBEAT, ERR_R_MALLOC_FAILURE);
+        return -1;
+    }
+    p = buf;
+    /* Message Type */
+    *p++ = TLS1_HB_REQUEST;
+    /* Payload length (18 bytes here) */
+    s2n(payload, p);
+    /* Sequence number */
+    s2n(s->tlsext_hb_seq, p);
+    /* 16 random bytes */
+    if (RAND_bytes(p, 16) <= 0) {
+        SSLerr(SSL_F_DTLS1_HEARTBEAT, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+    p += 16;
+    /* Random padding */
+    if (RAND_bytes(p, padding) <= 0) {
+        SSLerr(SSL_F_DTLS1_HEARTBEAT, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    ret = dtls1_write_bytes(s, TLS1_RT_HEARTBEAT, buf, 3 + payload + padding);
+    if (ret >= 0) {
+        if (s->msg_callback)
+            s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT,
+                            buf, 3 + payload + padding,
+                            s, s->msg_callback_arg);
+
+        dtls1_start_timer(s);
+        s->tlsext_hb_pending = 1;
+    }
+
+ err:
+    OPENSSL_free(buf);
+
+    return ret;
+}
+#endif
+
+int dtls1_shutdown(SSL *s)
+{
+    int ret;
+#ifndef OPENSSL_NO_SCTP
+    BIO *wbio;
+
+    wbio = SSL_get_wbio(s);
+    if (wbio != NULL && BIO_dgram_is_sctp(wbio) &&
+        !(s->shutdown & SSL_SENT_SHUTDOWN)) {
+        ret = BIO_dgram_sctp_wait_for_dry(wbio);
+        if (ret < 0)
+            return -1;
+
+        if (ret == 0)
+            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN, 1,
+                     NULL);
+    }
+#endif
+    ret = ssl3_shutdown(s);
+#ifndef OPENSSL_NO_SCTP
+    BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN, 0, NULL);
+#endif
+    return ret;
+}
+
+int dtls1_query_mtu(SSL *s)
+{
+    if (s->d1->link_mtu) {
+        s->d1->mtu =
+            s->d1->link_mtu - BIO_dgram_get_mtu_overhead(SSL_get_wbio(s));
+        s->d1->link_mtu = 0;
+    }
+
+    /* AHA!  Figure out the MTU, and stick to the right size */
+    if (s->d1->mtu < dtls1_min_mtu(s)) {
+        if (!(SSL_get_options(s) & SSL_OP_NO_QUERY_MTU)) {
+            s->d1->mtu =
+                BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
+
+            /*
+             * I've seen the kernel return bogus numbers when it doesn't know
+             * (initial write), so just make sure we have a reasonable number
+             */
+            if (s->d1->mtu < dtls1_min_mtu(s)) {
+                /* Set to min mtu */
+                s->d1->mtu = dtls1_min_mtu(s);
+                BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SET_MTU,
+                         s->d1->mtu, NULL);
+            }
+        } else
+            return 0;
+    }
+    return 1;
+}
+
+unsigned int dtls1_link_min_mtu(void)
+{
+    return (g_probable_mtu[(sizeof(g_probable_mtu) /
+                            sizeof(g_probable_mtu[0])) - 1]);
+}
+
+unsigned int dtls1_min_mtu(SSL *s)
+{
+    return dtls1_link_min_mtu() - BIO_dgram_get_mtu_overhead(SSL_get_wbio(s));
+}
diff --git a/ssl/d1_meth.c b/ssl/d1_meth.c
deleted file mode 100644 (file)
index 7340774..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/* ssl/d1_meth.h */
-/*
- * DTLS implementation written by Nagendra Modadugu
- * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
- */
-/* ====================================================================
- * Copyright (c) 1999-2005 The OpenSSL Project.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- *    software must display the following acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- *    endorse or promote products derived from this software without
- *    prior written permission. For written permission, please contact
- *    openssl-core@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- *    nor may "OpenSSL" appear in their names without prior written
- *    permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- *    acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com).  This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-#include <stdio.h>
-#include <openssl/objects.h>
-#include "ssl_locl.h"
-
-static const SSL_METHOD *dtls1_get_method(int ver);
-static const SSL_METHOD *dtls1_get_method(int ver)
-{
-    if (ver == DTLS1_VERSION)
-        return (DTLSv1_method());
-    else if (ver == DTLS1_2_VERSION)
-        return (DTLSv1_2_method());
-    else
-        return (NULL);
-}
-
-IMPLEMENT_dtls1_meth_func(DTLS1_VERSION,
-                          DTLSv1_method,
-                          dtls1_accept,
-                          dtls1_connect, dtls1_get_method, DTLSv1_enc_data)
-
-    IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION,
-                          DTLSv1_2_method,
-                          dtls1_accept,
-                          dtls1_connect, dtls1_get_method, DTLSv1_2_enc_data)
-
-    IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION,
-                          DTLS_method,
-                          dtls1_accept,
-                          dtls1_connect, dtls1_get_method, DTLSv1_2_enc_data)
diff --git a/ssl/d1_srvr.c b/ssl/d1_srvr.c
deleted file mode 100644 (file)
index 47c6203..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-/* ssl/d1_srvr.c */
-/*
- * DTLS implementation written by Nagendra Modadugu
- * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
- */
-/* ====================================================================
- * Copyright (c) 1999-2007 The OpenSSL Project.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- *    software must display the following acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- *    endorse or promote products derived from this software without
- *    prior written permission. For written permission, please contact
- *    openssl-core@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- *    nor may "OpenSSL" appear in their names without prior written
- *    permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- *    acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com).  This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to.  The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *    "This product includes cryptographic software written by
- *     Eric Young (eay@cryptsoft.com)"
- *    The word 'cryptographic' can be left out if the rouines from the library
- *    being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- *    the apps directory (application code) you must include an acknowledgement:
- *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed.  i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#include <stdio.h>
-#include "ssl_locl.h"
-#include <openssl/buffer.h>
-#include <openssl/rand.h>
-#include <openssl/objects.h>
-#include <openssl/evp.h>
-#include <openssl/x509.h>
-#include <openssl/md5.h>
-#include <openssl/bn.h>
-#ifndef OPENSSL_NO_DH
-# include <openssl/dh.h>
-#endif
-
-static const SSL_METHOD *dtls1_get_server_method(int ver);
-
-static const SSL_METHOD *dtls1_get_server_method(int ver)
-{
-    if (ver == DTLS1_VERSION)
-        return (DTLSv1_server_method());
-    else if (ver == DTLS1_2_VERSION)
-        return (DTLSv1_2_server_method());
-    else
-        return (NULL);
-}
-
-IMPLEMENT_dtls1_meth_func(DTLS1_VERSION,
-                          DTLSv1_server_method,
-                          dtls1_accept,
-                          ssl_undefined_function,
-                          dtls1_get_server_method, DTLSv1_enc_data)
-
-IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION,
-                          DTLSv1_2_server_method,
-                          dtls1_accept,
-                          ssl_undefined_function,
-                          dtls1_get_server_method, DTLSv1_2_enc_data)
-
-IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION,
-                          DTLS_server_method,
-                          dtls1_accept,
-                          ssl_undefined_function,
-                          dtls1_get_server_method, DTLSv1_2_enc_data)
-
-
-unsigned int dtls1_raw_hello_verify_request(unsigned char *buf,
-                                            unsigned char *cookie,
-                                            unsigned char cookie_len)
-{
-    unsigned int msg_len;
-    unsigned char *p;
-
-    p = buf;
-    /* Always use DTLS 1.0 version: see RFC 6347 */
-    *(p++) = DTLS1_VERSION >> 8;
-    *(p++) = DTLS1_VERSION & 0xFF;
-
-    *(p++) = (unsigned char)cookie_len;
-    memcpy(p, cookie, cookie_len);
-    p += cookie_len;
-    msg_len = p - buf;
-
-    return msg_len;
-}
-
-
-int dtls_construct_hello_verify_request(SSL *s)
-{
-    unsigned int len;
-    unsigned char *buf;
-
-    buf = (unsigned char *)s->init_buf->data;
-
-    if (s->ctx->app_gen_cookie_cb == NULL ||
-        s->ctx->app_gen_cookie_cb(s, s->d1->cookie,
-                                  &(s->d1->cookie_len)) == 0 ||
-        s->d1->cookie_len > 255) {
-        SSLerr(SSL_F_DTLS1_SEND_HELLO_VERIFY_REQUEST,
-               SSL_R_COOKIE_GEN_CALLBACK_FAILURE);
-        statem_set_error(s);
-        return 0;
-    }
-
-    len = dtls1_raw_hello_verify_request(&buf[DTLS1_HM_HEADER_LENGTH],
-                                         s->d1->cookie, s->d1->cookie_len);
-
-    dtls1_set_message_header(s, buf, DTLS1_MT_HELLO_VERIFY_REQUEST, len, 0,
-                             len);
-    len += DTLS1_HM_HEADER_LENGTH;
-
-    /* number of bytes to write */
-    s->init_num = len;
-    s->init_off = 0;
-
-    return 1;
-}
diff --git a/ssl/methods.c b/ssl/methods.c
new file mode 100644 (file)
index 0000000..4e7093e
--- /dev/null
@@ -0,0 +1,347 @@
+/* ssl/t1_meth.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2015 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+#include <stdio.h>
+#include <openssl/objects.h>
+#include "ssl_locl.h"
+
+/*
+ * TLS/SSLv3 methods
+ */
+
+static const SSL_METHOD *tls1_get_method(int ver)
+{
+    if (ver == TLS_ANY_VERSION)
+        return TLS_method();
+    if (ver == TLS1_2_VERSION)
+        return TLSv1_2_method();
+    if (ver == TLS1_1_VERSION)
+        return TLSv1_1_method();
+    if (ver == TLS1_VERSION)
+        return TLSv1_method();
+#ifndef OPENSSL_NO_SSL3
+    if (ver == SSL3_VERSION)
+        return (SSLv3_method());
+    else
+#endif
+    return NULL;
+}
+
+IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, TLS_method,
+                        statem_accept,
+                        statem_connect, tls1_get_method, TLSv1_2_enc_data)
+
+IMPLEMENT_tls_meth_func(TLS1_2_VERSION, TLSv1_2_method,
+                        statem_accept,
+                        statem_connect, tls1_get_method, TLSv1_2_enc_data)
+
+IMPLEMENT_tls_meth_func(TLS1_1_VERSION, TLSv1_1_method,
+                        statem_accept,
+                        statem_connect, tls1_get_method, TLSv1_1_enc_data)
+
+IMPLEMENT_tls_meth_func(TLS1_VERSION, TLSv1_method,
+                        statem_accept,
+                        statem_connect, tls1_get_method, TLSv1_enc_data)
+
+#ifndef OPENSSL_NO_SSL3_METHOD
+IMPLEMENT_ssl3_meth_func(SSLv3_method,
+                         statem_accept, statem_connect, tls1_get_method)
+#endif
+
+
+/*
+ * TLS/SSLv3 server methods
+ */
+
+static const SSL_METHOD *tls1_get_server_method(int ver)
+{
+    if (ver == TLS_ANY_VERSION)
+        return TLS_server_method();
+    if (ver == TLS1_2_VERSION)
+        return TLSv1_2_server_method();
+    if (ver == TLS1_1_VERSION)
+        return TLSv1_1_server_method();
+    if (ver == TLS1_VERSION)
+        return TLSv1_server_method();
+#ifndef OPENSSL_NO_SSL3
+    if (ver == SSL3_VERSION)
+        return (SSLv3_server_method());
+#endif
+    return NULL;
+}
+
+IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, TLS_server_method,
+                        statem_accept,
+                        ssl_undefined_function,
+                        tls1_get_server_method, TLSv1_2_enc_data)
+
+IMPLEMENT_tls_meth_func(TLS1_2_VERSION, TLSv1_2_server_method,
+                        statem_accept,
+                        ssl_undefined_function,
+                        tls1_get_server_method, TLSv1_2_enc_data)
+
+IMPLEMENT_tls_meth_func(TLS1_1_VERSION, TLSv1_1_server_method,
+                        statem_accept,
+                        ssl_undefined_function,
+                        tls1_get_server_method, TLSv1_1_enc_data)
+
+IMPLEMENT_tls_meth_func(TLS1_VERSION, TLSv1_server_method,
+                        statem_accept,
+                        ssl_undefined_function,
+                        tls1_get_server_method, TLSv1_enc_data)
+
+#ifndef OPENSSL_NO_SSL3_METHOD
+IMPLEMENT_ssl3_meth_func(SSLv3_server_method,
+                         statem_accept,
+                         ssl_undefined_function, tls1_get_server_method)
+#endif
+
+
+/*
+ * TLS/SSLv3 client methods
+ */
+
+static const SSL_METHOD *tls1_get_client_method(int ver)
+{
+    if (ver == TLS_ANY_VERSION)
+        return TLS_client_method();
+    if (ver == TLS1_2_VERSION)
+        return TLSv1_2_client_method();
+    if (ver == TLS1_1_VERSION)
+        return TLSv1_1_client_method();
+    if (ver == TLS1_VERSION)
+        return TLSv1_client_method();
+#ifndef OPENSSL_NO_SSL3
+    if (ver == SSL3_VERSION)
+        return (SSLv3_client_method());
+#endif
+    return NULL;
+}
+
+IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, TLS_client_method,
+                        ssl_undefined_function,
+                        statem_connect,
+                        tls1_get_client_method, TLSv1_2_enc_data)
+
+IMPLEMENT_tls_meth_func(TLS1_2_VERSION, TLSv1_2_client_method,
+                        ssl_undefined_function,
+                        statem_connect,
+                        tls1_get_client_method, TLSv1_2_enc_data)
+
+IMPLEMENT_tls_meth_func(TLS1_1_VERSION, TLSv1_1_client_method,
+                        ssl_undefined_function,
+                        statem_connect,
+                        tls1_get_client_method, TLSv1_1_enc_data)
+
+IMPLEMENT_tls_meth_func(TLS1_VERSION, TLSv1_client_method,
+                        ssl_undefined_function,
+                        statem_connect, tls1_get_client_method, TLSv1_enc_data)
+
+#ifndef OPENSSL_NO_SSL3_METHOD
+IMPLEMENT_ssl3_meth_func(SSLv3_client_method,
+                         ssl_undefined_function,
+                         statem_connect, tls1_get_client_method)
+#endif
+
+
+/*
+ * DTLS methods
+ */
+static const SSL_METHOD *dtls1_get_method(int ver)
+{
+    if (ver == DTLS1_VERSION)
+        return (DTLSv1_method());
+    else if (ver == DTLS1_2_VERSION)
+        return (DTLSv1_2_method());
+    else
+        return (NULL);
+}
+
+IMPLEMENT_dtls1_meth_func(DTLS1_VERSION,
+                          DTLSv1_method,
+                          statem_accept,
+                          statem_connect, dtls1_get_method, DTLSv1_enc_data)
+
+IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION,
+                          DTLSv1_2_method,
+                          statem_accept,
+                          statem_connect, dtls1_get_method, DTLSv1_2_enc_data)
+
+IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION,
+                          DTLS_method,
+                          statem_accept,
+                          statem_connect, dtls1_get_method, DTLSv1_2_enc_data)
+
+
+/*
+ * DTLS server methods
+ */
+
+static const SSL_METHOD *dtls1_get_server_method(int ver)
+{
+    if (ver == DTLS1_VERSION)
+        return (DTLSv1_server_method());
+    else if (ver == DTLS1_2_VERSION)
+        return (DTLSv1_2_server_method());
+    else
+        return (NULL);
+}
+
+IMPLEMENT_dtls1_meth_func(DTLS1_VERSION,
+                          DTLSv1_server_method,
+                          statem_accept,
+                          ssl_undefined_function,
+                          dtls1_get_server_method, DTLSv1_enc_data)
+
+IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION,
+                          DTLSv1_2_server_method,
+                          statem_accept,
+                          ssl_undefined_function,
+                          dtls1_get_server_method, DTLSv1_2_enc_data)
+
+IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION,
+                          DTLS_server_method,
+                          statem_accept,
+                          ssl_undefined_function,
+                          dtls1_get_server_method, DTLSv1_2_enc_data)
+
+
+/*
+ * DTLS client methods
+ */
+
+static const SSL_METHOD *dtls1_get_client_method(int ver)
+{
+    if (ver == DTLS1_VERSION || ver == DTLS1_BAD_VER)
+        return (DTLSv1_client_method());
+    else if (ver == DTLS1_2_VERSION)
+        return (DTLSv1_2_client_method());
+    else
+        return (NULL);
+}
+
+IMPLEMENT_dtls1_meth_func(DTLS1_VERSION,
+                          DTLSv1_client_method,
+                          ssl_undefined_function,
+                          statem_connect,
+                          dtls1_get_client_method, DTLSv1_enc_data)
+
+IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION,
+                          DTLSv1_2_client_method,
+                          ssl_undefined_function,
+                          statem_connect,
+                          dtls1_get_client_method, DTLSv1_2_enc_data)
+
+IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION,
+                          DTLS_client_method,
+                          ssl_undefined_function,
+                          statem_connect,
+                          dtls1_get_client_method, DTLSv1_2_enc_data)
diff --git a/ssl/s3_both.c b/ssl/s3_both.c
deleted file mode 100644 (file)
index 47f02db..0000000
+++ /dev/null
@@ -1,712 +0,0 @@
-/* ssl/s3_both.c */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to.  The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *    "This product includes cryptographic software written by
- *     Eric Young (eay@cryptsoft.com)"
- *    The word 'cryptographic' can be left out if the rouines from the library
- *    being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- *    the apps directory (application code) you must include an acknowledgement:
- *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed.  i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-/* ====================================================================
- * Copyright (c) 1998-2002 The OpenSSL Project.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- *    software must display the following acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- *    endorse or promote products derived from this software without
- *    prior written permission. For written permission, please contact
- *    openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- *    nor may "OpenSSL" appear in their names without prior written
- *    permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- *    acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com).  This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-/* ====================================================================
- * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
- * ECC cipher suite support in OpenSSL originally developed by
- * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
- */
-
-#include <limits.h>
-#include <string.h>
-#include <stdio.h>
-#include "ssl_locl.h"
-#include <openssl/buffer.h>
-#include <openssl/rand.h>
-#include <openssl/objects.h>
-#include <openssl/evp.h>
-#include <openssl/x509.h>
-
-/*
- * send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or
- * SSL3_RT_CHANGE_CIPHER_SPEC)
- */
-int ssl3_do_write(SSL *s, int type)
-{
-    int ret;
-
-    ret = ssl3_write_bytes(s, type, &s->init_buf->data[s->init_off],
-                           s->init_num);
-    if (ret < 0)
-        return (-1);
-    if (type == SSL3_RT_HANDSHAKE)
-        /*
-         * should not be done for 'Hello Request's, but in that case we'll
-         * ignore the result anyway
-         */
-        ssl3_finish_mac(s, (unsigned char *)&s->init_buf->data[s->init_off],
-                        ret);
-
-    if (ret == s->init_num) {
-        if (s->msg_callback)
-            s->msg_callback(1, s->version, type, s->init_buf->data,
-                            (size_t)(s->init_off + s->init_num), s,
-                            s->msg_callback_arg);
-        return (1);
-    }
-    s->init_off += ret;
-    s->init_num -= ret;
-    return (0);
-}
-
-int tls_construct_finished(SSL *s, const char *sender, int slen)
-{
-    unsigned char *p;
-    int i;
-    unsigned long l;
-
-    p = ssl_handshake_start(s);
-
-    i = s->method->ssl3_enc->final_finish_mac(s,
-                                              sender, slen,
-                                              s->s3->tmp.finish_md);
-    if (i <= 0)
-        return 0;
-    s->s3->tmp.finish_md_len = i;
-    memcpy(p, s->s3->tmp.finish_md, i);
-    l = i;
-
-    /*
-     * Copy the finished so we can use it for renegotiation checks
-     */
-    if (!s->server) {
-        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;
-    }
-
-    if (!ssl_set_handshake_header(s, SSL3_MT_FINISHED, l)) {
-        SSLerr(SSL_F_TLS_CONSTRUCT_FINISHED, ERR_R_INTERNAL_ERROR);
-        return 0;
-    }
-
-    return 1;
-}
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
-/*
- * ssl3_take_mac calculates the Finished MAC for the handshakes messages seen
- * to far.
- */
-static void ssl3_take_mac(SSL *s)
-{
-    const char *sender;
-    int slen;
-    /*
-     * If no new cipher setup return immediately: other functions will set
-     * the appropriate error.
-     */
-    if (s->s3->tmp.new_cipher == NULL)
-        return;
-    if (!s->server) {
-        sender = s->method->ssl3_enc->server_finished_label;
-        slen = s->method->ssl3_enc->server_finished_label_len;
-    } else {
-        sender = s->method->ssl3_enc->client_finished_label;
-        slen = s->method->ssl3_enc->client_finished_label_len;
-    }
-
-    s->s3->tmp.peer_finish_md_len = s->method->ssl3_enc->final_finish_mac(s,
-                                                                          sender,
-                                                                          slen,
-                                                                          s->s3->tmp.peer_finish_md);
-}
-#endif
-
-enum MSG_PROCESS_RETURN tls_process_change_cipher_spec(SSL *s, PACKET *pkt)
-{
-    int al;
-    long remain;
-    
-    remain = PACKET_remaining(pkt);
-    /*
-     * 'Change Cipher Spec' is just a single byte, which should already have
-     * been consumed by ssl_get_message() so there should be no bytes left,
-     * unless we're using DTLS1_BAD_VER, which has an extra 2 bytes
-     */
-    if (SSL_IS_DTLS(s)) {
-        if ((s->version == DTLS1_BAD_VER
-                        && remain != DTLS1_CCS_HEADER_LENGTH + 1)
-                    || (s->version != DTLS1_BAD_VER
-                        && remain != DTLS1_CCS_HEADER_LENGTH - 1)) {
-                al = SSL_AD_ILLEGAL_PARAMETER;
-                SSLerr(SSL_F_TLS_PROCESS_CHANGE_CIPHER_SPEC,
-                       SSL_R_BAD_CHANGE_CIPHER_SPEC);
-                goto f_err;
-        }
-    } else {
-        if (remain != 0) {
-            al = SSL_AD_ILLEGAL_PARAMETER;
-            SSLerr(SSL_F_TLS_PROCESS_CHANGE_CIPHER_SPEC,
-                   SSL_R_BAD_CHANGE_CIPHER_SPEC);
-            goto f_err;
-        }
-    }
-
-    /* Check we have a cipher to change to */
-    if (s->s3->tmp.new_cipher == NULL) {
-        al = SSL_AD_UNEXPECTED_MESSAGE;
-        SSLerr(SSL_F_TLS_PROCESS_CHANGE_CIPHER_SPEC, SSL_R_CCS_RECEIVED_EARLY);
-        goto f_err;
-    }
-
-    s->s3->change_cipher_spec = 1;
-    if (!ssl3_do_change_cipher_spec(s)) {
-        al = SSL_AD_INTERNAL_ERROR;
-        SSLerr(SSL_F_TLS_PROCESS_CHANGE_CIPHER_SPEC, ERR_R_INTERNAL_ERROR);
-        goto f_err;
-    }
-
-    if (SSL_IS_DTLS(s)) {
-        dtls1_reset_seq_numbers(s, SSL3_CC_READ);
-
-        if (s->version == DTLS1_BAD_VER)
-            s->d1->handshake_read_seq++;
-
-#ifndef OPENSSL_NO_SCTP
-        /*
-         * Remember that a CCS has been received, so that an old key of
-         * SCTP-Auth can be deleted when a CCS is sent. Will be ignored if no
-         * SCTP is used
-         */
-        BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD, 1, NULL);
-#endif
-    }
-
-    return MSG_PROCESS_CONTINUE_READING;
- f_err:
-    ssl3_send_alert(s, SSL3_AL_FATAL, al);
-    statem_set_error(s);
-    return MSG_PROCESS_ERROR;
-}
-
-enum MSG_PROCESS_RETURN tls_process_finished(SSL *s, PACKET *pkt)
-{
-    int al, i;
-
-    /* If this occurs, we have missed a message */
-    if (!s->s3->change_cipher_spec) {
-        al = SSL_AD_UNEXPECTED_MESSAGE;
-        SSLerr(SSL_F_TLS_PROCESS_FINISHED, SSL_R_GOT_A_FIN_BEFORE_A_CCS);
-        goto f_err;
-    }
-    s->s3->change_cipher_spec = 0;
-
-    i = s->s3->tmp.peer_finish_md_len;
-
-    if (i < 0 || (unsigned long)i != PACKET_remaining(pkt)) {
-        al = SSL_AD_DECODE_ERROR;
-        SSLerr(SSL_F_TLS_PROCESS_FINISHED, SSL_R_BAD_DIGEST_LENGTH);
-        goto f_err;
-    }
-
-    if (CRYPTO_memcmp(PACKET_data(pkt), s->s3->tmp.peer_finish_md, i) != 0) {
-        al = SSL_AD_DECRYPT_ERROR;
-        SSLerr(SSL_F_TLS_PROCESS_FINISHED, SSL_R_DIGEST_CHECK_FAILED);
-        goto f_err;
-    }
-
-    /*
-     * Copy the finished so we can use it for renegotiation checks
-     */
-    if (s->server) {
-        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 MSG_PROCESS_CONTINUE_PROCESSING;
- f_err:
-    ssl3_send_alert(s, SSL3_AL_FATAL, al);
-    statem_set_error(s);
-    return MSG_PROCESS_ERROR;
-}
-
-int tls_construct_change_cipher_spec(SSL *s)
-{
-    unsigned char *p;
-
-    p = (unsigned char *)s->init_buf->data;
-    *p = SSL3_MT_CCS;
-    s->init_num = 1;
-    s->init_off = 0;
-
-    return 1;
-}
-
-unsigned long ssl3_output_cert_chain(SSL *s, CERT_PKEY *cpk)
-{
-    unsigned char *p;
-    unsigned long l = 3 + SSL_HM_HEADER_LENGTH(s);
-
-    if (!ssl_add_cert_chain(s, cpk, &l))
-        return 0;
-
-    l -= 3 + SSL_HM_HEADER_LENGTH(s);
-    p = ssl_handshake_start(s);
-    l2n3(l, p);
-    l += 3;
-
-    if (!ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE, l)) {
-        SSLerr(SSL_F_SSL3_OUTPUT_CERT_CHAIN, ERR_R_INTERNAL_ERROR);
-        return 0;
-    }
-    return l + SSL_HM_HEADER_LENGTH(s);
-}
-
-enum WORK_STATE tls_finish_handshake(SSL *s, enum WORK_STATE wst)
-{
-    void (*cb) (const SSL *ssl, int type, int val) = NULL;
-
-#ifndef OPENSSL_NO_SCTP
-    if (SSL_IS_DTLS(s) && BIO_dgram_is_sctp(SSL_get_wbio(s))) {
-        enum WORK_STATE ret;
-        ret = dtls_wait_for_dry(s);
-        if (ret != WORK_FINISHED_CONTINUE)
-            return ret;
-    }
-#endif
-
-    /* clean a few things up */
-    ssl3_cleanup_key_block(s);
-
-    if (!SSL_IS_DTLS(s)) {
-        /*
-         * We don't do this in DTLS because we may still need the init_buf
-         * in case there are any unexpected retransmits
-         */
-        BUF_MEM_free(s->init_buf);
-        s->init_buf = NULL;
-    }
-
-    ssl_free_wbio_buffer(s);
-
-    s->init_num = 0;
-
-    if (!s->server || s->renegotiate == 2) {
-        /* skipped if we just sent a HelloRequest */
-        s->renegotiate = 0;
-        s->new_session = 0;
-
-        if (s->server) {
-            s->renegotiate = 0;
-            s->new_session = 0;
-
-            ssl_update_cache(s, SSL_SESS_CACHE_SERVER);
-
-            s->ctx->stats.sess_accept_good++;
-            s->handshake_func = ssl3_accept;
-        } else {
-            ssl_update_cache(s, SSL_SESS_CACHE_CLIENT);
-            if (s->hit)
-                s->ctx->stats.sess_hit++;
-
-            s->handshake_func = ssl3_connect;
-            s->ctx->stats.sess_connect_good++;
-        }
-
-        if (s->info_callback != NULL)
-            cb = s->info_callback;
-        else if (s->ctx->info_callback != NULL)
-            cb = s->ctx->info_callback;
-
-        if (cb != NULL)
-            cb(s, SSL_CB_HANDSHAKE_DONE, 1);
-
-        if (SSL_IS_DTLS(s)) {
-            /* done with handshaking */
-            s->d1->handshake_read_seq = 0;
-            s->d1->handshake_write_seq = 0;
-            s->d1->next_handshake_write_seq = 0;
-        }
-    }
-
-    return WORK_FINISHED_STOP;
-}
-
-int tls_get_message_header(SSL *s, int *mt)
-{
-    /* s->init_num < SSL3_HM_HEADER_LENGTH */
-    int skip_message, i, recvd_type, al;
-    unsigned char *p;
-    unsigned long l;
-
-    p = (unsigned char *)s->init_buf->data;
-
-    do {
-        while (s->init_num < SSL3_HM_HEADER_LENGTH) {
-            i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, &recvd_type,
-                &p[s->init_num], SSL3_HM_HEADER_LENGTH - s->init_num, 0);
-            if (i <= 0) {
-                s->rwstate = SSL_READING;
-                return 0;
-            }
-            if (recvd_type == SSL3_RT_CHANGE_CIPHER_SPEC) {
-                s->s3->tmp.message_type = *mt = SSL3_MT_CHANGE_CIPHER_SPEC;
-                s->init_num = i - 1;
-                s->s3->tmp.message_size = i;
-                return 1;
-            } else if (recvd_type != SSL3_RT_HANDSHAKE) {
-                al = SSL_AD_UNEXPECTED_MESSAGE;
-                SSLerr(SSL_F_TLS_GET_MESSAGE_HEADER, SSL_R_CCS_RECEIVED_EARLY);
-                goto f_err;
-            }
-            s->init_num += i;
-        }
-
-        skip_message = 0;
-        if (!s->server)
-            if (p[0] == SSL3_MT_HELLO_REQUEST)
-                /*
-                 * The server may always send 'Hello Request' messages --
-                 * we are doing a handshake anyway now, so ignore them if
-                 * their format is correct. Does not count for 'Finished'
-                 * MAC.
-                 */
-                if (p[1] == 0 && p[2] == 0 && p[3] == 0) {
-                    s->init_num = 0;
-                    skip_message = 1;
-
-                    if (s->msg_callback)
-                        s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
-                                        p, SSL3_HM_HEADER_LENGTH, s,
-                                        s->msg_callback_arg);
-                }
-    } while (skip_message);
-    /* s->init_num == SSL3_HM_HEADER_LENGTH */
-
-    *mt = *p;
-    s->s3->tmp.message_type = *(p++);
-
-    if(RECORD_LAYER_is_sslv2_record(&s->rlayer)) {
-        /*
-         * Only happens with SSLv3+ in an SSLv2 backward compatible
-         * ClientHello
-         */
-         /*
-          * Total message size is the remaining record bytes to read
-          * plus the SSL3_HM_HEADER_LENGTH bytes that we already read
-          */
-        l = RECORD_LAYER_get_rrec_length(&s->rlayer)
-            + SSL3_HM_HEADER_LENGTH;
-        if (l && !BUF_MEM_grow_clean(s->init_buf, (int)l)) {
-            SSLerr(SSL_F_TLS_GET_MESSAGE_HEADER, ERR_R_BUF_LIB);
-            goto err;
-        }
-        s->s3->tmp.message_size = l;
-
-        s->init_msg = s->init_buf->data;
-        s->init_num = SSL3_HM_HEADER_LENGTH;
-    } else {
-        n2l3(p, l);
-        /* BUF_MEM_grow takes an 'int' parameter */
-        if (l > (INT_MAX - SSL3_HM_HEADER_LENGTH)) {
-            al = SSL_AD_ILLEGAL_PARAMETER;
-            SSLerr(SSL_F_TLS_GET_MESSAGE_HEADER, SSL_R_EXCESSIVE_MESSAGE_SIZE);
-            goto f_err;
-        }
-        if (l && !BUF_MEM_grow_clean(s->init_buf,
-                                    (int)l + SSL3_HM_HEADER_LENGTH)) {
-            SSLerr(SSL_F_TLS_GET_MESSAGE_HEADER, ERR_R_BUF_LIB);
-            goto err;
-        }
-        s->s3->tmp.message_size = l;
-
-        s->init_msg = s->init_buf->data + SSL3_HM_HEADER_LENGTH;
-        s->init_num = 0;
-    }
-
-    return 1;
- f_err:
-    ssl3_send_alert(s, SSL3_AL_FATAL, al);
- err:
-    return 0;
-}
-
-int tls_get_message_body(SSL *s, unsigned long *len)
-{
-    long n;
-    unsigned char *p;
-    int i;
-
-    if (s->s3->tmp.message_type == SSL3_MT_CHANGE_CIPHER_SPEC) {
-        /* We've already read everything in */
-        *len = (unsigned long)s->init_num;
-        return 1;
-    }
-
-    p = s->init_msg;
-    n = s->s3->tmp.message_size - s->init_num;
-    while (n > 0) {
-        i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL,
-                                      &p[s->init_num], n, 0);
-        if (i <= 0) {
-            s->rwstate = SSL_READING;
-            *len = 0;
-            return 0;
-        }
-        s->init_num += i;
-        n -= i;
-    }
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
-    /*
-     * If receiving Finished, record MAC of prior handshake messages for
-     * Finished verification.
-     */
-    if (*s->init_buf->data == SSL3_MT_FINISHED)
-        ssl3_take_mac(s);
-#endif
-
-    /* Feed this message into MAC computation. */
-    if(RECORD_LAYER_is_sslv2_record(&s->rlayer)) {
-        ssl3_finish_mac(s, (unsigned char *)s->init_buf->data, s->init_num);
-        if (s->msg_callback)
-            s->msg_callback(0, SSL2_VERSION, 0,  s->init_buf->data,
-                            (size_t)s->init_num, s, s->msg_callback_arg);
-    } else {
-        ssl3_finish_mac(s, (unsigned char *)s->init_buf->data,
-            s->init_num + SSL3_HM_HEADER_LENGTH);
-        if (s->msg_callback)
-            s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->init_buf->data,
-                            (size_t)s->init_num + SSL3_HM_HEADER_LENGTH, s,
-                            s->msg_callback_arg);
-    }
-
-    /*
-     * init_num should never be negative...should probably be declared
-     * unsigned
-     */
-    if (s->init_num < 0) {
-        SSLerr(SSL_F_TLS_GET_MESSAGE_BODY, ERR_R_INTERNAL_ERROR);
-        ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
-        *len = 0;
-        return 0;
-    }
-    *len = (unsigned long)s->init_num;
-    return 1;
-}
-
-int ssl_cert_type(X509 *x, EVP_PKEY *pkey)
-{
-    EVP_PKEY *pk;
-    int ret = -1, i;
-
-    if (pkey == NULL)
-        pk = X509_get_pubkey(x);
-    else
-        pk = pkey;
-    if (pk == NULL)
-        goto err;
-
-    i = pk->type;
-    if (i == EVP_PKEY_RSA) {
-        ret = SSL_PKEY_RSA_ENC;
-    } else if (i == EVP_PKEY_DSA) {
-        ret = SSL_PKEY_DSA_SIGN;
-    }
-#ifndef OPENSSL_NO_EC
-    else if (i == EVP_PKEY_EC) {
-        ret = SSL_PKEY_ECC;
-    }
-#endif
-    else if (i == NID_id_GostR3410_2001) {
-        ret = SSL_PKEY_GOST01;
-    } else if (x && (i == EVP_PKEY_DH || i == EVP_PKEY_DHX)) {
-        /*
-         * For DH two cases: DH certificate signed with RSA and DH
-         * certificate signed with DSA.
-         */
-        i = X509_certificate_type(x, pk);
-        if (i & EVP_PKS_RSA)
-            ret = SSL_PKEY_DH_RSA;
-        else if (i & EVP_PKS_DSA)
-            ret = SSL_PKEY_DH_DSA;
-    }
-
- err:
-    if (!pkey)
-        EVP_PKEY_free(pk);
-    return (ret);
-}
-
-int ssl_verify_alarm_type(long type)
-{
-    int al;
-
-    switch (type) {
-    case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
-    case X509_V_ERR_UNABLE_TO_GET_CRL:
-    case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
-        al = SSL_AD_UNKNOWN_CA;
-        break;
-    case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
-    case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
-    case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
-    case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
-    case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
-    case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
-    case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
-    case X509_V_ERR_CERT_NOT_YET_VALID:
-    case X509_V_ERR_CRL_NOT_YET_VALID:
-    case X509_V_ERR_CERT_UNTRUSTED:
-    case X509_V_ERR_CERT_REJECTED:
-        al = SSL_AD_BAD_CERTIFICATE;
-        break;
-    case X509_V_ERR_CERT_SIGNATURE_FAILURE:
-    case X509_V_ERR_CRL_SIGNATURE_FAILURE:
-        al = SSL_AD_DECRYPT_ERROR;
-        break;
-    case X509_V_ERR_CERT_HAS_EXPIRED:
-    case X509_V_ERR_CRL_HAS_EXPIRED:
-        al = SSL_AD_CERTIFICATE_EXPIRED;
-        break;
-    case X509_V_ERR_CERT_REVOKED:
-        al = SSL_AD_CERTIFICATE_REVOKED;
-        break;
-    case X509_V_ERR_OUT_OF_MEM:
-        al = SSL_AD_INTERNAL_ERROR;
-        break;
-    case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
-    case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
-    case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
-    case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
-    case X509_V_ERR_CERT_CHAIN_TOO_LONG:
-    case X509_V_ERR_PATH_LENGTH_EXCEEDED:
-    case X509_V_ERR_INVALID_CA:
-        al = SSL_AD_UNKNOWN_CA;
-        break;
-    case X509_V_ERR_APPLICATION_VERIFICATION:
-        al = SSL_AD_HANDSHAKE_FAILURE;
-        break;
-    case X509_V_ERR_INVALID_PURPOSE:
-        al = SSL_AD_UNSUPPORTED_CERTIFICATE;
-        break;
-    default:
-        al = SSL_AD_CERTIFICATE_UNKNOWN;
-        break;
-    }
-    return (al);
-}
-
-int ssl_allow_compression(SSL *s)
-{
-    if (s->options & SSL_OP_NO_COMPRESSION)
-        return 0;
-    return ssl_security(s, SSL_SECOP_COMPRESSION, 0, 0, NULL);
-}
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
deleted file mode 100644 (file)
index 49a9f60..0000000
+++ /dev/null
@@ -1,2819 +0,0 @@
-/* ssl/s3_clnt.c */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to.  The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *    "This product includes cryptographic software written by
- *     Eric Young (eay@cryptsoft.com)"
- *    The word 'cryptographic' can be left out if the rouines from the library
- *    being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- *    the apps directory (application code) you must include an acknowledgement:
- *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed.  i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-/* ====================================================================
- * Copyright (c) 1998-2007 The OpenSSL Project.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- *    software must display the following acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- *    endorse or promote products derived from this software without
- *    prior written permission. For written permission, please contact
- *    openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- *    nor may "OpenSSL" appear in their names without prior written
- *    permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- *    acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com).  This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-/* ====================================================================
- * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
- *
- * Portions of the attached software ("Contribution") are developed by
- * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
- *
- * The Contribution is licensed pursuant to the OpenSSL open source
- * license provided above.
- *
- * ECC cipher suite support in OpenSSL originally written by
- * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories.
- *
- */
-/* ====================================================================
- * Copyright 2005 Nokia. All rights reserved.
- *
- * The portions of the attached software ("Contribution") is developed by
- * Nokia Corporation and is licensed pursuant to the OpenSSL open source
- * license.
- *
- * The Contribution, originally written by Mika Kousa and Pasi Eronen of
- * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
- * support (see RFC 4279) to OpenSSL.
- *
- * No patent licenses or other rights except those expressly stated in
- * the OpenSSL open source license shall be deemed granted or received
- * expressly, by implication, estoppel, or otherwise.
- *
- * No assurances are provided by Nokia that the Contribution does not
- * infringe the patent or other intellectual property rights of any third
- * party or that the license provides you with all the necessary rights
- * to make use of the Contribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
- * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
- * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
- * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
- * OTHERWISE.
- */
-
-#include <stdio.h>
-#include "ssl_locl.h"
-#include <openssl/buffer.h>
-#include <openssl/rand.h>
-#include <openssl/objects.h>
-#include <openssl/evp.h>
-#include <openssl/md5.h>
-#ifndef OPENSSL_NO_DH
-# include <openssl/dh.h>
-#endif
-#include <openssl/bn.h>
-#ifndef OPENSSL_NO_ENGINE
-# include <openssl/engine.h>
-#endif
-
-static int ssl_set_version(SSL *s);
-static int ca_dn_cmp(const X509_NAME *const *a, const X509_NAME *const *b);
-static int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk,
-                                    unsigned char *p);
-
-/*
- * Work out what version we should be using for the initial ClientHello if
- * the version is currently set to (D)TLS_ANY_VERSION.
- * Returns 1 on success
- * Returns 0 on error
- */
-static int ssl_set_version(SSL *s)
-{
-    unsigned long mask, options = s->options;
-
-    if (s->method->version == TLS_ANY_VERSION) {
-        /*
-         * SSL_OP_NO_X disables all protocols above X *if* there are
-         * some protocols below X enabled. This is required in order
-         * to maintain "version capability" vector contiguous. So
-         * that if application wants to disable TLS1.0 in favour of
-         * TLS1>=1, it would be insufficient to pass SSL_NO_TLSv1, the
-         * answer is SSL_OP_NO_TLSv1|SSL_OP_NO_SSLv3.
-         */
-        mask = SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1
-#if !defined(OPENSSL_NO_SSL3)
-            | SSL_OP_NO_SSLv3
-#endif
-            ;
-#if !defined(OPENSSL_NO_TLS1_2_CLIENT)
-        if (options & SSL_OP_NO_TLSv1_2) {
-            if ((options & mask) != mask) {
-                s->version = TLS1_1_VERSION;
-            } else {
-                SSLerr(SSL_F_SSL_SET_VERSION, SSL_R_NO_PROTOCOLS_AVAILABLE);
-                return 0;
-            }
-        } else {
-            s->version = TLS1_2_VERSION;
-        }
-#else
-        if ((options & mask) == mask) {
-            SSLerr(SSL_F_SSL_SET_VERSION, SSL_R_NO_PROTOCOLS_AVAILABLE);
-            return 0;
-        }
-        s->version = TLS1_1_VERSION;
-#endif
-
-        mask &= ~SSL_OP_NO_TLSv1_1;
-        if ((options & SSL_OP_NO_TLSv1_1) && (options & mask) != mask)
-            s->version = TLS1_VERSION;
-        mask &= ~SSL_OP_NO_TLSv1;
-#if !defined(OPENSSL_NO_SSL3)
-        if ((options & SSL_OP_NO_TLSv1) && (options & mask) != mask)
-            s->version = SSL3_VERSION;
-#endif
-
-        if (s->version != TLS1_2_VERSION && tls1_suiteb(s)) {
-            SSLerr(SSL_F_SSL_SET_VERSION,
-                   SSL_R_ONLY_TLS_1_2_ALLOWED_IN_SUITEB_MODE);
-            return 0;
-        }
-
-        if (s->version == SSL3_VERSION && FIPS_mode()) {
-            SSLerr(SSL_F_SSL_SET_VERSION, SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE);
-            return 0;
-        }
-
-    } else if (s->method->version == DTLS_ANY_VERSION) {
-        /* Determine which DTLS version to use */
-        /* If DTLS 1.2 disabled correct the version number */
-        if (options & SSL_OP_NO_DTLSv1_2) {
-            if (tls1_suiteb(s)) {
-                SSLerr(SSL_F_SSL_SET_VERSION,
-                       SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE);
-                return 0;
-            }
-            /*
-             * Disabling all versions is silly: return an error.
-             */
-            if (options & SSL_OP_NO_DTLSv1) {
-                SSLerr(SSL_F_SSL_SET_VERSION, SSL_R_WRONG_SSL_VERSION);
-                return 0;
-            }
-            /*
-             * Update method so we don't use any DTLS 1.2 features.
-             */
-            s->method = DTLSv1_client_method();
-            s->version = DTLS1_VERSION;
-        } else {
-            /*
-             * We only support one version: update method
-             */
-            if (options & SSL_OP_NO_DTLSv1)
-                s->method = DTLSv1_2_client_method();
-            s->version = DTLS1_2_VERSION;
-        }
-    }
-
-    s->client_version = s->version;
-
-    return 1;
-}
-
-int tls_construct_client_hello(SSL *s)
-{
-    unsigned char *buf;
-    unsigned char *p, *d;
-    int i;
-    unsigned long l;
-    int al = 0;
-#ifndef OPENSSL_NO_COMP
-    int j;
-    SSL_COMP *comp;
-#endif
-    SSL_SESSION *sess = s->session;
-
-    buf = (unsigned char *)s->init_buf->data;
-
-    /* Work out what SSL/TLS/DTLS version to use */
-    if (ssl_set_version(s) == 0)
-        goto err;
-
-    if ((sess == NULL) || (sess->ssl_version != s->version) ||
-        /*
-         * In the case of EAP-FAST, we can have a pre-shared
-         * "ticket" without a session ID.
-         */
-        (!sess->session_id_length && !sess->tlsext_tick) ||
-        (sess->not_resumable)) {
-        if (!ssl_get_new_session(s, 0))
-            goto err;
-    }
-    /* else use the pre-loaded session */
-
-    p = s->s3->client_random;
-
-    /*
-     * for DTLS if client_random is initialized, reuse it, we are
-     * required to use same upon reply to HelloVerify
-     */
-    if (SSL_IS_DTLS(s)) {
-        size_t idx;
-        i = 1;
-        for (idx = 0; idx < sizeof(s->s3->client_random); idx++) {
-            if (p[idx]) {
-                i = 0;
-                break;
-            }
-        }
-    } else
-        i = 1;
-
-    if (i && ssl_fill_hello_random(s, 0, p,
-                                   sizeof(s->s3->client_random)) <= 0)
-        goto err;
-
-    /* Do the message type and length last */
-    d = p = ssl_handshake_start(s);
-
-    /*-
-     * version indicates the negotiated version: for example from
-     * an SSLv2/v3 compatible client hello). The client_version
-     * field is the maximum version we permit and it is also
-     * used in RSA encrypted premaster secrets. Some servers can
-     * choke if we initially report a higher version then
-     * renegotiate to a lower one in the premaster secret. This
-     * didn't happen with TLS 1.0 as most servers supported it
-     * but it can with TLS 1.1 or later if the server only supports
-     * 1.0.
-     *
-     * Possible scenario with previous logic:
-     *      1. Client hello indicates TLS 1.2
-     *      2. Server hello says TLS 1.0
-     *      3. RSA encrypted premaster secret uses 1.2.
-     *      4. Handhaked proceeds using TLS 1.0.
-     *      5. Server sends hello request to renegotiate.
-     *      6. Client hello indicates TLS v1.0 as we now
-     *         know that is maximum server supports.
-     *      7. Server chokes on RSA encrypted premaster secret
-     *         containing version 1.0.
-     *
-     * For interoperability it should be OK to always use the
-     * maximum version we support in client hello and then rely
-     * on the checking of version to ensure the servers isn't
-     * being inconsistent: for example initially negotiating with
-     * TLS 1.0 and renegotiating with TLS 1.2. We do this by using
-     * client_version in client hello and not resetting it to
-     * the negotiated version.
-     */
-    *(p++) = s->client_version >> 8;
-    *(p++) = s->client_version & 0xff;
-
-    /* Random stuff */
-    memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE);
-    p += SSL3_RANDOM_SIZE;
-
-    /* Session ID */
-    if (s->new_session)
-        i = 0;
-    else
-        i = s->session->session_id_length;
-    *(p++) = i;
-    if (i != 0) {
-        if (i > (int)sizeof(s->session->session_id)) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
-        memcpy(p, s->session->session_id, i);
-        p += i;
-    }
-
-    /* cookie stuff for DTLS */
-    if (SSL_IS_DTLS(s)) {
-        if (s->d1->cookie_len > sizeof(s->d1->cookie)) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
-        *(p++) = s->d1->cookie_len;
-        memcpy(p, s->d1->cookie, s->d1->cookie_len);
-        p += s->d1->cookie_len;
-    }
-
-    /* Ciphers supported */
-    i = ssl_cipher_list_to_bytes(s, SSL_get_ciphers(s), &(p[2]));
-    if (i == 0) {
-        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, SSL_R_NO_CIPHERS_AVAILABLE);
-        goto err;
-    }
-#ifdef OPENSSL_MAX_TLS1_2_CIPHER_LENGTH
-    /*
-     * Some servers hang if client hello > 256 bytes as hack workaround
-     * chop number of supported ciphers to keep it well below this if we
-     * use TLS v1.2
-     */
-    if (TLS1_get_version(s) >= TLS1_2_VERSION
-        && i > OPENSSL_MAX_TLS1_2_CIPHER_LENGTH)
-        i = OPENSSL_MAX_TLS1_2_CIPHER_LENGTH & ~1;
-#endif
-    s2n(i, p);
-    p += i;
-
-    /* COMPRESSION */
-#ifdef OPENSSL_NO_COMP
-    *(p++) = 1;
-#else
-
-    if (!ssl_allow_compression(s) || !s->ctx->comp_methods)
-        j = 0;
-    else
-        j = sk_SSL_COMP_num(s->ctx->comp_methods);
-    *(p++) = 1 + j;
-    for (i = 0; i < j; i++) {
-        comp = sk_SSL_COMP_value(s->ctx->comp_methods, i);
-        *(p++) = comp->id;
-    }
-#endif
-    *(p++) = 0;             /* Add the NULL method */
-
-    /* TLS extensions */
-    if (ssl_prepare_clienthello_tlsext(s) <= 0) {
-        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT);
-        goto err;
-    }
-    if ((p =
-         ssl_add_clienthello_tlsext(s, p, buf + SSL3_RT_MAX_PLAIN_LENGTH,
-                                    &al)) == NULL) {
-        ssl3_send_alert(s, SSL3_AL_FATAL, al);
-        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
-        goto err;
-    }
-
-    l = p - d;
-    if (!ssl_set_handshake_header(s, SSL3_MT_CLIENT_HELLO, l)) {
-        ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
-        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
-        goto err;
-    }
-
-    return 1;
- err:
-    statem_set_error(s);
-    return 0;
-}
-
-enum MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
-{
-    STACK_OF(SSL_CIPHER) *sk;
-    const SSL_CIPHER *c;
-    PACKET session_id;
-    size_t session_id_len;
-    unsigned char *cipherchars;
-    int i, al = SSL_AD_INTERNAL_ERROR;
-    unsigned int compression;
-#ifndef OPENSSL_NO_COMP
-    SSL_COMP *comp;
-#endif
-
-    if (s->method->version == TLS_ANY_VERSION) {
-        unsigned int sversion;
-
-        if (!PACKET_get_net_2(pkt, &sversion)) {
-            al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
-            goto f_err;
-        }
-
-#if TLS_MAX_VERSION != TLS1_2_VERSION
-#error Code needs updating for new TLS version
-#endif
-#ifndef OPENSSL_NO_SSL3
-        if ((sversion == SSL3_VERSION) && !(s->options & SSL_OP_NO_SSLv3)) {
-            if (FIPS_mode()) {
-                SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO,
-                       SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE);
-                al = SSL_AD_PROTOCOL_VERSION;
-                goto f_err;
-            }
-            s->method = SSLv3_client_method();
-        } else
-#endif
-        if ((sversion == TLS1_VERSION) && !(s->options & SSL_OP_NO_TLSv1)) {
-            s->method = TLSv1_client_method();
-        } else if ((sversion == TLS1_1_VERSION) &&
-                   !(s->options & SSL_OP_NO_TLSv1_1)) {
-            s->method = TLSv1_1_client_method();
-        } else if ((sversion == TLS1_2_VERSION) &&
-                   !(s->options & SSL_OP_NO_TLSv1_2)) {
-            s->method = TLSv1_2_client_method();
-        } else {
-            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_UNSUPPORTED_PROTOCOL);
-            al = SSL_AD_PROTOCOL_VERSION;
-            goto f_err;
-        }
-        s->session->ssl_version = s->version = s->method->version;
-
-        if (!ssl_security(s, SSL_SECOP_VERSION, 0, s->version, NULL)) {
-            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_VERSION_TOO_LOW);
-            al = SSL_AD_PROTOCOL_VERSION;
-            goto f_err;
-        }
-    } else if (s->method->version == DTLS_ANY_VERSION) {
-        /* Work out correct protocol version to use */
-        unsigned int hversion;
-        int options;
-
-        if (!PACKET_get_net_2(pkt, &hversion)) {
-            al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
-            goto f_err;
-        }
-
-        options = s->options;
-        if (hversion == DTLS1_2_VERSION && !(options & SSL_OP_NO_DTLSv1_2))
-            s->method = DTLSv1_2_client_method();
-        else if (tls1_suiteb(s)) {
-            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO,
-                   SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE);
-            s->version = hversion;
-            al = SSL_AD_PROTOCOL_VERSION;
-            goto f_err;
-        } else if (hversion == DTLS1_VERSION && !(options & SSL_OP_NO_DTLSv1))
-            s->method = DTLSv1_client_method();
-        else {
-            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_WRONG_SSL_VERSION);
-            s->version = hversion;
-            al = SSL_AD_PROTOCOL_VERSION;
-            goto f_err;
-        }
-        s->session->ssl_version = s->version = s->method->version;
-    } else {
-        unsigned char *vers;
-
-        if (!PACKET_get_bytes(pkt, &vers, 2)) {
-            al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
-            goto f_err;
-        }
-        if ((vers[0] != (s->version >> 8))
-                || (vers[1] != (s->version & 0xff))) {
-            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_WRONG_SSL_VERSION);
-            s->version = (s->version & 0xff00) | vers[1];
-            al = SSL_AD_PROTOCOL_VERSION;
-            goto f_err;
-        }
-    }
-
-    /* load the server hello data */
-    /* load the server random */
-    if (!PACKET_copy_bytes(pkt, s->s3->server_random, SSL3_RANDOM_SIZE)) {
-        al = SSL_AD_DECODE_ERROR;
-        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
-        goto f_err;
-    }
-
-    s->hit = 0;
-
-    /* Get the session-id. */
-    if (!PACKET_get_length_prefixed_1(pkt, &session_id)) {
-        al = SSL_AD_DECODE_ERROR;
-        SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
-        goto f_err;
-    }
-    session_id_len = PACKET_remaining(&session_id);
-    if (session_id_len > sizeof s->session->session_id
-        || session_id_len > SSL3_SESSION_ID_SIZE) {
-        al = SSL_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_SSL3_SESSION_ID_TOO_LONG);
-        goto f_err;
-    }
-
-    if (!PACKET_get_bytes(pkt, &cipherchars, TLS_CIPHER_LEN)) {
-        SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
-        al = SSL_AD_DECODE_ERROR;
-        goto f_err;
-    }
-
-    /*
-     * Check if we can resume the session based on external pre-shared secret.
-     * EAP-FAST (RFC 4851) supports two types of session resumption.
-     * Resumption based on server-side state works with session IDs.
-     * Resumption based on pre-shared Protected Access Credentials (PACs)
-     * works by overriding the SessionTicket extension at the application
-     * layer, and does not send a session ID. (We do not know whether EAP-FAST
-     * servers would honour the session ID.) Therefore, the session ID alone
-     * is not a reliable indicator of session resumption, so we first check if
-     * we can resume, and later peek at the next handshake message to see if the
-     * server wants to resume.
-     */
-    if (s->version >= TLS1_VERSION && s->tls_session_secret_cb &&
-        s->session->tlsext_tick) {
-        SSL_CIPHER *pref_cipher = NULL;
-        s->session->master_key_length = sizeof(s->session->master_key);
-        if (s->tls_session_secret_cb(s, s->session->master_key,
-                                     &s->session->master_key_length,
-                                     NULL, &pref_cipher,
-                                     s->tls_session_secret_cb_arg)) {
-            s->session->cipher = pref_cipher ?
-                pref_cipher : ssl_get_cipher_by_char(s, cipherchars);
-        } else {
-            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
-            al = SSL_AD_INTERNAL_ERROR;
-            goto f_err;
-        }
-    }
-
-    if (session_id_len != 0 && session_id_len == s->session->session_id_length
-        && memcmp(PACKET_data(&session_id), s->session->session_id,
-                  session_id_len) == 0) {
-        if (s->sid_ctx_length != s->session->sid_ctx_length
-            || memcmp(s->session->sid_ctx, s->sid_ctx, s->sid_ctx_length)) {
-            /* actually a client application bug */
-            al = SSL_AD_ILLEGAL_PARAMETER;
-            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO,
-                   SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT);
-            goto f_err;
-        }
-        s->hit = 1;
-    } else {
-        /*
-         * If we were trying for session-id reuse but the server
-         * didn't echo the ID, make a new SSL_SESSION.
-         * In the case of EAP-FAST and PAC, we do not send a session ID,
-         * so the PAC-based session secret is always preserved. It'll be
-         * overwritten if the server refuses resumption.
-         */
-        if (s->session->session_id_length > 0) {
-            if (!ssl_get_new_session(s, 0)) {
-                goto f_err;
-            }
-        }
-
-        s->session->session_id_length = session_id_len;
-        /* session_id_len could be 0 */
-        memcpy(s->session->session_id, PACKET_data(&session_id),
-               session_id_len);
-    }
-
-    c = ssl_get_cipher_by_char(s, cipherchars);
-    if (c == NULL) {
-        /* unknown cipher */
-        al = SSL_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_UNKNOWN_CIPHER_RETURNED);
-        goto f_err;
-    }
-    /* Set version disabled mask now we know version */
-    if (!SSL_USE_TLS1_2_CIPHERS(s))
-        s->s3->tmp.mask_ssl = SSL_TLSV1_2;
-    else
-        s->s3->tmp.mask_ssl = 0;
-    /*
-     * If it is a disabled cipher we didn't send it in client hello, so
-     * return an error.
-     */
-    if (ssl_cipher_disabled(s, c, SSL_SECOP_CIPHER_CHECK)) {
-        al = SSL_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_WRONG_CIPHER_RETURNED);
-        goto f_err;
-    }
-
-    sk = ssl_get_ciphers_by_id(s);
-    i = sk_SSL_CIPHER_find(sk, c);
-    if (i < 0) {
-        /* we did not say we would use this cipher */
-        al = SSL_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_WRONG_CIPHER_RETURNED);
-        goto f_err;
-    }
-
-    /*
-     * Depending on the session caching (internal/external), the cipher
-     * and/or cipher_id values may not be set. Make sure that cipher_id is
-     * set and use it for comparison.
-     */
-    if (s->session->cipher)
-        s->session->cipher_id = s->session->cipher->id;
-    if (s->hit && (s->session->cipher_id != c->id)) {
-        al = SSL_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO,
-               SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED);
-        goto f_err;
-    }
-    s->s3->tmp.new_cipher = c;
-    /*
-     * Don't digest cached records if no sigalgs: we may need them for client
-     * authentication.
-     */
-    if (!SSL_USE_SIGALGS(s) && !ssl3_digest_cached_records(s, 0))
-        goto f_err;
-    /* lets get the compression algorithm */
-    /* COMPRESSION */
-    if (!PACKET_get_1(pkt, &compression)) {
-        SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
-        al = SSL_AD_DECODE_ERROR;
-        goto f_err;
-    }
-#ifdef OPENSSL_NO_COMP
-    if (compression != 0) {
-        al = SSL_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO,
-               SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
-        goto f_err;
-    }
-    /*
-     * If compression is disabled we'd better not try to resume a session
-     * using compression.
-     */
-    if (s->session->compress_meth != 0) {
-        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_INCONSISTENT_COMPRESSION);
-        goto f_err;
-    }
-#else
-    if (s->hit && compression != s->session->compress_meth) {
-        al = SSL_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO,
-               SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED);
-        goto f_err;
-    }
-    if (compression == 0)
-        comp = NULL;
-    else if (!ssl_allow_compression(s)) {
-        al = SSL_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_COMPRESSION_DISABLED);
-        goto f_err;
-    } else {
-        comp = ssl3_comp_find(s->ctx->comp_methods, compression);
-    }
-
-    if (compression != 0 && comp == NULL) {
-        al = SSL_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO,
-               SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
-        goto f_err;
-    } else {
-        s->s3->tmp.new_compression = comp;
-    }
-#endif
-
-    /* TLS extensions */
-    if (!ssl_parse_serverhello_tlsext(s, pkt)) {
-        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_PARSE_TLSEXT);
-        goto err;
-    }
-
-    if (PACKET_remaining(pkt) != 0) {
-        /* wrong packet length */
-        al = SSL_AD_DECODE_ERROR;
-        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_BAD_PACKET_LENGTH);
-        goto f_err;
-    }
-
-#ifndef OPENSSL_NO_SCTP
-    if (SSL_IS_DTLS(s) && s->hit) {
-        unsigned char sctpauthkey[64];
-        char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
-
-        /*
-         * Add new shared key for SCTP-Auth, will be ignored if
-         * no SCTP used.
-         */
-        snprintf((char *)labelbuffer,
-                 sizeof(DTLS1_SCTP_AUTH_LABEL),
-                 DTLS1_SCTP_AUTH_LABEL);
-
-        if (SSL_export_keying_material(s, sctpauthkey,
-                                   sizeof(sctpauthkey),
-                                   labelbuffer,
-                                   sizeof(labelbuffer), NULL, 0,
-                                   0) <= 0)
-            goto err;
-
-        BIO_ctrl(SSL_get_wbio(s),
-                 BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
-                 sizeof(sctpauthkey), sctpauthkey);
-    }
-#endif
-
-    return MSG_PROCESS_CONTINUE_READING;
- f_err:
-    ssl3_send_alert(s, SSL3_AL_FATAL, al);
- err:
-    statem_set_error(s);
-    return MSG_PROCESS_ERROR;
-}
-
-enum MSG_PROCESS_RETURN tls_process_server_certificate(SSL *s, PACKET *pkt)
-{
-    int al, i, ret = MSG_PROCESS_ERROR, exp_idx;
-    unsigned long cert_list_len, cert_len;
-    X509 *x = NULL;
-    unsigned char *certstart, *certbytes;
-    STACK_OF(X509) *sk = NULL;
-    EVP_PKEY *pkey = NULL;
-
-    if ((sk = sk_X509_new_null()) == NULL) {
-        SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE, ERR_R_MALLOC_FAILURE);
-        goto err;
-    }
-
-    if (!PACKET_get_net_3(pkt, &cert_list_len)
-            || PACKET_remaining(pkt) != cert_list_len) {
-        al = SSL_AD_DECODE_ERROR;
-        SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE, SSL_R_LENGTH_MISMATCH);
-        goto f_err;
-    }
-    while (PACKET_remaining(pkt)) {
-        if (!PACKET_get_net_3(pkt, &cert_len)
-                || !PACKET_get_bytes(pkt, &certbytes, cert_len)) {
-            al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE,
-                   SSL_R_CERT_LENGTH_MISMATCH);
-            goto f_err;
-        }
-
-        certstart = certbytes;
-        x = d2i_X509(NULL, (const unsigned char **)&certbytes, cert_len);
-        if (x == NULL) {
-            al = SSL_AD_BAD_CERTIFICATE;
-            SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE, ERR_R_ASN1_LIB);
-            goto f_err;
-        }
-        if (certbytes != (certstart + cert_len)) {
-            al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE,
-                   SSL_R_CERT_LENGTH_MISMATCH);
-            goto f_err;
-        }
-        if (!sk_X509_push(sk, x)) {
-            SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE, ERR_R_MALLOC_FAILURE);
-            goto err;
-        }
-        x = NULL;
-    }
-
-    i = ssl_verify_cert_chain(s, sk);
-    if (s->verify_mode != SSL_VERIFY_NONE && i <= 0) {
-        al = ssl_verify_alarm_type(s->verify_result);
-        SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE,
-               SSL_R_CERTIFICATE_VERIFY_FAILED);
-        goto f_err;
-    }
-    ERR_clear_error();          /* but we keep s->verify_result */
-    if (i > 1) {
-        SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE, i);
-        al = SSL_AD_HANDSHAKE_FAILURE;
-        goto f_err;
-    }
-
-    s->session->peer_chain = sk;
-    /*
-     * Inconsistency alert: cert_chain does include the peer's certificate,
-     * which we don't include in s3_srvr.c
-     */
-    x = sk_X509_value(sk, 0);
-    sk = NULL;
-    /*
-     * VRS 19990621: possible memory leak; sk=null ==> !sk_pop_free() @end
-     */
-
-    pkey = X509_get_pubkey(x);
-
-    if (pkey == NULL || EVP_PKEY_missing_parameters(pkey)) {
-        x = NULL;
-        al = SSL3_AL_FATAL;
-        SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE,
-               SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS);
-        goto f_err;
-    }
-
-    i = ssl_cert_type(x, pkey);
-    if (i < 0) {
-        x = NULL;
-        al = SSL3_AL_FATAL;
-        SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE,
-               SSL_R_UNKNOWN_CERTIFICATE_TYPE);
-        goto f_err;
-    }
-
-    exp_idx = ssl_cipher_get_cert_index(s->s3->tmp.new_cipher);
-    if (exp_idx >= 0 && i != exp_idx) {
-        x = NULL;
-        al = SSL_AD_ILLEGAL_PARAMETER;
-        SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE,
-               SSL_R_WRONG_CERTIFICATE_TYPE);
-        goto f_err;
-    }
-    s->session->peer_type = i;
-
-    X509_free(s->session->peer);
-    X509_up_ref(x);
-    s->session->peer = x;
-    s->session->verify_result = s->verify_result;
-
-    x = NULL;
-    ret = MSG_PROCESS_CONTINUE_READING;
-    goto done;
-
- f_err:
-    ssl3_send_alert(s, SSL3_AL_FATAL, al);
- err:
-    statem_set_error(s);
- done:
-    EVP_PKEY_free(pkey);
-    X509_free(x);
-    sk_X509_pop_free(sk, X509_free);
-    return ret;
-}
-
-enum MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
-{
-#ifndef OPENSSL_NO_RSA
-    unsigned char *q, md_buf[EVP_MAX_MD_SIZE * 2];
-#endif
-    EVP_MD_CTX md_ctx;
-    int al, j, verify_ret;
-    long alg_k, alg_a;
-    EVP_PKEY *pkey = NULL;
-    const EVP_MD *md = NULL;
-#ifndef OPENSSL_NO_RSA
-    RSA *rsa = NULL;
-#endif
-#ifndef OPENSSL_NO_DH
-    DH *dh = NULL;
-#endif
-#ifndef OPENSSL_NO_EC
-    EC_KEY *ecdh = NULL;
-    BN_CTX *bn_ctx = NULL;
-    EC_POINT *srvr_ecpoint = NULL;
-    int curve_nid = 0;
-#endif
-    PACKET save_param_start, signature;
-
-    EVP_MD_CTX_init(&md_ctx);
-
-    alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
-
-    save_param_start = *pkt;
-
-#ifndef OPENSSL_NO_RSA
-    RSA_free(s->s3->peer_rsa_tmp);
-    s->s3->peer_rsa_tmp = NULL;
-#endif
-#ifndef OPENSSL_NO_DH
-    DH_free(s->s3->peer_dh_tmp);
-    s->s3->peer_dh_tmp = NULL;
-#endif
-#ifndef OPENSSL_NO_EC
-    EC_KEY_free(s->s3->peer_ecdh_tmp);
-    s->s3->peer_ecdh_tmp = NULL;
-#endif
-
-    alg_a = s->s3->tmp.new_cipher->algorithm_auth;
-
-    al = SSL_AD_DECODE_ERROR;
-
-#ifndef OPENSSL_NO_PSK
-    /* PSK ciphersuites are preceded by an identity hint */
-    if (alg_k & SSL_PSK) {
-        PACKET psk_identity_hint;
-        if (!PACKET_get_length_prefixed_2(pkt, &psk_identity_hint)) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
-            goto f_err;
-        }
-
-        /*
-         * Store PSK identity hint for later use, hint is used in
-         * ssl3_send_client_key_exchange.  Assume that the maximum length of
-         * a PSK identity hint can be as long as the maximum length of a PSK
-         * identity.
-         */
-        if (PACKET_remaining(&psk_identity_hint) > PSK_MAX_IDENTITY_LEN) {
-            al = SSL_AD_HANDSHAKE_FAILURE;
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_DATA_LENGTH_TOO_LONG);
-            goto f_err;
-        }
-
-        if (!PACKET_strndup(&psk_identity_hint,
-                            &s->session->psk_identity_hint)) {
-            al = SSL_AD_INTERNAL_ERROR;
-            goto f_err;
-        }
-    }
-
-    /* Nothing else to do for plain PSK or RSAPSK */
-    if (alg_k & (SSL_kPSK | SSL_kRSAPSK)) {
-    } else
-#endif                          /* !OPENSSL_NO_PSK */
-#ifndef OPENSSL_NO_SRP
-    if (alg_k & SSL_kSRP) {
-        PACKET prime, generator, salt, server_pub;
-        if (!PACKET_get_length_prefixed_2(pkt, &prime)
-            || !PACKET_get_length_prefixed_2(pkt, &generator)
-            || !PACKET_get_length_prefixed_1(pkt, &salt)
-            || !PACKET_get_length_prefixed_2(pkt, &server_pub)) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
-            goto f_err;
-        }
-
-        if ((s->srp_ctx.N =
-             BN_bin2bn(PACKET_data(&prime),
-                       PACKET_remaining(&prime), NULL)) == NULL
-            || (s->srp_ctx.g =
-                BN_bin2bn(PACKET_data(&generator),
-                          PACKET_remaining(&generator), NULL)) == NULL
-            || (s->srp_ctx.s =
-                BN_bin2bn(PACKET_data(&salt),
-                          PACKET_remaining(&salt), NULL)) == NULL
-            || (s->srp_ctx.B =
-                BN_bin2bn(PACKET_data(&server_pub),
-                          PACKET_remaining(&server_pub), NULL)) == NULL) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_BN_LIB);
-            goto err;
-        }
-
-        if (!srp_verify_server_param(s, &al)) {
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_BAD_SRP_PARAMETERS);
-            goto f_err;
-        }
-
-/* We must check if there is a certificate */
-        if (alg_a & (SSL_aRSA|SSL_aDSS))
-            pkey = X509_get_pubkey(s->session->peer);
-    } else
-#endif                          /* !OPENSSL_NO_SRP */
-#ifndef OPENSSL_NO_RSA
-    if (alg_k & SSL_kRSA) {
-        PACKET mod, exp;
-        /* Temporary RSA keys only allowed in export ciphersuites */
-        if (!SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)) {
-            al = SSL_AD_UNEXPECTED_MESSAGE;
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_UNEXPECTED_MESSAGE);
-            goto f_err;
-        }
-
-        if (!PACKET_get_length_prefixed_2(pkt, &mod)
-            || !PACKET_get_length_prefixed_2(pkt, &exp)) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
-            goto f_err;
-        }
-
-        if ((rsa = RSA_new()) == NULL) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
-            goto err;
-        }
-
-        if ((rsa->n = BN_bin2bn(PACKET_data(&mod), PACKET_remaining(&mod),
-                                rsa->n)) == NULL
-            || (rsa->e = BN_bin2bn(PACKET_data(&exp), PACKET_remaining(&exp),
-                                   rsa->e)) == NULL) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_BN_LIB);
-            goto err;
-        }
-
-        /* this should be because we are using an export cipher */
-        if (alg_a & SSL_aRSA)
-            pkey = X509_get_pubkey(s->session->peer);
-        else {
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
-
-        if (EVP_PKEY_bits(pkey) <= SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) {
-            al = SSL_AD_UNEXPECTED_MESSAGE;
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_UNEXPECTED_MESSAGE);
-            goto f_err;
-        }
-
-        s->s3->peer_rsa_tmp = rsa;
-        rsa = NULL;
-    }
-#else                           /* OPENSSL_NO_RSA */
-    if (0) ;
-#endif
-#ifndef OPENSSL_NO_DH
-    else if (alg_k & (SSL_kDHE | SSL_kDHEPSK)) {
-        PACKET prime, generator, pub_key;
-
-        if (!PACKET_get_length_prefixed_2(pkt, &prime)
-            || !PACKET_get_length_prefixed_2(pkt, &generator)
-            || !PACKET_get_length_prefixed_2(pkt, &pub_key)) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
-            goto f_err;
-        }
-
-        if ((dh = DH_new()) == NULL) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_DH_LIB);
-            goto err;
-        }
-
-        if ((dh->p = BN_bin2bn(PACKET_data(&prime),
-                               PACKET_remaining(&prime), NULL)) == NULL
-            || (dh->g = BN_bin2bn(PACKET_data(&generator),
-                                  PACKET_remaining(&generator), NULL)) == NULL
-            || (dh->pub_key =
-                BN_bin2bn(PACKET_data(&pub_key),
-                          PACKET_remaining(&pub_key), NULL)) == NULL) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_BN_LIB);
-            goto err;
-        }
-
-        if (BN_is_zero(dh->p) || BN_is_zero(dh->g) || BN_is_zero(dh->pub_key)) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_DH_VALUE);
-            goto f_err;
-        }
-
-        if (!ssl_security(s, SSL_SECOP_TMP_DH, DH_security_bits(dh), 0, dh)) {
-            al = SSL_AD_HANDSHAKE_FAILURE;
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_DH_KEY_TOO_SMALL);
-            goto f_err;
-        }
-        if (alg_a & (SSL_aRSA|SSL_aDSS))
-            pkey = X509_get_pubkey(s->session->peer);
-        /* else anonymous DH, so no certificate or pkey. */
-
-        s->s3->peer_dh_tmp = dh;
-        dh = NULL;
-    }
-#endif                          /* !OPENSSL_NO_DH */
-
-#ifndef OPENSSL_NO_EC
-    else if (alg_k & (SSL_kECDHE | SSL_kECDHEPSK)) {
-        EC_GROUP *ngroup;
-        const EC_GROUP *group;
-        PACKET encoded_pt;
-        unsigned char *ecparams;
-
-        if ((ecdh = EC_KEY_new()) == NULL) {
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
-            goto err;
-        }
-
-        /*
-         * Extract elliptic curve parameters and the server's ephemeral ECDH
-         * public key. For now we only support named (not generic) curves and
-         * ECParameters in this case is just three bytes.
-         */
-        if (!PACKET_get_bytes(pkt, &ecparams, 3)) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_TOO_SHORT);
-            goto f_err;
-        }
-        /*
-         * Check curve is one of our preferences, if not server has sent an
-         * invalid curve. ECParameters is 3 bytes.
-         */
-        if (!tls1_check_curve(s, ecparams, 3)) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_WRONG_CURVE);
-            goto f_err;
-        }
-
-        if ((curve_nid = tls1_ec_curve_id2nid(*(ecparams + 2))) == 0) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE,
-                   SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS);
-            goto f_err;
-        }
-
-        ngroup = EC_GROUP_new_by_curve_name(curve_nid);
-        if (ngroup == NULL) {
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_EC_LIB);
-            goto err;
-        }
-        if (EC_KEY_set_group(ecdh, ngroup) == 0) {
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_EC_LIB);
-            goto err;
-        }
-        EC_GROUP_free(ngroup);
-
-        group = EC_KEY_get0_group(ecdh);
-
-        if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) &&
-            (EC_GROUP_get_degree(group) > 163)) {
-            al = SSL_AD_EXPORT_RESTRICTION;
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE,
-                   SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER);
-            goto f_err;
-        }
-
-        /* Next, get the encoded ECPoint */
-        if (((srvr_ecpoint = EC_POINT_new(group)) == NULL) ||
-            ((bn_ctx = BN_CTX_new()) == NULL)) {
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
-            goto err;
-        }
-
-        if (!PACKET_get_length_prefixed_1(pkt, &encoded_pt)) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
-            goto f_err;
-        }
-
-        if (EC_POINT_oct2point(group, srvr_ecpoint, PACKET_data(&encoded_pt),
-                               PACKET_remaining(&encoded_pt), bn_ctx) == 0) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_ECPOINT);
-            goto f_err;
-        }
-
-        /*
-         * The ECC/TLS specification does not mention the use of DSA to sign
-         * ECParameters in the server key exchange message. We do support RSA
-         * and ECDSA.
-         */
-        if (0) ;
-# ifndef OPENSSL_NO_RSA
-        else if (alg_a & SSL_aRSA)
-            pkey = X509_get_pubkey(s->session->peer);
-# endif
-# ifndef OPENSSL_NO_EC
-        else if (alg_a & SSL_aECDSA)
-            pkey = X509_get_pubkey(s->session->peer);
-# endif
-        /* else anonymous ECDH, so no certificate or pkey. */
-        EC_KEY_set_public_key(ecdh, srvr_ecpoint);
-        s->s3->peer_ecdh_tmp = ecdh;
-        ecdh = NULL;
-        BN_CTX_free(bn_ctx);
-        bn_ctx = NULL;
-        EC_POINT_free(srvr_ecpoint);
-        srvr_ecpoint = NULL;
-    } else if (alg_k) {
-        al = SSL_AD_UNEXPECTED_MESSAGE;
-        SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_UNEXPECTED_MESSAGE);
-        goto f_err;
-    }
-#endif                          /* !OPENSSL_NO_EC */
-
-    /* if it was signed, check the signature */
-    if (pkey != NULL) {
-        PACKET params;
-        /*
-         * |pkt| now points to the beginning of the signature, so the difference
-         * equals the length of the parameters.
-         */
-        if (!PACKET_get_sub_packet(&save_param_start, &params,
-                                   PACKET_remaining(&save_param_start) -
-                                   PACKET_remaining(pkt))) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
-            goto f_err;
-        }
-
-        if (SSL_USE_SIGALGS(s)) {
-            unsigned char *sigalgs;
-            int rv;
-            if (!PACKET_get_bytes(pkt, &sigalgs, 2)) {
-                SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_TOO_SHORT);
-                goto f_err;
-            }
-            rv = tls12_check_peer_sigalg(&md, s, sigalgs, pkey);
-            if (rv == -1)
-                goto err;
-            else if (rv == 0) {
-                goto f_err;
-            }
-#ifdef SSL_DEBUG
-            fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md));
-#endif
-        } else {
-            md = EVP_sha1();
-        }
-
-        if (!PACKET_get_length_prefixed_2(pkt, &signature)
-            || PACKET_remaining(pkt) != 0) {
-            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
-            goto f_err;
-        }
-        j = EVP_PKEY_size(pkey);
-        if (j < 0) {
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
-            goto f_err;
-        }
-
-        /*
-         * Check signature length
-         */
-        if (PACKET_remaining(&signature) > (size_t)j) {
-            /* wrong packet length */
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_WRONG_SIGNATURE_LENGTH);
-            goto f_err;
-        }
-#ifndef OPENSSL_NO_RSA
-        if (pkey->type == EVP_PKEY_RSA && !SSL_USE_SIGALGS(s)) {
-            int num;
-            unsigned int size;
-
-            j = 0;
-            q = md_buf;
-            for (num = 2; num > 0; num--) {
-                EVP_MD_CTX_set_flags(&md_ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
-                EVP_DigestInit_ex(&md_ctx, (num == 2)
-                                  ? s->ctx->md5 : s->ctx->sha1, NULL);
-                EVP_DigestUpdate(&md_ctx, &(s->s3->client_random[0]),
-                                 SSL3_RANDOM_SIZE);
-                EVP_DigestUpdate(&md_ctx, &(s->s3->server_random[0]),
-                                 SSL3_RANDOM_SIZE);
-                EVP_DigestUpdate(&md_ctx, PACKET_data(&params),
-                                 PACKET_remaining(&params));
-                EVP_DigestFinal_ex(&md_ctx, q, &size);
-                q += size;
-                j += size;
-            }
-            verify_ret =
-                RSA_verify(NID_md5_sha1, md_buf, j, PACKET_data(&signature),
-                           PACKET_remaining(&signature), pkey->pkey.rsa);
-            if (verify_ret < 0) {
-                al = SSL_AD_DECRYPT_ERROR;
-                SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_BAD_RSA_DECRYPT);
-                goto f_err;
-            }
-            if (verify_ret == 0) {
-                /* bad signature */
-                al = SSL_AD_DECRYPT_ERROR;
-                SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_BAD_SIGNATURE);
-                goto f_err;
-            }
-        } else
-#endif
-        {
-            EVP_VerifyInit_ex(&md_ctx, md, NULL);
-            EVP_VerifyUpdate(&md_ctx, &(s->s3->client_random[0]),
-                             SSL3_RANDOM_SIZE);
-            EVP_VerifyUpdate(&md_ctx, &(s->s3->server_random[0]),
-                             SSL3_RANDOM_SIZE);
-            EVP_VerifyUpdate(&md_ctx, PACKET_data(&params),
-                             PACKET_remaining(&params));
-            if (EVP_VerifyFinal(&md_ctx, PACKET_data(&signature),
-                                PACKET_remaining(&signature), pkey) <= 0) {
-                /* bad signature */
-                al = SSL_AD_DECRYPT_ERROR;
-                SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_BAD_SIGNATURE);
-                goto f_err;
-            }
-        }
-    } else {
-        /* aNULL, aSRP or PSK do not need public keys */
-        if (!(alg_a & (SSL_aNULL | SSL_aSRP)) && !(alg_k & SSL_PSK)) {
-            /* Might be wrong key type, check it */
-            if (ssl3_check_cert_and_algorithm(s))
-                /* Otherwise this shouldn't happen */
-                SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
-        /* still data left over */
-        if (PACKET_remaining(pkt) != 0) {
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_EXTRA_DATA_IN_MESSAGE);
-            goto f_err;
-        }
-    }
-    EVP_PKEY_free(pkey);
-    EVP_MD_CTX_cleanup(&md_ctx);
-    return MSG_PROCESS_CONTINUE_READING;
- f_err:
-    ssl3_send_alert(s, SSL3_AL_FATAL, al);
- err:
-    EVP_PKEY_free(pkey);
-#ifndef OPENSSL_NO_RSA
-    RSA_free(rsa);
-#endif
-#ifndef OPENSSL_NO_DH
-    DH_free(dh);
-#endif
-#ifndef OPENSSL_NO_EC
-    BN_CTX_free(bn_ctx);
-    EC_POINT_free(srvr_ecpoint);
-    EC_KEY_free(ecdh);
-#endif
-    EVP_MD_CTX_cleanup(&md_ctx);
-    statem_set_error(s);
-    return MSG_PROCESS_ERROR;
-}
-
-enum MSG_PROCESS_RETURN tls_process_certificate_request(SSL *s, PACKET *pkt)
-{
-    int ret = MSG_PROCESS_ERROR;
-    unsigned int list_len, ctype_num, i, name_len;
-    X509_NAME *xn = NULL;
-    unsigned char *data;
-    unsigned char *namestart, *namebytes;
-    STACK_OF(X509_NAME) *ca_sk = NULL;
-
-    if ((ca_sk = sk_X509_NAME_new(ca_dn_cmp)) == NULL) {
-        SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, ERR_R_MALLOC_FAILURE);
-        goto err;
-    }
-
-    /* get the certificate types */
-    if (!PACKET_get_1(pkt, &ctype_num)
-            || !PACKET_get_bytes(pkt, &data, ctype_num)) {
-        ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-        SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, SSL_R_LENGTH_MISMATCH);
-        goto err;
-    }
-    OPENSSL_free(s->cert->ctypes);
-    s->cert->ctypes = NULL;
-    if (ctype_num > SSL3_CT_NUMBER) {
-        /* If we exceed static buffer copy all to cert structure */
-        s->cert->ctypes = OPENSSL_malloc(ctype_num);
-        if (s->cert->ctypes == NULL) {
-            SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, ERR_R_MALLOC_FAILURE);
-            goto err;
-        }
-        memcpy(s->cert->ctypes, data, ctype_num);
-        s->cert->ctype_num = (size_t)ctype_num;
-        ctype_num = SSL3_CT_NUMBER;
-    }
-    for (i = 0; i < ctype_num; i++)
-        s->s3->tmp.ctype[i] = data[i];
-
-    if (SSL_USE_SIGALGS(s)) {
-        if (!PACKET_get_net_2(pkt, &list_len)
-                || !PACKET_get_bytes(pkt, &data, list_len)) {
-            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-            SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST,
-                   SSL_R_LENGTH_MISMATCH);
-            goto err;
-        }
-
-        /* Clear certificate digests and validity flags */
-        for (i = 0; i < SSL_PKEY_NUM; i++) {
-            s->s3->tmp.md[i] = NULL;
-            s->s3->tmp.valid_flags[i] = 0;
-        }
-        if ((list_len & 1) || !tls1_save_sigalgs(s, data, list_len)) {
-            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-            SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST,
-                   SSL_R_SIGNATURE_ALGORITHMS_ERROR);
-            goto err;
-        }
-        if (!tls1_process_sigalgs(s)) {
-            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
-            SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, ERR_R_MALLOC_FAILURE);
-            goto err;
-        }
-    }
-
-    /* get the CA RDNs */
-    if (!PACKET_get_net_2(pkt, &list_len)
-            || PACKET_remaining(pkt) != list_len) {
-        ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-        SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, SSL_R_LENGTH_MISMATCH);
-        goto err;
-    }
-
-    while (PACKET_remaining(pkt)) {
-        if (!PACKET_get_net_2(pkt, &name_len)
-                || !PACKET_get_bytes(pkt, &namebytes, name_len)) {
-            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-            SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST,
-                   SSL_R_LENGTH_MISMATCH);
-            goto err;
-        }
-
-        namestart = namebytes;
-
-        if ((xn = d2i_X509_NAME(NULL, (const unsigned char **)&namebytes,
-                                name_len)) == NULL) {
-            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-            SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, ERR_R_ASN1_LIB);
-            goto err;
-        }
-
-        if (namebytes != (namestart + name_len)) {
-            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-            SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST,
-                   SSL_R_CA_DN_LENGTH_MISMATCH);
-            goto err;
-        }
-        if (!sk_X509_NAME_push(ca_sk, xn)) {
-            SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, ERR_R_MALLOC_FAILURE);
-            goto err;
-        }
-    }
-
-    /* we should setup a certificate to return.... */
-    s->s3->tmp.cert_req = 1;
-    s->s3->tmp.ctype_num = ctype_num;
-    sk_X509_NAME_pop_free(s->s3->tmp.ca_names, X509_NAME_free);
-    s->s3->tmp.ca_names = ca_sk;
-    ca_sk = NULL;
-
-    ret = MSG_PROCESS_CONTINUE_READING;
-    goto done;
- err:
-    statem_set_error(s);
- done:
-    sk_X509_NAME_pop_free(ca_sk, X509_NAME_free);
-    return ret;
-}
-
-static int ca_dn_cmp(const X509_NAME *const *a, const X509_NAME *const *b)
-{
-    return (X509_NAME_cmp(*a, *b));
-}
-
-enum MSG_PROCESS_RETURN tls_process_new_session_ticket(SSL *s, PACKET *pkt)
-{
-    int al;
-    unsigned int ticklen;
-    unsigned long ticket_lifetime_hint;
-
-    if (!PACKET_get_net_4(pkt, &ticket_lifetime_hint)
-            || !PACKET_get_net_2(pkt, &ticklen)
-            || PACKET_remaining(pkt) != ticklen) {
-        al = SSL_AD_DECODE_ERROR;
-        SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET, SSL_R_LENGTH_MISMATCH);
-        goto f_err;
-    }
-
-    /* Server is allowed to change its mind and send an empty ticket. */
-    if (ticklen == 0)
-        return 1;
-
-    if (s->session->session_id_length > 0) {
-        int i = s->session_ctx->session_cache_mode;
-        SSL_SESSION *new_sess;
-        /*
-         * We reused an existing session, so we need to replace it with a new
-         * one
-         */
-        if (i & SSL_SESS_CACHE_CLIENT) {
-            /*
-             * Remove the old session from the cache
-             */
-            if (i & SSL_SESS_CACHE_NO_INTERNAL_STORE) {
-                if (s->session_ctx->remove_session_cb != NULL)
-                    s->session_ctx->remove_session_cb(s->session_ctx,
-                                                      s->session);
-            } else {
-                /* We carry on if this fails */
-                SSL_CTX_remove_session(s->session_ctx, s->session);
-            }
-        }
-
-        if ((new_sess = ssl_session_dup(s->session, 0)) == 0) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_NEW_SESSION_TICKET, ERR_R_MALLOC_FAILURE);
-            goto f_err;
-        }
-
-        SSL_SESSION_free(s->session);
-        s->session = new_sess;
-    }
-
-    OPENSSL_free(s->session->tlsext_tick);
-    s->session->tlsext_ticklen = 0;
-
-    s->session->tlsext_tick = OPENSSL_malloc(ticklen);
-    if (!s->session->tlsext_tick) {
-        SSLerr(SSL_F_TLS_PROCESS_NEW_SESSION_TICKET, ERR_R_MALLOC_FAILURE);
-        goto err;
-    }
-    if (!PACKET_copy_bytes(pkt, s->session->tlsext_tick, ticklen)) {
-        al = SSL_AD_DECODE_ERROR;
-        SSLerr(SSL_F_TLS_PROCESS_NEW_SESSION_TICKET, SSL_R_LENGTH_MISMATCH);
-        goto f_err;
-    }
-
-    s->session->tlsext_tick_lifetime_hint = ticket_lifetime_hint;
-    s->session->tlsext_ticklen = ticklen;
-    /*
-     * There are two ways to detect a resumed ticket session. 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(s->session->tlsext_tick, ticklen,
-               s->session->session_id, &s->session->session_id_length,
-               EVP_sha256(), NULL);
-    return MSG_PROCESS_CONTINUE_READING;
- f_err:
-    ssl3_send_alert(s, SSL3_AL_FATAL, al);
- err:
-    statem_set_error(s);
-    return MSG_PROCESS_ERROR;
-}
-
-enum MSG_PROCESS_RETURN tls_process_cert_status(SSL *s, PACKET *pkt)
-{
-    int al;
-    unsigned long resplen;
-    unsigned int type;
-
-    if (!PACKET_get_1(pkt, &type)
-            || type != TLSEXT_STATUSTYPE_ocsp) {
-        al = SSL_AD_DECODE_ERROR;
-        SSLerr(SSL_F_TLS_PROCESS_CERT_STATUS, SSL_R_UNSUPPORTED_STATUS_TYPE);
-        goto f_err;
-    }
-    if (!PACKET_get_net_3(pkt, &resplen)
-            || PACKET_remaining(pkt) != resplen) {
-        al = SSL_AD_DECODE_ERROR;
-        SSLerr(SSL_F_TLS_PROCESS_CERT_STATUS, SSL_R_LENGTH_MISMATCH);
-        goto f_err;
-    }
-    OPENSSL_free(s->tlsext_ocsp_resp);
-    s->tlsext_ocsp_resp = OPENSSL_malloc(resplen);
-    if (!s->tlsext_ocsp_resp) {
-        al = SSL_AD_INTERNAL_ERROR;
-        SSLerr(SSL_F_TLS_PROCESS_CERT_STATUS, ERR_R_MALLOC_FAILURE);
-        goto f_err;
-    }
-    if (!PACKET_copy_bytes(pkt, s->tlsext_ocsp_resp, resplen)) {
-        al = SSL_AD_DECODE_ERROR;
-        SSLerr(SSL_F_TLS_PROCESS_CERT_STATUS, SSL_R_LENGTH_MISMATCH);
-        goto f_err;
-    }
-    s->tlsext_ocsp_resplen = resplen;
-    if (s->ctx->tlsext_status_cb) {
-        int ret;
-        ret = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
-        if (ret == 0) {
-            al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE;
-            SSLerr(SSL_F_TLS_PROCESS_CERT_STATUS, SSL_R_INVALID_STATUS_RESPONSE);
-            goto f_err;
-        }
-        if (ret < 0) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_CERT_STATUS, ERR_R_MALLOC_FAILURE);
-            goto f_err;
-        }
-    }
-    return MSG_PROCESS_CONTINUE_READING;
- f_err:
-    ssl3_send_alert(s, SSL3_AL_FATAL, al);
-    statem_set_error(s);
-    return MSG_PROCESS_ERROR;
-}
-
-enum MSG_PROCESS_RETURN tls_process_server_done(SSL *s, PACKET *pkt)
-{
-    if (PACKET_remaining(pkt) > 0) {
-        /* should contain no data */
-        ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
-        SSLerr(SSL_F_TLS_PROCESS_SERVER_DONE, SSL_R_LENGTH_MISMATCH);
-        statem_set_error(s);
-        return MSG_PROCESS_ERROR;
-    }
-
-#ifndef OPENSSL_NO_SRP
-    if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP) {
-        if (SRP_Calc_A_param(s) <= 0) {
-            SSLerr(SSL_F_TLS_PROCESS_SERVER_DONE, SSL_R_SRP_A_CALC);
-            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
-            statem_set_error(s);
-            return MSG_PROCESS_ERROR;
-        }
-    }
-#endif
-
-#ifndef OPENSSL_NO_SCTP
-    /* Only applies to renegotiation */
-    if (SSL_IS_DTLS(s) && BIO_dgram_is_sctp(SSL_get_wbio(s))
-            && s->renegotiate != 0)
-        return MSG_PROCESS_CONTINUE_PROCESSING;
-    else
-#endif
-        return MSG_PROCESS_FINISHED_READING;
-}
-
-int tls_construct_client_key_exchange(SSL *s)
-{
-    unsigned char *p;
-    int n;
-#ifndef OPENSSL_NO_PSK
-    size_t pskhdrlen = 0;
-#endif
-    unsigned long alg_k;
-#ifndef OPENSSL_NO_RSA
-    unsigned char *q;
-    EVP_PKEY *pkey = NULL;
-#endif
-#ifndef OPENSSL_NO_EC
-    EC_KEY *clnt_ecdh = NULL;
-    const EC_POINT *srvr_ecpoint = NULL;
-    EVP_PKEY *srvr_pub_pkey = NULL;
-    unsigned char *encodedPoint = NULL;
-    int encoded_pt_len = 0;
-    BN_CTX *bn_ctx = NULL;
-#endif
-    unsigned char *pms = NULL;
-    size_t pmslen = 0;
-    alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
-
-    p = ssl_handshake_start(s);
-
-
-#ifndef OPENSSL_NO_PSK
-    if (alg_k & SSL_PSK) {
-        int psk_err = 1;
-        /*
-         * The callback needs PSK_MAX_IDENTITY_LEN + 1 bytes to return a
-         * \0-terminated identity. The last byte is for us for simulating
-         * strnlen.
-         */
-        char identity[PSK_MAX_IDENTITY_LEN + 1];
-        size_t identitylen;
-        unsigned char psk[PSK_MAX_PSK_LEN];
-        size_t psklen;
-
-        if (s->psk_client_callback == NULL) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                   SSL_R_PSK_NO_CLIENT_CB);
-            goto err;
-        }
-
-        memset(identity, 0, sizeof(identity));
-
-        psklen = s->psk_client_callback(s, s->session->psk_identity_hint,
-                                        identity, sizeof(identity) - 1,
-                                        psk, sizeof(psk));
-
-        if (psklen > PSK_MAX_PSK_LEN) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                   ERR_R_INTERNAL_ERROR);
-            goto psk_err;
-        } else if (psklen == 0) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                   SSL_R_PSK_IDENTITY_NOT_FOUND);
-            goto psk_err;
-        }
-
-        OPENSSL_free(s->s3->tmp.psk);
-        s->s3->tmp.psk = BUF_memdup(psk, psklen);
-        OPENSSL_cleanse(psk, psklen);
-
-        if (s->s3->tmp.psk == NULL) {
-            OPENSSL_cleanse(identity, sizeof(identity));
-            goto memerr;
-        }
-
-        s->s3->tmp.psklen = psklen;
-
-        identitylen = strlen(identity);
-        if (identitylen > PSK_MAX_IDENTITY_LEN) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                   ERR_R_INTERNAL_ERROR);
-            goto psk_err;
-        }
-        OPENSSL_free(s->session->psk_identity);
-        s->session->psk_identity = BUF_strdup(identity);
-        if (s->session->psk_identity == NULL) {
-            OPENSSL_cleanse(identity, sizeof(identity));
-            goto memerr;
-        }
-
-        s2n(identitylen, p);
-        memcpy(p, identity, identitylen);
-        pskhdrlen = 2 + identitylen;
-        p += identitylen;
-        psk_err = 0;
-psk_err:
-        OPENSSL_cleanse(identity, sizeof(identity));
-        if (psk_err != 0) {
-            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
-            goto err;
-        }
-    }
-    if (alg_k & SSL_kPSK) {
-        n = 0;
-    } else
-#endif
-
-    /* Fool emacs indentation */
-    if (0) {
-    }
-#ifndef OPENSSL_NO_RSA
-    else if (alg_k & (SSL_kRSA | SSL_kRSAPSK)) {
-        RSA *rsa;
-        pmslen = SSL_MAX_MASTER_KEY_LENGTH;
-        pms = OPENSSL_malloc(pmslen);
-        if (!pms)
-            goto memerr;
-
-        if (s->session->peer == NULL) {
-            /*
-             * We should always have a server certificate with SSL_kRSA.
-             */
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                   ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
-
-        if (s->s3->peer_rsa_tmp != NULL)
-            rsa = s->s3->peer_rsa_tmp;
-        else {
-            pkey = X509_get_pubkey(s->session->peer);
-            if ((pkey == NULL) || (pkey->type != EVP_PKEY_RSA)
-                || (pkey->pkey.rsa == NULL)) {
-                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                       ERR_R_INTERNAL_ERROR);
-                EVP_PKEY_free(pkey);
-                goto err;
-            }
-            rsa = pkey->pkey.rsa;
-            EVP_PKEY_free(pkey);
-        }
-
-        pms[0] = s->client_version >> 8;
-        pms[1] = s->client_version & 0xff;
-        if (RAND_bytes(pms + 2, pmslen - 2) <= 0)
-            goto err;
-
-        q = p;
-        /* Fix buf for TLS and beyond */
-        if (s->version > SSL3_VERSION)
-            p += 2;
-        n = RSA_public_encrypt(pmslen, pms, p, rsa, RSA_PKCS1_PADDING);
-# ifdef PKCS1_CHECK
-        if (s->options & SSL_OP_PKCS1_CHECK_1)
-            p[1]++;
-        if (s->options & SSL_OP_PKCS1_CHECK_2)
-            tmp_buf[0] = 0x70;
-# endif
-        if (n <= 0) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                   SSL_R_BAD_RSA_ENCRYPT);
-            goto err;
-        }
-
-        /* Fix buf for TLS and beyond */
-        if (s->version > SSL3_VERSION) {
-            s2n(n, q);
-            n += 2;
-        }
-    }
-#endif
-#ifndef OPENSSL_NO_DH
-    else if (alg_k & (SSL_kDHE | SSL_kDHr | SSL_kDHd | SSL_kDHEPSK)) {
-        DH *dh_srvr, *dh_clnt;
-        if (s->s3->peer_dh_tmp != NULL)
-            dh_srvr = s->s3->peer_dh_tmp;
-        else {
-            /* we get them from the cert */
-            EVP_PKEY *spkey = NULL;
-            dh_srvr = NULL;
-            spkey = X509_get_pubkey(s->session->peer);
-            if (spkey) {
-                dh_srvr = EVP_PKEY_get1_DH(spkey);
-                EVP_PKEY_free(spkey);
-            }
-            if (dh_srvr == NULL) {
-                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                       ERR_R_INTERNAL_ERROR);
-                goto err;
-            }
-        }
-        if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY) {
-            /* Use client certificate key */
-            EVP_PKEY *clkey = s->cert->key->privatekey;
-            dh_clnt = NULL;
-            if (clkey)
-                dh_clnt = EVP_PKEY_get1_DH(clkey);
-            if (dh_clnt == NULL) {
-                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                       ERR_R_INTERNAL_ERROR);
-                goto err;
-            }
-        } else {
-            /* generate a new random key */
-            if ((dh_clnt = DHparams_dup(dh_srvr)) == NULL) {
-                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB);
-                goto err;
-            }
-            if (!DH_generate_key(dh_clnt)) {
-                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB);
-                DH_free(dh_clnt);
-                goto err;
-            }
-        }
-
-        pmslen = DH_size(dh_clnt);
-        pms = OPENSSL_malloc(pmslen);
-        if (!pms)
-            goto memerr;
-
-        /*
-         * use the 'p' output buffer for the DH key, but make sure to
-         * clear it out afterwards
-         */
-
-        n = DH_compute_key(pms, dh_srvr->pub_key, dh_clnt);
-        if (s->s3->peer_dh_tmp == NULL)
-            DH_free(dh_srvr);
-
-        if (n <= 0) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB);
-            DH_free(dh_clnt);
-            goto err;
-        }
-        pmslen = n;
-
-        if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY)
-            n = 0;
-        else {
-            /* send off the data */
-            n = BN_num_bytes(dh_clnt->pub_key);
-            s2n(n, p);
-            BN_bn2bin(dh_clnt->pub_key, p);
-            n += 2;
-        }
-
-        DH_free(dh_clnt);
-    }
-#endif
-
-#ifndef OPENSSL_NO_EC
-    else if (alg_k & (SSL_kECDHE | SSL_kECDHr | SSL_kECDHe | SSL_kECDHEPSK)) {
-        const EC_GROUP *srvr_group = NULL;
-        EC_KEY *tkey;
-        int ecdh_clnt_cert = 0;
-        int field_size = 0;
-        /*
-         * Did we send out the client's ECDH share for use in premaster
-         * computation as part of client certificate? If so, set
-         * ecdh_clnt_cert to 1.
-         */
-        if ((alg_k & (SSL_kECDHr | SSL_kECDHe)) && (s->cert != NULL)) {
-            /*-
-             * XXX: For now, we do not support client
-             * authentication using ECDH certificates.
-             * To add such support, one needs to add
-             * code that checks for appropriate
-             * conditions and sets ecdh_clnt_cert to 1.
-             * For example, the cert have an ECC
-             * key on the same curve as the server's
-             * and the key should be authorized for
-             * key agreement.
-             *
-             * One also needs to add code in ssl3_connect
-             * to skip sending the certificate verify
-             * message.
-             *
-             * if ((s->cert->key->privatekey != NULL) &&
-             *     (s->cert->key->privatekey->type ==
-             *      EVP_PKEY_EC) && ...)
-             * ecdh_clnt_cert = 1;
-             */
-        }
-
-        if (s->s3->peer_ecdh_tmp != NULL) {
-            tkey = s->s3->peer_ecdh_tmp;
-        } else {
-            /* Get the Server Public Key from Cert */
-            srvr_pub_pkey = X509_get_pubkey(s->session->peer);
-            if ((srvr_pub_pkey == NULL)
-                || (srvr_pub_pkey->type != EVP_PKEY_EC)
-                || (srvr_pub_pkey->pkey.ec == NULL)) {
-                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                       ERR_R_INTERNAL_ERROR);
-                goto err;
-            }
-
-            tkey = srvr_pub_pkey->pkey.ec;
-        }
-
-        srvr_group = EC_KEY_get0_group(tkey);
-        srvr_ecpoint = EC_KEY_get0_public_key(tkey);
-
-        if ((srvr_group == NULL) || (srvr_ecpoint == NULL)) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                   ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
-
-        if ((clnt_ecdh = EC_KEY_new()) == NULL) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                   ERR_R_MALLOC_FAILURE);
-            goto err;
-        }
-
-        if (!EC_KEY_set_group(clnt_ecdh, srvr_group)) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
-            goto err;
-        }
-        if (ecdh_clnt_cert) {
-            /*
-             * Reuse key info from our certificate We only need our
-             * private key to perform the ECDH computation.
-             */
-            const BIGNUM *priv_key;
-            tkey = s->cert->key->privatekey->pkey.ec;
-            priv_key = EC_KEY_get0_private_key(tkey);
-            if (priv_key == NULL) {
-                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                       ERR_R_MALLOC_FAILURE);
-                goto err;
-            }
-            if (!EC_KEY_set_private_key(clnt_ecdh, priv_key)) {
-                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
-                goto err;
-            }
-        } else {
-            /* Generate a new ECDH key pair */
-            if (!(EC_KEY_generate_key(clnt_ecdh))) {
-                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                       ERR_R_ECDH_LIB);
-                goto err;
-            }
-        }
-
-        /*
-         * use the 'p' output buffer for the ECDH key, but make sure to
-         * clear it out afterwards
-         */
-
-        field_size = EC_GROUP_get_degree(srvr_group);
-        if (field_size <= 0) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
-            goto err;
-        }
-        pmslen = (field_size + 7) / 8;
-        pms = OPENSSL_malloc(pmslen);
-        if (!pms)
-            goto memerr;
-        n = ECDH_compute_key(pms, pmslen, srvr_ecpoint, clnt_ecdh, NULL);
-        if (n <= 0 || pmslen != (size_t)n) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
-            goto err;
-        }
-
-        if (ecdh_clnt_cert) {
-            /* Send empty client key exch message */
-            n = 0;
-        } else {
-            /*
-             * First check the size of encoding and allocate memory
-             * accordingly.
-             */
-            encoded_pt_len =
-                EC_POINT_point2oct(srvr_group,
-                                   EC_KEY_get0_public_key(clnt_ecdh),
-                                   POINT_CONVERSION_UNCOMPRESSED,
-                                   NULL, 0, NULL);
-
-            encodedPoint = (unsigned char *)
-                OPENSSL_malloc(encoded_pt_len * sizeof(unsigned char));
-            bn_ctx = BN_CTX_new();
-            if ((encodedPoint == NULL) || (bn_ctx == NULL)) {
-                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                       ERR_R_MALLOC_FAILURE);
-                goto err;
-            }
-
-            /* Encode the public key */
-            n = EC_POINT_point2oct(srvr_group,
-                                   EC_KEY_get0_public_key(clnt_ecdh),
-                                   POINT_CONVERSION_UNCOMPRESSED,
-                                   encodedPoint, encoded_pt_len, bn_ctx);
-
-            *p = n;         /* length of encoded point */
-            /* Encoded point will be copied here */
-            p += 1;
-            /* copy the point */
-            memcpy(p, encodedPoint, n);
-            /* increment n to account for length field */
-            n += 1;
-        }
-
-        /* Free allocated memory */
-        BN_CTX_free(bn_ctx);
-        OPENSSL_free(encodedPoint);
-        EC_KEY_free(clnt_ecdh);
-        EVP_PKEY_free(srvr_pub_pkey);
-    }
-#endif                          /* !OPENSSL_NO_EC */
-    else if (alg_k & SSL_kGOST) {
-        /* GOST key exchange message creation */
-        EVP_PKEY_CTX *pkey_ctx;
-        X509 *peer_cert;
-        size_t msglen;
-        unsigned int md_len;
-        unsigned char shared_ukm[32], tmp[256];
-        EVP_MD_CTX *ukm_hash;
-        EVP_PKEY *pub_key;
-
-        pmslen = 32;
-        pms = OPENSSL_malloc(pmslen);
-        if (!pms)
-            goto memerr;
-
-        /*
-         * Get server sertificate PKEY and create ctx from it
-         */
-        peer_cert = s->session->peer;
-        if (!peer_cert) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                   SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER);
-            goto err;
-        }
-
-        pkey_ctx = EVP_PKEY_CTX_new(pub_key =
-                                    X509_get_pubkey(peer_cert), NULL);
-        /*
-         * If we have send a certificate, and certificate key
-         *
-         * * parameters match those of server certificate, use
-         * certificate key for key exchange
-         */
-
-        /* Otherwise, generate ephemeral key pair */
-
-        EVP_PKEY_encrypt_init(pkey_ctx);
-        /* Generate session key */
-        if (RAND_bytes(pms, pmslen) <= 0) {
-            EVP_PKEY_CTX_free(pkey_ctx);
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                   ERR_R_INTERNAL_ERROR);
-            goto err;
-        };
-        /*
-         * If we have client certificate, use its secret as peer key
-         */
-        if (s->s3->tmp.cert_req && s->cert->key->privatekey) {
-            if (EVP_PKEY_derive_set_peer
-                (pkey_ctx, s->cert->key->privatekey) <= 0) {
-                /*
-                 * If there was an error - just ignore it. Ephemeral key
-                 * * would be used
-                 */
-                ERR_clear_error();
-            }
-        }
-        /*
-         * Compute shared IV and store it in algorithm-specific context
-         * data
-         */
-        ukm_hash = EVP_MD_CTX_create();
-        EVP_DigestInit(ukm_hash,
-                       EVP_get_digestbynid(NID_id_GostR3411_94));
-        EVP_DigestUpdate(ukm_hash, s->s3->client_random,
-                         SSL3_RANDOM_SIZE);
-        EVP_DigestUpdate(ukm_hash, s->s3->server_random,
-                         SSL3_RANDOM_SIZE);
-        EVP_DigestFinal_ex(ukm_hash, shared_ukm, &md_len);
-        EVP_MD_CTX_destroy(ukm_hash);
-        if (EVP_PKEY_CTX_ctrl
-            (pkey_ctx, -1, EVP_PKEY_OP_ENCRYPT, EVP_PKEY_CTRL_SET_IV, 8,
-             shared_ukm) < 0) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                   SSL_R_LIBRARY_BUG);
-            goto err;
-        }
-        /* Make GOST keytransport blob message */
-        /*
-         * Encapsulate it into sequence
-         */
-        *(p++) = V_ASN1_SEQUENCE | V_ASN1_CONSTRUCTED;
-        msglen = 255;
-        if (EVP_PKEY_encrypt(pkey_ctx, tmp, &msglen, pms, pmslen) < 0) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                   SSL_R_LIBRARY_BUG);
-            goto err;
-        }
-        if (msglen >= 0x80) {
-            *(p++) = 0x81;
-            *(p++) = msglen & 0xff;
-            n = msglen + 3;
-        } else {
-            *(p++) = msglen & 0xff;
-            n = msglen + 2;
-        }
-        memcpy(p, tmp, msglen);
-        /* Check if pubkey from client certificate was used */
-        if (EVP_PKEY_CTX_ctrl
-            (pkey_ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 2, NULL) > 0) {
-            /* Set flag "skip certificate verify" */
-            s->s3->flags |= TLS1_FLAGS_SKIP_CERT_VERIFY;
-        }
-        EVP_PKEY_CTX_free(pkey_ctx);
-        EVP_PKEY_free(pub_key);
-
-    }
-#ifndef OPENSSL_NO_SRP
-    else if (alg_k & SSL_kSRP) {
-        if (s->srp_ctx.A != NULL) {
-            /* send off the data */
-            n = BN_num_bytes(s->srp_ctx.A);
-            s2n(n, p);
-            BN_bn2bin(s->srp_ctx.A, p);
-            n += 2;
-        } else {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                   ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
-        OPENSSL_free(s->session->srp_username);
-        s->session->srp_username = BUF_strdup(s->srp_ctx.login);
-        if (s->session->srp_username == NULL) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
-                   ERR_R_MALLOC_FAILURE);
-            goto err;
-        }
-    }
-#endif
-    else {
-        ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
-        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
-        goto err;
-    }
-
-#ifndef OPENSSL_NO_PSK
-    n += pskhdrlen;
-#endif
-
-    if (!ssl_set_handshake_header(s, SSL3_MT_CLIENT_KEY_EXCHANGE, n)) {
-        ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
-        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
-        goto err;
-    }
-
-    s->s3->tmp.pms = pms;
-    s->s3->tmp.pmslen = pmslen;
-
-    return 1;
- memerr:
-    ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
-    SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
- err:
-    OPENSSL_clear_free(pms, pmslen);
-    s->s3->tmp.pms = NULL;
-#ifndef OPENSSL_NO_EC
-    BN_CTX_free(bn_ctx);
-    OPENSSL_free(encodedPoint);
-    EC_KEY_free(clnt_ecdh);
-    EVP_PKEY_free(srvr_pub_pkey);
-#endif
-#ifndef OPENSSL_NO_PSK
-    OPENSSL_clear_free(s->s3->tmp.psk, s->s3->tmp.psklen);
-    s->s3->tmp.psk = NULL;
-#endif
-    statem_set_error(s);
-    return 0;
-}
-
-int tls_client_key_exchange_post_work(SSL *s)
-{
-    unsigned char *pms = NULL;
-    size_t pmslen = 0;
-
-#ifndef OPENSSL_NO_SRP
-    /* Check for SRP */
-    if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP) {
-        if (!srp_generate_client_master_secret(s)) {
-            SSLerr(SSL_F_TLS_CLIENT_KEY_EXCHANGE_POST_WORK,
-                   ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
-        return 1;
-    }
-#endif
-    pms = s->s3->tmp.pms;
-    pmslen = s->s3->tmp.pmslen;
-
-    if (pms == NULL && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) {
-        ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
-        SSLerr(SSL_F_TLS_CLIENT_KEY_EXCHANGE_POST_WORK, ERR_R_MALLOC_FAILURE);
-        goto err;
-    }
-    if (!ssl_generate_master_secret(s, pms, pmslen, 1)) {
-        ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
-        SSLerr(SSL_F_TLS_CLIENT_KEY_EXCHANGE_POST_WORK, ERR_R_INTERNAL_ERROR);
-        goto err;
-    }
-
-#ifndef OPENSSL_NO_SCTP
-    if (SSL_IS_DTLS(s)) {
-        unsigned char sctpauthkey[64];
-        char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
-
-        /*
-         * Add new shared key for SCTP-Auth, will be ignored if no SCTP
-         * used.
-         */
-        snprintf((char *)labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL),
-                 DTLS1_SCTP_AUTH_LABEL);
-
-        if (SSL_export_keying_material(s, sctpauthkey,
-                                   sizeof(sctpauthkey), labelbuffer,
-                                   sizeof(labelbuffer), NULL, 0, 0) <= 0)
-            goto err;
-
-        BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
-                 sizeof(sctpauthkey), sctpauthkey);
-    }
-#endif
-
-    return 1;
- err:
-    OPENSSL_clear_free(pms, pmslen);
-    s->s3->tmp.pms = NULL;
-    return 0;
-}
-
-int tls_construct_client_verify(SSL *s)
-{
-    unsigned char *p;
-    unsigned char data[MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH];
-    EVP_PKEY *pkey;
-    EVP_PKEY_CTX *pctx = NULL;
-    EVP_MD_CTX mctx;
-    unsigned u = 0;
-    unsigned long n;
-    int j;
-
-    EVP_MD_CTX_init(&mctx);
-
-    p = ssl_handshake_start(s);
-    pkey = s->cert->key->privatekey;
-/* Create context from key and test if sha1 is allowed as digest */
-    pctx = EVP_PKEY_CTX_new(pkey, NULL);
-    EVP_PKEY_sign_init(pctx);
-    if (EVP_PKEY_CTX_set_signature_md(pctx, EVP_sha1()) > 0) {
-        if (!SSL_USE_SIGALGS(s))
-            s->method->ssl3_enc->cert_verify_mac(s,
-                                                 NID_sha1,
-                                                 &(data
-                                                   [MD5_DIGEST_LENGTH]));
-    } else {
-        ERR_clear_error();
-    }
-    /*
-     * For TLS v1.2 send signature algorithm and signature using agreed
-     * digest and cached handshake records.
-     */
-    if (SSL_USE_SIGALGS(s)) {
-        long hdatalen = 0;
-        void *hdata;
-        const EVP_MD *md = s->s3->tmp.md[s->cert->key - s->cert->pkeys];
-        hdatalen = BIO_get_mem_data(s->s3->handshake_buffer, &hdata);
-        if (hdatalen <= 0 || !tls12_get_sigandhash(p, pkey, md)) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
-        p += 2;
-#ifdef SSL_DEBUG
-        fprintf(stderr, "Using TLS 1.2 with client alg %s\n",
-                EVP_MD_name(md));
-#endif
-        if (!EVP_SignInit_ex(&mctx, md, NULL)
-            || !EVP_SignUpdate(&mctx, hdata, hdatalen)
-            || !EVP_SignFinal(&mctx, p + 2, &u, pkey)) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_EVP_LIB);
-            goto err;
-        }
-        s2n(u, p);
-        n = u + 4;
-        /* Digest cached records and discard handshake buffer */
-        if (!ssl3_digest_cached_records(s, 0))
-            goto err;
-    } else
-#ifndef OPENSSL_NO_RSA
-    if (pkey->type == EVP_PKEY_RSA) {
-        s->method->ssl3_enc->cert_verify_mac(s, NID_md5, &(data[0]));
-        if (RSA_sign(NID_md5_sha1, data,
-                     MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH,
-                     &(p[2]), &u, pkey->pkey.rsa) <= 0) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_RSA_LIB);
-            goto err;
-        }
-        s2n(u, p);
-        n = u + 2;
-    } else
-#endif
-#ifndef OPENSSL_NO_DSA
-    if (pkey->type == EVP_PKEY_DSA) {
-        if (!DSA_sign(pkey->save_type,
-                      &(data[MD5_DIGEST_LENGTH]),
-                      SHA_DIGEST_LENGTH, &(p[2]),
-                      (unsigned int *)&j, pkey->pkey.dsa)) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_DSA_LIB);
-            goto err;
-        }
-        s2n(j, p);
-        n = j + 2;
-    } else
-#endif
-#ifndef OPENSSL_NO_EC
-    if (pkey->type == EVP_PKEY_EC) {
-        if (!ECDSA_sign(pkey->save_type,
-                        &(data[MD5_DIGEST_LENGTH]),
-                        SHA_DIGEST_LENGTH, &(p[2]),
-                        (unsigned int *)&j, pkey->pkey.ec)) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_ECDSA_LIB);
-            goto err;
-        }
-        s2n(j, p);
-        n = j + 2;
-    } else
-#endif
-    if (pkey->type == NID_id_GostR3410_2001) {
-        unsigned char signbuf[64];
-        int i;
-        size_t sigsize = 64;
-        s->method->ssl3_enc->cert_verify_mac(s,
-                                             NID_id_GostR3411_94, data);
-        if (EVP_PKEY_sign(pctx, signbuf, &sigsize, data, 32) <= 0) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
-        for (i = 63, j = 0; i >= 0; j++, i--) {
-            p[2 + j] = signbuf[i];
-        }
-        s2n(j, p);
-        n = j + 2;
-    } else {
-        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
-        goto err;
-    }
-    if (!ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE_VERIFY, n)) {
-        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
-        goto err;
-    }
-
-    EVP_MD_CTX_cleanup(&mctx);
-    EVP_PKEY_CTX_free(pctx);
-    return 1;
- err:
-    EVP_MD_CTX_cleanup(&mctx);
-    EVP_PKEY_CTX_free(pctx);
-    return 0;
-}
-
-/*
- * Check a certificate can be used for client authentication. Currently check
- * cert exists, if we have a suitable digest for TLS 1.2 if static DH client
- * certificates can be used and optionally checks suitability for Suite B.
- */
-static int ssl3_check_client_certificate(SSL *s)
-{
-    unsigned long alg_k;
-    if (!s->cert || !s->cert->key->x509 || !s->cert->key->privatekey)
-        return 0;
-    /* If no suitable signature algorithm can't use certificate */
-    if (SSL_USE_SIGALGS(s) && !s->s3->tmp.md[s->cert->key - s->cert->pkeys])
-        return 0;
-    /*
-     * If strict mode check suitability of chain before using it. This also
-     * adjusts suite B digest if necessary.
-     */
-    if (s->cert->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT &&
-        !tls1_check_chain(s, NULL, NULL, NULL, -2))
-        return 0;
-    alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
-    /* See if we can use client certificate for fixed DH */
-    if (alg_k & (SSL_kDHr | SSL_kDHd)) {
-        int i = s->session->peer_type;
-        EVP_PKEY *clkey = NULL, *spkey = NULL;
-        clkey = s->cert->key->privatekey;
-        /* If client key not DH assume it can be used */
-        if (EVP_PKEY_id(clkey) != EVP_PKEY_DH)
-            return 1;
-        if (i >= 0)
-            spkey = X509_get_pubkey(s->session->peer);
-        if (spkey) {
-            /* Compare server and client parameters */
-            i = EVP_PKEY_cmp_parameters(clkey, spkey);
-            EVP_PKEY_free(spkey);
-            if (i != 1)
-                return 0;
-        }
-        s->s3->flags |= TLS1_FLAGS_SKIP_CERT_VERIFY;
-    }
-    return 1;
-}
-
-enum WORK_STATE tls_prepare_client_certificate(SSL *s, enum WORK_STATE wst)
-{
-    X509 *x509 = NULL;
-    EVP_PKEY *pkey = NULL;
-    int i;
-
-    if (wst == WORK_MORE_A) {
-        /* Let cert callback update client certificates if required */
-        if (s->cert->cert_cb) {
-            i = s->cert->cert_cb(s, s->cert->cert_cb_arg);
-            if (i < 0) {
-                s->rwstate = SSL_X509_LOOKUP;
-                return WORK_MORE_A;
-            }
-            if (i == 0) {
-                ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
-                statem_set_error(s);
-                return 0;
-            }
-            s->rwstate = SSL_NOTHING;
-        }
-        if (ssl3_check_client_certificate(s))
-            return WORK_FINISHED_CONTINUE;
-
-        /* Fall through to WORK_MORE_B */
-        wst = WORK_MORE_B;
-    }
-
-    /* We need to get a client cert */
-    if (wst == WORK_MORE_B) {
-        /*
-         * If we get an error, we need to ssl->rwstate=SSL_X509_LOOKUP;
-         * return(-1); We then get retied later
-         */
-        i = ssl_do_client_cert_cb(s, &x509, &pkey);
-        if (i < 0) {
-            s->rwstate = SSL_X509_LOOKUP;
-            return WORK_MORE_B;
-        }
-        s->rwstate = SSL_NOTHING;
-        if ((i == 1) && (pkey != NULL) && (x509 != NULL)) {
-            if (!SSL_use_certificate(s, x509) || !SSL_use_PrivateKey(s, pkey))
-                i = 0;
-        } else if (i == 1) {
-            i = 0;
-            SSLerr(SSL_F_TLS_PREPARE_CLIENT_CERTIFICATE,
-                   SSL_R_BAD_DATA_RETURNED_BY_CALLBACK);
-        }
-
-        X509_free(x509);
-        EVP_PKEY_free(pkey);
-        if (i && !ssl3_check_client_certificate(s))
-            i = 0;
-        if (i == 0) {
-            if (s->version == SSL3_VERSION) {
-                s->s3->tmp.cert_req = 0;
-                ssl3_send_alert(s, SSL3_AL_WARNING, SSL_AD_NO_CERTIFICATE);
-                return WORK_FINISHED_CONTINUE;
-            } else {
-                s->s3->tmp.cert_req = 2;
-                if (!ssl3_digest_cached_records(s, 0)) {
-                    ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
-                    statem_set_error(s);
-                    return 0;
-                }
-            }
-        }
-
-        return WORK_FINISHED_CONTINUE;
-    }
-
-    /* Shouldn't ever get here */
-    return WORK_ERROR;
-}
-
-int tls_construct_client_certificate(SSL *s)
-{
-    if (!ssl3_output_cert_chain(s,
-                                (s->s3->tmp.cert_req ==
-                                 2) ? NULL : s->cert->key)) {
-        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_CERTIFICATE, ERR_R_INTERNAL_ERROR);
-        ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
-        statem_set_error(s);
-        return 0;
-    }
-
-    return 1;
-}
-
-#define has_bits(i,m)   (((i)&(m)) == (m))
-
-int ssl3_check_cert_and_algorithm(SSL *s)
-{
-    int i, idx;
-    long alg_k, alg_a;
-    EVP_PKEY *pkey = NULL;
-    int pkey_bits;
-#ifndef OPENSSL_NO_RSA
-    RSA *rsa;
-#endif
-#ifndef OPENSSL_NO_DH
-    DH *dh;
-#endif
-    int al = SSL_AD_HANDSHAKE_FAILURE;
-
-    alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
-    alg_a = s->s3->tmp.new_cipher->algorithm_auth;
-
-    /* we don't have a certificate */
-    if ((alg_a & SSL_aNULL) || (alg_k & SSL_kPSK))
-        return (1);
-#ifndef OPENSSL_NO_RSA
-    rsa = s->s3->peer_rsa_tmp;
-#endif
-#ifndef OPENSSL_NO_DH
-    dh = s->s3->peer_dh_tmp;
-#endif
-
-    /* This is the passed certificate */
-
-    idx = s->session->peer_type;
-#ifndef OPENSSL_NO_EC
-    if (idx == SSL_PKEY_ECC) {
-        if (ssl_check_srvr_ecc_cert_and_alg(s->session->peer, s) == 0) {
-            /* check failed */
-            SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, SSL_R_BAD_ECC_CERT);
-            goto f_err;
-        } else {
-            return 1;
-        }
-    } else if (alg_a & SSL_aECDSA) {
-        SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
-               SSL_R_MISSING_ECDSA_SIGNING_CERT);
-        goto f_err;
-    } else if (alg_k & (SSL_kECDHr | SSL_kECDHe)) {
-        SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, SSL_R_MISSING_ECDH_CERT);
-        goto f_err;
-    }
-#endif
-    pkey = X509_get_pubkey(s->session->peer);
-    pkey_bits = EVP_PKEY_bits(pkey);
-    i = X509_certificate_type(s->session->peer, pkey);
-    EVP_PKEY_free(pkey);
-
-    /* Check that we have a certificate if we require one */
-    if ((alg_a & SSL_aRSA) && !has_bits(i, EVP_PK_RSA | EVP_PKT_SIGN)) {
-        SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
-               SSL_R_MISSING_RSA_SIGNING_CERT);
-        goto f_err;
-    }
-#ifndef OPENSSL_NO_DSA
-    else if ((alg_a & SSL_aDSS) && !has_bits(i, EVP_PK_DSA | EVP_PKT_SIGN)) {
-        SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
-               SSL_R_MISSING_DSA_SIGNING_CERT);
-        goto f_err;
-    }
-#endif
-#ifndef OPENSSL_NO_RSA
-    if (alg_k & (SSL_kRSA | SSL_kRSAPSK)) {
-        if (!SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) &&
-            !has_bits(i, EVP_PK_RSA | EVP_PKT_ENC)) {
-            SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
-                   SSL_R_MISSING_RSA_ENCRYPTING_CERT);
-            goto f_err;
-        } else if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)) {
-            if (pkey_bits <= SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) {
-                if (!has_bits(i, EVP_PK_RSA | EVP_PKT_ENC)) {
-                    SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
-                           SSL_R_MISSING_RSA_ENCRYPTING_CERT);
-                    goto f_err;
-                }
-                if (rsa != NULL) {
-                    /* server key exchange is not allowed. */
-                    al = SSL_AD_INTERNAL_ERROR;
-                    SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, ERR_R_INTERNAL_ERROR);
-                    goto f_err;
-                }
-            }
-        }
-    }
-#endif
-#ifndef OPENSSL_NO_DH
-    if ((alg_k & SSL_kDHE) && (dh == NULL)) {
-        al = SSL_AD_INTERNAL_ERROR;
-        SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, ERR_R_INTERNAL_ERROR);
-        goto f_err;
-    } else if ((alg_k & SSL_kDHr) && !SSL_USE_SIGALGS(s) &&
-               !has_bits(i, EVP_PK_DH | EVP_PKS_RSA)) {
-        SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
-               SSL_R_MISSING_DH_RSA_CERT);
-        goto f_err;
-    }
-# ifndef OPENSSL_NO_DSA
-    else if ((alg_k & SSL_kDHd) && !SSL_USE_SIGALGS(s) &&
-             !has_bits(i, EVP_PK_DH | EVP_PKS_DSA)) {
-        SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
-               SSL_R_MISSING_DH_DSA_CERT);
-        goto f_err;
-    }
-# endif
-#endif
-
-    if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) &&
-        pkey_bits > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) {
-#ifndef OPENSSL_NO_RSA
-        if (alg_k & SSL_kRSA) {
-            if (rsa == NULL) {
-                SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
-                       SSL_R_MISSING_EXPORT_TMP_RSA_KEY);
-                goto f_err;
-            } else if (RSA_bits(rsa) >
-                SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) {
-                /* We have a temporary RSA key but it's too large. */
-                al = SSL_AD_EXPORT_RESTRICTION;
-                SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
-                       SSL_R_MISSING_EXPORT_TMP_RSA_KEY);
-                goto f_err;
-            }
-        } else
-#endif
-#ifndef OPENSSL_NO_DH
-        if (alg_k & SSL_kDHE) {
-            if (DH_bits(dh) >
-                SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) {
-                /* We have a temporary DH key but it's too large. */
-                al = SSL_AD_EXPORT_RESTRICTION;
-                SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
-                       SSL_R_MISSING_EXPORT_TMP_DH_KEY);
-                goto f_err;
-            }
-        } else if (alg_k & (SSL_kDHr | SSL_kDHd)) {
-            /* The cert should have had an export DH key. */
-            al = SSL_AD_EXPORT_RESTRICTION;
-            SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
-                   SSL_R_MISSING_EXPORT_TMP_DH_KEY);
-                goto f_err;
-        } else
-#endif
-        {
-            SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
-                   SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE);
-            goto f_err;
-        }
-    }
-    return (1);
- f_err:
-    ssl3_send_alert(s, SSL3_AL_FATAL, al);
-    return (0);
-}
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
-int tls_construct_next_proto(SSL *s)
-{
-    unsigned int len, padding_len;
-    unsigned char *d;
-
-    len = s->next_proto_negotiated_len;
-    padding_len = 32 - ((len + 2) % 32);
-    d = (unsigned char *)s->init_buf->data;
-    d[4] = len;
-    memcpy(d + 5, s->next_proto_negotiated, len);
-    d[5 + len] = padding_len;
-    memset(d + 6 + len, 0, padding_len);
-    *(d++) = SSL3_MT_NEXT_PROTO;
-    l2n3(2 + len + padding_len, d);
-    s->init_num = 4 + 2 + len + padding_len;
-    s->init_off = 0;
-
-    return 1;
-}
-#endif
-
-int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey)
-{
-    int i = 0;
-#ifndef OPENSSL_NO_ENGINE
-    if (s->ctx->client_cert_engine) {
-        i = ENGINE_load_ssl_client_cert(s->ctx->client_cert_engine, s,
-                                        SSL_get_client_CA_list(s),
-                                        px509, ppkey, NULL, NULL, NULL);
-        if (i != 0)
-            return i;
-    }
-#endif
-    if (s->ctx->client_cert_cb)
-        i = s->ctx->client_cert_cb(s, px509, ppkey);
-    return i;
-}
-
-int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk,
-                             unsigned char *p)
-{
-    int i, j = 0;
-    SSL_CIPHER *c;
-    unsigned char *q;
-    int empty_reneg_info_scsv = !s->renegotiate;
-    /* Set disabled masks for this session */
-    ssl_set_client_disabled(s);
-
-    if (sk == NULL)
-        return (0);
-    q = p;
-
-    for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) {
-        c = sk_SSL_CIPHER_value(sk, i);
-        /* Skip disabled ciphers */
-        if (ssl_cipher_disabled(s, c, SSL_SECOP_CIPHER_SUPPORTED))
-            continue;
-#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL
-        if (c->id == SSL3_CK_SCSV) {
-            if (!empty_reneg_info_scsv)
-                continue;
-            else
-                empty_reneg_info_scsv = 0;
-        }
-#endif
-        j = s->method->put_cipher_by_char(c, p);
-        p += j;
-    }
-    /*
-     * If p == q, no ciphers; caller indicates an error. Otherwise, add
-     * applicable SCSVs.
-     */
-    if (p != q) {
-        if (empty_reneg_info_scsv) {
-            static SSL_CIPHER scsv = {
-                0, NULL, SSL3_CK_SCSV, 0, 0, 0, 0, 0, 0, 0, 0, 0
-            };
-            j = s->method->put_cipher_by_char(&scsv, p);
-            p += j;
-#ifdef OPENSSL_RI_DEBUG
-            fprintf(stderr,
-                    "TLS_EMPTY_RENEGOTIATION_INFO_SCSV sent by client\n");
-#endif
-        }
-        if (s->mode & SSL_MODE_SEND_FALLBACK_SCSV) {
-            static SSL_CIPHER scsv = {
-                0, NULL, SSL3_CK_FALLBACK_SCSV, 0, 0, 0, 0, 0, 0, 0, 0, 0
-            };
-            j = s->method->put_cipher_by_char(&scsv, p);
-            p += j;
-        }
-    }
-
-    return (p - q);
-}
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
deleted file mode 100644 (file)
index 4442223..0000000
+++ /dev/null
@@ -1,2878 +0,0 @@
-/* ssl/s3_srvr.c -*- mode:C; c-file-style: "eay" -*- */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to.  The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *    "This product includes cryptographic software written by
- *     Eric Young (eay@cryptsoft.com)"
- *    The word 'cryptographic' can be left out if the rouines from the library
- *    being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- *    the apps directory (application code) you must include an acknowledgement:
- *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed.  i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-/* ====================================================================
- * Copyright (c) 1998-2007 The OpenSSL Project.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- *    software must display the following acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- *    endorse or promote products derived from this software without
- *    prior written permission. For written permission, please contact
- *    openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- *    nor may "OpenSSL" appear in their names without prior written
- *    permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- *    acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com).  This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-/* ====================================================================
- * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
- *
- * Portions of the attached software ("Contribution") are developed by
- * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
- *
- * The Contribution is licensed pursuant to the OpenSSL open source
- * license provided above.
- *
- * ECC cipher suite support in OpenSSL originally written by
- * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories.
- *
- */
-/* ====================================================================
- * Copyright 2005 Nokia. All rights reserved.
- *
- * The portions of the attached software ("Contribution") is developed by
- * Nokia Corporation and is licensed pursuant to the OpenSSL open source
- * license.
- *
- * The Contribution, originally written by Mika Kousa and Pasi Eronen of
- * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
- * support (see RFC 4279) to OpenSSL.
- *
- * No patent licenses or other rights except those expressly stated in
- * the OpenSSL open source license shall be deemed granted or received
- * expressly, by implication, estoppel, or otherwise.
- *
- * No assurances are provided by Nokia that the Contribution does not
- * infringe the patent or other intellectual property rights of any third
- * party or that the license provides you with all the necessary rights
- * to make use of the Contribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
- * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
- * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
- * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
- * OTHERWISE.
- */
-
-
-#include <stdio.h>
-#include "ssl_locl.h"
-#include "internal/constant_time_locl.h"
-#include <openssl/buffer.h>
-#include <openssl/rand.h>
-#include <openssl/objects.h>
-#include <openssl/evp.h>
-#include <openssl/hmac.h>
-#include <openssl/x509.h>
-#ifndef OPENSSL_NO_DH
-# include <openssl/dh.h>
-#endif
-#include <openssl/bn.h>
-#include <openssl/md5.h>
-
-static STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s,
-                                                      PACKET *cipher_suites,
-                                                      STACK_OF(SSL_CIPHER) **skp,
-                                                      int sslv2format, int *al);
-
-#ifndef OPENSSL_NO_SRP
-static int ssl_check_srp_ext_ClientHello(SSL *s, int *al)
-{
-    int ret = SSL_ERROR_NONE;
-
-    *al = SSL_AD_UNRECOGNIZED_NAME;
-
-    if ((s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP) &&
-        (s->srp_ctx.TLS_ext_srp_username_callback != NULL)) {
-        if (s->srp_ctx.login == NULL) {
-            /*
-             * RFC 5054 says SHOULD reject, we do so if There is no srp
-             * login name
-             */
-            ret = SSL3_AL_FATAL;
-            *al = SSL_AD_UNKNOWN_PSK_IDENTITY;
-        } else {
-            ret = SSL_srp_server_param_with_username(s, al);
-        }
-    }
-    return ret;
-}
-#endif
-
-int tls_construct_hello_request(SSL *s)
-{
-    if (!ssl_set_handshake_header(s, SSL3_MT_HELLO_REQUEST, 0)) {
-        SSLerr(SSL_F_TLS_CONSTRUCT_HELLO_REQUEST, ERR_R_INTERNAL_ERROR);
-        statem_set_error(s);
-        return 0;
-    }
-
-    return 1;
-}
-
-enum MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt)
-{
-    int i, al = SSL_AD_INTERNAL_ERROR;
-    unsigned int j, complen = 0;
-    unsigned long id;
-    SSL_CIPHER *c;
-#ifndef OPENSSL_NO_COMP
-    SSL_COMP *comp = NULL;
-#endif
-    STACK_OF(SSL_CIPHER) *ciphers = NULL;
-    int protverr = 1;
-    /* |cookie| will only be initialized for DTLS. */
-    PACKET session_id, cipher_suites, compression, extensions, cookie;
-    int is_v2_record;
-
-    is_v2_record = RECORD_LAYER_is_sslv2_record(&s->rlayer);
-
-    PACKET_null_init(&cookie);
-    /* First lets get s->client_version set correctly */
-    if (is_v2_record) {
-        unsigned int version;
-        unsigned int mt;
-        /*-
-         * An SSLv3/TLSv1 backwards-compatible CLIENT-HELLO in an SSLv2
-         * header is sent directly on the wire, not wrapped as a TLS
-         * record. Our record layer just processes the message length and passes
-         * the rest right through. Its format is:
-         * Byte  Content
-         * 0-1   msg_length - decoded by the record layer
-         * 2     msg_type - s->init_msg points here
-         * 3-4   version
-         * 5-6   cipher_spec_length
-         * 7-8   session_id_length
-         * 9-10  challenge_length
-         * ...   ...
-         */
-
-        if (!PACKET_get_1(pkt, &mt)
-                || mt != SSL2_MT_CLIENT_HELLO) {
-            /*
-             * Should never happen. We should have tested this in the record
-             * layer in order to have determined that this is a SSLv2 record
-             * in the first place
-             */
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
-
-        if (!PACKET_get_net_2(pkt, &version)) {
-            /* No protocol version supplied! */
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL);
-            goto err;
-        }
-        if (version == 0x0002) {
-            /* This is real SSLv2. We don't support it. */
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL);
-            goto err;
-        } else if ((version & 0xff00) == (SSL3_VERSION_MAJOR << 8)) {
-            /* SSLv3/TLS */
-            s->client_version = version;
-        } else {
-            /* No idea what protocol this is */
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL);
-            goto err;
-        }
-    } else {
-        /*
-         * use version from inside client hello, not from record header (may
-         * differ: see RFC 2246, Appendix E, second paragraph)
-         */
-        if(!PACKET_get_net_2(pkt, (unsigned int *)&s->client_version)) {
-            al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_LENGTH_TOO_SHORT);
-            goto f_err;
-        }
-    }
-
-    /* Do SSL/TLS version negotiation if applicable */
-    if (!SSL_IS_DTLS(s)) {
-        if (s->version != TLS_ANY_VERSION) {
-            if (s->client_version >= s->version) {
-                protverr = 0;
-            }
-        } else if (s->client_version >= SSL3_VERSION) {
-            switch(s->client_version) {
-            default:
-            case TLS1_2_VERSION:
-                if(!(s->options & SSL_OP_NO_TLSv1_2)) {
-                    s->version = TLS1_2_VERSION;
-                    s->method = TLSv1_2_server_method();
-                    protverr = 0;
-                    break;
-                }
-                /* Deliberately fall through */
-            case TLS1_1_VERSION:
-                if(!(s->options & SSL_OP_NO_TLSv1_1)) {
-                    s->version = TLS1_1_VERSION;
-                    s->method = TLSv1_1_server_method();
-                    protverr = 0;
-                    break;
-                }
-                /* Deliberately fall through */
-            case TLS1_VERSION:
-                if(!(s->options & SSL_OP_NO_TLSv1)) {
-                    s->version = TLS1_VERSION;
-                    s->method = TLSv1_server_method();
-                    protverr = 0;
-                    break;
-                }
-                /* Deliberately fall through */
-            case SSL3_VERSION:
-#ifndef OPENSSL_NO_SSL3
-                if(!(s->options & SSL_OP_NO_SSLv3)) {
-                    s->version = SSL3_VERSION;
-                    s->method = SSLv3_server_method();
-                    protverr = 0;
-                    break;
-                }
-#else
-                break;
-#endif
-            }
-        }
-    } else if (s->client_version <= s->version
-                || s->method->version == DTLS_ANY_VERSION) {
-        /*
-         * For DTLS we just check versions are potentially compatible. Version
-         * negotiation comes later.
-         */
-        protverr = 0;
-    }
-
-    if (protverr) {
-        SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL);
-        if ((!s->enc_write_ctx && !s->write_hash)) {
-            /*
-             * similar to ssl3_get_record, send alert using remote version
-             * number
-             */
-            s->version = s->client_version;
-        }
-        al = SSL_AD_PROTOCOL_VERSION;
-        goto f_err;
-    }
-
-    /* Parse the message and load client random. */
-    if (is_v2_record) {
-        /*
-         * Handle an SSLv2 backwards compatible ClientHello
-         * Note, this is only for SSLv3+ using the backward compatible format.
-         * Real SSLv2 is not supported, and is rejected above.
-         */
-        unsigned int cipher_len, session_id_len, challenge_len;
-        PACKET challenge;
-
-        if (!PACKET_get_net_2(pkt, &cipher_len)
-                || !PACKET_get_net_2(pkt, &session_id_len)
-                || !PACKET_get_net_2(pkt, &challenge_len)) {
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO,
-                   SSL_R_RECORD_LENGTH_MISMATCH);
-            al = SSL_AD_DECODE_ERROR;
-            goto f_err;
-        }
-
-        if (!PACKET_get_sub_packet(pkt, &cipher_suites, cipher_len)
-            || !PACKET_get_sub_packet(pkt, &session_id, session_id_len)
-            || !PACKET_get_sub_packet(pkt, &challenge, challenge_len)
-            /* No extensions. */
-            || PACKET_remaining(pkt) != 0) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_RECORD_LENGTH_MISMATCH);
-            al = SSL_AD_DECODE_ERROR;
-            goto f_err;
-        }
-
-        /* Load the client random */
-        challenge_len = challenge_len > SSL3_RANDOM_SIZE ? SSL3_RANDOM_SIZE :
-            challenge_len;
-        memset(s->s3->client_random, 0, SSL3_RANDOM_SIZE);
-        if (!PACKET_copy_bytes(&challenge,
-                               s->s3->client_random + SSL3_RANDOM_SIZE -
-                               challenge_len, challenge_len)) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
-            al = SSL_AD_INTERNAL_ERROR;
-            goto f_err;
-        }
-
-        PACKET_null_init(&compression);
-        PACKET_null_init(&extensions);
-    } else {
-        /* Regular ClientHello. */
-        if (!PACKET_copy_bytes(pkt, s->s3->client_random, SSL3_RANDOM_SIZE)
-            || !PACKET_get_length_prefixed_1(pkt, &session_id)) {
-            al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH);
-            goto f_err;
-        }
-
-        if (SSL_IS_DTLS(s)) {
-            if (!PACKET_get_length_prefixed_1(pkt, &cookie)) {
-                al = SSL_AD_DECODE_ERROR;
-                SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH);
-                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) {
-                if (PACKET_remaining(&cookie) == 0)
-                return 1;
-            }
-        }
-
-        if (!PACKET_get_length_prefixed_2(pkt, &cipher_suites)
-            || !PACKET_get_length_prefixed_1(pkt, &compression)) {
-                al = SSL_AD_DECODE_ERROR;
-                SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH);
-                goto f_err;
-        }
-        /* Could be empty. */
-        extensions = *pkt;
-    }
-
-    s->hit = 0;
-
-    /*
-     * We don't allow resumption in a backwards compatible ClientHello.
-     * TODO(openssl-team): in TLS1.1+, session_id MUST be empty.
-     *
-     * Versions before 0.9.7 always allow clients to resume sessions in
-     * renegotiation. 0.9.7 and later allow this by default, but optionally
-     * ignore resumption requests with flag
-     * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION (it's a new flag rather
-     * than a change to default behavior so that applications relying on
-     * this for security won't even compile against older library versions).
-     * 1.0.1 and later also have a function SSL_renegotiate_abbreviated() to
-     * request renegotiation but not a new session (s->new_session remains
-     * unset): for servers, this essentially just means that the
-     * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION setting will be
-     * ignored.
-     */
-    if (is_v2_record ||
-        (s->new_session &&
-         (s->options & SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION))) {
-        if (!ssl_get_new_session(s, 1))
-            goto err;
-    } else {
-        i = ssl_get_prev_session(s, &extensions, &session_id);
-        /*
-         * Only resume if the session's version matches the negotiated
-         * version.
-         * RFC 5246 does not provide much useful advice on resumption
-         * with a different protocol version. It doesn't forbid it but
-         * the sanity of such behaviour would be questionable.
-         * In practice, clients do not accept a version mismatch and
-         * will abort the handshake with an error.
-         */
-        if (i == 1 && s->version == s->session->ssl_version) {
-            /* previous session */
-            s->hit = 1;
-        } else if (i == -1) {
-            goto err;
-        } else {
-            /* i == 0 */
-            if (!ssl_get_new_session(s, 1))
-                goto err;
-        }
-    }
-
-    if (SSL_IS_DTLS(s)) {
-        /* Empty cookie was already handled above by returning early. */
-        if (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) {
-            if (s->ctx->app_verify_cookie_cb != NULL) {
-                if (s->ctx->app_verify_cookie_cb(s, PACKET_data(&cookie),
-                                                 PACKET_remaining(&cookie)) == 0) {
-                    al = SSL_AD_HANDSHAKE_FAILURE;
-                    SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,
-                           SSL_R_COOKIE_MISMATCH);
-                    goto f_err;
-                    /* else cookie verification succeeded */
-                }
-            /* default verification */
-            } else if (!PACKET_equal(&cookie, s->d1->cookie,
-                                     s->d1->cookie_len)) {
-                al = SSL_AD_HANDSHAKE_FAILURE;
-                SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_COOKIE_MISMATCH);
-                goto f_err;
-            }
-            s->d1->cookie_verified = 1;
-        }
-        if (s->method->version == DTLS_ANY_VERSION) {
-            /* Select version to use */
-            if (s->client_version <= DTLS1_2_VERSION &&
-                !(s->options & SSL_OP_NO_DTLSv1_2)) {
-                s->version = DTLS1_2_VERSION;
-                s->method = DTLSv1_2_server_method();
-            } else if (tls1_suiteb(s)) {
-                SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,
-                       SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE);
-                s->version = s->client_version;
-                al = SSL_AD_PROTOCOL_VERSION;
-                goto f_err;
-            } else if (s->client_version <= DTLS1_VERSION &&
-                       !(s->options & SSL_OP_NO_DTLSv1)) {
-                s->version = DTLS1_VERSION;
-                s->method = DTLSv1_server_method();
-            } else {
-                SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,
-                       SSL_R_WRONG_VERSION_NUMBER);
-                s->version = s->client_version;
-                al = SSL_AD_PROTOCOL_VERSION;
-                goto f_err;
-            }
-            s->session->ssl_version = s->version;
-        }
-    }
-
-    if (ssl_bytes_to_cipher_list(s, &cipher_suites, &(ciphers),
-                                 is_v2_record, &al) == NULL) {
-        goto f_err;
-    }
-
-    /* If it is a hit, check that the cipher is in the list */
-    if (s->hit) {
-        j = 0;
-        id = s->session->cipher->id;
-
-#ifdef CIPHER_DEBUG
-        fprintf(stderr, "client sent %d ciphers\n",
-                sk_SSL_CIPHER_num(ciphers));
-#endif
-        for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) {
-            c = sk_SSL_CIPHER_value(ciphers, i);
-#ifdef CIPHER_DEBUG
-            fprintf(stderr, "client [%2d of %2d]:%s\n",
-                    i, sk_SSL_CIPHER_num(ciphers), SSL_CIPHER_get_name(c));
-#endif
-            if (c->id == id) {
-                j = 1;
-                break;
-            }
-        }
-        if (j == 0) {
-            /*
-             * we need to have the cipher in the cipher list if we are asked
-             * to reuse it
-             */
-            al = SSL_AD_ILLEGAL_PARAMETER;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,
-                   SSL_R_REQUIRED_CIPHER_MISSING);
-            goto f_err;
-        }
-    }
-
-    complen = PACKET_remaining(&compression);
-    for (j = 0; j < complen; j++) {
-        if (PACKET_data(&compression)[j] == 0)
-            break;
-    }
-
-    if (j >= complen) {
-        /* no compress */
-        al = SSL_AD_DECODE_ERROR;
-        SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_NO_COMPRESSION_SPECIFIED);
-        goto f_err;
-    }
-    
-    /* TLS extensions */
-    if (s->version >= SSL3_VERSION) {
-        if (!ssl_parse_clienthello_tlsext(s, &extensions)) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_PARSE_TLSEXT);
-            goto err;
-        }
-    }
-
-    /*
-     * Check if we want to use external pre-shared secret for this handshake
-     * for not reused session only. We need to generate server_random before
-     * calling tls_session_secret_cb in order to allow SessionTicket
-     * processing to use it in key derivation.
-     */
-    {
-        unsigned char *pos;
-        pos = s->s3->server_random;
-        if (ssl_fill_hello_random(s, 1, pos, SSL3_RANDOM_SIZE) <= 0) {
-            goto f_err;
-        }
-    }
-
-    if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb) {
-        SSL_CIPHER *pref_cipher = NULL;
-
-        s->session->master_key_length = sizeof(s->session->master_key);
-        if (s->tls_session_secret_cb(s, s->session->master_key,
-                                     &s->session->master_key_length, ciphers,
-                                     &pref_cipher,
-                                     s->tls_session_secret_cb_arg)) {
-            s->hit = 1;
-            s->session->ciphers = ciphers;
-            s->session->verify_result = X509_V_OK;
-
-            ciphers = NULL;
-
-            /* check if some cipher was preferred by call back */
-            pref_cipher =
-                pref_cipher ? pref_cipher : ssl3_choose_cipher(s,
-                                                               s->
-                                                               session->ciphers,
-                                                               SSL_get_ciphers
-                                                               (s));
-            if (pref_cipher == NULL) {
-                al = SSL_AD_HANDSHAKE_FAILURE;
-                SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_NO_SHARED_CIPHER);
-                goto f_err;
-            }
-
-            s->session->cipher = pref_cipher;
-            sk_SSL_CIPHER_free(s->cipher_list);
-            s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
-            sk_SSL_CIPHER_free(s->cipher_list_by_id);
-            s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
-        }
-    }
-
-    /*
-     * Worst case, we will use the NULL compression, but if we have other
-     * options, we will now look for them.  We have complen-1 compression
-     * algorithms from the client, starting at q.
-     */
-    s->s3->tmp.new_compression = NULL;
-#ifndef OPENSSL_NO_COMP
-    /* This only happens if we have a cache hit */
-    if (s->session->compress_meth != 0) {
-        int m, comp_id = s->session->compress_meth;
-        unsigned int k;
-        /* Perform sanity checks on resumed compression algorithm */
-        /* Can't disable compression */
-        if (!ssl_allow_compression(s)) {
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO,
-                   SSL_R_INCONSISTENT_COMPRESSION);
-            goto f_err;
-        }
-        /* Look for resumed compression method */
-        for (m = 0; m < sk_SSL_COMP_num(s->ctx->comp_methods); m++) {
-            comp = sk_SSL_COMP_value(s->ctx->comp_methods, m);
-            if (comp_id == comp->id) {
-                s->s3->tmp.new_compression = comp;
-                break;
-            }
-        }
-        if (s->s3->tmp.new_compression == NULL) {
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO,
-                   SSL_R_INVALID_COMPRESSION_ALGORITHM);
-            goto f_err;
-        }
-        /* Look for resumed method in compression list */
-        for (k = 0; k < complen; k++) {
-            if (PACKET_data(&compression)[k] == comp_id)
-                break;
-        }
-        if (k >= complen) {
-            al = SSL_AD_ILLEGAL_PARAMETER;
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO,
-                   SSL_R_REQUIRED_COMPRESSSION_ALGORITHM_MISSING);
-            goto f_err;
-        }
-    } else if (s->hit)
-        comp = NULL;
-    else if (ssl_allow_compression(s) && s->ctx->comp_methods) {
-        /* See if we have a match */
-        int m, nn, v, done = 0;
-        unsigned int o;
-
-        nn = sk_SSL_COMP_num(s->ctx->comp_methods);
-        for (m = 0; m < nn; m++) {
-            comp = sk_SSL_COMP_value(s->ctx->comp_methods, m);
-            v = comp->id;
-            for (o = 0; o < complen; o++) {
-                if (v == PACKET_data(&compression)[o]) {
-                    done = 1;
-                    break;
-                }
-            }
-            if (done)
-                break;
-        }
-        if (done)
-            s->s3->tmp.new_compression = comp;
-        else
-            comp = NULL;
-    }
-#else
-    /*
-     * If compression is disabled we'd better not try to resume a session
-     * using compression.
-     */
-    if (s->session->compress_meth != 0) {
-        SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_INCONSISTENT_COMPRESSION);
-        goto f_err;
-    }
-#endif
-
-    /*
-     * Given s->session->ciphers and SSL_get_ciphers, we must pick a cipher
-     */
-
-    if (!s->hit) {
-#ifdef OPENSSL_NO_COMP
-        s->session->compress_meth = 0;
-#else
-        s->session->compress_meth = (comp == NULL) ? 0 : comp->id;
-#endif
-        sk_SSL_CIPHER_free(s->session->ciphers);
-        s->session->ciphers = ciphers;
-        if (ciphers == NULL) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
-            goto f_err;
-        }
-        ciphers = NULL;
-        if (!tls1_set_server_sigalgs(s)) {
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT);
-            goto err;
-        }
-    }
-
-    sk_SSL_CIPHER_free(ciphers);
-    return MSG_PROCESS_CONTINUE_PROCESSING;
- f_err:
-    ssl3_send_alert(s, SSL3_AL_FATAL, al);
- err:
-    statem_set_error(s);
-
-    sk_SSL_CIPHER_free(ciphers);
-    return MSG_PROCESS_ERROR;
-
-}
-
-enum WORK_STATE tls_post_process_client_hello(SSL *s, enum WORK_STATE wst)
-{
-    int al;
-    SSL_CIPHER *cipher;
-
-    if (wst == WORK_MORE_A) {
-        if (!s->hit) {
-            /* Let cert callback update server certificates if required */
-            if (s->cert->cert_cb) {
-                int rv = s->cert->cert_cb(s, s->cert->cert_cb_arg);
-                if (rv == 0) {
-                    al = SSL_AD_INTERNAL_ERROR;
-                    SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO, SSL_R_CERT_CB_ERROR);
-                    goto f_err;
-                }
-                if (rv < 0) {
-                    s->rwstate = SSL_X509_LOOKUP;
-                    return WORK_MORE_A;
-                }
-                s->rwstate = SSL_NOTHING;
-            }
-            cipher = ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
-
-            if (cipher == NULL) {
-                al = SSL_AD_HANDSHAKE_FAILURE;
-                SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO, SSL_R_NO_SHARED_CIPHER);
-                goto f_err;
-            }
-            s->s3->tmp.new_cipher = cipher;
-            /* check whether we should disable session resumption */
-            if (s->not_resumable_session_cb != NULL)
-                s->session->not_resumable = s->not_resumable_session_cb(s,
-                    ((cipher->algorithm_mkey & (SSL_kDHE | SSL_kECDHE)) != 0));
-            if (s->session->not_resumable)
-                /* do not send a session ticket */
-                s->tlsext_ticket_expected = 0;
-        } else {
-            /* Session-id reuse */
-            s->s3->tmp.new_cipher = s->session->cipher;
-        }
-
-        if (!SSL_USE_SIGALGS(s) || !(s->verify_mode & SSL_VERIFY_PEER)) {
-            if (!ssl3_digest_cached_records(s, 0))
-                goto f_err;
-        }
-
-        /*-
-         * we now have the following setup.
-         * client_random
-         * cipher_list          - our prefered list of ciphers
-         * ciphers              - the clients prefered list of ciphers
-         * compression          - basically ignored right now
-         * ssl version is set   - sslv3
-         * s->session           - The ssl session has been setup.
-         * s->hit               - session reuse flag
-         * s->s3->tmp.new_cipher- the new cipher to use.
-         */
-
-        /* Handles TLS extensions that we couldn't check earlier */
-        if (s->version >= SSL3_VERSION) {
-            if (ssl_check_clienthello_tlsext_late(s) <= 0) {
-                SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT);
-                goto f_err;
-            }
-        }
-
-        wst = WORK_MORE_B;
-    }
-#ifndef OPENSSL_NO_SRP
-    if (wst == WORK_MORE_B) {
-        int ret;
-        if ((ret = ssl_check_srp_ext_ClientHello(s, &al)) < 0) {
-            /*
-             * callback indicates further work to be done
-             */
-            s->rwstate = SSL_X509_LOOKUP;
-            return WORK_MORE_B;
-        }
-        if (ret != SSL_ERROR_NONE) {
-            /*
-             * This is not really an error but the only means to for
-             * a client to detect whether srp is supported.
-             */
-            if (al != TLS1_AD_UNKNOWN_PSK_IDENTITY)
-                SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO,
-                           SSL_R_CLIENTHELLO_TLSEXT);
-            goto f_err;
-        }
-    }
-#endif
-    s->renegotiate = 2;
-
-    return WORK_FINISHED_STOP;
- f_err:
-    ssl3_send_alert(s, SSL3_AL_FATAL, al);
-    statem_set_error(s);
-    return WORK_ERROR;
-}
-
-int tls_construct_server_hello(SSL *s)
-{
-    unsigned char *buf;
-    unsigned char *p, *d;
-    int i, sl;
-    int al = 0;
-    unsigned long l;
-
-    buf = (unsigned char *)s->init_buf->data;
-
-    /* Do the message type and length last */
-    d = p = ssl_handshake_start(s);
-
-    *(p++) = s->version >> 8;
-    *(p++) = s->version & 0xff;
-
-    /*
-     * Random stuff. Filling of the server_random takes place in
-     * tls_process_client_hello()
-     */
-    memcpy(p, s->s3->server_random, SSL3_RANDOM_SIZE);
-    p += SSL3_RANDOM_SIZE;
-
-    /*-
-     * There are several cases for the session ID to send
-     * back in the server hello:
-     * - For session reuse from the session cache,
-     *   we send back the old session ID.
-     * - If stateless session reuse (using a session ticket)
-     *   is successful, we send back the client's "session ID"
-     *   (which doesn't actually identify the session).
-     * - If it is a new session, we send back the new
-     *   session ID.
-     * - However, if we want the new session to be single-use,
-     *   we send back a 0-length session ID.
-     * s->hit is non-zero in either case of session reuse,
-     * so the following won't overwrite an ID that we're supposed
-     * to send back.
-     */
-    if (s->session->not_resumable ||
-        (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER)
-         && !s->hit))
-        s->session->session_id_length = 0;
-
-    sl = s->session->session_id_length;
-    if (sl > (int)sizeof(s->session->session_id)) {
-        SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
-        statem_set_error(s);
-        return 0;
-    }
-    *(p++) = sl;
-    memcpy(p, s->session->session_id, sl);
-    p += sl;
-
-    /* put the cipher */
-    i = ssl3_put_cipher_by_char(s->s3->tmp.new_cipher, p);
-    p += i;
-
-    /* put the compression method */
-#ifdef OPENSSL_NO_COMP
-    *(p++) = 0;
-#else
-    if (s->s3->tmp.new_compression == NULL)
-        *(p++) = 0;
-    else
-        *(p++) = s->s3->tmp.new_compression->id;
-#endif
-
-    if (ssl_prepare_serverhello_tlsext(s) <= 0) {
-        SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_HELLO, SSL_R_SERVERHELLO_TLSEXT);
-        statem_set_error(s);
-        return 0;
-    }
-    if ((p =
-         ssl_add_serverhello_tlsext(s, p, buf + SSL3_RT_MAX_PLAIN_LENGTH,
-                                    &al)) == NULL) {
-        ssl3_send_alert(s, SSL3_AL_FATAL, al);
-        SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
-        statem_set_error(s);
-        return 0;
-    }
-
-    /* do the header */
-    l = (p - d);
-    if (!ssl_set_handshake_header(s, SSL3_MT_SERVER_HELLO, l)) {
-        SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
-        statem_set_error(s);
-        return 0;
-    }
-
-    return 1;
-}
-
-int tls_construct_server_done(SSL *s)
-{
-    if (!ssl_set_handshake_header(s, SSL3_MT_SERVER_DONE, 0)) {
-        SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_DONE, ERR_R_INTERNAL_ERROR);
-        statem_set_error(s);
-        return 0;
-    }
-
-    if (!s->s3->tmp.cert_request) {
-        if (!ssl3_digest_cached_records(s, 0)) {
-            statem_set_error(s);
-        }
-    }
-
-    return 1;
-}
-
-int tls_construct_server_key_exchange(SSL *s)
-{
-#ifndef OPENSSL_NO_RSA
-    unsigned char *q;
-    int j, num;
-    RSA *rsa;
-    unsigned char md_buf[MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH];
-    unsigned int u;
-#endif
-#ifndef OPENSSL_NO_DH
-    DH *dh = NULL, *dhp;
-#endif
-#ifndef OPENSSL_NO_EC
-    EC_KEY *ecdh = NULL, *ecdhp;
-    unsigned char *encodedPoint = NULL;
-    int encodedlen = 0;
-    int curve_id = 0;
-    BN_CTX *bn_ctx = NULL;
-#endif
-    EVP_PKEY *pkey;
-    const EVP_MD *md = NULL;
-    unsigned char *p, *d;
-    int al, i;
-    unsigned long type;
-    int n;
-    CERT *cert;
-    BIGNUM *r[4];
-    int nr[4], kn;
-    BUF_MEM *buf;
-    EVP_MD_CTX md_ctx;
-
-    EVP_MD_CTX_init(&md_ctx);
-
-    type = s->s3->tmp.new_cipher->algorithm_mkey;
-    cert = s->cert;
-
-    buf = s->init_buf;
-
-    r[0] = r[1] = r[2] = r[3] = NULL;
-    n = 0;
-#ifndef OPENSSL_NO_PSK
-    if (type & SSL_PSK) {
-        /*
-         * reserve size for record length and PSK identity hint
-         */
-        n += 2;
-        if (s->cert->psk_identity_hint)
-            n += strlen(s->cert->psk_identity_hint);
-    }
-    /* Plain PSK or RSAPSK nothing to do */
-    if (type & (SSL_kPSK | SSL_kRSAPSK)) {
-    } else
-#endif                          /* !OPENSSL_NO_PSK */
-#ifndef OPENSSL_NO_RSA
-    if (type & SSL_kRSA) {
-        rsa = cert->rsa_tmp;
-        if ((rsa == NULL) && (s->cert->rsa_tmp_cb != NULL)) {
-            rsa = s->cert->rsa_tmp_cb(s,
-                                      SSL_C_IS_EXPORT(s->s3->
-                                                      tmp.new_cipher),
-                                      SSL_C_EXPORT_PKEYLENGTH(s->s3->
-                                                              tmp.new_cipher));
-            if (rsa == NULL) {
-                al = SSL_AD_HANDSHAKE_FAILURE;
-                SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
-                       SSL_R_ERROR_GENERATING_TMP_RSA_KEY);
-                goto f_err;
-            }
-            RSA_up_ref(rsa);
-            cert->rsa_tmp = rsa;
-        }
-        if (rsa == NULL) {
-            al = SSL_AD_HANDSHAKE_FAILURE;
-            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
-                   SSL_R_MISSING_TMP_RSA_KEY);
-            goto f_err;
-        }
-        r[0] = rsa->n;
-        r[1] = rsa->e;
-        s->s3->tmp.use_rsa_tmp = 1;
-    } else
-#endif
-#ifndef OPENSSL_NO_DH
-    if (type & (SSL_kDHE | SSL_kDHEPSK)) {
-        if (s->cert->dh_tmp_auto) {
-            dhp = ssl_get_auto_dh(s);
-            if (dhp == NULL) {
-                al = SSL_AD_INTERNAL_ERROR;
-                SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
-                       ERR_R_INTERNAL_ERROR);
-                goto f_err;
-            }
-        } else
-            dhp = cert->dh_tmp;
-        if ((dhp == NULL) && (s->cert->dh_tmp_cb != NULL))
-            dhp = s->cert->dh_tmp_cb(s,
-                                     SSL_C_IS_EXPORT(s->s3->
-                                                     tmp.new_cipher),
-                                     SSL_C_EXPORT_PKEYLENGTH(s->s3->
-                                                             tmp.new_cipher));
-        if (dhp == NULL) {
-            al = SSL_AD_HANDSHAKE_FAILURE;
-            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
-                   SSL_R_MISSING_TMP_DH_KEY);
-            goto f_err;
-        }
-        if (!ssl_security(s, SSL_SECOP_TMP_DH,
-                          DH_security_bits(dhp), 0, dhp)) {
-            al = SSL_AD_HANDSHAKE_FAILURE;
-            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
-                   SSL_R_DH_KEY_TOO_SMALL);
-            goto f_err;
-        }
-        if (s->s3->tmp.dh != NULL) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
-                   ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
-
-        if (s->cert->dh_tmp_auto)
-            dh = dhp;
-        else if ((dh = DHparams_dup(dhp)) == NULL) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_DH_LIB);
-            goto err;
-        }
-
-        s->s3->tmp.dh = dh;
-        if ((dhp->pub_key == NULL ||
-             dhp->priv_key == NULL ||
-             (s->options & SSL_OP_SINGLE_DH_USE))) {
-            if (!DH_generate_key(dh)) {
-                SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_DH_LIB);
-                goto err;
-            }
-        } else {
-            dh->pub_key = BN_dup(dhp->pub_key);
-            dh->priv_key = BN_dup(dhp->priv_key);
-            if ((dh->pub_key == NULL) || (dh->priv_key == NULL)) {
-                SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_DH_LIB);
-                goto err;
-            }
-        }
-        r[0] = dh->p;
-        r[1] = dh->g;
-        r[2] = dh->pub_key;
-    } else
-#endif
-#ifndef OPENSSL_NO_EC
-    if (type & (SSL_kECDHE | SSL_kECDHEPSK)) {
-        const EC_GROUP *group;
-
-        ecdhp = cert->ecdh_tmp;
-        if (s->cert->ecdh_tmp_auto) {
-            /* Get NID of appropriate shared curve */
-            int nid = tls1_shared_curve(s, -2);
-            if (nid != NID_undef)
-                ecdhp = EC_KEY_new_by_curve_name(nid);
-        } else if ((ecdhp == NULL) && s->cert->ecdh_tmp_cb) {
-            ecdhp = s->cert->ecdh_tmp_cb(s,
-                                         SSL_C_IS_EXPORT(s->s3->
-                                                         tmp.new_cipher),
-                                         SSL_C_EXPORT_PKEYLENGTH(s->
-                                                                 s3->tmp.new_cipher));
-        }
-        if (ecdhp == NULL) {
-            al = SSL_AD_HANDSHAKE_FAILURE;
-            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
-                   SSL_R_MISSING_TMP_ECDH_KEY);
-            goto f_err;
-        }
-
-        if (s->s3->tmp.ecdh != NULL) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
-                   ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
-
-        /* Duplicate the ECDH structure. */
-        if (ecdhp == NULL) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_ECDH_LIB);
-            goto err;
-        }
-        if (s->cert->ecdh_tmp_auto)
-            ecdh = ecdhp;
-        else if ((ecdh = EC_KEY_dup(ecdhp)) == NULL) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_ECDH_LIB);
-            goto err;
-        }
-
-        s->s3->tmp.ecdh = ecdh;
-        if ((EC_KEY_get0_public_key(ecdh) == NULL) ||
-            (EC_KEY_get0_private_key(ecdh) == NULL) ||
-            (s->options & SSL_OP_SINGLE_ECDH_USE)) {
-            if (!EC_KEY_generate_key(ecdh)) {
-                SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
-                       ERR_R_ECDH_LIB);
-                goto err;
-            }
-        }
-
-        if (((group = EC_KEY_get0_group(ecdh)) == NULL) ||
-            (EC_KEY_get0_public_key(ecdh) == NULL) ||
-            (EC_KEY_get0_private_key(ecdh) == NULL)) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_ECDH_LIB);
-            goto err;
-        }
-
-        if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) &&
-            (EC_GROUP_get_degree(group) > 163)) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
-                   SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER);
-            goto err;
-        }
-
-        /*
-         * XXX: For now, we only support ephemeral ECDH keys over named
-         * (not generic) curves. For supported named curves, curve_id is
-         * non-zero.
-         */
-        if ((curve_id =
-             tls1_ec_nid2curve_id(EC_GROUP_get_curve_name(group)))
-            == 0) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
-                   SSL_R_UNSUPPORTED_ELLIPTIC_CURVE);
-            goto err;
-        }
-
-        /*
-         * Encode the public key. First check the size of encoding and
-         * allocate memory accordingly.
-         */
-        encodedlen = EC_POINT_point2oct(group,
-                                        EC_KEY_get0_public_key(ecdh),
-                                        POINT_CONVERSION_UNCOMPRESSED,
-                                        NULL, 0, NULL);
-
-        encodedPoint = (unsigned char *)
-            OPENSSL_malloc(encodedlen * sizeof(unsigned char));
-        bn_ctx = BN_CTX_new();
-        if ((encodedPoint == NULL) || (bn_ctx == NULL)) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
-                   ERR_R_MALLOC_FAILURE);
-            goto err;
-        }
-
-        encodedlen = EC_POINT_point2oct(group,
-                                        EC_KEY_get0_public_key(ecdh),
-                                        POINT_CONVERSION_UNCOMPRESSED,
-                                        encodedPoint, encodedlen, bn_ctx);
-
-        if (encodedlen == 0) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_ECDH_LIB);
-            goto err;
-        }
-
-        BN_CTX_free(bn_ctx);
-        bn_ctx = NULL;
-
-        /*
-         * XXX: For now, we only support named (not generic) curves in
-         * ECDH ephemeral key exchanges. In this situation, we need four
-         * additional bytes to encode the entire ServerECDHParams
-         * structure.
-         */
-        n += 4 + encodedlen;
-
-        /*
-         * We'll generate the serverKeyExchange message explicitly so we
-         * can set these to NULLs
-         */
-        r[0] = NULL;
-        r[1] = NULL;
-        r[2] = NULL;
-        r[3] = NULL;
-    } else
-#endif                          /* !OPENSSL_NO_EC */
-#ifndef OPENSSL_NO_SRP
-    if (type & SSL_kSRP) {
-        if ((s->srp_ctx.N == NULL) ||
-            (s->srp_ctx.g == NULL) ||
-            (s->srp_ctx.s == NULL) || (s->srp_ctx.B == NULL)) {
-            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
-                   SSL_R_MISSING_SRP_PARAM);
-            goto err;
-        }
-        r[0] = s->srp_ctx.N;
-        r[1] = s->srp_ctx.g;
-        r[2] = s->srp_ctx.s;
-        r[3] = s->srp_ctx.B;
-    } else
-#endif
-    {
-        al = SSL_AD_HANDSHAKE_FAILURE;
-        SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
-               SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE);
-        goto f_err;
-    }
-    for (i = 0; i < 4 && r[i] != NULL; i++) {
-        nr[i] = BN_num_bytes(r[i]);
-#ifndef OPENSSL_NO_SRP
-        if ((i == 2) && (type & SSL_kSRP))
-            n += 1 + nr[i];
-        else
-#endif
-            n += 2 + nr[i];
-    }
-
-    if (!(s->s3->tmp.new_cipher->algorithm_auth & (SSL_aNULL|SSL_aSRP))
-        && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_PSK)) {
-        if ((pkey = ssl_get_sign_pkey(s, s->s3->tmp.new_cipher, &md))
-            == NULL) {
-            al = SSL_AD_DECODE_ERROR;
-            goto f_err;
-        }
-        kn = EVP_PKEY_size(pkey);
-    } else {
-        pkey = NULL;
-        kn = 0;
-    }
-
-    if (!BUF_MEM_grow_clean(buf, n + SSL_HM_HEADER_LENGTH(s) + kn)) {
-        SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_LIB_BUF);
-        goto err;
-    }
-    d = p = ssl_handshake_start(s);
-
-#ifndef OPENSSL_NO_PSK
-    if (type & SSL_PSK) {
-        /* copy PSK identity hint */
-        if (s->cert->psk_identity_hint) {
-            s2n(strlen(s->cert->psk_identity_hint), p);
-            strncpy((char *)p, s->cert->psk_identity_hint,
-                    strlen(s->cert->psk_identity_hint));
-            p += strlen(s->cert->psk_identity_hint);
-        } else {
-            s2n(0, p);
-        }
-    }
-#endif
-
-    for (i = 0; i < 4 && r[i] != NULL; i++) {
-#ifndef OPENSSL_NO_SRP
-        if ((i == 2) && (type & SSL_kSRP)) {
-            *p = nr[i];
-            p++;
-        } else
-#endif
-            s2n(nr[i], p);
-        BN_bn2bin(r[i], p);
-        p += nr[i];
-    }
-
-#ifndef OPENSSL_NO_EC
-    if (type & (SSL_kECDHE | SSL_kECDHEPSK)) {
-        /*
-         * XXX: For now, we only support named (not generic) curves. In
-         * this situation, the serverKeyExchange message has: [1 byte
-         * CurveType], [2 byte CurveName] [1 byte length of encoded
-         * point], followed by the actual encoded point itself
-         */
-        *p = NAMED_CURVE_TYPE;
-        p += 1;
-        *p = 0;
-        p += 1;
-        *p = curve_id;
-        p += 1;
-        *p = encodedlen;
-        p += 1;
-        memcpy(p, encodedPoint, encodedlen);
-        OPENSSL_free(encodedPoint);
-        encodedPoint = NULL;
-        p += encodedlen;
-    }
-#endif
-
-    /* not anonymous */
-    if (pkey != NULL) {
-        /*
-         * n is the length of the params, they start at &(d[4]) and p
-         * points to the space at the end.
-         */
-#ifndef OPENSSL_NO_RSA
-        if (pkey->type == EVP_PKEY_RSA && !SSL_USE_SIGALGS(s)) {
-            q = md_buf;
-            j = 0;
-            for (num = 2; num > 0; num--) {
-                EVP_MD_CTX_set_flags(&md_ctx,
-                                     EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
-                EVP_DigestInit_ex(&md_ctx, (num == 2)
-                                  ? s->ctx->md5 : s->ctx->sha1, NULL);
-                EVP_DigestUpdate(&md_ctx, &(s->s3->client_random[0]),
-                                 SSL3_RANDOM_SIZE);
-                EVP_DigestUpdate(&md_ctx, &(s->s3->server_random[0]),
-                                 SSL3_RANDOM_SIZE);
-                EVP_DigestUpdate(&md_ctx, d, n);
-                EVP_DigestFinal_ex(&md_ctx, q, (unsigned int *)&i);
-                q += i;
-                j += i;
-            }
-            if (RSA_sign(NID_md5_sha1, md_buf, j,
-                         &(p[2]), &u, pkey->pkey.rsa) <= 0) {
-                SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_LIB_RSA);
-                goto err;
-            }
-            s2n(u, p);
-            n += u + 2;
-        } else
-#endif
-        if (md) {
-            /* send signature algorithm */
-            if (SSL_USE_SIGALGS(s)) {
-                if (!tls12_get_sigandhash(p, pkey, md)) {
-                    /* Should never happen */
-                    al = SSL_AD_INTERNAL_ERROR;
-                    SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
-                           ERR_R_INTERNAL_ERROR);
-                    goto f_err;
-                }
-                p += 2;
-            }
-#ifdef SSL_DEBUG
-            fprintf(stderr, "Using hash %s\n", EVP_MD_name(md));
-#endif
-            EVP_SignInit_ex(&md_ctx, md, NULL);
-            EVP_SignUpdate(&md_ctx, &(s->s3->client_random[0]),
-                           SSL3_RANDOM_SIZE);
-            EVP_SignUpdate(&md_ctx, &(s->s3->server_random[0]),
-                           SSL3_RANDOM_SIZE);
-            EVP_SignUpdate(&md_ctx, d, n);
-            if (!EVP_SignFinal(&md_ctx, &(p[2]),
-                               (unsigned int *)&i, pkey)) {
-                SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_LIB_EVP);
-                goto err;
-            }
-            s2n(i, p);
-            n += i + 2;
-            if (SSL_USE_SIGALGS(s))
-                n += 2;
-        } else {
-            /* Is this error check actually needed? */
-            al = SSL_AD_HANDSHAKE_FAILURE;
-            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
-                   SSL_R_UNKNOWN_PKEY_TYPE);
-            goto f_err;
-        }
-    }
-
-    if (!ssl_set_handshake_header(s, SSL3_MT_SERVER_KEY_EXCHANGE, n)) {
-        al = SSL_AD_HANDSHAKE_FAILURE;
-        SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
-        goto f_err;
-    }
-
-    EVP_MD_CTX_cleanup(&md_ctx);
-    return 1;
- f_err:
-    ssl3_send_alert(s, SSL3_AL_FATAL, al);
- err:
-#ifndef OPENSSL_NO_EC
-    OPENSSL_free(encodedPoint);
-    BN_CTX_free(bn_ctx);
-#endif
-    EVP_MD_CTX_cleanup(&md_ctx);
-    statem_set_error(s);
-    return 0;
-}
-
-int tls_construct_certificate_request(SSL *s)
-{
-    unsigned char *p, *d;
-    int i, j, nl, off, n;
-    STACK_OF(X509_NAME) *sk = NULL;
-    X509_NAME *name;
-    BUF_MEM *buf;
-
-    buf = s->init_buf;
-
-    d = p = ssl_handshake_start(s);
-
-    /* get the list of acceptable cert types */
-    p++;
-    n = ssl3_get_req_cert_type(s, p);
-    d[0] = n;
-    p += n;
-    n++;
-
-    if (SSL_USE_SIGALGS(s)) {
-        const unsigned char *psigs;
-        unsigned char *etmp = p;
-        nl = tls12_get_psigalgs(s, &psigs);
-        /* Skip over length for now */
-        p += 2;
-        nl = tls12_copy_sigalgs(s, p, psigs, nl);
-        /* Now fill in length */
-        s2n(nl, etmp);
-        p += nl;
-        n += nl + 2;
-    }
-
-    off = n;
-    p += 2;
-    n += 2;
-
-    sk = SSL_get_client_CA_list(s);
-    nl = 0;
-    if (sk != NULL) {
-        for (i = 0; i < sk_X509_NAME_num(sk); i++) {
-            name = sk_X509_NAME_value(sk, i);
-            j = i2d_X509_NAME(name, NULL);
-            if (!BUF_MEM_grow_clean
-                (buf, SSL_HM_HEADER_LENGTH(s) + n + j + 2)) {
-                SSLerr(SSL_F_TLS_CONSTRUCT_CERTIFICATE_REQUEST,
-                       ERR_R_BUF_LIB);
-                goto err;
-            }
-            p = ssl_handshake_start(s) + n;
-            s2n(j, p);
-            i2d_X509_NAME(name, &p);
-            n += 2 + j;
-            nl += 2 + j;
-        }
-    }
-    /* else no CA names */
-    p = ssl_handshake_start(s) + off;
-    s2n(nl, p);
-
-    if (!ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE_REQUEST, n)) {
-        SSLerr(SSL_F_TLS_CONSTRUCT_CERTIFICATE_REQUEST, ERR_R_INTERNAL_ERROR);
-        goto err;
-    }
-
-    s->s3->tmp.cert_request = 1;
-
-    return 1;
- err:
-    statem_set_error(s);
-    return 0;
-}
-
-enum MSG_PROCESS_RETURN tls_process_client_key_exchange(SSL *s, PACKET *pkt)
-{
-    int al;
-    unsigned int i;
-    unsigned long alg_k;
-#ifndef OPENSSL_NO_RSA
-    RSA *rsa = NULL;
-    EVP_PKEY *pkey = NULL;
-#endif
-#ifndef OPENSSL_NO_DH
-    BIGNUM *pub = NULL;
-    DH *dh_srvr, *dh_clnt = NULL;
-#endif
-#ifndef OPENSSL_NO_EC
-    EC_KEY *srvr_ecdh = NULL;
-    EVP_PKEY *clnt_pub_pkey = NULL;
-    EC_POINT *clnt_ecpoint = NULL;
-    BN_CTX *bn_ctx = NULL;
-#endif
-    PACKET enc_premaster;
-    unsigned char *data, *rsa_decrypt = NULL;
-
-    alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
-
-#ifndef OPENSSL_NO_PSK
-    /* For PSK parse and retrieve identity, obtain PSK key */
-    if (alg_k & SSL_PSK) {
-        unsigned char psk[PSK_MAX_PSK_LEN];
-        size_t psklen;
-        PACKET psk_identity;
-
-        if (!PACKET_get_length_prefixed_2(pkt, &psk_identity)) {
-            al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
-            goto f_err;
-        }
-        if (PACKET_remaining(&psk_identity) > PSK_MAX_IDENTITY_LEN) {
-            al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
-                   SSL_R_DATA_LENGTH_TOO_LONG);
-            goto f_err;
-        }
-        if (s->psk_server_callback == NULL) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
-                   SSL_R_PSK_NO_SERVER_CB);
-            goto f_err;
-        }
-
-        if (!PACKET_strndup(&psk_identity, &s->session->psk_identity)) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
-            al = SSL_AD_INTERNAL_ERROR;
-            goto f_err;
-        }
-
-        psklen = s->psk_server_callback(s, s->session->psk_identity,
-                                         psk, sizeof(psk));
-
-        if (psklen > PSK_MAX_PSK_LEN) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
-            goto f_err;
-        } else if (psklen == 0) {
-            /*
-             * PSK related to the given identity not found
-             */
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
-                   SSL_R_PSK_IDENTITY_NOT_FOUND);
-            al = SSL_AD_UNKNOWN_PSK_IDENTITY;
-            goto f_err;
-        }
-
-        OPENSSL_free(s->s3->tmp.psk);
-        s->s3->tmp.psk = BUF_memdup(psk, psklen);
-        OPENSSL_cleanse(psk, psklen);
-
-        if (s->s3->tmp.psk == NULL) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
-            goto f_err;
-        }
-
-        s->s3->tmp.psklen = psklen;
-    }
-    if (alg_k & SSL_kPSK) {
-        /* Identity extracted earlier: should be nothing left */
-        if (PACKET_remaining(pkt) != 0) {
-            al = SSL_AD_HANDSHAKE_FAILURE;
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
-            goto f_err;
-        }
-        /* PSK handled by ssl_generate_master_secret */
-        if (!ssl_generate_master_secret(s, NULL, 0, 0)) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
-            goto f_err;
-        }
-    } else
-#endif
-#ifndef OPENSSL_NO_RSA
-    if (alg_k & (SSL_kRSA | SSL_kRSAPSK)) {
-        unsigned char rand_premaster_secret[SSL_MAX_MASTER_KEY_LENGTH];
-        int decrypt_len;
-        unsigned char decrypt_good, version_good;
-        size_t j;
-
-        /* FIX THIS UP EAY EAY EAY EAY */
-        if (s->s3->tmp.use_rsa_tmp) {
-            if ((s->cert != NULL) && (s->cert->rsa_tmp != NULL))
-                rsa = s->cert->rsa_tmp;
-            /*
-             * Don't do a callback because rsa_tmp should be sent already
-             */
-            if (rsa == NULL) {
-                al = SSL_AD_HANDSHAKE_FAILURE;
-                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
-                       SSL_R_MISSING_TMP_RSA_PKEY);
-                goto f_err;
-
-            }
-        } else {
-            pkey = s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey;
-            if ((pkey == NULL) ||
-                (pkey->type != EVP_PKEY_RSA) || (pkey->pkey.rsa == NULL)) {
-                al = SSL_AD_HANDSHAKE_FAILURE;
-                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
-                       SSL_R_MISSING_RSA_CERTIFICATE);
-                goto f_err;
-            }
-            rsa = pkey->pkey.rsa;
-        }
-
-        /* SSLv3 and pre-standard DTLS omit the length bytes. */
-        if (s->version == SSL3_VERSION || s->version == DTLS1_BAD_VER) {
-            enc_premaster = *pkt;
-        } else {
-            PACKET orig = *pkt;
-            if (!PACKET_get_length_prefixed_2(pkt, &enc_premaster)
-                || PACKET_remaining(pkt) != 0) {
-                /* Try SSLv3 behaviour for TLS. */
-                if (s->options & SSL_OP_TLS_D5_BUG) {
-                    enc_premaster = orig;
-                } else {
-                    al = SSL_AD_DECODE_ERROR;
-                    SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
-                    goto f_err;
-                }
-            }
-        }
-
-        /*
-         * We want to be sure that the plaintext buffer size makes it safe to
-         * iterate over the entire size of a premaster secret
-         * (SSL_MAX_MASTER_KEY_LENGTH). Reject overly short RSA keys because
-         * their ciphertext cannot accommodate a premaster secret anyway.
-         */
-        if (RSA_size(rsa) < SSL_MAX_MASTER_KEY_LENGTH) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
-                   RSA_R_KEY_SIZE_TOO_SMALL);
-            goto f_err;
-        }
-
-        rsa_decrypt = OPENSSL_malloc(RSA_size(rsa));
-        if (rsa_decrypt == NULL) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
-            goto f_err;
-        }
-
-        /*
-         * We must not leak whether a decryption failure occurs because of
-         * Bleichenbacher's attack on PKCS #1 v1.5 RSA padding (see RFC 2246,
-         * section 7.4.7.1). The code follows that advice of the TLS RFC and
-         * generates a random premaster secret for the case that the decrypt
-         * fails. See https://tools.ietf.org/html/rfc5246#section-7.4.7.1
-         */
-
-        if (RAND_bytes(rand_premaster_secret,
-                       sizeof(rand_premaster_secret)) <= 0) {
-            goto err;
-        }
-
-        decrypt_len = RSA_private_decrypt(PACKET_remaining(&enc_premaster),
-                                          PACKET_data(&enc_premaster),
-                                          rsa_decrypt, rsa, RSA_PKCS1_PADDING);
-        ERR_clear_error();
-
-        /*
-         * decrypt_len should be SSL_MAX_MASTER_KEY_LENGTH. decrypt_good will
-         * be 0xff if so and zero otherwise.
-         */
-        decrypt_good =
-            constant_time_eq_int_8(decrypt_len, SSL_MAX_MASTER_KEY_LENGTH);
-
-        /*
-         * If the version in the decrypted pre-master secret is correct then
-         * version_good will be 0xff, otherwise it'll be zero. The
-         * Klima-Pokorny-Rosa extension of Bleichenbacher's attack
-         * (http://eprint.iacr.org/2003/052/) exploits the version number
-         * check as a "bad version oracle". Thus version checks are done in
-         * constant time and are treated like any other decryption error.
-         */
-        version_good =
-            constant_time_eq_8(rsa_decrypt[0],
-                               (unsigned)(s->client_version >> 8));
-        version_good &=
-            constant_time_eq_8(rsa_decrypt[1],
-                               (unsigned)(s->client_version & 0xff));
-
-        /*
-         * The premaster secret must contain the same version number as the
-         * ClientHello to detect version rollback attacks (strangely, the
-         * protocol does not offer such protection for DH ciphersuites).
-         * However, buggy clients exist that send the negotiated protocol
-         * version instead if the server does not support the requested
-         * protocol version. If SSL_OP_TLS_ROLLBACK_BUG is set, tolerate such
-         * clients.
-         */
-        if (s->options & SSL_OP_TLS_ROLLBACK_BUG) {
-            unsigned char workaround_good;
-            workaround_good =
-                constant_time_eq_8(rsa_decrypt[0], (unsigned)(s->version >> 8));
-            workaround_good &=
-                constant_time_eq_8(rsa_decrypt[1],
-                                   (unsigned)(s->version & 0xff));
-            version_good |= workaround_good;
-        }
-
-        /*
-         * Both decryption and version must be good for decrypt_good to
-         * remain non-zero (0xff).
-         */
-        decrypt_good &= version_good;
-
-        /*
-         * Now copy rand_premaster_secret over from p using
-         * decrypt_good_mask. If decryption failed, then p does not
-         * contain valid plaintext, however, a check above guarantees
-         * it is still sufficiently large to read from.
-         */
-        for (j = 0; j < sizeof(rand_premaster_secret); j++) {
-            rsa_decrypt[j] =
-                constant_time_select_8(decrypt_good, rsa_decrypt[j],
-                                       rand_premaster_secret[j]);
-        }
-
-        if (!ssl_generate_master_secret(s, rsa_decrypt,
-                                        sizeof(rand_premaster_secret), 0)) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
-            goto f_err;
-        }
-        OPENSSL_free(rsa_decrypt);
-        rsa_decrypt = NULL;
-    } else
-#endif
-#ifndef OPENSSL_NO_DH
-    if (alg_k & (SSL_kDHE | SSL_kDHr | SSL_kDHd | SSL_kDHEPSK)) {
-        int idx = -1;
-        EVP_PKEY *skey = NULL;
-        PACKET bookmark = *pkt;
-        unsigned char shared[(OPENSSL_DH_MAX_MODULUS_BITS + 7) / 8];
-
-        if (!PACKET_get_net_2(pkt, &i)) {
-            if (alg_k & (SSL_kDHE | SSL_kDHEPSK)) {
-                al = SSL_AD_HANDSHAKE_FAILURE;
-                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
-                       SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG);
-                goto f_err;
-            }
-            i = 0;
-        }
-        if (PACKET_remaining(pkt) != i) {
-            if (!(s->options & SSL_OP_SSLEAY_080_CLIENT_DH_BUG)) {
-                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
-                       SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG);
-                goto err;
-            } else {
-                *pkt = bookmark;
-                i = PACKET_remaining(pkt);
-            }
-        }
-        if (alg_k & SSL_kDHr)
-            idx = SSL_PKEY_DH_RSA;
-        else if (alg_k & SSL_kDHd)
-            idx = SSL_PKEY_DH_DSA;
-        if (idx >= 0) {
-            skey = s->cert->pkeys[idx].privatekey;
-            if ((skey == NULL) ||
-                (skey->type != EVP_PKEY_DH) || (skey->pkey.dh == NULL)) {
-                al = SSL_AD_HANDSHAKE_FAILURE;
-                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
-                       SSL_R_MISSING_RSA_CERTIFICATE);
-                goto f_err;
-            }
-            dh_srvr = skey->pkey.dh;
-        } else if (s->s3->tmp.dh == NULL) {
-            al = SSL_AD_HANDSHAKE_FAILURE;
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
-                   SSL_R_MISSING_TMP_DH_KEY);
-            goto f_err;
-        } else
-            dh_srvr = s->s3->tmp.dh;
-
-        if (PACKET_remaining(pkt) == 0L) {
-            /* Get pubkey from cert */
-            EVP_PKEY *clkey = X509_get_pubkey(s->session->peer);
-            if (clkey) {
-                if (EVP_PKEY_cmp_parameters(clkey, skey) == 1)
-                    dh_clnt = EVP_PKEY_get1_DH(clkey);
-            }
-            if (dh_clnt == NULL) {
-                al = SSL_AD_HANDSHAKE_FAILURE;
-                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
-                       SSL_R_MISSING_TMP_DH_KEY);
-                goto f_err;
-            }
-            EVP_PKEY_free(clkey);
-            pub = dh_clnt->pub_key;
-        } else {
-            if (!PACKET_get_bytes(pkt, &data, i)) {
-                /* We already checked we have enough data */
-                al = SSL_AD_INTERNAL_ERROR;
-                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
-                       ERR_R_INTERNAL_ERROR);
-                goto f_err;
-            }
-            pub = BN_bin2bn(data, i, NULL);
-        }
-        if (pub == NULL) {
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, SSL_R_BN_LIB);
-            goto err;
-        }
-
-        i = DH_compute_key(shared, pub, dh_srvr);
-
-        if (i <= 0) {
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB);
-            BN_clear_free(pub);
-            goto err;
-        }
-
-        DH_free(s->s3->tmp.dh);
-        s->s3->tmp.dh = NULL;
-        if (dh_clnt)
-            DH_free(dh_clnt);
-        else
-            BN_clear_free(pub);
-        pub = NULL;
-        if (!ssl_generate_master_secret(s, shared, i, 0)) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
-            goto f_err;
-        }
-        if (dh_clnt) {
-            s->no_cert_verify = 1;
-            return MSG_PROCESS_CONTINUE_PROCESSING;
-        }
-    } else
-#endif
-
-#ifndef OPENSSL_NO_EC
-    if (alg_k & (SSL_kECDHE | SSL_kECDHr | SSL_kECDHe | SSL_kECDHEPSK)) {
-        int field_size = 0;
-        const EC_KEY *tkey;
-        const EC_GROUP *group;
-        const BIGNUM *priv_key;
-        unsigned char *shared;
-
-        /* initialize structures for server's ECDH key pair */
-        if ((srvr_ecdh = EC_KEY_new()) == NULL) {
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
-            goto err;
-        }
-
-        /* Let's get server private key and group information */
-        if (alg_k & (SSL_kECDHr | SSL_kECDHe)) {
-            /* use the certificate */
-            tkey = s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec;
-        } else {
-            /*
-             * use the ephermeral values we saved when generating the
-             * ServerKeyExchange msg.
-             */
-            tkey = s->s3->tmp.ecdh;
-        }
-
-        group = EC_KEY_get0_group(tkey);
-        priv_key = EC_KEY_get0_private_key(tkey);
-
-        if (!EC_KEY_set_group(srvr_ecdh, group) ||
-            !EC_KEY_set_private_key(srvr_ecdh, priv_key)) {
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
-            goto err;
-        }
-
-        /* Let's get client's public key */
-        if ((clnt_ecpoint = EC_POINT_new(group)) == NULL) {
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
-            goto err;
-        }
-
-        if (PACKET_remaining(pkt) == 0L) {
-            /* Client Publickey was in Client Certificate */
-
-            if (alg_k & (SSL_kECDHE | SSL_kECDHEPSK)) {
-                al = SSL_AD_HANDSHAKE_FAILURE;
-                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
-                       SSL_R_MISSING_TMP_ECDH_KEY);
-                goto f_err;
-            }
-            if (((clnt_pub_pkey = X509_get_pubkey(s->session->peer))
-                 == NULL) || (clnt_pub_pkey->type != EVP_PKEY_EC)) {
-                /*
-                 * XXX: For now, we do not support client authentication
-                 * using ECDH certificates so this branch (n == 0L) of the
-                 * code is never executed. When that support is added, we
-                 * ought to ensure the key received in the certificate is
-                 * authorized for key agreement. ECDH_compute_key implicitly
-                 * checks that the two ECDH shares are for the same group.
-                 */
-                al = SSL_AD_HANDSHAKE_FAILURE;
-                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
-                       SSL_R_UNABLE_TO_DECODE_ECDH_CERTS);
-                goto f_err;
-            }
-
-            if (EC_POINT_copy(clnt_ecpoint,
-                              EC_KEY_get0_public_key(clnt_pub_pkey->
-                                                     pkey.ec)) == 0) {
-                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
-                goto err;
-            }
-            s->no_cert_verify = 1;
-        } else {
-            /*
-             * Get client's public key from encoded point in the
-             * ClientKeyExchange message.
-             */
-            if ((bn_ctx = BN_CTX_new()) == NULL) {
-                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
-                       ERR_R_MALLOC_FAILURE);
-                goto err;
-            }
-
-            /* Get encoded point length */
-            if (!PACKET_get_1(pkt, &i)) {
-                al = SSL_AD_DECODE_ERROR;
-                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
-                       SSL_R_LENGTH_MISMATCH);
-                goto f_err;
-            }
-            if (!PACKET_get_bytes(pkt, &data, i)
-                    || PACKET_remaining(pkt) != 0) {
-                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
-                goto err;
-            }
-            if (EC_POINT_oct2point(group, clnt_ecpoint, data, i, bn_ctx) == 0) {
-                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
-                goto err;
-            }
-        }
-
-        /* Compute the shared pre-master secret */
-        field_size = EC_GROUP_get_degree(group);
-        if (field_size <= 0) {
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
-            goto err;
-        }
-        shared = OPENSSL_malloc((field_size + 7) / 8);
-        if (shared == NULL) {
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
-            goto err;
-        }
-        i = ECDH_compute_key(shared, (field_size + 7) / 8, clnt_ecpoint,
-                             srvr_ecdh, NULL);
-        if (i <= 0) {
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
-            OPENSSL_free(shared);
-            goto err;
-        }
-
-        EVP_PKEY_free(clnt_pub_pkey);
-        EC_POINT_free(clnt_ecpoint);
-        EC_KEY_free(srvr_ecdh);
-        BN_CTX_free(bn_ctx);
-        EC_KEY_free(s->s3->tmp.ecdh);
-        s->s3->tmp.ecdh = NULL;
-
-        if (!ssl_generate_master_secret(s, shared, i, 1)) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
-            goto f_err;
-        }
-        return MSG_PROCESS_CONTINUE_PROCESSING;
-    } else
-#endif
-#ifndef OPENSSL_NO_SRP
-    if (alg_k & SSL_kSRP) {
-        if (!PACKET_get_net_2(pkt, &i)
-                || !PACKET_get_bytes(pkt, &data, i)) {
-            al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, SSL_R_BAD_SRP_A_LENGTH);
-            goto f_err;
-        }
-        if ((s->srp_ctx.A = BN_bin2bn(data, i, NULL)) == NULL) {
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_BN_LIB);
-            goto err;
-        }
-        if (BN_ucmp(s->srp_ctx.A, s->srp_ctx.N) >= 0
-            || BN_is_zero(s->srp_ctx.A)) {
-            al = SSL_AD_ILLEGAL_PARAMETER;
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
-                   SSL_R_BAD_SRP_PARAMETERS);
-            goto f_err;
-        }
-        OPENSSL_free(s->session->srp_username);
-        s->session->srp_username = BUF_strdup(s->srp_ctx.login);
-        if (s->session->srp_username == NULL) {
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
-            goto err;
-        }
-
-        if (!srp_generate_server_master_secret(s)) {
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
-            goto err;
-        }
-    } else
-#endif                          /* OPENSSL_NO_SRP */
-    if (alg_k & SSL_kGOST) {
-        EVP_PKEY_CTX *pkey_ctx;
-        EVP_PKEY *client_pub_pkey = NULL, *pk = NULL;
-        unsigned char premaster_secret[32], *start;
-        size_t outlen = 32, inlen;
-        unsigned long alg_a;
-        int Ttag, Tclass;
-        long Tlen;
-        long sess_key_len;
-
-        /* Get our certificate private key */
-        alg_a = s->s3->tmp.new_cipher->algorithm_auth;
-        if (alg_a & SSL_aGOST01)
-            pk = s->cert->pkeys[SSL_PKEY_GOST01].privatekey;
-
-        pkey_ctx = EVP_PKEY_CTX_new(pk, NULL);
-        EVP_PKEY_decrypt_init(pkey_ctx);
-        /*
-         * If client certificate is present and is of the same type, maybe
-         * use it for key exchange.  Don't mind errors from
-         * EVP_PKEY_derive_set_peer, because it is completely valid to use a
-         * client certificate for authorization only.
-         */
-        client_pub_pkey = X509_get_pubkey(s->session->peer);
-        if (client_pub_pkey) {
-            if (EVP_PKEY_derive_set_peer(pkey_ctx, client_pub_pkey) <= 0)
-                ERR_clear_error();
-        }
-        /* Decrypt session key */
-        sess_key_len = PACKET_remaining(pkt);
-        if (!PACKET_get_bytes(pkt, &data, sess_key_len)) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
-            goto f_err;
-        }
-        if (ASN1_get_object ((const unsigned char **)&data, &Tlen, &Ttag,
-                             &Tclass, sess_key_len) != V_ASN1_CONSTRUCTED
-            || Ttag != V_ASN1_SEQUENCE
-            || Tclass != V_ASN1_UNIVERSAL) {
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
-                   SSL_R_DECRYPTION_FAILED);
-            goto gerr;
-        }
-        start = data;
-        inlen = Tlen;
-        if (EVP_PKEY_decrypt
-            (pkey_ctx, premaster_secret, &outlen, start, inlen) <= 0) {
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
-                   SSL_R_DECRYPTION_FAILED);
-            goto gerr;
-        }
-        /* Generate master secret */
-        if (!ssl_generate_master_secret(s, premaster_secret,
-                                        sizeof(premaster_secret), 0)) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
-            goto f_err;
-        }
-        /* Check if pubkey from client certificate was used */
-        if (EVP_PKEY_CTX_ctrl
-            (pkey_ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 2, NULL) > 0)
-            s->no_cert_verify = 1;
-
-        EVP_PKEY_free(client_pub_pkey);
-        EVP_PKEY_CTX_free(pkey_ctx);
-        return MSG_PROCESS_CONTINUE_PROCESSING;
- gerr:
-        EVP_PKEY_free(client_pub_pkey);
-        EVP_PKEY_CTX_free(pkey_ctx);
-        goto err;
-    } else {
-        al = SSL_AD_HANDSHAKE_FAILURE;
-        SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, SSL_R_UNKNOWN_CIPHER_TYPE);
-        goto f_err;
-    }
-
-    return MSG_PROCESS_CONTINUE_PROCESSING;
- f_err:
-    ssl3_send_alert(s, SSL3_AL_FATAL, al);
-#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_RSA) || !defined(OPENSSL_NO_EC) || defined(OPENSSL_NO_SRP)
- err:
-#endif
-#ifndef OPENSSL_NO_EC
-    EVP_PKEY_free(clnt_pub_pkey);
-    EC_POINT_free(clnt_ecpoint);
-    EC_KEY_free(srvr_ecdh);
-    BN_CTX_free(bn_ctx);
-    OPENSSL_free(rsa_decrypt);
-#endif
-#ifndef OPENSSL_NO_PSK
-    OPENSSL_clear_free(s->s3->tmp.psk, s->s3->tmp.psklen);
-    s->s3->tmp.psk = NULL;
-#endif
-    statem_set_error(s);
-    return MSG_PROCESS_ERROR;
-}
-
-enum WORK_STATE tls_post_process_client_key_exchange(SSL *s,
-                                                      enum WORK_STATE wst)
-{
-#ifndef OPENSSL_NO_SCTP
-    if (wst == WORK_MORE_A) {
-        if (SSL_IS_DTLS(s)) {
-            unsigned char sctpauthkey[64];
-            char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
-            /*
-             * Add new shared key for SCTP-Auth, will be ignored if no SCTP
-             * used.
-             */
-            snprintf((char *)labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL),
-                     DTLS1_SCTP_AUTH_LABEL);
-
-            if (SSL_export_keying_material(s, sctpauthkey,
-                                       sizeof(sctpauthkey), labelbuffer,
-                                       sizeof(labelbuffer), NULL, 0, 0) <= 0) {
-                statem_set_error(s);
-                return WORK_ERROR;;
-            }
-
-            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
-                     sizeof(sctpauthkey), sctpauthkey);
-        }
-        wst = WORK_MORE_B;
-    }
-
-    if ((wst == WORK_MORE_B)
-            /* Is this SCTP? */
-            && BIO_dgram_is_sctp(SSL_get_wbio(s))
-            /* Are we renegotiating? */
-            && s->renegotiate
-            /* Are we going to skip the CertificateVerify? */
-            && (s->session->peer == NULL || s->no_cert_verify)
-            && BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s))) {
-        s->s3->in_read_app_data = 2;
-        s->rwstate = SSL_READING;
-        BIO_clear_retry_flags(SSL_get_rbio(s));
-        BIO_set_retry_read(SSL_get_rbio(s));
-        statem_set_sctp_read_sock(s, 1);
-        return WORK_MORE_B;
-    } else {
-        statem_set_sctp_read_sock(s, 0);
-    }
-#endif
-
-    if (s->no_cert_verify) {
-        /* No certificate verify so we no longer need the handshake_buffer */
-        BIO_free(s->s3->handshake_buffer);
-        return WORK_FINISHED_CONTINUE;
-    } else if (SSL_USE_SIGALGS(s)) {
-        if (!s->session->peer) {
-            /* No peer certificate so we no longer need the handshake_buffer */
-            BIO_free(s->s3->handshake_buffer);
-            return WORK_FINISHED_CONTINUE;
-        }
-        if (!s->s3->handshake_buffer) {
-            SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_KEY_EXCHANGE,
-                   ERR_R_INTERNAL_ERROR);
-            statem_set_error(s);
-            return WORK_ERROR;
-        }
-        /*
-         * For sigalgs freeze the handshake buffer. If we support
-         * extms we've done this already so this is a no-op
-         */
-        if (!ssl3_digest_cached_records(s, 1)) {
-            statem_set_error(s);
-            return WORK_ERROR;
-        }
-    } else {
-        int offset = 0;
-        int dgst_num;
-
-        /*
-         * We need to get hashes here so if there is a client cert,
-         * it can be verified FIXME - digest processing for
-         * CertificateVerify should be generalized. But it is next
-         * step
-         */
-        if (!ssl3_digest_cached_records(s, 0)) {
-            statem_set_error(s);
-            return WORK_ERROR;
-        }
-        for (dgst_num = 0; dgst_num < SSL_MAX_DIGEST; dgst_num++) {
-            if (s->s3->handshake_dgst[dgst_num]) {
-                int dgst_size;
-
-                s->method->ssl3_enc->cert_verify_mac(s,
-                                                     EVP_MD_CTX_type
-                                                     (s->
-                                                      s3->handshake_dgst
-                                                      [dgst_num]),
-                                                     &(s->s3->
-                                                       tmp.cert_verify_md
-                                                       [offset]));
-                dgst_size =
-                    EVP_MD_CTX_size(s->s3->handshake_dgst[dgst_num]);
-                if (dgst_size < 0) {
-                    statem_set_error(s);
-                return WORK_ERROR;
-                }
-                offset += dgst_size;
-            }
-        }
-    }
-
-    return WORK_FINISHED_CONTINUE;
-}
-
-enum MSG_PROCESS_RETURN tls_process_cert_verify(SSL *s, PACKET *pkt)
-{
-    EVP_PKEY *pkey = NULL;
-    unsigned char *sig, *data;
-    int al, ret = MSG_PROCESS_ERROR;
-    int type = 0, i, j;
-    unsigned int len;
-    X509 *peer;
-    const EVP_MD *md = NULL;
-    EVP_MD_CTX mctx;
-    EVP_MD_CTX_init(&mctx);
-
-    peer = s->session->peer;
-    pkey = X509_get_pubkey(peer);
-    type = X509_certificate_type(peer, pkey);
-
-    if (!(type & EVP_PKT_SIGN)) {
-        SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY,
-               SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE);
-        al = SSL_AD_ILLEGAL_PARAMETER;
-        goto f_err;
-    }
-
-    /* Check for broken implementations of GOST ciphersuites */
-    /*
-     * If key is GOST and n is exactly 64, it is bare signature without
-     * length field
-     */
-    if (PACKET_remaining(pkt) == 64 && pkey->type == NID_id_GostR3410_2001) {
-        len = 64;
-    } else {
-        if (SSL_USE_SIGALGS(s)) {
-            int rv;
-
-            if (!PACKET_get_bytes(pkt, &sig, 2)) {
-                al = SSL_AD_DECODE_ERROR;
-                goto f_err;
-            }
-            rv = tls12_check_peer_sigalg(&md, s, sig, pkey);
-            if (rv == -1) {
-                al = SSL_AD_INTERNAL_ERROR;
-                goto f_err;
-            } else if (rv == 0) {
-                al = SSL_AD_DECODE_ERROR;
-                goto f_err;
-            }
-#ifdef SSL_DEBUG
-            fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md));
-#endif
-        }
-        if (!PACKET_get_net_2(pkt, &len)) {
-            SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_LENGTH_MISMATCH);
-            al = SSL_AD_DECODE_ERROR;
-            goto f_err;
-        }
-    }
-    j = EVP_PKEY_size(pkey);
-    if (((int)len > j) || ((int)PACKET_remaining(pkt) > j)
-            || (PACKET_remaining(pkt) == 0)) {
-        SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_WRONG_SIGNATURE_SIZE);
-        al = SSL_AD_DECODE_ERROR;
-        goto f_err;
-    }
-    if (!PACKET_get_bytes(pkt, &data, len)) {
-        SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_LENGTH_MISMATCH);
-        al = SSL_AD_DECODE_ERROR;
-        goto f_err;
-    }
-
-    if (SSL_USE_SIGALGS(s)) {
-        long hdatalen = 0;
-        void *hdata;
-        hdatalen = BIO_get_mem_data(s->s3->handshake_buffer, &hdata);
-        if (hdatalen <= 0) {
-            SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, ERR_R_INTERNAL_ERROR);
-            al = SSL_AD_INTERNAL_ERROR;
-            goto f_err;
-        }
-#ifdef SSL_DEBUG
-        fprintf(stderr, "Using TLS 1.2 with client verify alg %s\n",
-                EVP_MD_name(md));
-#endif
-        if (!EVP_VerifyInit_ex(&mctx, md, NULL)
-            || !EVP_VerifyUpdate(&mctx, hdata, hdatalen)) {
-            SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, ERR_R_EVP_LIB);
-            al = SSL_AD_INTERNAL_ERROR;
-            goto f_err;
-        }
-
-        if (EVP_VerifyFinal(&mctx, data, len, pkey) <= 0) {
-            al = SSL_AD_DECRYPT_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_BAD_SIGNATURE);
-            goto f_err;
-        }
-    } else
-#ifndef OPENSSL_NO_RSA
-    if (pkey->type == EVP_PKEY_RSA) {
-        i = RSA_verify(NID_md5_sha1, s->s3->tmp.cert_verify_md,
-                       MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH, data, len,
-                       pkey->pkey.rsa);
-        if (i < 0) {
-            al = SSL_AD_DECRYPT_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_BAD_RSA_DECRYPT);
-            goto f_err;
-        }
-        if (i == 0) {
-            al = SSL_AD_DECRYPT_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_BAD_RSA_SIGNATURE);
-            goto f_err;
-        }
-    } else
-#endif
-#ifndef OPENSSL_NO_DSA
-    if (pkey->type == EVP_PKEY_DSA) {
-        j = DSA_verify(pkey->save_type,
-                       &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]),
-                       SHA_DIGEST_LENGTH, data, len, pkey->pkey.dsa);
-        if (j <= 0) {
-            /* bad signature */
-            al = SSL_AD_DECRYPT_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_BAD_DSA_SIGNATURE);
-            goto f_err;
-        }
-    } else
-#endif
-#ifndef OPENSSL_NO_EC
-    if (pkey->type == EVP_PKEY_EC) {
-        j = ECDSA_verify(pkey->save_type,
-                         &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]),
-                         SHA_DIGEST_LENGTH, data, len, pkey->pkey.ec);
-        if (j <= 0) {
-            /* bad signature */
-            al = SSL_AD_DECRYPT_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_BAD_ECDSA_SIGNATURE);
-            goto f_err;
-        }
-    } else
-#endif
-    if (pkey->type == NID_id_GostR3410_2001) {
-        unsigned char signature[64];
-        int idx;
-        EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(pkey, NULL);
-        EVP_PKEY_verify_init(pctx);
-        if (len != 64) {
-            fprintf(stderr, "GOST signature length is %d", len);
-        }
-        for (idx = 0; idx < 64; idx++) {
-            signature[63 - idx] = data[idx];
-        }
-        j = EVP_PKEY_verify(pctx, signature, 64, s->s3->tmp.cert_verify_md,
-                            32);
-        EVP_PKEY_CTX_free(pctx);
-        if (j <= 0) {
-            al = SSL_AD_DECRYPT_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_BAD_ECDSA_SIGNATURE);
-            goto f_err;
-        }
-    } else {
-        SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, ERR_R_INTERNAL_ERROR);
-        al = SSL_AD_UNSUPPORTED_CERTIFICATE;
-        goto f_err;
-    }
-
-    ret = MSG_PROCESS_CONTINUE_PROCESSING;
-    if (0) {
- f_err:
-        ssl3_send_alert(s, SSL3_AL_FATAL, al);
-        statem_set_error(s);
-    }
-    BIO_free(s->s3->handshake_buffer);
-    s->s3->handshake_buffer = NULL;
-    EVP_MD_CTX_cleanup(&mctx);
-    EVP_PKEY_free(pkey);
-    return ret;
-}
-
-enum MSG_PROCESS_RETURN tls_process_client_certificate(SSL *s, PACKET *pkt)
-{
-    int i, al, ret = MSG_PROCESS_ERROR;
-    X509 *x = NULL;
-    unsigned long l, llen;
-    const unsigned char *certstart;
-    unsigned char *certbytes;
-    STACK_OF(X509) *sk = NULL;
-    PACKET spkt;
-
-    if ((sk = sk_X509_new_null()) == NULL) {
-        SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, ERR_R_MALLOC_FAILURE);
-        goto f_err;
-    }
-
-    if (!PACKET_get_net_3(pkt, &llen)
-            || !PACKET_get_sub_packet(pkt, &spkt, llen)
-            || PACKET_remaining(pkt) != 0) {
-        al = SSL_AD_DECODE_ERROR;
-        SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, SSL_R_LENGTH_MISMATCH);
-        goto f_err;
-    }
-
-    while (PACKET_remaining(&spkt) > 0) {
-        if (!PACKET_get_net_3(&spkt, &l)
-                || !PACKET_get_bytes(&spkt, &certbytes, l)) {
-            al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
-                   SSL_R_CERT_LENGTH_MISMATCH);
-            goto f_err;
-        }
-
-        certstart = certbytes;
-        x = d2i_X509(NULL, (const unsigned char **)&certbytes, l);
-        if (x == NULL) {
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, ERR_R_ASN1_LIB);
-            goto f_err;
-        }
-        if (certbytes != (certstart + l)) {
-            al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
-                   SSL_R_CERT_LENGTH_MISMATCH);
-            goto f_err;
-        }
-        if (!sk_X509_push(sk, x)) {
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, ERR_R_MALLOC_FAILURE);
-            goto f_err;
-        }
-        x = NULL;
-    }
-
-    if (sk_X509_num(sk) <= 0) {
-        /* TLS does not mind 0 certs returned */
-        if (s->version == SSL3_VERSION) {
-            al = SSL_AD_HANDSHAKE_FAILURE;
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
-                   SSL_R_NO_CERTIFICATES_RETURNED);
-            goto f_err;
-        }
-        /* Fail for TLS only if we required a certificate */
-        else if ((s->verify_mode & SSL_VERIFY_PEER) &&
-                 (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) {
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
-                   SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
-            al = SSL_AD_HANDSHAKE_FAILURE;
-            goto f_err;
-        }
-        /* No client certificate so digest cached records */
-        if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s, 0)) {
-            al = SSL_AD_INTERNAL_ERROR;
-            goto f_err;
-        }
-    } else {
-        EVP_PKEY *pkey;
-        i = ssl_verify_cert_chain(s, sk);
-        if (i <= 0) {
-            al = ssl_verify_alarm_type(s->verify_result);
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
-                   SSL_R_CERTIFICATE_VERIFY_FAILED);
-            goto f_err;
-        }
-        if (i > 1) {
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, i);
-            al = SSL_AD_HANDSHAKE_FAILURE;
-            goto f_err;
-        }
-        pkey = X509_get_pubkey(sk_X509_value(sk, 0));
-        if (pkey == NULL) {
-            al = SSL3_AD_HANDSHAKE_FAILURE;
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
-                   SSL_R_UNKNOWN_CERTIFICATE_TYPE);
-            goto f_err;
-        }
-        EVP_PKEY_free(pkey);
-    }
-
-    X509_free(s->session->peer);
-    s->session->peer = sk_X509_shift(sk);
-    s->session->verify_result = s->verify_result;
-
-    sk_X509_pop_free(s->session->peer_chain, X509_free);
-    s->session->peer_chain = sk;
-    /*
-     * Inconsistency alert: cert_chain does *not* include the peer's own
-     * certificate, while we do include it in s3_clnt.c
-     */
-    sk = NULL;
-    ret = MSG_PROCESS_CONTINUE_READING;
-    goto done;
-
- f_err:
-    ssl3_send_alert(s, SSL3_AL_FATAL, al);
-    statem_set_error(s);
- done:
-    X509_free(x);
-    sk_X509_pop_free(sk, X509_free);
-    return ret;
-}
-
-int tls_construct_server_certificate(SSL *s)
-{
-    CERT_PKEY *cpk;
-
-    cpk = ssl_get_server_send_pkey(s);
-    if (cpk == NULL) {
-        SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_CERTIFICATE, ERR_R_INTERNAL_ERROR);
-        statem_set_error(s);
-        return 0;
-    }
-
-    if (!ssl3_output_cert_chain(s, cpk)) {
-        SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_CERTIFICATE, ERR_R_INTERNAL_ERROR);
-        statem_set_error(s);
-        return 0;
-    }
-
-    return 1;
-}
-
-int tls_construct_new_session_ticket(SSL *s)
-{
-    unsigned char *senc = NULL;
-    EVP_CIPHER_CTX ctx;
-    HMAC_CTX hctx;
-    unsigned char *p, *macstart;
-    const unsigned char *const_p;
-    int len, slen_full, slen;
-    SSL_SESSION *sess;
-    unsigned int hlen;
-    SSL_CTX *tctx = s->initial_ctx;
-    unsigned char iv[EVP_MAX_IV_LENGTH];
-    unsigned char key_name[16];
-
-    /* get session encoding length */
-    slen_full = i2d_SSL_SESSION(s->session, NULL);
-    /*
-     * Some length values are 16 bits, so forget it if session is too
-     * long
-     */
-    if (slen_full == 0 || slen_full > 0xFF00) {
-        statem_set_error(s);
-        return 0;
-    }
-    senc = OPENSSL_malloc(slen_full);
-    if (!senc) {
-        statem_set_error(s);
-        return 0;
-    }
-
-    EVP_CIPHER_CTX_init(&ctx);
-    HMAC_CTX_init(&hctx);
-
-    p = senc;
-    if (!i2d_SSL_SESSION(s->session, &p))
-        goto err;
-
-    /*
-     * create a fresh copy (not shared with other threads) to clean up
-     */
-    const_p = senc;
-    sess = d2i_SSL_SESSION(NULL, &const_p, slen_full);
-    if (sess == NULL)
-        goto err;
-    sess->session_id_length = 0; /* ID is irrelevant for the ticket */
-
-    slen = i2d_SSL_SESSION(sess, NULL);
-    if (slen == 0 || slen > slen_full) { /* shouldn't ever happen */
-        SSL_SESSION_free(sess);
-        goto err;
-    }
-    p = senc;
-    if (!i2d_SSL_SESSION(sess, &p)) {
-        SSL_SESSION_free(sess);
-        goto err;
-    }
-    SSL_SESSION_free(sess);
-
-    /*-
-     * Grow buffer if need be: the length calculation is as
-     * follows handshake_header_length +
-     * 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,
-                      SSL_HM_HEADER_LENGTH(s) + 22 + EVP_MAX_IV_LENGTH +
-                      EVP_MAX_BLOCK_LENGTH + EVP_MAX_MD_SIZE + slen))
-        goto err;
-
-    p = ssl_handshake_start(s);
-    /*
-     * 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)
-            goto err;
-    } else {
-        if (RAND_bytes(iv, 16) <= 0)
-            goto err;
-        if (!EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL,
-                                tctx->tlsext_tick_aes_key, iv))
-            goto err;
-        if (!HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16,
-                          EVP_sha256(), NULL))
-            goto err;
-        memcpy(key_name, tctx->tlsext_tick_key_name, 16);
-    }
-
-    /*
-     * Ticket lifetime hint (advisory only): We leave this unspecified
-     * for resumed session (for simplicity), and guess that tickets for
-     * new sessions will live as long as their sessions.
-     */
-    l2n(s->hit ? 0 : s->session->timeout, 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 */
-    if (!EVP_EncryptUpdate(&ctx, p, &len, senc, slen))
-        goto err;
-    p += len;
-    if (!EVP_EncryptFinal(&ctx, p, &len))
-        goto err;
-    p += len;
-
-    if (!HMAC_Update(&hctx, macstart, p - macstart))
-        goto err;
-    if (!HMAC_Final(&hctx, p, &hlen))
-        goto err;
-
-    EVP_CIPHER_CTX_cleanup(&ctx);
-    HMAC_CTX_cleanup(&hctx);
-
-    p += hlen;
-    /* Now write out lengths: p points to end of data written */
-    /* Total length */
-    len = p - ssl_handshake_start(s);
-    /* Skip ticket lifetime hint */
-    p = ssl_handshake_start(s) + 4;
-    s2n(len - 6, p);
-    if (!ssl_set_handshake_header(s, SSL3_MT_NEWSESSION_TICKET, len))
-        goto err;
-    OPENSSL_free(senc);
-
-    return 1;
- err:
-    OPENSSL_free(senc);
-    EVP_CIPHER_CTX_cleanup(&ctx);
-    HMAC_CTX_cleanup(&hctx);
-    statem_set_error(s);
-    return 0;
-}
-
-int tls_construct_cert_status(SSL *s)
-{
-    unsigned char *p;
-    /*-
-     * Grow buffer if need be: the length calculation is as
-     * follows 1 (message type) + 3 (message length) +
-     * 1 (ocsp response type) + 3 (ocsp response length)
-     * + (ocsp response)
-     */
-    if (!BUF_MEM_grow(s->init_buf, 8 + s->tlsext_ocsp_resplen)) {
-        statem_set_error(s);
-        return 0;
-    }
-
-    p = (unsigned char *)s->init_buf->data;
-
-    /* do the header */
-    *(p++) = SSL3_MT_CERTIFICATE_STATUS;
-    /* message length */
-    l2n3(s->tlsext_ocsp_resplen + 4, p);
-    /* status type */
-    *(p++) = s->tlsext_status_type;
-    /* length of OCSP response */
-    l2n3(s->tlsext_ocsp_resplen, p);
-    /* actual response */
-    memcpy(p, s->tlsext_ocsp_resp, s->tlsext_ocsp_resplen);
-    /* number of bytes to write */
-    s->init_num = 8 + s->tlsext_ocsp_resplen;
-    s->init_off = 0;
-
-    return 1;
-}
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
-/*
- * tls_process_next_proto reads a Next Protocol Negotiation handshake message.
- * It sets the next_proto member in s if found
- */
-enum MSG_PROCESS_RETURN tls_process_next_proto(SSL *s, PACKET *pkt)
-{
-    PACKET next_proto, padding;
-    size_t next_proto_len;
-
-    /*-
-     * The payload looks like:
-     *   uint8 proto_len;
-     *   uint8 proto[proto_len];
-     *   uint8 padding_len;
-     *   uint8 padding[padding_len];
-     */
-    if (!PACKET_get_length_prefixed_1(pkt, &next_proto)
-        || !PACKET_get_length_prefixed_1(pkt, &padding)
-        || PACKET_remaining(pkt) > 0) {
-        SSLerr(SSL_F_TLS_PROCESS_NEXT_PROTO, SSL_R_LENGTH_MISMATCH);
-        goto err;
-    }
-
-    if (!PACKET_memdup(&next_proto, &s->next_proto_negotiated,
-                       &next_proto_len)) {
-        s->next_proto_negotiated_len = 0;
-        goto err;
-    }
-
-    s->next_proto_negotiated_len = (unsigned char)next_proto_len;
-
-    return MSG_PROCESS_CONTINUE_READING;
-err:
-    statem_set_error(s);
-    return MSG_PROCESS_ERROR;
-}
-#endif
-
-#define SSLV2_CIPHER_LEN    3
-
-STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s,
-                                               PACKET *cipher_suites,
-                                               STACK_OF(SSL_CIPHER) **skp,
-                                               int sslv2format, int *al
-                                               )
-{
-    const SSL_CIPHER *c;
-    STACK_OF(SSL_CIPHER) *sk;
-    int n;
-    /* 3 = SSLV2_CIPHER_LEN > TLS_CIPHER_LEN = 2. */
-    unsigned char cipher[SSLV2_CIPHER_LEN];
-
-    s->s3->send_connection_binding = 0;
-
-    n = sslv2format ? SSLV2_CIPHER_LEN : TLS_CIPHER_LEN;
-
-    if (PACKET_remaining(cipher_suites) == 0) {
-        SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST, SSL_R_NO_CIPHERS_SPECIFIED);
-        *al = SSL_AD_ILLEGAL_PARAMETER;
-        return NULL;
-    }
-
-    if (PACKET_remaining(cipher_suites) % n != 0) {
-        SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST,
-               SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST);
-        *al = SSL_AD_DECODE_ERROR;
-        return NULL;
-    }
-
-    if ((skp == NULL) || (*skp == NULL)) {
-        sk = sk_SSL_CIPHER_new_null(); /* change perhaps later */
-        if(sk == NULL) {
-            SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST, ERR_R_MALLOC_FAILURE);
-            *al = SSL_AD_INTERNAL_ERROR;
-            return NULL;
-        }
-    } else {
-        sk = *skp;
-        sk_SSL_CIPHER_zero(sk);
-    }
-
-    if (!PACKET_memdup(cipher_suites, &s->s3->tmp.ciphers_raw,
-                       &s->s3->tmp.ciphers_rawlen)) {
-        *al = SSL_AD_INTERNAL_ERROR;
-        goto err;
-    }
-
-    while (PACKET_copy_bytes(cipher_suites, cipher, n)) {
-        /*
-         * SSLv3 ciphers wrapped in an SSLv2-compatible ClientHello have the
-         * first byte set to zero, while true SSLv2 ciphers have a non-zero
-         * first byte. We don't support any true SSLv2 ciphers, so skip them.
-         */
-        if (sslv2format && cipher[0] != '\0')
-                continue;
-
-        /* Check for TLS_EMPTY_RENEGOTIATION_INFO_SCSV */
-        if ((cipher[n - 2] == ((SSL3_CK_SCSV >> 8) & 0xff)) &&
-            (cipher[n - 1] == (SSL3_CK_SCSV & 0xff))) {
-            /* SCSV fatal if renegotiating */
-            if (s->renegotiate) {
-                SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST,
-                       SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING);
-                *al = SSL_AD_HANDSHAKE_FAILURE;
-                goto err;
-            }
-            s->s3->send_connection_binding = 1;
-#ifdef OPENSSL_RI_DEBUG
-            fprintf(stderr, "SCSV received by server\n");
-#endif
-            continue;
-        }
-
-        /* Check for TLS_FALLBACK_SCSV */
-        if ((cipher[n - 2] == ((SSL3_CK_FALLBACK_SCSV >> 8) & 0xff)) &&
-            (cipher[n - 1] == (SSL3_CK_FALLBACK_SCSV & 0xff))) {
-            /*
-             * The SCSV indicates that the client previously tried a higher
-             * version. Fail if the current version is an unexpected
-             * downgrade.
-             */
-            if (!SSL_ctrl(s, SSL_CTRL_CHECK_PROTO_VERSION, 0, NULL)) {
-                SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST,
-                       SSL_R_INAPPROPRIATE_FALLBACK);
-                *al = SSL_AD_INAPPROPRIATE_FALLBACK;
-                goto err;
-            }
-            continue;
-        }
-
-        /* For SSLv2-compat, ignore leading 0-byte. */
-        c = ssl_get_cipher_by_char(s, sslv2format ? &cipher[1] : cipher);
-        if (c != NULL) {
-            if (!sk_SSL_CIPHER_push(sk, c)) {
-                SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST, ERR_R_MALLOC_FAILURE);
-                *al = SSL_AD_INTERNAL_ERROR;
-                goto err;
-            }
-        }
-    }
-    if (PACKET_remaining(cipher_suites) > 0) {
-        *al = SSL_AD_INTERNAL_ERROR;
-        SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST, ERR_R_INTERNAL_ERROR);
-        goto err;
-    }
-
-    if (skp != NULL)
-        *skp = sk;
-    return (sk);
- err:
-    if ((skp == NULL) || (*skp == NULL))
-        sk_SSL_CIPHER_free(sk);
-    return NULL;
-}
index ab095c826762958ac41d69ff84ed8006b068f3b0..25afff8c9be6d862d36447cd2c736b3d0440b16b 100644 (file)
 # include <openssl/symhacks.h>
 
 #include "record/record.h"
+#include "statem/statem.h"
 #include "packet_locl.h"
 
 # ifdef OPENSSL_BUILD_SHLIBSSL
@@ -715,88 +716,6 @@ struct ssl_comp_st {
 DECLARE_STACK_OF(SSL_COMP)
 DECLARE_LHASH_OF(SSL_SESSION);
 
-/*
- * Valid return codes used for functions performing work prior to or after
- * sending or receiving a message
- */
-enum WORK_STATE {
-    /* Something went wrong */
-    WORK_ERROR,
-    /* We're done working and there shouldn't be anything else to do after */
-    WORK_FINISHED_STOP,
-    /* We're done working move onto the next thing */
-    WORK_FINISHED_CONTINUE,
-    /* We're working on phase A */
-    WORK_MORE_A,
-    /* We're working on phase B */
-    WORK_MORE_B
-};
-
-/* Write transition return codes */
-enum WRITE_TRAN {
-    /* Something went wrong */
-    WRITE_TRAN_ERROR,
-    /* A transition was successfully completed and we should continue */
-    WRITE_TRAN_CONTINUE,
-    /* There is no more write work to be done */
-    WRITE_TRAN_FINISHED
-};
-
-/* Message processing return codes */
-enum MSG_PROCESS_RETURN {
-    MSG_PROCESS_ERROR,
-    MSG_PROCESS_FINISHED_READING,
-    MSG_PROCESS_CONTINUE_PROCESSING,
-    MSG_PROCESS_CONTINUE_READING
-};
-
-/* Message flow states */
-enum MSG_FLOW_STATE {
-    /* No handshake in progress */
-    MSG_FLOW_UNINITED,
-    /* A permanent error with this connection */
-    MSG_FLOW_ERROR,
-    /* We are about to renegotiate */
-    MSG_FLOW_RENEGOTIATE,
-    /* We are reading messages */
-    MSG_FLOW_READING,
-    /* We are writing messages */
-    MSG_FLOW_WRITING,
-    /* Handshake has finished */
-    MSG_FLOW_FINISHED
-};
-
-/* Read states */
-enum READ_STATE {
-    READ_STATE_HEADER,
-    READ_STATE_BODY,
-    READ_STATE_POST_PROCESS
-};
-
-/* Write states */
-enum WRITE_STATE {
-    WRITE_STATE_TRANSITION,
-    WRITE_STATE_PRE_WORK,
-    WRITE_STATE_SEND,
-    WRITE_STATE_POST_WORK
-};
-
-struct statem_st {
-    enum MSG_FLOW_STATE state;
-    enum WRITE_STATE write_state;
-    enum WORK_STATE write_state_work;
-    enum READ_STATE read_state;
-    enum WORK_STATE read_state_work;
-    enum HANDSHAKE_STATE hand_state;
-    int in_init;
-    int read_state_first_init;
-    int use_timer;
-#ifndef OPENSSL_NO_SCTP
-    int in_sctp_read_sock;
-#endif
-};
-typedef struct statem_st STATEM;
-
 
 struct ssl_ctx_st {
     const SSL_METHOD *method;
@@ -2033,18 +1952,6 @@ __owur SSL_CIPHER *ssl3_choose_cipher(SSL *ssl, STACK_OF(SSL_CIPHER) *clnt,
 __owur int ssl3_digest_cached_records(SSL *s, int keep);
 __owur int ssl3_new(SSL *s);
 void ssl3_free(SSL *s);
-__owur int ssl3_accept(SSL *s);
-__owur int ssl3_connect(SSL *s);
-void statem_clear(SSL *s);
-void statem_set_renegotiate(SSL *s);
-void statem_set_error(SSL *s);
-int statem_in_error(const SSL *s);
-void statem_set_in_init(SSL *s, int init);
-__owur int statem_app_data_allowed(SSL *s);
-#ifndef OPENSSL_NO_SCTP
-void statem_set_sctp_read_sock(SSL *s, int read_sock);
-__owur int statem_in_sctp_read_sock(SSL *s);
-#endif
 __owur int ssl3_read(SSL *s, void *buf, int len);
 __owur int ssl3_peek(SSL *s, void *buf, int len);
 __owur int ssl3_write(SSL *s, const void *buf, int len);
@@ -2091,13 +1998,14 @@ void dtls1_start_timer(SSL *s);
 void dtls1_stop_timer(SSL *s);
 __owur int dtls1_is_timer_expired(SSL *s);
 void dtls1_double_timeout(SSL *s);
-__owur unsigned int dtls1_raw_hello_verify_request(unsigned char *buf,
-                                                   unsigned char *cookie,
-                                                   unsigned char cookie_len);
+__owur unsigned int dtls_raw_hello_verify_request(unsigned char *buf,
+                                                  unsigned char *cookie,
+                                                  unsigned char cookie_len);
 __owur int dtls1_send_newsession_ticket(SSL *s);
 __owur unsigned int dtls1_min_mtu(SSL *s);
 __owur unsigned int dtls1_link_min_mtu(void);
 void dtls1_hm_fragment_free(hm_fragment *frag);
+__owur int dtls1_query_mtu(SSL *s);
 
 /* some client-only functions */
 __owur int tls_construct_client_hello(SSL *s);
@@ -2154,8 +2062,6 @@ long tls1_ctrl(SSL *s, int cmd, long larg, void *parg);
 long tls1_callback_ctrl(SSL *s, int cmd, void (*fp) (void));
 
 __owur int dtls1_new(SSL *s);
-__owur int dtls1_accept(SSL *s);
-__owur int dtls1_connect(SSL *s);
 void dtls1_free(SSL *s);
 void dtls1_clear(SSL *s);
 long dtls1_ctrl(SSL *s, int cmd, long larg, void *parg);
diff --git a/ssl/statem.c b/ssl/statem.c
deleted file mode 100644 (file)
index 81af75c..0000000
+++ /dev/null
@@ -1,2251 +0,0 @@
-/* ssl/statem.c */
-/*
- * Written by Matt Caswell for the OpenSSL project.
- */
-/* ====================================================================
- * Copyright (c) 1998-2015 The OpenSSL Project.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- *    software must display the following acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- *    endorse or promote products derived from this software without
- *    prior written permission. For written permission, please contact
- *    openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- *    nor may "OpenSSL" appear in their names without prior written
- *    permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- *    acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com).  This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
- *
- */
-
-#include <openssl/rand.h>
-#include "ssl_locl.h"
-
-/*
- * This file implements the SSL/TLS/DTLS state machines.
- *
- * There are two primary state machines:
- *
- * 1) Message flow state machine
- * 2) Handshake state machine
- *
- * The Message flow state machine controls the reading and sending of messages
- * including handling of non-blocking IO events, flushing of the underlying
- * write BIO, handling unexpected messages, etc. It is itself broken into two
- * separate sub-state machines which control reading and writing respectively.
- *
- * The Handshake state machine keeps track of the current SSL/TLS handshake
- * state. Transitions of the handshake state are the result of events that
- * occur within the Message flow state machine.
- *
- * Overall it looks like this:
- *
- * ---------------------------------------------            -------------------
- * |                                           |            |                 |
- * | Message flow state machine                |            |                 |
- * |                                           |            |                 |
- * | -------------------- -------------------- | Transition | Handshake state |
- * | | MSG_FLOW_READING    | | MSG_FLOW_WRITING    | | Event      | machine         |
- * | | sub-state        | | sub-state        | |----------->|                 |
- * | | machine for      | | machine for      | |            |                 |
- * | | reading messages | | writing messages | |            |                 |
- * | -------------------- -------------------- |            |                 |
- * |                                           |            |                 |
- * ---------------------------------------------            -------------------
- *
- */
-
-/* Sub state machine return values */
-enum SUB_STATE_RETURN {
-    /* Something bad happened or NBIO */
-    SUB_STATE_ERROR,
-    /* Sub state finished go to the next sub state */
-    SUB_STATE_FINISHED,
-    /* Sub state finished and handshake was completed */
-    SUB_STATE_END_HANDSHAKE
-};
-
-static int state_machine(SSL *s, int server);
-static void init_read_state_machine(SSL *s);
-static enum SUB_STATE_RETURN read_state_machine(SSL *s);
-static void init_write_state_machine(SSL *s);
-static enum SUB_STATE_RETURN write_state_machine(SSL *s);
-static inline int cert_req_allowed(SSL *s);
-static inline int key_exchange_skip_allowed(SSL *s);
-static int client_read_transition(SSL *s, int mt);
-static enum WRITE_TRAN client_write_transition(SSL *s);
-static enum WORK_STATE client_pre_work(SSL *s, enum WORK_STATE wst);
-static enum WORK_STATE client_post_work(SSL *s, enum WORK_STATE wst);
-static int client_construct_message(SSL *s);
-static unsigned long client_max_message_size(SSL *s);
-static enum MSG_PROCESS_RETURN client_process_message(SSL *s, PACKET *pkt);
-static enum WORK_STATE client_post_process_message(SSL *s, enum WORK_STATE wst);
-static int server_read_transition(SSL *s, int mt);
-static inline int send_server_key_exchange(SSL *s);
-static inline int send_certificate_request(SSL *s);
-static enum WRITE_TRAN server_write_transition(SSL *s);
-static enum WORK_STATE server_pre_work(SSL *s, enum WORK_STATE wst);
-static enum WORK_STATE server_post_work(SSL *s, enum WORK_STATE wst);
-static int server_construct_message(SSL *s);
-static unsigned long server_max_message_size(SSL *s);
-static enum MSG_PROCESS_RETURN server_process_message(SSL *s, PACKET *pkt);
-static enum WORK_STATE server_post_process_message(SSL *s, enum WORK_STATE wst);
-
-
-enum HANDSHAKE_STATE SSL_state(const SSL *ssl)
-{
-    return ssl->statem.hand_state;
-}
-
-void SSL_set_state(SSL *ssl, enum HANDSHAKE_STATE state)
-{
-    /*
-     * This function seems like a really bad idea. Should we remove it
-     * completely?
-     */
-    ssl->statem.hand_state = state;
-}
-
-int SSL_in_init(SSL *s)
-{
-    return s->statem.in_init;
-}
-
-int SSL_is_init_finished(SSL *s)
-{
-    return !(s->statem.in_init) && (s->statem.hand_state == TLS_ST_OK);
-}
-
-int SSL_in_before(SSL *s)
-{
-    /*
-     * Historically being "in before" meant before anything had happened. In the
-     * current code though we remain in the "before" state for a while after we
-     * have started the handshake process (e.g. as a server waiting for the
-     * first message to arrive). There "in before" is taken to mean "in before"
-     * and not started any handshake process yet.
-     */
-    return (s->statem.hand_state == TLS_ST_BEFORE)
-        && (s->statem.state == MSG_FLOW_UNINITED);
-}
-
-/*
- * Clear the state machine state and reset back to MSG_FLOW_UNINITED
- */
-void statem_clear(SSL *s)
-{
-    s->statem.state = MSG_FLOW_UNINITED;
-    s->statem.hand_state = TLS_ST_BEFORE;
-    s->statem.in_init = 1;
-}
-
-/*
- * Set the state machine up ready for a renegotiation handshake
- */
-void statem_set_renegotiate(SSL *s)
-{
-    s->statem.state = MSG_FLOW_RENEGOTIATE;
-    s->statem.in_init = 1;
-}
-
-/*
- * Put the state machine into an error state. This is a permanent error for
- * the current connection.
- */
-void statem_set_error(SSL *s)
-{
-    s->statem.state = MSG_FLOW_ERROR;
-}
-
-/*
- * Discover whether the current connection is in the error state.
- *
- * Valid return values are:
- *   1: Yes
- *   0: No
- */
-int statem_in_error(const SSL *s)
-{
-    if (s->statem.state == MSG_FLOW_ERROR)
-        return 1;
-
-    return 0;
-}
-
-void statem_set_in_init(SSL *s, int init)
-{
-    s->statem.in_init = init;
-}
-
-int ssl3_connect(SSL *s) {
-    return state_machine(s, 0);
-}
-
-int dtls1_connect(SSL *s)
-{
-    return state_machine(s, 0);
-}
-
-int ssl3_accept(SSL *s)
-{
-    return state_machine(s, 1);
-}
-
-int dtls1_accept(SSL *s)
-{
-    return state_machine(s, 1);
-}
-
-/*
- * The main message flow state machine. We start in the MSG_FLOW_UNINITED or
- * MSG_FLOW_RENEGOTIATE state and finish in MSG_FLOW_FINISHED. Valid states and
- * transitions are as follows:
- *
- * MSG_FLOW_UNINITED     MSG_FLOW_RENEGOTIATE
- *        |                       |
- *        +-----------------------+
- *        v
- * MSG_FLOW_WRITING <---> MSG_FLOW_READING
- *        |
- *        V
- * MSG_FLOW_FINISHED
- *        |
- *        V
- *    [SUCCESS]
- *
- * We may exit at any point due to an error or NBIO event. If an NBIO event
- * occurs then we restart at the point we left off when we are recalled.
- * MSG_FLOW_WRITING and MSG_FLOW_READING have sub-state machines associated with them.
- *
- * In addition to the above there is also the MSG_FLOW_ERROR state. We can move
- * into that state at any point in the event that an irrecoverable error occurs.
- *
- * Valid return values are:
- *   1: Success
- * <=0: NBIO or error
- */
-static int state_machine(SSL *s, int server) {
-    BUF_MEM *buf = NULL;
-    unsigned long Time = (unsigned long)time(NULL);
-    void (*cb) (const SSL *ssl, int type, int val) = NULL;
-    STATEM *st = &s->statem;
-    int ret = -1;
-    int ssret;
-
-    if (st->state == MSG_FLOW_ERROR) {
-        /* Shouldn't have been called if we're already in the error state */
-        return -1;
-    }
-
-    RAND_add(&Time, sizeof(Time), 0);
-    ERR_clear_error();
-    clear_sys_error();
-
-    if (s->info_callback != NULL)
-        cb = s->info_callback;
-    else if (s->ctx->info_callback != NULL)
-        cb = s->ctx->info_callback;
-
-    s->in_handshake++;
-    if (!SSL_in_init(s) || SSL_in_before(s)) {
-        if (!SSL_clear(s))
-            return -1;
-    }
-
-#ifndef OPENSSL_NO_SCTP
-    if (SSL_IS_DTLS(s)) {
-        /*
-         * Notify SCTP BIO socket to enter handshake mode and prevent stream
-         * identifier other than 0. Will be ignored if no SCTP is used.
-         */
-        BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE,
-                 s->in_handshake, NULL);
-    }
-#endif
-
-#ifndef OPENSSL_NO_HEARTBEATS
-    /*
-     * If we're awaiting a HeartbeatResponse, pretend we already got and
-     * don't await it anymore, because Heartbeats don't make sense during
-     * handshakes anyway.
-     */
-    if (s->tlsext_hb_pending) {
-        if (SSL_IS_DTLS(s))
-            dtls1_stop_timer(s);
-        s->tlsext_hb_pending = 0;
-        s->tlsext_hb_seq++;
-    }
-#endif
-
-    /* Initialise state machine */
-
-    if (st->state == MSG_FLOW_RENEGOTIATE) {
-        s->renegotiate = 1;
-        if (!server)
-            s->ctx->stats.sess_connect_renegotiate++;
-    }
-
-    if (st->state == MSG_FLOW_UNINITED || st->state == MSG_FLOW_RENEGOTIATE) {
-        if (st->state == MSG_FLOW_UNINITED) {
-            st->hand_state = TLS_ST_BEFORE;
-        }
-
-        s->server = server;
-        if (cb != NULL)
-            cb(s, SSL_CB_HANDSHAKE_START, 1);
-
-        if (SSL_IS_DTLS(s)) {
-            if ((s->version & 0xff00) != (DTLS1_VERSION & 0xff00) &&
-                    (server
-                    || (s->version & 0xff00) != (DTLS1_BAD_VER & 0xff00))) {
-                SSLerr(SSL_F_STATE_MACHINE, ERR_R_INTERNAL_ERROR);
-                goto end;
-            }
-        } else {
-            if ((s->version >> 8) != SSL3_VERSION_MAJOR
-                    && s->version != TLS_ANY_VERSION) {
-                SSLerr(SSL_F_STATE_MACHINE, ERR_R_INTERNAL_ERROR);
-                goto end;
-            }
-        }
-
-        if (!SSL_IS_DTLS(s)) {
-            if (s->version != TLS_ANY_VERSION &&
-                    !ssl_security(s, SSL_SECOP_VERSION, 0, s->version, NULL)) {
-                SSLerr(SSL_F_STATE_MACHINE, SSL_R_VERSION_TOO_LOW);
-                goto end;
-            }
-        }
-
-        if (s->init_buf == NULL) {
-            if ((buf = BUF_MEM_new()) == NULL) {
-                goto end;
-            }
-            if (!BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) {
-                goto end;
-            }
-            s->init_buf = buf;
-            buf = NULL;
-        }
-
-        if (!ssl3_setup_buffers(s)) {
-            goto end;
-        }
-        s->init_num = 0;
-
-        /*
-         * Should have been reset by tls_process_finished, too.
-         */
-        s->s3->change_cipher_spec = 0;
-
-        if (!server || st->state != MSG_FLOW_RENEGOTIATE) {
-                /*
-                 * Ok, we now need to push on a buffering BIO ...but not with
-                 * SCTP
-                 */
-#ifndef OPENSSL_NO_SCTP
-                if (!SSL_IS_DTLS(s) || !BIO_dgram_is_sctp(SSL_get_wbio(s)))
-#endif
-                    if (!ssl_init_wbio_buffer(s, server ? 1 : 0)) {
-                        goto end;
-                    }
-
-            ssl3_init_finished_mac(s);
-        }
-
-        if (server) {
-            if (st->state != MSG_FLOW_RENEGOTIATE) {
-                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_STATE_MACHINE,
-                       SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
-                ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
-                statem_set_error(s);
-                goto end;
-            } else {
-                /*
-                 * s->state == SSL_ST_RENEGOTIATE, we will just send a
-                 * HelloRequest
-                 */
-                s->ctx->stats.sess_accept_renegotiate++;
-            }
-        } else {
-            s->ctx->stats.sess_connect++;
-
-            /* mark client_random uninitialized */
-            memset(s->s3->client_random, 0, sizeof(s->s3->client_random));
-            s->hit = 0;
-
-            s->s3->tmp.cert_request = 0;
-
-            if (SSL_IS_DTLS(s)) {
-                st->use_timer = 1;
-            }
-        }
-
-        st->state = MSG_FLOW_WRITING;
-        init_write_state_machine(s);
-        st->read_state_first_init = 1;
-    }
-
-    while(st->state != MSG_FLOW_FINISHED) {
-        if(st->state == MSG_FLOW_READING) {
-            ssret = read_state_machine(s);
-            if (ssret == SUB_STATE_FINISHED) {
-                st->state = MSG_FLOW_WRITING;
-                init_write_state_machine(s);
-            } else {
-                /* NBIO or error */
-                goto end;
-            }
-        } else if (st->state == MSG_FLOW_WRITING) {
-            ssret = write_state_machine(s);
-            if (ssret == SUB_STATE_FINISHED) {
-                st->state = MSG_FLOW_READING;
-                init_read_state_machine(s);
-            } else if (ssret == SUB_STATE_END_HANDSHAKE) {
-                st->state = MSG_FLOW_FINISHED;
-            } else {
-                /* NBIO or error */
-                goto end;
-            }
-        } else {
-            /* Error */
-            statem_set_error(s);
-            goto end;
-        }
-    }
-
-    st->state = MSG_FLOW_UNINITED;
-    ret = 1;
-
- end:
-    s->in_handshake--;
-
-#ifndef OPENSSL_NO_SCTP
-    if (SSL_IS_DTLS(s)) {
-        /*
-         * Notify SCTP BIO socket to leave handshake mode and allow stream
-         * identifier other than 0. Will be ignored if no SCTP is used.
-         */
-        BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE,
-                 s->in_handshake, NULL);
-    }
-#endif
-
-    BUF_MEM_free(buf);
-    if (cb != NULL) {
-        if (server)
-            cb(s, SSL_CB_ACCEPT_EXIT, ret);
-        else
-            cb(s, SSL_CB_CONNECT_EXIT, ret);
-    }
-    return ret;
-}
-
-/*
- * Initialise the MSG_FLOW_READING sub-state machine
- */
-static void init_read_state_machine(SSL *s)
-{
-    STATEM *st = &s->statem;
-
-    st->read_state = READ_STATE_HEADER;
-}
-
-/*
- * This function implements the sub-state machine when the message flow is in
- * MSG_FLOW_READING. The valid sub-states and transitions are:
- *
- * READ_STATE_HEADER <--+<-------------+
- *        |             |              |
- *        v             |              |
- * READ_STATE_BODY -----+-->READ_STATE_POST_PROCESS
- *        |                            |
- *        +----------------------------+
- *        v
- * [SUB_STATE_FINISHED]
- *
- * READ_STATE_HEADER has the responsibility for reading in the message header
- * and transitioning the state of the handshake state machine.
- *
- * READ_STATE_BODY reads in the rest of the message and then subsequently
- * processes it.
- *
- * READ_STATE_POST_PROCESS is an optional step that may occur if some post
- * processing activity performed on the message may block.
- *
- * Any of the above states could result in an NBIO event occuring in which case
- * control returns to the calling application. When this function is recalled we
- * will resume in the same state where we left off.
- */
-static enum SUB_STATE_RETURN read_state_machine(SSL *s) {
-    STATEM *st = &s->statem;
-    int ret, mt;
-    unsigned long len;
-    int (*transition)(SSL *s, int mt);
-    PACKET pkt;
-    enum MSG_PROCESS_RETURN (*process_message)(SSL *s, PACKET *pkt);
-    enum WORK_STATE (*post_process_message)(SSL *s, enum WORK_STATE wst);
-    unsigned long (*max_message_size)(SSL *s);
-    void (*cb) (const SSL *ssl, int type, int val) = NULL;
-
-    if (s->info_callback != NULL)
-        cb = s->info_callback;
-    else if (s->ctx->info_callback != NULL)
-        cb = s->ctx->info_callback;
-
-    if(s->server) {
-        transition = server_read_transition;
-        process_message = server_process_message;
-        max_message_size = server_max_message_size;
-        post_process_message = server_post_process_message;
-    } else {
-        transition = client_read_transition;
-        process_message = client_process_message;
-        max_message_size = client_max_message_size;
-        post_process_message = client_post_process_message;
-    }
-
-    if (st->read_state_first_init) {
-        s->first_packet = 1;
-        st->read_state_first_init = 0;
-    }
-
-    while(1) {
-        switch(st->read_state) {
-        case READ_STATE_HEADER:
-            s->init_num = 0;
-            /* Get the state the peer wants to move to */
-            if (SSL_IS_DTLS(s)) {
-                /*
-                 * In DTLS we get the whole message in one go - header and body
-                 */
-                ret = dtls_get_message(s, &mt, &len);
-            } else {
-                ret = tls_get_message_header(s, &mt);
-            }
-
-            if (ret == 0) {
-                /* Could be non-blocking IO */
-                return SUB_STATE_ERROR;
-            }
-
-            if (cb != NULL) {
-                /* Notify callback of an impending state change */
-                if (s->server)
-                    cb(s, SSL_CB_ACCEPT_LOOP, 1);
-                else
-                    cb(s, SSL_CB_CONNECT_LOOP, 1);
-            }
-            /*
-             * Validate that we are allowed to move to the new state and move
-             * to that state if so
-             */
-            if(!transition(s, mt)) {
-                ssl3_send_alert(s, SSL3_AL_FATAL, SSL3_AD_UNEXPECTED_MESSAGE);
-                SSLerr(SSL_F_READ_STATE_MACHINE, SSL_R_UNEXPECTED_MESSAGE);
-                return SUB_STATE_ERROR;
-            }
-
-            if (s->s3->tmp.message_size > max_message_size(s)) {
-                ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
-                SSLerr(SSL_F_READ_STATE_MACHINE, SSL_R_EXCESSIVE_MESSAGE_SIZE);
-                return SUB_STATE_ERROR;
-            }
-
-            st->read_state = READ_STATE_BODY;
-            /* Fall through */
-
-        case READ_STATE_BODY:
-            if (!SSL_IS_DTLS(s)) {
-                /* We already got this above for DTLS */
-                ret = tls_get_message_body(s, &len);
-                if (ret == 0) {
-                    /* Could be non-blocking IO */
-                    return SUB_STATE_ERROR;
-                }
-            }
-
-            s->first_packet = 0;
-            if (!PACKET_buf_init(&pkt, s->init_msg, len)) {
-                ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
-                SSLerr(SSL_F_READ_STATE_MACHINE, ERR_R_INTERNAL_ERROR);
-                return SUB_STATE_ERROR;
-            }
-            ret = process_message(s, &pkt);
-            if (ret == MSG_PROCESS_ERROR) {
-                return SUB_STATE_ERROR;
-            }
-
-            if (ret == MSG_PROCESS_FINISHED_READING) {
-                if (SSL_IS_DTLS(s)) {
-                    dtls1_stop_timer(s);
-                }
-                return SUB_STATE_FINISHED;
-            }
-
-            if (ret == MSG_PROCESS_CONTINUE_PROCESSING) {
-                st->read_state = READ_STATE_POST_PROCESS;
-                st->read_state_work = WORK_MORE_A;
-            } else {
-                st->read_state = READ_STATE_HEADER;
-            }
-            break;
-
-        case READ_STATE_POST_PROCESS:
-            st->read_state_work = post_process_message(s, st->read_state_work);
-            switch(st->read_state_work) {
-            default:
-                return SUB_STATE_ERROR;
-
-            case WORK_FINISHED_CONTINUE:
-                st->read_state = READ_STATE_HEADER;
-                break;
-
-            case WORK_FINISHED_STOP:
-                if (SSL_IS_DTLS(s)) {
-                    dtls1_stop_timer(s);
-                }
-                return SUB_STATE_FINISHED;
-            }
-            break;
-
-        default:
-            /* Shouldn't happen */
-            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
-            SSLerr(SSL_F_READ_STATE_MACHINE, ERR_R_INTERNAL_ERROR);
-            statem_set_error(s);
-            return SUB_STATE_ERROR;
-        }
-    }
-}
-
-/*
- * Send a previously constructed message to the peer.
- */
-static int statem_do_write(SSL *s)
-{
-    STATEM *st = &s->statem;
-
-    if (st->hand_state == TLS_ST_CW_CHANGE
-            || st->hand_state == TLS_ST_SW_CHANGE) {
-        if (SSL_IS_DTLS(s))
-            return dtls1_do_write(s, SSL3_RT_CHANGE_CIPHER_SPEC);
-        else
-            return ssl3_do_write(s, SSL3_RT_CHANGE_CIPHER_SPEC);
-    } else {
-        return ssl_do_write(s);
-    }
-}
-
-/*
- * Initialise the MSG_FLOW_WRITING sub-state machine
- */
-static void init_write_state_machine(SSL *s)
-{
-    STATEM *st = &s->statem;
-
-    st->write_state = WRITE_STATE_TRANSITION;
-}
-
-/*
- * This function implements the sub-state machine when the message flow is in
- * MSG_FLOW_WRITING. The valid sub-states and transitions are:
- *
- * +-> WRITE_STATE_TRANSITION ------> [SUB_STATE_FINISHED]
- * |             |
- * |             v
- * |      WRITE_STATE_PRE_WORK -----> [SUB_STATE_END_HANDSHAKE]
- * |             |
- * |             v
- * |       WRITE_STATE_SEND
- * |             |
- * |             v
- * |     WRITE_STATE_POST_WORK
- * |             |
- * +-------------+
- *
- * WRITE_STATE_TRANSITION transitions the state of the handshake state machine
-
- * WRITE_STATE_PRE_WORK performs any work necessary to prepare the later
- * sending of the message. This could result in an NBIO event occuring in
- * which case control returns to the calling application. When this function
- * is recalled we will resume in the same state where we left off.
- *
- * WRITE_STATE_SEND sends the message and performs any work to be done after
- * sending.
- *
- * WRITE_STATE_POST_WORK performs any work necessary after the sending of the
- * message has been completed. As for WRITE_STATE_PRE_WORK this could also
- * result in an NBIO event.
- */
-static enum SUB_STATE_RETURN write_state_machine(SSL *s)
-{
-    STATEM *st = &s->statem;
-    int ret;
-    enum WRITE_TRAN (*transition)(SSL *s);
-    enum WORK_STATE (*pre_work)(SSL *s, enum WORK_STATE wst);
-    enum WORK_STATE (*post_work)(SSL *s, enum WORK_STATE wst);
-    int (*construct_message)(SSL *s);
-    void (*cb) (const SSL *ssl, int type, int val) = NULL;
-
-    if (s->info_callback != NULL)
-        cb = s->info_callback;
-    else if (s->ctx->info_callback != NULL)
-        cb = s->ctx->info_callback;
-
-    if(s->server) {
-        transition = server_write_transition;
-        pre_work = server_pre_work;
-        post_work = server_post_work;
-        construct_message = server_construct_message;
-    } else {
-        transition = client_write_transition;
-        pre_work = client_pre_work;
-        post_work = client_post_work;
-        construct_message = client_construct_message;
-    }
-
-    while(1) {
-        switch(st->write_state) {
-        case WRITE_STATE_TRANSITION:
-            if (cb != NULL) {
-                /* Notify callback of an impending state change */
-                if (s->server)
-                    cb(s, SSL_CB_ACCEPT_LOOP, 1);
-                else
-                    cb(s, SSL_CB_CONNECT_LOOP, 1);
-            }
-            switch(transition(s)) {
-            case WRITE_TRAN_CONTINUE:
-                st->write_state = WRITE_STATE_PRE_WORK;
-                st->write_state_work = WORK_MORE_A;
-                break;
-
-            case WRITE_TRAN_FINISHED:
-                return SUB_STATE_FINISHED;
-                break;
-
-            default:
-                return SUB_STATE_ERROR;
-            }
-            break;
-
-        case WRITE_STATE_PRE_WORK:
-            switch(st->write_state_work = pre_work(s, st->write_state_work)) {
-            default:
-                return SUB_STATE_ERROR;
-
-            case WORK_FINISHED_CONTINUE:
-                st->write_state = WRITE_STATE_SEND;
-                break;
-
-            case WORK_FINISHED_STOP:
-                return SUB_STATE_END_HANDSHAKE;
-            }
-            if(construct_message(s) == 0)
-                return SUB_STATE_ERROR;
-
-            /* Fall through */
-
-        case WRITE_STATE_SEND:
-            if (SSL_IS_DTLS(s) && st->use_timer) {
-                dtls1_start_timer(s);
-            }
-            ret = statem_do_write(s);
-            if (ret <= 0) {
-                return SUB_STATE_ERROR;
-            }
-            st->write_state = WRITE_STATE_POST_WORK;
-            st->write_state_work = WORK_MORE_A;
-            /* Fall through */
-
-        case WRITE_STATE_POST_WORK:
-            switch(st->write_state_work = post_work(s, st->write_state_work)) {
-            default:
-                return SUB_STATE_ERROR;
-
-            case WORK_FINISHED_CONTINUE:
-                st->write_state = WRITE_STATE_TRANSITION;
-                break;
-
-            case WORK_FINISHED_STOP:
-                return SUB_STATE_END_HANDSHAKE;
-            }
-            break;
-
-        default:
-            return SUB_STATE_ERROR;
-        }
-    }
-}
-
-/*
- * Flush the write BIO
- */
-static int statem_flush(SSL *s)
-{
-    s->rwstate = SSL_WRITING;
-    if (BIO_flush(s->wbio) <= 0) {
-        return 0;
-    }
-    s->rwstate = SSL_NOTHING;
-
-    return 1;
-}
-
-/*
- * Called by the record layer to determine whether application data is
- * allowed to be sent in the current handshake state or not.
- *
- * Return values are:
- *   1: Yes (application data allowed)
- *   0: No (application data not allowed)
- */
-int statem_app_data_allowed(SSL *s)
-{
-    STATEM *st = &s->statem;
-
-    if (st->state == MSG_FLOW_UNINITED || st->state == MSG_FLOW_RENEGOTIATE)
-        return 0;
-
-    if (!s->s3->in_read_app_data || (s->s3->total_renegotiations == 0))
-        return 0;
-
-    if (s->server) {
-        /*
-         * If we're a server and we haven't got as far as writing our
-         * ServerHello yet then we allow app data
-         */
-        if (st->hand_state == TLS_ST_BEFORE
-                || st->hand_state == TLS_ST_SR_CLNT_HELLO)
-            return 1;
-    } else {
-        /*
-         * If we're a client and we haven't read the ServerHello yet then we
-         * allow app data
-         */
-        if (st->hand_state == TLS_ST_CW_CLNT_HELLO)
-            return 1;
-    }
-
-    return 0;
-}
-
-
-#ifndef OPENSSL_NO_SCTP
-/*
- * Set flag used by SCTP to determine whether we are in the read sock state
- */
-void statem_set_sctp_read_sock(SSL *s, int read_sock)
-{
-    s->statem.in_sctp_read_sock = read_sock;
-}
-
-/*
- * Called by the record layer to determine whether we are in the read sock
- * state or not.
- *
- * Return values are:
- *   1: Yes (we are in the read sock state)
- *   0: No (we are not in the read sock state)
- */
-int statem_in_sctp_read_sock(SSL *s)
-{
-    return s->statem.in_sctp_read_sock;
-}
-#endif
-
-/*
- * Is a CertificateRequest message allowed at the moment or not?
- *
- *  Return values are:
- *  1: Yes
- *  0: No
- */
-static inline int cert_req_allowed(SSL *s)
-{
-    /* TLS does not like anon-DH with client cert */
-    if (s->version > SSL3_VERSION
-            && (s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL))
-        return 0;
-
-    return 1;
-}
-
-/*
- * Are we allowed to skip the ServerKeyExchange message?
- *
- *  Return values are:
- *  1: Yes
- *  0: No
- */
-static inline int key_exchange_skip_allowed(SSL *s)
-{
-    long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
-
-    /*
-     * Can't skip server key exchange if this is an ephemeral
-     * ciphersuite.
-     */
-    if (alg_k & (SSL_kDHE | SSL_kECDHE)) {
-        return 0;
-    }
-
-    return 1;
-}
-
-/*
- * client_read_transition() encapsulates the logic for the allowed handshake
- * state transitions when the client is reading messages from the server. The
- * message type that the server has sent is provided in |mt|. The current state
- * is in |s->statem.hand_state|.
- *
- *  Return values are:
- *  1: Success (transition allowed)
- *  0: Error (transition not allowed)
- */
-static int client_read_transition(SSL *s, int mt)
-{
-    STATEM *st = &s->statem;
-
-    switch(st->hand_state) {
-    case TLS_ST_CW_CLNT_HELLO:
-        if (mt == SSL3_MT_SERVER_HELLO) {
-            st->hand_state = TLS_ST_CR_SRVR_HELLO;
-            return 1;
-        }
-
-        if (SSL_IS_DTLS(s)) {
-            if (mt == DTLS1_MT_HELLO_VERIFY_REQUEST) {
-                st->hand_state = DTLS_ST_CR_HELLO_VERIFY_REQUEST;
-                return 1;
-            }
-        }
-        break;
-
-    case TLS_ST_CR_SRVR_HELLO:
-        if (s->hit) {
-            if (s->tlsext_ticket_expected) {
-                if (mt == SSL3_MT_NEWSESSION_TICKET) {
-                    st->hand_state = TLS_ST_CR_SESSION_TICKET;
-                    return 1;
-                }
-            } else if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
-                st->hand_state = TLS_ST_CR_CHANGE;
-                return 1;
-            }
-        } else {
-            if (SSL_IS_DTLS(s) && mt == DTLS1_MT_HELLO_VERIFY_REQUEST) {
-                st->hand_state = DTLS_ST_CR_HELLO_VERIFY_REQUEST;
-                return 1;
-            } else if (!(s->s3->tmp.new_cipher->algorithm_auth
-                        & (SSL_aNULL | SSL_aSRP | SSL_aPSK))) {
-                if (mt == SSL3_MT_CERTIFICATE) {
-                    st->hand_state = TLS_ST_CR_CERT;
-                    return 1;
-                }
-            } else {
-                if (mt == SSL3_MT_SERVER_KEY_EXCHANGE) {
-                    st->hand_state = TLS_ST_CR_KEY_EXCH;
-                    return 1;
-                } else if (key_exchange_skip_allowed(s)) {
-                    if (mt == SSL3_MT_CERTIFICATE_REQUEST
-                            && cert_req_allowed(s)) {
-                        st->hand_state = TLS_ST_CR_CERT_REQ;
-                        return 1;
-                    } else if (mt == SSL3_MT_SERVER_DONE) {
-                        st->hand_state = TLS_ST_CR_SRVR_DONE;
-                        return 1;
-                    }
-                }
-            }
-        }
-        break;
-
-    case TLS_ST_CR_CERT:
-        if (s->tlsext_status_expected) {
-            if (mt == SSL3_MT_CERTIFICATE_STATUS) {
-                st->hand_state = TLS_ST_CR_CERT_STATUS;
-                return 1;
-            }
-        } else {
-            if (mt == SSL3_MT_SERVER_KEY_EXCHANGE) {
-                st->hand_state = TLS_ST_CR_KEY_EXCH;
-                return 1;
-            } else if (key_exchange_skip_allowed(s)) {
-                if (mt == SSL3_MT_CERTIFICATE_REQUEST && cert_req_allowed(s)) {
-                    st->hand_state = TLS_ST_CR_CERT_REQ;
-                    return 1;
-                } else if (mt == SSL3_MT_SERVER_DONE) {
-                    st->hand_state = TLS_ST_CR_SRVR_DONE;
-                    return 1;
-                }
-            }
-        }
-        break;
-
-    case TLS_ST_CR_CERT_STATUS:
-        if (mt == SSL3_MT_SERVER_KEY_EXCHANGE) {
-            st->hand_state = TLS_ST_CR_KEY_EXCH;
-            return 1;
-        } else if (key_exchange_skip_allowed(s)) {
-            if (mt == SSL3_MT_CERTIFICATE_REQUEST && cert_req_allowed(s)) {
-                st->hand_state = TLS_ST_CR_CERT_REQ;
-                return 1;
-            } else if (mt == SSL3_MT_SERVER_DONE) {
-                st->hand_state = TLS_ST_CR_SRVR_DONE;
-                return 1;
-            }
-        }
-        break;
-
-    case TLS_ST_CR_KEY_EXCH:
-        if (mt == SSL3_MT_CERTIFICATE_REQUEST && cert_req_allowed(s)) {
-            st->hand_state = TLS_ST_CR_CERT_REQ;
-            return 1;
-        } else if (mt == SSL3_MT_SERVER_DONE) {
-            st->hand_state = TLS_ST_CR_SRVR_DONE;
-            return 1;
-        }
-        break;
-
-    case TLS_ST_CR_CERT_REQ:
-        if (mt == SSL3_MT_SERVER_DONE) {
-            st->hand_state = TLS_ST_CR_SRVR_DONE;
-            return 1;
-        }
-        break;
-
-    case TLS_ST_CW_FINISHED:
-        if (mt == SSL3_MT_NEWSESSION_TICKET && s->tlsext_ticket_expected) {
-            st->hand_state = TLS_ST_CR_SESSION_TICKET;
-            return 1;
-        } else if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
-            st->hand_state = TLS_ST_CR_CHANGE;
-            return 1;
-        }
-        break;
-
-    case TLS_ST_CR_SESSION_TICKET:
-        if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
-            st->hand_state = TLS_ST_CR_CHANGE;
-            return 1;
-        }
-        break;
-
-    case TLS_ST_CR_CHANGE:
-        if (mt == SSL3_MT_FINISHED) {
-            st->hand_state = TLS_ST_CR_FINISHED;
-            return 1;
-        }
-        break;
-
-    default:
-        break;
-    }
-
-    /* No valid transition found */
-    return 0;
-}
-
-/*
- * client_write_transition() works out what handshake state to move to next
- * when the client is writing messages to be sent to the server.
- */
-static enum WRITE_TRAN client_write_transition(SSL *s)
-{
-    STATEM *st = &s->statem;
-
-    switch(st->hand_state) {
-        case TLS_ST_OK:
-            /* Renegotiation - fall through */
-        case TLS_ST_BEFORE:
-            st->hand_state = TLS_ST_CW_CLNT_HELLO;
-            return WRITE_TRAN_CONTINUE;
-
-        case TLS_ST_CW_CLNT_HELLO:
-            /*
-             * No transition at the end of writing because we don't know what
-             * we will be sent
-             */
-            return WRITE_TRAN_FINISHED;
-
-        case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
-            st->hand_state = TLS_ST_CW_CLNT_HELLO;
-            return WRITE_TRAN_CONTINUE;
-
-        case TLS_ST_CR_SRVR_DONE:
-            if (s->s3->tmp.cert_req)
-                st->hand_state = TLS_ST_CW_CERT;
-            else
-                st->hand_state = TLS_ST_CW_KEY_EXCH;
-            return WRITE_TRAN_CONTINUE;
-
-        case TLS_ST_CW_CERT:
-            st->hand_state = TLS_ST_CW_KEY_EXCH;
-            return WRITE_TRAN_CONTINUE;
-
-        case TLS_ST_CW_KEY_EXCH:
-            /*
-             * For TLS, cert_req is set to 2, so a cert chain of nothing is
-             * sent, but no verify packet is sent
-             */
-            /*
-             * XXX: For now, we do not support client authentication in ECDH
-             * cipher suites with ECDH (rather than ECDSA) certificates. We
-             * need to skip the certificate verify message when client's
-             * ECDH public key is sent inside the client certificate.
-             */
-            if (s->s3->tmp.cert_req == 1) {
-                st->hand_state = TLS_ST_CW_CERT_VRFY;
-            } else {
-                st->hand_state = TLS_ST_CW_CHANGE;
-            }
-            if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY) {
-                st->hand_state = TLS_ST_CW_CHANGE;
-            }
-            return WRITE_TRAN_CONTINUE;
-
-        case TLS_ST_CW_CERT_VRFY:
-            st->hand_state = TLS_ST_CW_CHANGE;
-            return WRITE_TRAN_CONTINUE;
-
-        case TLS_ST_CW_CHANGE:
-#if defined(OPENSSL_NO_NEXTPROTONEG)
-            st->hand_state = TLS_ST_CW_FINISHED;
-#else
-            if (!SSL_IS_DTLS(s) && s->s3->next_proto_neg_seen)
-                st->hand_state = TLS_ST_CW_NEXT_PROTO;
-            else
-                st->hand_state = TLS_ST_CW_FINISHED;
-#endif
-            return WRITE_TRAN_CONTINUE;
-
-#if !defined(OPENSSL_NO_NEXTPROTONEG)
-        case TLS_ST_CW_NEXT_PROTO:
-            st->hand_state = TLS_ST_CW_FINISHED;
-            return WRITE_TRAN_CONTINUE;
-#endif
-
-        case TLS_ST_CW_FINISHED:
-            if (s->hit) {
-                st->hand_state = TLS_ST_OK;
-                statem_set_in_init(s, 0);
-                return WRITE_TRAN_CONTINUE;
-            } else {
-                return WRITE_TRAN_FINISHED;
-            }
-
-        case TLS_ST_CR_FINISHED:
-            if (s->hit) {
-                st->hand_state = TLS_ST_CW_CHANGE;
-                return WRITE_TRAN_CONTINUE;
-            } else {
-                st->hand_state = TLS_ST_OK;
-                statem_set_in_init(s, 0);
-                return WRITE_TRAN_CONTINUE;
-            }
-
-        default:
-            /* Shouldn't happen */
-            return WRITE_TRAN_ERROR;
-    }
-}
-
-/*
- * Perform any pre work that needs to be done prior to sending a message from
- * the client to the server.
- */
-static enum WORK_STATE client_pre_work(SSL *s, enum WORK_STATE wst)
-{
-    STATEM *st = &s->statem;
-
-    switch(st->hand_state) {
-    case TLS_ST_CW_CLNT_HELLO:
-        s->shutdown = 0;
-        if (SSL_IS_DTLS(s)) {
-            /* every DTLS ClientHello resets Finished MAC */
-            ssl3_init_finished_mac(s);
-        }
-        break;
-
-    case TLS_ST_CW_CERT:
-        return tls_prepare_client_certificate(s, wst);
-
-    case TLS_ST_CW_CHANGE:
-        if (SSL_IS_DTLS(s)) {
-            if (s->hit) {
-                /*
-                 * We're into the last flight so we don't retransmit these
-                 * messages unless we need to.
-                 */
-                st->use_timer = 0;
-            }
-#ifndef OPENSSL_NO_SCTP
-            if (BIO_dgram_is_sctp(SSL_get_wbio(s)))
-                return dtls_wait_for_dry(s);
-#endif
-        }
-        return WORK_FINISHED_CONTINUE;
-
-    case TLS_ST_OK:
-        return tls_finish_handshake(s, wst);
-
-    default:
-        /* No pre work to be done */
-        break;
-    }
-
-    return WORK_FINISHED_CONTINUE;
-}
-
-/*
- * Perform any work that needs to be done after sending a message from the
- * client to the server.
- */
-static enum WORK_STATE client_post_work(SSL *s, enum WORK_STATE wst)
-{
-    STATEM *st = &s->statem;
-
-    s->init_num = 0;
-
-    switch(st->hand_state) {
-    case TLS_ST_CW_CLNT_HELLO:
-        if (SSL_IS_DTLS(s) && s->d1->cookie_len > 0 && statem_flush(s) != 1)
-            return WORK_MORE_A;
-#ifndef OPENSSL_NO_SCTP
-        /* Disable buffering for SCTP */
-        if (!SSL_IS_DTLS(s) || !BIO_dgram_is_sctp(SSL_get_wbio(s))) {
-#endif
-            /*
-             * turn on buffering for the next lot of output
-             */
-            if (s->bbio != s->wbio)
-                s->wbio = BIO_push(s->bbio, s->wbio);
-#ifndef OPENSSL_NO_SCTP
-            }
-#endif
-        if (SSL_IS_DTLS(s)) {
-            /* Treat the next message as the first packet */
-            s->first_packet = 1;
-        }
-        break;
-
-    case TLS_ST_CW_KEY_EXCH:
-        if (tls_client_key_exchange_post_work(s) == 0)
-            return WORK_ERROR;
-        break;
-
-    case TLS_ST_CW_CHANGE:
-        s->session->cipher = s->s3->tmp.new_cipher;
-#ifdef OPENSSL_NO_COMP
-        s->session->compress_meth = 0;
-#else
-        if (s->s3->tmp.new_compression == NULL)
-            s->session->compress_meth = 0;
-        else
-            s->session->compress_meth = s->s3->tmp.new_compression->id;
-#endif
-        if (!s->method->ssl3_enc->setup_key_block(s))
-            return WORK_ERROR;
-
-        if (!s->method->ssl3_enc->change_cipher_state(s,
-                                                      SSL3_CHANGE_CIPHER_CLIENT_WRITE))
-            return WORK_ERROR;
-
-        if (SSL_IS_DTLS(s)) {
-#ifndef OPENSSL_NO_SCTP
-            if (s->hit) {
-                /*
-                 * Change to new shared key of SCTP-Auth, will be ignored if
-                 * no SCTP used.
-                 */
-                BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY,
-                         0, NULL);
-            }
-#endif
-
-            dtls1_reset_seq_numbers(s, SSL3_CC_WRITE);
-        }
-        break;
-
-    case TLS_ST_CW_FINISHED:
-#ifndef OPENSSL_NO_SCTP
-        if (wst == WORK_MORE_A && SSL_IS_DTLS(s) && s->hit == 0) {
-            /*
-             * Change to new shared key of SCTP-Auth, will be ignored if
-             * no SCTP used.
-             */
-            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY,
-                     0, NULL);
-        }
-#endif
-        if (statem_flush(s) != 1)
-            return WORK_MORE_B;
-
-        if (s->hit && tls_finish_handshake(s, WORK_MORE_A) != 1)
-                return WORK_ERROR;
-        break;
-
-    default:
-        /* No post work to be done */
-        break;
-    }
-
-    return WORK_FINISHED_CONTINUE;
-}
-
-/*
- * Construct a message to be sent from the client to the server.
- *
- * Valid return values are:
- *   1: Success
- *   0: Error
- */
-static int client_construct_message(SSL *s)
-{
-    STATEM *st = &s->statem;
-
-    switch(st->hand_state) {
-    case TLS_ST_CW_CLNT_HELLO:
-        return tls_construct_client_hello(s);
-
-    case TLS_ST_CW_CERT:
-        return tls_construct_client_certificate(s);
-
-    case TLS_ST_CW_KEY_EXCH:
-        return tls_construct_client_key_exchange(s);
-
-    case TLS_ST_CW_CERT_VRFY:
-        return tls_construct_client_verify(s);
-
-    case TLS_ST_CW_CHANGE:
-        if (SSL_IS_DTLS(s))
-            return dtls_construct_change_cipher_spec(s);
-        else
-            return tls_construct_change_cipher_spec(s);
-
-#if !defined(OPENSSL_NO_NEXTPROTONEG)
-    case TLS_ST_CW_NEXT_PROTO:
-        return tls_construct_next_proto(s);
-#endif
-    case TLS_ST_CW_FINISHED:
-        return tls_construct_finished(s,
-                                      s->method->
-                                      ssl3_enc->client_finished_label,
-                                      s->method->
-                                      ssl3_enc->client_finished_label_len);
-
-    default:
-        /* Shouldn't happen */
-        break;
-    }
-
-    return 0;
-}
-
-/* The spec allows for a longer length than this, but we limit it */
-#define HELLO_VERIFY_REQUEST_MAX_LENGTH 258
-#define SERVER_HELLO_MAX_LENGTH         20000
-#define SERVER_KEY_EXCH_MAX_LENGTH      102400
-#define SERVER_HELLO_DONE_MAX_LENGTH    0
-#define CCS_MAX_LENGTH                  1
-/* Max should actually be 36 but we are generous */
-#define FINISHED_MAX_LENGTH             64
-
-/*
- * Returns the maximum allowed length for the current message that we are
- * reading. Excludes the message header.
- */
-static unsigned long client_max_message_size(SSL *s)
-{
-    STATEM *st = &s->statem;
-
-    switch(st->hand_state) {
-        case TLS_ST_CR_SRVR_HELLO:
-            return SERVER_HELLO_MAX_LENGTH;
-
-        case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
-            return HELLO_VERIFY_REQUEST_MAX_LENGTH;
-
-        case TLS_ST_CR_CERT:
-            return s->max_cert_list;
-
-        case TLS_ST_CR_CERT_STATUS:
-            return SSL3_RT_MAX_PLAIN_LENGTH;
-
-        case TLS_ST_CR_KEY_EXCH:
-            return SERVER_KEY_EXCH_MAX_LENGTH;
-
-        case TLS_ST_CR_CERT_REQ:
-            return SSL3_RT_MAX_PLAIN_LENGTH;
-
-        case TLS_ST_CR_SRVR_DONE:
-            return SERVER_HELLO_DONE_MAX_LENGTH;
-
-        case TLS_ST_CR_CHANGE:
-            return CCS_MAX_LENGTH;
-
-        case TLS_ST_CR_SESSION_TICKET:
-            return SSL3_RT_MAX_PLAIN_LENGTH;
-
-        case TLS_ST_CR_FINISHED:
-            return FINISHED_MAX_LENGTH;
-
-        default:
-            /* Shouldn't happen */
-            break;
-    }
-
-    return 0;
-}
-
-/*
- * Process a message that the client has been received from the server.
- */
-static enum MSG_PROCESS_RETURN client_process_message(SSL *s, PACKET *pkt)
-{
-    STATEM *st = &s->statem;
-
-    switch(st->hand_state) {
-        case TLS_ST_CR_SRVR_HELLO:
-            return tls_process_server_hello(s, pkt);
-
-        case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
-            return dtls_process_hello_verify(s, pkt);
-
-        case TLS_ST_CR_CERT:
-            return tls_process_server_certificate(s, pkt);
-
-        case TLS_ST_CR_CERT_STATUS:
-            return tls_process_cert_status(s, pkt);
-
-        case TLS_ST_CR_KEY_EXCH:
-            return tls_process_key_exchange(s, pkt);
-
-        case TLS_ST_CR_CERT_REQ:
-            return tls_process_certificate_request(s, pkt);
-
-        case TLS_ST_CR_SRVR_DONE:
-            return tls_process_server_done(s, pkt);
-
-        case TLS_ST_CR_CHANGE:
-            return tls_process_change_cipher_spec(s, pkt);
-
-        case TLS_ST_CR_SESSION_TICKET:
-            return tls_process_new_session_ticket(s, pkt);
-
-        case TLS_ST_CR_FINISHED:
-            return tls_process_finished(s, pkt);
-
-        default:
-            /* Shouldn't happen */
-            break;
-    }
-
-    return MSG_PROCESS_ERROR;
-}
-
-/*
- * Perform any further processing required following the receipt of a message
- * from the server
- */
-static enum WORK_STATE client_post_process_message(SSL *s, enum WORK_STATE wst)
-{
-    STATEM *st = &s->statem;
-
-    switch(st->hand_state) {
-#ifndef OPENSSL_NO_SCTP
-    case TLS_ST_CR_SRVR_DONE:
-        /* We only get here if we are using SCTP and we are renegotiating */
-        if (BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s))) {
-            s->s3->in_read_app_data = 2;
-            s->rwstate = SSL_READING;
-            BIO_clear_retry_flags(SSL_get_rbio(s));
-            BIO_set_retry_read(SSL_get_rbio(s));
-            statem_set_sctp_read_sock(s, 1);
-            return WORK_MORE_A;
-        }
-        statem_set_sctp_read_sock(s, 0);
-        return WORK_FINISHED_STOP;
-#endif
-
-    case TLS_ST_CR_FINISHED:
-        if (!s->hit)
-            return tls_finish_handshake(s, wst);
-        else
-            return WORK_FINISHED_STOP;
-    default:
-        break;
-    }
-
-    /* Shouldn't happen */
-    return WORK_ERROR;
-}
-
-
-/*
- * server_read_transition() encapsulates the logic for the allowed handshake
- * state transitions when the server is reading messages from the client. The
- * message type that the client has sent is provided in |mt|. The current state
- * is in |s->statem.hand_state|.
- *
- *  Valid return values are:
- *  1: Success (transition allowed)
- *  0: Error (transition not allowed)
- */
-static int server_read_transition(SSL *s, int mt)
-{
-    STATEM *st = &s->statem;
-
-    switch(st->hand_state) {
-    case TLS_ST_BEFORE:
-    case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
-        if (mt == SSL3_MT_CLIENT_HELLO) {
-            st->hand_state = TLS_ST_SR_CLNT_HELLO;
-            return 1;
-        }
-        break;
-
-    case TLS_ST_SW_SRVR_DONE:
-        /*
-         * If we get a CKE message after a ServerDone then either
-         * 1) We didn't request a Certificate
-         * OR
-         * 2) If we did request one then
-         *      a) We allow no Certificate to be returned
-         *      AND
-         *      b) We are running SSL3 (in TLS1.0+ the client must return a 0
-         *         list if we requested a certificate)
-         */
-        if (mt == SSL3_MT_CLIENT_KEY_EXCHANGE
-                && (!s->s3->tmp.cert_request
-                    || (!((s->verify_mode & SSL_VERIFY_PEER) &&
-                          (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT))
-                        && (s->version == SSL3_VERSION)))) {
-            st->hand_state = TLS_ST_SR_KEY_EXCH;
-            return 1;
-        } else if (s->s3->tmp.cert_request) {
-            if (mt == SSL3_MT_CERTIFICATE) {
-                st->hand_state = TLS_ST_SR_CERT;
-                return 1;
-            } 
-        }
-        break;
-
-    case TLS_ST_SR_CERT:
-        if (mt == SSL3_MT_CLIENT_KEY_EXCHANGE) {
-            st->hand_state = TLS_ST_SR_KEY_EXCH;
-            return 1;
-        }
-        break;
-
-    case TLS_ST_SR_KEY_EXCH:
-        /*
-         * We should only process a CertificateVerify message if we have
-         * received a Certificate from the client. If so then |s->session->peer|
-         * will be non NULL. In some instances a CertificateVerify message is
-         * not required even if the peer has sent a Certificate (e.g. such as in
-         * the case of static DH). In that case |s->no_cert_verify| should be
-         * set.
-         */
-        if (s->session->peer == NULL || s->no_cert_verify) {
-            if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
-                /*
-                 * For the ECDH ciphersuites when the client sends its ECDH
-                 * pub key in a certificate, the CertificateVerify message is
-                 * not sent. Also for GOST ciphersuites when the client uses
-                 * its key from the certificate for key exchange.
-                 */
-                st->hand_state = TLS_ST_SR_CHANGE;
-                return 1;
-            }
-        } else {
-            if (mt == SSL3_MT_CERTIFICATE_VERIFY) {
-                st->hand_state = TLS_ST_SR_CERT_VRFY;
-                return 1;
-            }
-        }
-        break;
-
-    case TLS_ST_SR_CERT_VRFY:
-        if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
-            st->hand_state = TLS_ST_SR_CHANGE;
-            return 1;
-        }
-        break;
-
-    case TLS_ST_SR_CHANGE:
-#ifndef OPENSSL_NO_NEXTPROTONEG
-        if (s->s3->next_proto_neg_seen) {
-            if (mt == SSL3_MT_NEXT_PROTO) {
-                st->hand_state = TLS_ST_SR_NEXT_PROTO;
-                return 1;
-            }
-        } else {
-#endif
-            if (mt == SSL3_MT_FINISHED) {
-                st->hand_state = TLS_ST_SR_FINISHED;
-                return 1;
-            }
-#ifndef OPENSSL_NO_NEXTPROTONEG
-        }
-#endif
-        break;
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
-    case TLS_ST_SR_NEXT_PROTO:
-        if (mt == SSL3_MT_FINISHED) {
-            st->hand_state = TLS_ST_SR_FINISHED;
-            return 1;
-        }
-        break;
-#endif
-
-    case TLS_ST_SW_FINISHED:
-        if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
-            st->hand_state = TLS_ST_SR_CHANGE;
-            return 1;
-        }
-        break;
-
-    default:
-        break;
-    }
-
-    /* No valid transition found */
-    return 0;
-}
-
-/*
- * Should we send a ServerKeyExchange message?
- *
- * Valid return values are:
- *   1: Yes
- *   0: No
- */
-static inline int send_server_key_exchange(SSL *s)
-{
-    unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
-
-    /*
-     * only send a ServerKeyExchange if DH, fortezza or RSA but we have a
-     * sign only certificate PSK: may send PSK identity hints For
-     * ECC ciphersuites, we send a serverKeyExchange message only if
-     * the cipher suite is either ECDH-anon or ECDHE. In other cases,
-     * the server certificate contains the server's public key for
-     * key exchange.
-     */
-    if (   (alg_k & SSL_kDHE)
-        || (alg_k & SSL_kECDHE)
-        || ((alg_k & SSL_kRSA)
-            && (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL
-                || (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)
-                    && EVP_PKEY_size(s->cert->pkeys
-                                     [SSL_PKEY_RSA_ENC].privatekey) *
-                    8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)
-                   )
-               )
-           )
-        /*
-         * PSK: send ServerKeyExchange if PSK identity hint if
-         * provided
-         */
-#ifndef OPENSSL_NO_PSK
-        /* Only send SKE if we have identity hint for plain PSK */
-        || ((alg_k & (SSL_kPSK | SSL_kRSAPSK))
-            && s->cert->psk_identity_hint)
-        /* For other PSK always send SKE */
-        || (alg_k & (SSL_PSK & (SSL_kDHEPSK | SSL_kECDHEPSK)))
-#endif
-#ifndef OPENSSL_NO_SRP
-        /* SRP: send ServerKeyExchange */
-        || (alg_k & SSL_kSRP)
-#endif
-       ) {
-        return 1;
-    }
-
-    return 0;
-}
-
-/*
- * Should we send a CertificateRequest message?
- *
- * Valid return values are:
- *   1: Yes
- *   0: No
- */
-static inline int send_certificate_request(SSL *s)
-{
-    if (
-           /* don't request cert unless asked for it: */
-           s->verify_mode & SSL_VERIFY_PEER
-           /*
-            * if SSL_VERIFY_CLIENT_ONCE is set, don't request cert
-            * during re-negotiation:
-            */
-           && ((s->session->peer == NULL) ||
-               !(s->verify_mode & SSL_VERIFY_CLIENT_ONCE))
-           /*
-            * never request cert in anonymous ciphersuites (see
-            * section "Certificate request" in SSL 3 drafts and in
-            * RFC 2246):
-            */
-           && (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
-           /*
-            * ... except when the application insists on
-            * verification (against the specs, but s3_clnt.c accepts
-            * this for SSL 3)
-            */
-               || (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT))
-           /* don't request certificate for SRP auth */
-           && !(s->s3->tmp.new_cipher->algorithm_auth & SSL_aSRP)
-           /*
-            * With normal PSK Certificates and Certificate Requests
-            * are omitted
-            */
-           && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_PSK)) {
-        return 1;
-    }
-
-    return 0;
-}
-
-/*
- * server_write_transition() works out what handshake state to move to next
- * when the server is writing messages to be sent to the client.
- */
-static enum WRITE_TRAN server_write_transition(SSL *s)
-{
-    STATEM *st = &s->statem;
-
-    switch(st->hand_state) {
-        case TLS_ST_BEFORE:
-            /* Just go straight to trying to read from the client */;
-            return WRITE_TRAN_FINISHED;
-
-        case TLS_ST_OK:
-            /* We must be trying to renegotiate */
-            st->hand_state = TLS_ST_SW_HELLO_REQ;
-            return WRITE_TRAN_CONTINUE;
-
-        case TLS_ST_SW_HELLO_REQ:
-            st->hand_state = TLS_ST_OK;
-            statem_set_in_init(s, 0);
-            return WRITE_TRAN_CONTINUE;
-
-        case TLS_ST_SR_CLNT_HELLO:
-            if (SSL_IS_DTLS(s) && !s->d1->cookie_verified
-                    && (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE))
-                st->hand_state = DTLS_ST_SW_HELLO_VERIFY_REQUEST;
-            else
-                st->hand_state = TLS_ST_SW_SRVR_HELLO;
-            return WRITE_TRAN_CONTINUE;
-
-        case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
-            return WRITE_TRAN_FINISHED;
-
-        case TLS_ST_SW_SRVR_HELLO:
-            if (s->hit) {
-                if (s->tlsext_ticket_expected)
-                    st->hand_state = TLS_ST_SW_SESSION_TICKET;
-                else
-                    st->hand_state = TLS_ST_SW_CHANGE;
-            } else {
-                /* Check if it is anon DH or anon ECDH, */
-                /* normal PSK or SRP */
-                if (!(s->s3->tmp.new_cipher->algorithm_auth &
-                     (SSL_aNULL | SSL_aSRP | SSL_aPSK))) {
-                    st->hand_state = TLS_ST_SW_CERT;
-                } else if (send_server_key_exchange(s)) {
-                    st->hand_state = TLS_ST_SW_KEY_EXCH;
-                } else if (send_certificate_request(s)) {
-                    st->hand_state = TLS_ST_SW_CERT_REQ;
-                } else {
-                    st->hand_state = TLS_ST_SW_SRVR_DONE;
-                }
-            }
-            return WRITE_TRAN_CONTINUE;
-
-        case TLS_ST_SW_CERT:
-            if (s->tlsext_status_expected) {
-                st->hand_state = TLS_ST_SW_CERT_STATUS;
-                return WRITE_TRAN_CONTINUE;
-            }
-            /* Fall through */
-
-        case TLS_ST_SW_CERT_STATUS:
-            if (send_server_key_exchange(s)) {
-                st->hand_state = TLS_ST_SW_KEY_EXCH;
-                return WRITE_TRAN_CONTINUE;
-            }
-            /* Fall through */
-
-        case TLS_ST_SW_KEY_EXCH:
-            if (send_certificate_request(s)) {
-                st->hand_state = TLS_ST_SW_CERT_REQ;
-                return WRITE_TRAN_CONTINUE;
-            }
-            /* Fall through */
-
-        case TLS_ST_SW_CERT_REQ:
-            st->hand_state = TLS_ST_SW_SRVR_DONE;
-            return WRITE_TRAN_CONTINUE;
-
-        case TLS_ST_SW_SRVR_DONE:
-            return WRITE_TRAN_FINISHED;
-
-        case TLS_ST_SR_FINISHED:
-            if (s->hit) {
-                st->hand_state = TLS_ST_OK;
-                statem_set_in_init(s, 0);
-                return WRITE_TRAN_CONTINUE;
-            } else if (s->tlsext_ticket_expected) {
-                st->hand_state = TLS_ST_SW_SESSION_TICKET;
-            } else {
-                st->hand_state = TLS_ST_SW_CHANGE;
-            }
-            return WRITE_TRAN_CONTINUE;
-
-        case TLS_ST_SW_SESSION_TICKET:
-            st->hand_state = TLS_ST_SW_CHANGE;
-            return WRITE_TRAN_CONTINUE;
-
-        case TLS_ST_SW_CHANGE:
-            st->hand_state = TLS_ST_SW_FINISHED;
-            return WRITE_TRAN_CONTINUE;
-
-        case TLS_ST_SW_FINISHED:
-            if (s->hit) {
-                return WRITE_TRAN_FINISHED;
-            }
-            st->hand_state = TLS_ST_OK;
-            statem_set_in_init(s, 0);
-            return WRITE_TRAN_CONTINUE;
-
-        default:
-            /* Shouldn't happen */
-            return WRITE_TRAN_ERROR;
-    }
-}
-
-/*
- * Perform any pre work that needs to be done prior to sending a message from
- * the server to the client.
- */
-static enum WORK_STATE server_pre_work(SSL *s, enum WORK_STATE wst)
-{
-    STATEM *st = &s->statem;
-
-    switch(st->hand_state) {
-    case TLS_ST_SW_HELLO_REQ:
-        s->shutdown = 0;
-        if (SSL_IS_DTLS(s))
-            dtls1_clear_record_buffer(s);
-        break;
-
-    case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
-        s->shutdown = 0;
-        if (SSL_IS_DTLS(s)) {
-            dtls1_clear_record_buffer(s);
-            /* We don't buffer this message so don't use the timer */
-            st->use_timer = 0;
-        }
-        break;
-
-    case TLS_ST_SW_SRVR_HELLO:
-        if (SSL_IS_DTLS(s)) {
-            /*
-             * Messages we write from now on should be bufferred and
-             * retransmitted if necessary, so we need to use the timer now
-             */
-            st->use_timer = 1;
-        }
-        break;
-
-    case TLS_ST_SW_SRVR_DONE:
-#ifndef OPENSSL_NO_SCTP
-        if (SSL_IS_DTLS(s) && BIO_dgram_is_sctp(SSL_get_wbio(s)))
-            return dtls_wait_for_dry(s);
-#endif
-        return WORK_FINISHED_CONTINUE;
-
-    case TLS_ST_SW_SESSION_TICKET:
-        if (SSL_IS_DTLS(s)) {
-            /*
-             * We're into the last flight. We don't retransmit the last flight
-             * unless we need to, so we don't use the timer
-             */
-            st->use_timer = 0;
-        }
-        break;
-
-    case TLS_ST_SW_CHANGE:
-        s->session->cipher = s->s3->tmp.new_cipher;
-        if (!s->method->ssl3_enc->setup_key_block(s)) {
-            statem_set_error(s);
-            return WORK_ERROR;
-        }
-        if (SSL_IS_DTLS(s)) {
-            /*
-             * We're into the last flight. We don't retransmit the last flight
-             * unless we need to, so we don't use the timer. This might have
-             * already been set to 0 if we sent a NewSessionTicket message,
-             * but we'll set it again here in case we didn't.
-             */
-            st->use_timer = 0;
-        }
-        return WORK_FINISHED_CONTINUE;
-
-    case TLS_ST_OK:
-        return tls_finish_handshake(s, wst);
-
-    default:
-        /* No pre work to be done */
-        break;
-    }
-
-    return WORK_FINISHED_CONTINUE;
-}
-
-/*
- * Perform any work that needs to be done after sending a message from the
- * server to the client.
- */
-static enum WORK_STATE server_post_work(SSL *s, enum WORK_STATE wst)
-{
-    STATEM *st = &s->statem;
-
-    s->init_num = 0;
-
-    switch(st->hand_state) {
-    case TLS_ST_SW_HELLO_REQ:
-        if (statem_flush(s) != 1)
-            return WORK_MORE_A;
-        ssl3_init_finished_mac(s);
-        break;
-
-    case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
-        if (statem_flush(s) != 1)
-            return WORK_MORE_A;
-        /* HelloVerifyRequest resets Finished MAC */
-        if (s->version != DTLS1_BAD_VER)
-            ssl3_init_finished_mac(s);
-        /*
-         * The next message should be another ClientHello which we need to
-         * treat like it was the first packet
-         */
-        s->first_packet = 1;
-        break;
-
-    case TLS_ST_SW_SRVR_HELLO:
-#ifndef OPENSSL_NO_SCTP
-        if (SSL_IS_DTLS(s) && s->hit) {
-            unsigned char sctpauthkey[64];
-            char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
-
-            /*
-             * Add new shared key for SCTP-Auth, will be ignored if no
-             * SCTP used.
-             */
-            snprintf((char *)labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL),
-                     DTLS1_SCTP_AUTH_LABEL);
-
-            if (SSL_export_keying_material(s, sctpauthkey,
-                    sizeof(sctpauthkey), labelbuffer,
-                    sizeof(labelbuffer), NULL, 0, 0) <= 0) {
-                statem_set_error(s);
-                return WORK_ERROR;
-            }
-
-            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
-                     sizeof(sctpauthkey), sctpauthkey);
-        }
-#endif
-        break;
-
-    case TLS_ST_SW_CHANGE:
-#ifndef OPENSSL_NO_SCTP
-        if (SSL_IS_DTLS(s) && !s->hit) {
-            /*
-             * Change to new shared key of SCTP-Auth, will be ignored if
-             * no SCTP used.
-             */
-            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY,
-                     0, NULL);
-        }
-#endif
-        if (!s->method->ssl3_enc->change_cipher_state(s,
-                SSL3_CHANGE_CIPHER_SERVER_WRITE)) {
-            statem_set_error(s);
-            return WORK_ERROR;
-        }
-
-        if (SSL_IS_DTLS(s))
-            dtls1_reset_seq_numbers(s, SSL3_CC_WRITE);
-        break;
-
-    case TLS_ST_SW_SRVR_DONE:
-        if (statem_flush(s) != 1)
-            return WORK_MORE_A;
-        break;
-
-    case TLS_ST_SW_FINISHED:
-        if (statem_flush(s) != 1)
-            return WORK_MORE_A;
-#ifndef OPENSSL_NO_SCTP
-        if (SSL_IS_DTLS(s) && s->hit) {
-            /*
-             * Change to new shared key of SCTP-Auth, will be ignored if
-             * no SCTP used.
-             */
-            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY,
-                     0, NULL);
-        }
-#endif
-        break;
-
-    default:
-        /* No post work to be done */
-        break;
-    }
-
-    return WORK_FINISHED_CONTINUE;
-}
-
-/*
- * Construct a message to be sent from the server to the client.
- *
- * Valid return values are:
- *   1: Success
- *   0: Error
- */
-static int server_construct_message(SSL *s)
-{
-    STATEM *st = &s->statem;
-
-    switch(st->hand_state) {
-    case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
-        return dtls_construct_hello_verify_request(s);
-
-    case TLS_ST_SW_HELLO_REQ:
-        return tls_construct_hello_request(s);
-
-    case TLS_ST_SW_SRVR_HELLO:
-        return tls_construct_server_hello(s);
-
-    case TLS_ST_SW_CERT:
-        return tls_construct_server_certificate(s);
-
-    case TLS_ST_SW_KEY_EXCH:
-        return tls_construct_server_key_exchange(s);
-
-    case TLS_ST_SW_CERT_REQ:
-        return tls_construct_certificate_request(s);
-
-    case TLS_ST_SW_SRVR_DONE:
-        return tls_construct_server_done(s);
-
-    case TLS_ST_SW_SESSION_TICKET:
-        return tls_construct_new_session_ticket(s);
-
-    case TLS_ST_SW_CERT_STATUS:
-        return tls_construct_cert_status(s);
-
-    case TLS_ST_SW_CHANGE:
-        if (SSL_IS_DTLS(s))
-            return dtls_construct_change_cipher_spec(s);
-        else
-            return tls_construct_change_cipher_spec(s);
-
-    case TLS_ST_SW_FINISHED:
-        return tls_construct_finished(s,
-                                      s->method->
-                                      ssl3_enc->server_finished_label,
-                                      s->method->
-                                      ssl3_enc->server_finished_label_len);
-
-    default:
-        /* Shouldn't happen */
-        break;
-    }
-
-    return 0;
-}
-
-#define CLIENT_KEY_EXCH_MAX_LENGTH      2048
-#define NEXT_PROTO_MAX_LENGTH           514
-
-/*
- * Returns the maximum allowed length for the current message that we are
- * reading. Excludes the message header.
- */
-static unsigned long server_max_message_size(SSL *s)
-{
-    STATEM *st = &s->statem;
-
-    switch(st->hand_state) {
-    case TLS_ST_SR_CLNT_HELLO:
-        return SSL3_RT_MAX_PLAIN_LENGTH;
-
-    case TLS_ST_SR_CERT:
-        return s->max_cert_list;
-
-    case TLS_ST_SR_KEY_EXCH:
-        return CLIENT_KEY_EXCH_MAX_LENGTH;
-
-    case TLS_ST_SR_CERT_VRFY:
-        return SSL3_RT_MAX_PLAIN_LENGTH;
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
-    case TLS_ST_SR_NEXT_PROTO:
-        return NEXT_PROTO_MAX_LENGTH;
-#endif
-
-    case TLS_ST_SR_CHANGE:
-        return CCS_MAX_LENGTH;
-
-    case TLS_ST_SR_FINISHED:
-        return FINISHED_MAX_LENGTH;
-
-    default:
-        /* Shouldn't happen */
-        break;
-    }
-
-    return 0;
-}
-
-/*
- * Process a message that the server has received from the client.
- */
-static enum MSG_PROCESS_RETURN  server_process_message(SSL *s, PACKET *pkt)
-{
-    STATEM *st = &s->statem;
-
-    switch(st->hand_state) {
-    case TLS_ST_SR_CLNT_HELLO:
-        return tls_process_client_hello(s, pkt);
-
-    case TLS_ST_SR_CERT:
-        return tls_process_client_certificate(s, pkt);
-
-    case TLS_ST_SR_KEY_EXCH:
-        return tls_process_client_key_exchange(s, pkt);
-
-    case TLS_ST_SR_CERT_VRFY:
-        return tls_process_cert_verify(s, pkt);
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
-    case TLS_ST_SR_NEXT_PROTO:
-        return tls_process_next_proto(s, pkt);
-#endif
-
-    case TLS_ST_SR_CHANGE:
-        return tls_process_change_cipher_spec(s, pkt);
-
-    case TLS_ST_SR_FINISHED:
-        return tls_process_finished(s, pkt);
-
-    default:
-        /* Shouldn't happen */
-        break;
-    }
-
-    return MSG_PROCESS_ERROR;
-}
-
-/*
- * Perform any further processing required following the receipt of a message
- * from the client
- */
-static enum WORK_STATE server_post_process_message(SSL *s, enum WORK_STATE wst)
-{
-    STATEM *st = &s->statem;
-
-    switch(st->hand_state) {
-    case TLS_ST_SR_CLNT_HELLO:
-        return tls_post_process_client_hello(s, wst);
-
-    case TLS_ST_SR_KEY_EXCH:
-        return tls_post_process_client_key_exchange(s, wst);
-
-    case TLS_ST_SR_CERT_VRFY:
-#ifndef OPENSSL_NO_SCTP
-        if (    /* Is this SCTP? */
-                BIO_dgram_is_sctp(SSL_get_wbio(s))
-                /* Are we renegotiating? */
-                && s->renegotiate
-                && BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s))) {
-            s->s3->in_read_app_data = 2;
-            s->rwstate = SSL_READING;
-            BIO_clear_retry_flags(SSL_get_rbio(s));
-            BIO_set_retry_read(SSL_get_rbio(s));
-            statem_set_sctp_read_sock(s, 1);
-            return WORK_MORE_A;
-        } else {
-            statem_set_sctp_read_sock(s, 0);
-        }
-#endif
-        return WORK_FINISHED_CONTINUE;
-
-
-    case TLS_ST_SR_FINISHED:
-        if (s->hit)
-            return tls_finish_handshake(s, wst);
-        else
-            return WORK_FINISHED_STOP;
-    default:
-        break;
-    }
-
-    /* Shouldn't happen */
-    return WORK_ERROR;
-}
diff --git a/ssl/statem/statem.c b/ssl/statem/statem.c
new file mode 100644 (file)
index 0000000..7e4f524
--- /dev/null
@@ -0,0 +1,2241 @@
+/* ssl/statem/statem.c */
+/*
+ * Written by Matt Caswell for the OpenSSL project.
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2015 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <openssl/rand.h>
+#include "../ssl_locl.h"
+
+/*
+ * This file implements the SSL/TLS/DTLS state machines.
+ *
+ * There are two primary state machines:
+ *
+ * 1) Message flow state machine
+ * 2) Handshake state machine
+ *
+ * The Message flow state machine controls the reading and sending of messages
+ * including handling of non-blocking IO events, flushing of the underlying
+ * write BIO, handling unexpected messages, etc. It is itself broken into two
+ * separate sub-state machines which control reading and writing respectively.
+ *
+ * The Handshake state machine keeps track of the current SSL/TLS handshake
+ * state. Transitions of the handshake state are the result of events that
+ * occur within the Message flow state machine.
+ *
+ * Overall it looks like this:
+ *
+ * ---------------------------------------------            -------------------
+ * |                                           |            |                 |
+ * | Message flow state machine                |            |                 |
+ * |                                           |            |                 |
+ * | -------------------- -------------------- | Transition | Handshake state |
+ * | | MSG_FLOW_READING    | | MSG_FLOW_WRITING    | | Event      | machine         |
+ * | | sub-state        | | sub-state        | |----------->|                 |
+ * | | machine for      | | machine for      | |            |                 |
+ * | | reading messages | | writing messages | |            |                 |
+ * | -------------------- -------------------- |            |                 |
+ * |                                           |            |                 |
+ * ---------------------------------------------            -------------------
+ *
+ */
+
+/* Sub state machine return values */
+enum SUB_STATE_RETURN {
+    /* Something bad happened or NBIO */
+    SUB_STATE_ERROR,
+    /* Sub state finished go to the next sub state */
+    SUB_STATE_FINISHED,
+    /* Sub state finished and handshake was completed */
+    SUB_STATE_END_HANDSHAKE
+};
+
+static int state_machine(SSL *s, int server);
+static void init_read_state_machine(SSL *s);
+static enum SUB_STATE_RETURN read_state_machine(SSL *s);
+static void init_write_state_machine(SSL *s);
+static enum SUB_STATE_RETURN write_state_machine(SSL *s);
+static inline int cert_req_allowed(SSL *s);
+static inline int key_exchange_skip_allowed(SSL *s);
+static int client_read_transition(SSL *s, int mt);
+static enum WRITE_TRAN client_write_transition(SSL *s);
+static enum WORK_STATE client_pre_work(SSL *s, enum WORK_STATE wst);
+static enum WORK_STATE client_post_work(SSL *s, enum WORK_STATE wst);
+static int client_construct_message(SSL *s);
+static unsigned long client_max_message_size(SSL *s);
+static enum MSG_PROCESS_RETURN client_process_message(SSL *s, PACKET *pkt);
+static enum WORK_STATE client_post_process_message(SSL *s, enum WORK_STATE wst);
+static int server_read_transition(SSL *s, int mt);
+static inline int send_server_key_exchange(SSL *s);
+static inline int send_certificate_request(SSL *s);
+static enum WRITE_TRAN server_write_transition(SSL *s);
+static enum WORK_STATE server_pre_work(SSL *s, enum WORK_STATE wst);
+static enum WORK_STATE server_post_work(SSL *s, enum WORK_STATE wst);
+static int server_construct_message(SSL *s);
+static unsigned long server_max_message_size(SSL *s);
+static enum MSG_PROCESS_RETURN server_process_message(SSL *s, PACKET *pkt);
+static enum WORK_STATE server_post_process_message(SSL *s, enum WORK_STATE wst);
+
+
+enum HANDSHAKE_STATE SSL_state(const SSL *ssl)
+{
+    return ssl->statem.hand_state;
+}
+
+void SSL_set_state(SSL *ssl, enum HANDSHAKE_STATE state)
+{
+    /*
+     * This function seems like a really bad idea. Should we remove it
+     * completely?
+     */
+    ssl->statem.hand_state = state;
+}
+
+int SSL_in_init(SSL *s)
+{
+    return s->statem.in_init;
+}
+
+int SSL_is_init_finished(SSL *s)
+{
+    return !(s->statem.in_init) && (s->statem.hand_state == TLS_ST_OK);
+}
+
+int SSL_in_before(SSL *s)
+{
+    /*
+     * Historically being "in before" meant before anything had happened. In the
+     * current code though we remain in the "before" state for a while after we
+     * have started the handshake process (e.g. as a server waiting for the
+     * first message to arrive). There "in before" is taken to mean "in before"
+     * and not started any handshake process yet.
+     */
+    return (s->statem.hand_state == TLS_ST_BEFORE)
+        && (s->statem.state == MSG_FLOW_UNINITED);
+}
+
+/*
+ * Clear the state machine state and reset back to MSG_FLOW_UNINITED
+ */
+void statem_clear(SSL *s)
+{
+    s->statem.state = MSG_FLOW_UNINITED;
+    s->statem.hand_state = TLS_ST_BEFORE;
+    s->statem.in_init = 1;
+}
+
+/*
+ * Set the state machine up ready for a renegotiation handshake
+ */
+void statem_set_renegotiate(SSL *s)
+{
+    s->statem.state = MSG_FLOW_RENEGOTIATE;
+    s->statem.in_init = 1;
+}
+
+/*
+ * Put the state machine into an error state. This is a permanent error for
+ * the current connection.
+ */
+void statem_set_error(SSL *s)
+{
+    s->statem.state = MSG_FLOW_ERROR;
+}
+
+/*
+ * Discover whether the current connection is in the error state.
+ *
+ * Valid return values are:
+ *   1: Yes
+ *   0: No
+ */
+int statem_in_error(const SSL *s)
+{
+    if (s->statem.state == MSG_FLOW_ERROR)
+        return 1;
+
+    return 0;
+}
+
+void statem_set_in_init(SSL *s, int init)
+{
+    s->statem.in_init = init;
+}
+
+int statem_connect(SSL *s) {
+    return state_machine(s, 0);
+}
+
+int statem_accept(SSL *s)
+{
+    return state_machine(s, 1);
+}
+
+/*
+ * The main message flow state machine. We start in the MSG_FLOW_UNINITED or
+ * MSG_FLOW_RENEGOTIATE state and finish in MSG_FLOW_FINISHED. Valid states and
+ * transitions are as follows:
+ *
+ * MSG_FLOW_UNINITED     MSG_FLOW_RENEGOTIATE
+ *        |                       |
+ *        +-----------------------+
+ *        v
+ * MSG_FLOW_WRITING <---> MSG_FLOW_READING
+ *        |
+ *        V
+ * MSG_FLOW_FINISHED
+ *        |
+ *        V
+ *    [SUCCESS]
+ *
+ * We may exit at any point due to an error or NBIO event. If an NBIO event
+ * occurs then we restart at the point we left off when we are recalled.
+ * MSG_FLOW_WRITING and MSG_FLOW_READING have sub-state machines associated with them.
+ *
+ * In addition to the above there is also the MSG_FLOW_ERROR state. We can move
+ * into that state at any point in the event that an irrecoverable error occurs.
+ *
+ * Valid return values are:
+ *   1: Success
+ * <=0: NBIO or error
+ */
+static int state_machine(SSL *s, int server) {
+    BUF_MEM *buf = NULL;
+    unsigned long Time = (unsigned long)time(NULL);
+    void (*cb) (const SSL *ssl, int type, int val) = NULL;
+    STATEM *st = &s->statem;
+    int ret = -1;
+    int ssret;
+
+    if (st->state == MSG_FLOW_ERROR) {
+        /* Shouldn't have been called if we're already in the error state */
+        return -1;
+    }
+
+    RAND_add(&Time, sizeof(Time), 0);
+    ERR_clear_error();
+    clear_sys_error();
+
+    if (s->info_callback != NULL)
+        cb = s->info_callback;
+    else if (s->ctx->info_callback != NULL)
+        cb = s->ctx->info_callback;
+
+    s->in_handshake++;
+    if (!SSL_in_init(s) || SSL_in_before(s)) {
+        if (!SSL_clear(s))
+            return -1;
+    }
+
+#ifndef OPENSSL_NO_SCTP
+    if (SSL_IS_DTLS(s)) {
+        /*
+         * Notify SCTP BIO socket to enter handshake mode and prevent stream
+         * identifier other than 0. Will be ignored if no SCTP is used.
+         */
+        BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE,
+                 s->in_handshake, NULL);
+    }
+#endif
+
+#ifndef OPENSSL_NO_HEARTBEATS
+    /*
+     * If we're awaiting a HeartbeatResponse, pretend we already got and
+     * don't await it anymore, because Heartbeats don't make sense during
+     * handshakes anyway.
+     */
+    if (s->tlsext_hb_pending) {
+        if (SSL_IS_DTLS(s))
+            dtls1_stop_timer(s);
+        s->tlsext_hb_pending = 0;
+        s->tlsext_hb_seq++;
+    }
+#endif
+
+    /* Initialise state machine */
+
+    if (st->state == MSG_FLOW_RENEGOTIATE) {
+        s->renegotiate = 1;
+        if (!server)
+            s->ctx->stats.sess_connect_renegotiate++;
+    }
+
+    if (st->state == MSG_FLOW_UNINITED || st->state == MSG_FLOW_RENEGOTIATE) {
+        if (st->state == MSG_FLOW_UNINITED) {
+            st->hand_state = TLS_ST_BEFORE;
+        }
+
+        s->server = server;
+        if (cb != NULL)
+            cb(s, SSL_CB_HANDSHAKE_START, 1);
+
+        if (SSL_IS_DTLS(s)) {
+            if ((s->version & 0xff00) != (DTLS1_VERSION & 0xff00) &&
+                    (server
+                    || (s->version & 0xff00) != (DTLS1_BAD_VER & 0xff00))) {
+                SSLerr(SSL_F_STATE_MACHINE, ERR_R_INTERNAL_ERROR);
+                goto end;
+            }
+        } else {
+            if ((s->version >> 8) != SSL3_VERSION_MAJOR
+                    && s->version != TLS_ANY_VERSION) {
+                SSLerr(SSL_F_STATE_MACHINE, ERR_R_INTERNAL_ERROR);
+                goto end;
+            }
+        }
+
+        if (!SSL_IS_DTLS(s)) {
+            if (s->version != TLS_ANY_VERSION &&
+                    !ssl_security(s, SSL_SECOP_VERSION, 0, s->version, NULL)) {
+                SSLerr(SSL_F_STATE_MACHINE, SSL_R_VERSION_TOO_LOW);
+                goto end;
+            }
+        }
+
+        if (s->init_buf == NULL) {
+            if ((buf = BUF_MEM_new()) == NULL) {
+                goto end;
+            }
+            if (!BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) {
+                goto end;
+            }
+            s->init_buf = buf;
+            buf = NULL;
+        }
+
+        if (!ssl3_setup_buffers(s)) {
+            goto end;
+        }
+        s->init_num = 0;
+
+        /*
+         * Should have been reset by tls_process_finished, too.
+         */
+        s->s3->change_cipher_spec = 0;
+
+        if (!server || st->state != MSG_FLOW_RENEGOTIATE) {
+                /*
+                 * Ok, we now need to push on a buffering BIO ...but not with
+                 * SCTP
+                 */
+#ifndef OPENSSL_NO_SCTP
+                if (!SSL_IS_DTLS(s) || !BIO_dgram_is_sctp(SSL_get_wbio(s)))
+#endif
+                    if (!ssl_init_wbio_buffer(s, server ? 1 : 0)) {
+                        goto end;
+                    }
+
+            ssl3_init_finished_mac(s);
+        }
+
+        if (server) {
+            if (st->state != MSG_FLOW_RENEGOTIATE) {
+                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_STATE_MACHINE,
+                       SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
+                ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+                statem_set_error(s);
+                goto end;
+            } else {
+                /*
+                 * s->state == SSL_ST_RENEGOTIATE, we will just send a
+                 * HelloRequest
+                 */
+                s->ctx->stats.sess_accept_renegotiate++;
+            }
+        } else {
+            s->ctx->stats.sess_connect++;
+
+            /* mark client_random uninitialized */
+            memset(s->s3->client_random, 0, sizeof(s->s3->client_random));
+            s->hit = 0;
+
+            s->s3->tmp.cert_request = 0;
+
+            if (SSL_IS_DTLS(s)) {
+                st->use_timer = 1;
+            }
+        }
+
+        st->state = MSG_FLOW_WRITING;
+        init_write_state_machine(s);
+        st->read_state_first_init = 1;
+    }
+
+    while(st->state != MSG_FLOW_FINISHED) {
+        if(st->state == MSG_FLOW_READING) {
+            ssret = read_state_machine(s);
+            if (ssret == SUB_STATE_FINISHED) {
+                st->state = MSG_FLOW_WRITING;
+                init_write_state_machine(s);
+            } else {
+                /* NBIO or error */
+                goto end;
+            }
+        } else if (st->state == MSG_FLOW_WRITING) {
+            ssret = write_state_machine(s);
+            if (ssret == SUB_STATE_FINISHED) {
+                st->state = MSG_FLOW_READING;
+                init_read_state_machine(s);
+            } else if (ssret == SUB_STATE_END_HANDSHAKE) {
+                st->state = MSG_FLOW_FINISHED;
+            } else {
+                /* NBIO or error */
+                goto end;
+            }
+        } else {
+            /* Error */
+            statem_set_error(s);
+            goto end;
+        }
+    }
+
+    st->state = MSG_FLOW_UNINITED;
+    ret = 1;
+
+ end:
+    s->in_handshake--;
+
+#ifndef OPENSSL_NO_SCTP
+    if (SSL_IS_DTLS(s)) {
+        /*
+         * Notify SCTP BIO socket to leave handshake mode and allow stream
+         * identifier other than 0. Will be ignored if no SCTP is used.
+         */
+        BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE,
+                 s->in_handshake, NULL);
+    }
+#endif
+
+    BUF_MEM_free(buf);
+    if (cb != NULL) {
+        if (server)
+            cb(s, SSL_CB_ACCEPT_EXIT, ret);
+        else
+            cb(s, SSL_CB_CONNECT_EXIT, ret);
+    }
+    return ret;
+}
+
+/*
+ * Initialise the MSG_FLOW_READING sub-state machine
+ */
+static void init_read_state_machine(SSL *s)
+{
+    STATEM *st = &s->statem;
+
+    st->read_state = READ_STATE_HEADER;
+}
+
+/*
+ * This function implements the sub-state machine when the message flow is in
+ * MSG_FLOW_READING. The valid sub-states and transitions are:
+ *
+ * READ_STATE_HEADER <--+<-------------+
+ *        |             |              |
+ *        v             |              |
+ * READ_STATE_BODY -----+-->READ_STATE_POST_PROCESS
+ *        |                            |
+ *        +----------------------------+
+ *        v
+ * [SUB_STATE_FINISHED]
+ *
+ * READ_STATE_HEADER has the responsibility for reading in the message header
+ * and transitioning the state of the handshake state machine.
+ *
+ * READ_STATE_BODY reads in the rest of the message and then subsequently
+ * processes it.
+ *
+ * READ_STATE_POST_PROCESS is an optional step that may occur if some post
+ * processing activity performed on the message may block.
+ *
+ * Any of the above states could result in an NBIO event occuring in which case
+ * control returns to the calling application. When this function is recalled we
+ * will resume in the same state where we left off.
+ */
+static enum SUB_STATE_RETURN read_state_machine(SSL *s) {
+    STATEM *st = &s->statem;
+    int ret, mt;
+    unsigned long len;
+    int (*transition)(SSL *s, int mt);
+    PACKET pkt;
+    enum MSG_PROCESS_RETURN (*process_message)(SSL *s, PACKET *pkt);
+    enum WORK_STATE (*post_process_message)(SSL *s, enum WORK_STATE wst);
+    unsigned long (*max_message_size)(SSL *s);
+    void (*cb) (const SSL *ssl, int type, int val) = NULL;
+
+    if (s->info_callback != NULL)
+        cb = s->info_callback;
+    else if (s->ctx->info_callback != NULL)
+        cb = s->ctx->info_callback;
+
+    if(s->server) {
+        transition = server_read_transition;
+        process_message = server_process_message;
+        max_message_size = server_max_message_size;
+        post_process_message = server_post_process_message;
+    } else {
+        transition = client_read_transition;
+        process_message = client_process_message;
+        max_message_size = client_max_message_size;
+        post_process_message = client_post_process_message;
+    }
+
+    if (st->read_state_first_init) {
+        s->first_packet = 1;
+        st->read_state_first_init = 0;
+    }
+
+    while(1) {
+        switch(st->read_state) {
+        case READ_STATE_HEADER:
+            s->init_num = 0;
+            /* Get the state the peer wants to move to */
+            if (SSL_IS_DTLS(s)) {
+                /*
+                 * In DTLS we get the whole message in one go - header and body
+                 */
+                ret = dtls_get_message(s, &mt, &len);
+            } else {
+                ret = tls_get_message_header(s, &mt);
+            }
+
+            if (ret == 0) {
+                /* Could be non-blocking IO */
+                return SUB_STATE_ERROR;
+            }
+
+            if (cb != NULL) {
+                /* Notify callback of an impending state change */
+                if (s->server)
+                    cb(s, SSL_CB_ACCEPT_LOOP, 1);
+                else
+                    cb(s, SSL_CB_CONNECT_LOOP, 1);
+            }
+            /*
+             * Validate that we are allowed to move to the new state and move
+             * to that state if so
+             */
+            if(!transition(s, mt)) {
+                ssl3_send_alert(s, SSL3_AL_FATAL, SSL3_AD_UNEXPECTED_MESSAGE);
+                SSLerr(SSL_F_READ_STATE_MACHINE, SSL_R_UNEXPECTED_MESSAGE);
+                return SUB_STATE_ERROR;
+            }
+
+            if (s->s3->tmp.message_size > max_message_size(s)) {
+                ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+                SSLerr(SSL_F_READ_STATE_MACHINE, SSL_R_EXCESSIVE_MESSAGE_SIZE);
+                return SUB_STATE_ERROR;
+            }
+
+            st->read_state = READ_STATE_BODY;
+            /* Fall through */
+
+        case READ_STATE_BODY:
+            if (!SSL_IS_DTLS(s)) {
+                /* We already got this above for DTLS */
+                ret = tls_get_message_body(s, &len);
+                if (ret == 0) {
+                    /* Could be non-blocking IO */
+                    return SUB_STATE_ERROR;
+                }
+            }
+
+            s->first_packet = 0;
+            if (!PACKET_buf_init(&pkt, s->init_msg, len)) {
+                ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+                SSLerr(SSL_F_READ_STATE_MACHINE, ERR_R_INTERNAL_ERROR);
+                return SUB_STATE_ERROR;
+            }
+            ret = process_message(s, &pkt);
+            if (ret == MSG_PROCESS_ERROR) {
+                return SUB_STATE_ERROR;
+            }
+
+            if (ret == MSG_PROCESS_FINISHED_READING) {
+                if (SSL_IS_DTLS(s)) {
+                    dtls1_stop_timer(s);
+                }
+                return SUB_STATE_FINISHED;
+            }
+
+            if (ret == MSG_PROCESS_CONTINUE_PROCESSING) {
+                st->read_state = READ_STATE_POST_PROCESS;
+                st->read_state_work = WORK_MORE_A;
+            } else {
+                st->read_state = READ_STATE_HEADER;
+            }
+            break;
+
+        case READ_STATE_POST_PROCESS:
+            st->read_state_work = post_process_message(s, st->read_state_work);
+            switch(st->read_state_work) {
+            default:
+                return SUB_STATE_ERROR;
+
+            case WORK_FINISHED_CONTINUE:
+                st->read_state = READ_STATE_HEADER;
+                break;
+
+            case WORK_FINISHED_STOP:
+                if (SSL_IS_DTLS(s)) {
+                    dtls1_stop_timer(s);
+                }
+                return SUB_STATE_FINISHED;
+            }
+            break;
+
+        default:
+            /* Shouldn't happen */
+            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+            SSLerr(SSL_F_READ_STATE_MACHINE, ERR_R_INTERNAL_ERROR);
+            statem_set_error(s);
+            return SUB_STATE_ERROR;
+        }
+    }
+}
+
+/*
+ * Send a previously constructed message to the peer.
+ */
+static int statem_do_write(SSL *s)
+{
+    STATEM *st = &s->statem;
+
+    if (st->hand_state == TLS_ST_CW_CHANGE
+            || st->hand_state == TLS_ST_SW_CHANGE) {
+        if (SSL_IS_DTLS(s))
+            return dtls1_do_write(s, SSL3_RT_CHANGE_CIPHER_SPEC);
+        else
+            return ssl3_do_write(s, SSL3_RT_CHANGE_CIPHER_SPEC);
+    } else {
+        return ssl_do_write(s);
+    }
+}
+
+/*
+ * Initialise the MSG_FLOW_WRITING sub-state machine
+ */
+static void init_write_state_machine(SSL *s)
+{
+    STATEM *st = &s->statem;
+
+    st->write_state = WRITE_STATE_TRANSITION;
+}
+
+/*
+ * This function implements the sub-state machine when the message flow is in
+ * MSG_FLOW_WRITING. The valid sub-states and transitions are:
+ *
+ * +-> WRITE_STATE_TRANSITION ------> [SUB_STATE_FINISHED]
+ * |             |
+ * |             v
+ * |      WRITE_STATE_PRE_WORK -----> [SUB_STATE_END_HANDSHAKE]
+ * |             |
+ * |             v
+ * |       WRITE_STATE_SEND
+ * |             |
+ * |             v
+ * |     WRITE_STATE_POST_WORK
+ * |             |
+ * +-------------+
+ *
+ * WRITE_STATE_TRANSITION transitions the state of the handshake state machine
+
+ * WRITE_STATE_PRE_WORK performs any work necessary to prepare the later
+ * sending of the message. This could result in an NBIO event occuring in
+ * which case control returns to the calling application. When this function
+ * is recalled we will resume in the same state where we left off.
+ *
+ * WRITE_STATE_SEND sends the message and performs any work to be done after
+ * sending.
+ *
+ * WRITE_STATE_POST_WORK performs any work necessary after the sending of the
+ * message has been completed. As for WRITE_STATE_PRE_WORK this could also
+ * result in an NBIO event.
+ */
+static enum SUB_STATE_RETURN write_state_machine(SSL *s)
+{
+    STATEM *st = &s->statem;
+    int ret;
+    enum WRITE_TRAN (*transition)(SSL *s);
+    enum WORK_STATE (*pre_work)(SSL *s, enum WORK_STATE wst);
+    enum WORK_STATE (*post_work)(SSL *s, enum WORK_STATE wst);
+    int (*construct_message)(SSL *s);
+    void (*cb) (const SSL *ssl, int type, int val) = NULL;
+
+    if (s->info_callback != NULL)
+        cb = s->info_callback;
+    else if (s->ctx->info_callback != NULL)
+        cb = s->ctx->info_callback;
+
+    if(s->server) {
+        transition = server_write_transition;
+        pre_work = server_pre_work;
+        post_work = server_post_work;
+        construct_message = server_construct_message;
+    } else {
+        transition = client_write_transition;
+        pre_work = client_pre_work;
+        post_work = client_post_work;
+        construct_message = client_construct_message;
+    }
+
+    while(1) {
+        switch(st->write_state) {
+        case WRITE_STATE_TRANSITION:
+            if (cb != NULL) {
+                /* Notify callback of an impending state change */
+                if (s->server)
+                    cb(s, SSL_CB_ACCEPT_LOOP, 1);
+                else
+                    cb(s, SSL_CB_CONNECT_LOOP, 1);
+            }
+            switch(transition(s)) {
+            case WRITE_TRAN_CONTINUE:
+                st->write_state = WRITE_STATE_PRE_WORK;
+                st->write_state_work = WORK_MORE_A;
+                break;
+
+            case WRITE_TRAN_FINISHED:
+                return SUB_STATE_FINISHED;
+                break;
+
+            default:
+                return SUB_STATE_ERROR;
+            }
+            break;
+
+        case WRITE_STATE_PRE_WORK:
+            switch(st->write_state_work = pre_work(s, st->write_state_work)) {
+            default:
+                return SUB_STATE_ERROR;
+
+            case WORK_FINISHED_CONTINUE:
+                st->write_state = WRITE_STATE_SEND;
+                break;
+
+            case WORK_FINISHED_STOP:
+                return SUB_STATE_END_HANDSHAKE;
+            }
+            if(construct_message(s) == 0)
+                return SUB_STATE_ERROR;
+
+            /* Fall through */
+
+        case WRITE_STATE_SEND:
+            if (SSL_IS_DTLS(s) && st->use_timer) {
+                dtls1_start_timer(s);
+            }
+            ret = statem_do_write(s);
+            if (ret <= 0) {
+                return SUB_STATE_ERROR;
+            }
+            st->write_state = WRITE_STATE_POST_WORK;
+            st->write_state_work = WORK_MORE_A;
+            /* Fall through */
+
+        case WRITE_STATE_POST_WORK:
+            switch(st->write_state_work = post_work(s, st->write_state_work)) {
+            default:
+                return SUB_STATE_ERROR;
+
+            case WORK_FINISHED_CONTINUE:
+                st->write_state = WRITE_STATE_TRANSITION;
+                break;
+
+            case WORK_FINISHED_STOP:
+                return SUB_STATE_END_HANDSHAKE;
+            }
+            break;
+
+        default:
+            return SUB_STATE_ERROR;
+        }
+    }
+}
+
+/*
+ * Flush the write BIO
+ */
+static int statem_flush(SSL *s)
+{
+    s->rwstate = SSL_WRITING;
+    if (BIO_flush(s->wbio) <= 0) {
+        return 0;
+    }
+    s->rwstate = SSL_NOTHING;
+
+    return 1;
+}
+
+/*
+ * Called by the record layer to determine whether application data is
+ * allowed to be sent in the current handshake state or not.
+ *
+ * Return values are:
+ *   1: Yes (application data allowed)
+ *   0: No (application data not allowed)
+ */
+int statem_app_data_allowed(SSL *s)
+{
+    STATEM *st = &s->statem;
+
+    if (st->state == MSG_FLOW_UNINITED || st->state == MSG_FLOW_RENEGOTIATE)
+        return 0;
+
+    if (!s->s3->in_read_app_data || (s->s3->total_renegotiations == 0))
+        return 0;
+
+    if (s->server) {
+        /*
+         * If we're a server and we haven't got as far as writing our
+         * ServerHello yet then we allow app data
+         */
+        if (st->hand_state == TLS_ST_BEFORE
+                || st->hand_state == TLS_ST_SR_CLNT_HELLO)
+            return 1;
+    } else {
+        /*
+         * If we're a client and we haven't read the ServerHello yet then we
+         * allow app data
+         */
+        if (st->hand_state == TLS_ST_CW_CLNT_HELLO)
+            return 1;
+    }
+
+    return 0;
+}
+
+
+#ifndef OPENSSL_NO_SCTP
+/*
+ * Set flag used by SCTP to determine whether we are in the read sock state
+ */
+void statem_set_sctp_read_sock(SSL *s, int read_sock)
+{
+    s->statem.in_sctp_read_sock = read_sock;
+}
+
+/*
+ * Called by the record layer to determine whether we are in the read sock
+ * state or not.
+ *
+ * Return values are:
+ *   1: Yes (we are in the read sock state)
+ *   0: No (we are not in the read sock state)
+ */
+int statem_in_sctp_read_sock(SSL *s)
+{
+    return s->statem.in_sctp_read_sock;
+}
+#endif
+
+/*
+ * Is a CertificateRequest message allowed at the moment or not?
+ *
+ *  Return values are:
+ *  1: Yes
+ *  0: No
+ */
+static inline int cert_req_allowed(SSL *s)
+{
+    /* TLS does not like anon-DH with client cert */
+    if (s->version > SSL3_VERSION
+            && (s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL))
+        return 0;
+
+    return 1;
+}
+
+/*
+ * Are we allowed to skip the ServerKeyExchange message?
+ *
+ *  Return values are:
+ *  1: Yes
+ *  0: No
+ */
+static inline int key_exchange_skip_allowed(SSL *s)
+{
+    long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+
+    /*
+     * Can't skip server key exchange if this is an ephemeral
+     * ciphersuite.
+     */
+    if (alg_k & (SSL_kDHE | SSL_kECDHE)) {
+        return 0;
+    }
+
+    return 1;
+}
+
+/*
+ * client_read_transition() encapsulates the logic for the allowed handshake
+ * state transitions when the client is reading messages from the server. The
+ * message type that the server has sent is provided in |mt|. The current state
+ * is in |s->statem.hand_state|.
+ *
+ *  Return values are:
+ *  1: Success (transition allowed)
+ *  0: Error (transition not allowed)
+ */
+static int client_read_transition(SSL *s, int mt)
+{
+    STATEM *st = &s->statem;
+
+    switch(st->hand_state) {
+    case TLS_ST_CW_CLNT_HELLO:
+        if (mt == SSL3_MT_SERVER_HELLO) {
+            st->hand_state = TLS_ST_CR_SRVR_HELLO;
+            return 1;
+        }
+
+        if (SSL_IS_DTLS(s)) {
+            if (mt == DTLS1_MT_HELLO_VERIFY_REQUEST) {
+                st->hand_state = DTLS_ST_CR_HELLO_VERIFY_REQUEST;
+                return 1;
+            }
+        }
+        break;
+
+    case TLS_ST_CR_SRVR_HELLO:
+        if (s->hit) {
+            if (s->tlsext_ticket_expected) {
+                if (mt == SSL3_MT_NEWSESSION_TICKET) {
+                    st->hand_state = TLS_ST_CR_SESSION_TICKET;
+                    return 1;
+                }
+            } else if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+                st->hand_state = TLS_ST_CR_CHANGE;
+                return 1;
+            }
+        } else {
+            if (SSL_IS_DTLS(s) && mt == DTLS1_MT_HELLO_VERIFY_REQUEST) {
+                st->hand_state = DTLS_ST_CR_HELLO_VERIFY_REQUEST;
+                return 1;
+            } else if (!(s->s3->tmp.new_cipher->algorithm_auth
+                        & (SSL_aNULL | SSL_aSRP | SSL_aPSK))) {
+                if (mt == SSL3_MT_CERTIFICATE) {
+                    st->hand_state = TLS_ST_CR_CERT;
+                    return 1;
+                }
+            } else {
+                if (mt == SSL3_MT_SERVER_KEY_EXCHANGE) {
+                    st->hand_state = TLS_ST_CR_KEY_EXCH;
+                    return 1;
+                } else if (key_exchange_skip_allowed(s)) {
+                    if (mt == SSL3_MT_CERTIFICATE_REQUEST
+                            && cert_req_allowed(s)) {
+                        st->hand_state = TLS_ST_CR_CERT_REQ;
+                        return 1;
+                    } else if (mt == SSL3_MT_SERVER_DONE) {
+                        st->hand_state = TLS_ST_CR_SRVR_DONE;
+                        return 1;
+                    }
+                }
+            }
+        }
+        break;
+
+    case TLS_ST_CR_CERT:
+        if (s->tlsext_status_expected) {
+            if (mt == SSL3_MT_CERTIFICATE_STATUS) {
+                st->hand_state = TLS_ST_CR_CERT_STATUS;
+                return 1;
+            }
+        } else {
+            if (mt == SSL3_MT_SERVER_KEY_EXCHANGE) {
+                st->hand_state = TLS_ST_CR_KEY_EXCH;
+                return 1;
+            } else if (key_exchange_skip_allowed(s)) {
+                if (mt == SSL3_MT_CERTIFICATE_REQUEST && cert_req_allowed(s)) {
+                    st->hand_state = TLS_ST_CR_CERT_REQ;
+                    return 1;
+                } else if (mt == SSL3_MT_SERVER_DONE) {
+                    st->hand_state = TLS_ST_CR_SRVR_DONE;
+                    return 1;
+                }
+            }
+        }
+        break;
+
+    case TLS_ST_CR_CERT_STATUS:
+        if (mt == SSL3_MT_SERVER_KEY_EXCHANGE) {
+            st->hand_state = TLS_ST_CR_KEY_EXCH;
+            return 1;
+        } else if (key_exchange_skip_allowed(s)) {
+            if (mt == SSL3_MT_CERTIFICATE_REQUEST && cert_req_allowed(s)) {
+                st->hand_state = TLS_ST_CR_CERT_REQ;
+                return 1;
+            } else if (mt == SSL3_MT_SERVER_DONE) {
+                st->hand_state = TLS_ST_CR_SRVR_DONE;
+                return 1;
+            }
+        }
+        break;
+
+    case TLS_ST_CR_KEY_EXCH:
+        if (mt == SSL3_MT_CERTIFICATE_REQUEST && cert_req_allowed(s)) {
+            st->hand_state = TLS_ST_CR_CERT_REQ;
+            return 1;
+        } else if (mt == SSL3_MT_SERVER_DONE) {
+            st->hand_state = TLS_ST_CR_SRVR_DONE;
+            return 1;
+        }
+        break;
+
+    case TLS_ST_CR_CERT_REQ:
+        if (mt == SSL3_MT_SERVER_DONE) {
+            st->hand_state = TLS_ST_CR_SRVR_DONE;
+            return 1;
+        }
+        break;
+
+    case TLS_ST_CW_FINISHED:
+        if (mt == SSL3_MT_NEWSESSION_TICKET && s->tlsext_ticket_expected) {
+            st->hand_state = TLS_ST_CR_SESSION_TICKET;
+            return 1;
+        } else if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+            st->hand_state = TLS_ST_CR_CHANGE;
+            return 1;
+        }
+        break;
+
+    case TLS_ST_CR_SESSION_TICKET:
+        if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+            st->hand_state = TLS_ST_CR_CHANGE;
+            return 1;
+        }
+        break;
+
+    case TLS_ST_CR_CHANGE:
+        if (mt == SSL3_MT_FINISHED) {
+            st->hand_state = TLS_ST_CR_FINISHED;
+            return 1;
+        }
+        break;
+
+    default:
+        break;
+    }
+
+    /* No valid transition found */
+    return 0;
+}
+
+/*
+ * client_write_transition() works out what handshake state to move to next
+ * when the client is writing messages to be sent to the server.
+ */
+static enum WRITE_TRAN client_write_transition(SSL *s)
+{
+    STATEM *st = &s->statem;
+
+    switch(st->hand_state) {
+        case TLS_ST_OK:
+            /* Renegotiation - fall through */
+        case TLS_ST_BEFORE:
+            st->hand_state = TLS_ST_CW_CLNT_HELLO;
+            return WRITE_TRAN_CONTINUE;
+
+        case TLS_ST_CW_CLNT_HELLO:
+            /*
+             * No transition at the end of writing because we don't know what
+             * we will be sent
+             */
+            return WRITE_TRAN_FINISHED;
+
+        case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
+            st->hand_state = TLS_ST_CW_CLNT_HELLO;
+            return WRITE_TRAN_CONTINUE;
+
+        case TLS_ST_CR_SRVR_DONE:
+            if (s->s3->tmp.cert_req)
+                st->hand_state = TLS_ST_CW_CERT;
+            else
+                st->hand_state = TLS_ST_CW_KEY_EXCH;
+            return WRITE_TRAN_CONTINUE;
+
+        case TLS_ST_CW_CERT:
+            st->hand_state = TLS_ST_CW_KEY_EXCH;
+            return WRITE_TRAN_CONTINUE;
+
+        case TLS_ST_CW_KEY_EXCH:
+            /*
+             * For TLS, cert_req is set to 2, so a cert chain of nothing is
+             * sent, but no verify packet is sent
+             */
+            /*
+             * XXX: For now, we do not support client authentication in ECDH
+             * cipher suites with ECDH (rather than ECDSA) certificates. We
+             * need to skip the certificate verify message when client's
+             * ECDH public key is sent inside the client certificate.
+             */
+            if (s->s3->tmp.cert_req == 1) {
+                st->hand_state = TLS_ST_CW_CERT_VRFY;
+            } else {
+                st->hand_state = TLS_ST_CW_CHANGE;
+            }
+            if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY) {
+                st->hand_state = TLS_ST_CW_CHANGE;
+            }
+            return WRITE_TRAN_CONTINUE;
+
+        case TLS_ST_CW_CERT_VRFY:
+            st->hand_state = TLS_ST_CW_CHANGE;
+            return WRITE_TRAN_CONTINUE;
+
+        case TLS_ST_CW_CHANGE:
+#if defined(OPENSSL_NO_NEXTPROTONEG)
+            st->hand_state = TLS_ST_CW_FINISHED;
+#else
+            if (!SSL_IS_DTLS(s) && s->s3->next_proto_neg_seen)
+                st->hand_state = TLS_ST_CW_NEXT_PROTO;
+            else
+                st->hand_state = TLS_ST_CW_FINISHED;
+#endif
+            return WRITE_TRAN_CONTINUE;
+
+#if !defined(OPENSSL_NO_NEXTPROTONEG)
+        case TLS_ST_CW_NEXT_PROTO:
+            st->hand_state = TLS_ST_CW_FINISHED;
+            return WRITE_TRAN_CONTINUE;
+#endif
+
+        case TLS_ST_CW_FINISHED:
+            if (s->hit) {
+                st->hand_state = TLS_ST_OK;
+                statem_set_in_init(s, 0);
+                return WRITE_TRAN_CONTINUE;
+            } else {
+                return WRITE_TRAN_FINISHED;
+            }
+
+        case TLS_ST_CR_FINISHED:
+            if (s->hit) {
+                st->hand_state = TLS_ST_CW_CHANGE;
+                return WRITE_TRAN_CONTINUE;
+            } else {
+                st->hand_state = TLS_ST_OK;
+                statem_set_in_init(s, 0);
+                return WRITE_TRAN_CONTINUE;
+            }
+
+        default:
+            /* Shouldn't happen */
+            return WRITE_TRAN_ERROR;
+    }
+}
+
+/*
+ * Perform any pre work that needs to be done prior to sending a message from
+ * the client to the server.
+ */
+static enum WORK_STATE client_pre_work(SSL *s, enum WORK_STATE wst)
+{
+    STATEM *st = &s->statem;
+
+    switch(st->hand_state) {
+    case TLS_ST_CW_CLNT_HELLO:
+        s->shutdown = 0;
+        if (SSL_IS_DTLS(s)) {
+            /* every DTLS ClientHello resets Finished MAC */
+            ssl3_init_finished_mac(s);
+        }
+        break;
+
+    case TLS_ST_CW_CERT:
+        return tls_prepare_client_certificate(s, wst);
+
+    case TLS_ST_CW_CHANGE:
+        if (SSL_IS_DTLS(s)) {
+            if (s->hit) {
+                /*
+                 * We're into the last flight so we don't retransmit these
+                 * messages unless we need to.
+                 */
+                st->use_timer = 0;
+            }
+#ifndef OPENSSL_NO_SCTP
+            if (BIO_dgram_is_sctp(SSL_get_wbio(s)))
+                return dtls_wait_for_dry(s);
+#endif
+        }
+        return WORK_FINISHED_CONTINUE;
+
+    case TLS_ST_OK:
+        return tls_finish_handshake(s, wst);
+
+    default:
+        /* No pre work to be done */
+        break;
+    }
+
+    return WORK_FINISHED_CONTINUE;
+}
+
+/*
+ * Perform any work that needs to be done after sending a message from the
+ * client to the server.
+ */
+static enum WORK_STATE client_post_work(SSL *s, enum WORK_STATE wst)
+{
+    STATEM *st = &s->statem;
+
+    s->init_num = 0;
+
+    switch(st->hand_state) {
+    case TLS_ST_CW_CLNT_HELLO:
+        if (SSL_IS_DTLS(s) && s->d1->cookie_len > 0 && statem_flush(s) != 1)
+            return WORK_MORE_A;
+#ifndef OPENSSL_NO_SCTP
+        /* Disable buffering for SCTP */
+        if (!SSL_IS_DTLS(s) || !BIO_dgram_is_sctp(SSL_get_wbio(s))) {
+#endif
+            /*
+             * turn on buffering for the next lot of output
+             */
+            if (s->bbio != s->wbio)
+                s->wbio = BIO_push(s->bbio, s->wbio);
+#ifndef OPENSSL_NO_SCTP
+            }
+#endif
+        if (SSL_IS_DTLS(s)) {
+            /* Treat the next message as the first packet */
+            s->first_packet = 1;
+        }
+        break;
+
+    case TLS_ST_CW_KEY_EXCH:
+        if (tls_client_key_exchange_post_work(s) == 0)
+            return WORK_ERROR;
+        break;
+
+    case TLS_ST_CW_CHANGE:
+        s->session->cipher = s->s3->tmp.new_cipher;
+#ifdef OPENSSL_NO_COMP
+        s->session->compress_meth = 0;
+#else
+        if (s->s3->tmp.new_compression == NULL)
+            s->session->compress_meth = 0;
+        else
+            s->session->compress_meth = s->s3->tmp.new_compression->id;
+#endif
+        if (!s->method->ssl3_enc->setup_key_block(s))
+            return WORK_ERROR;
+
+        if (!s->method->ssl3_enc->change_cipher_state(s,
+                                                      SSL3_CHANGE_CIPHER_CLIENT_WRITE))
+            return WORK_ERROR;
+
+        if (SSL_IS_DTLS(s)) {
+#ifndef OPENSSL_NO_SCTP
+            if (s->hit) {
+                /*
+                 * Change to new shared key of SCTP-Auth, will be ignored if
+                 * no SCTP used.
+                 */
+                BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY,
+                         0, NULL);
+            }
+#endif
+
+            dtls1_reset_seq_numbers(s, SSL3_CC_WRITE);
+        }
+        break;
+
+    case TLS_ST_CW_FINISHED:
+#ifndef OPENSSL_NO_SCTP
+        if (wst == WORK_MORE_A && SSL_IS_DTLS(s) && s->hit == 0) {
+            /*
+             * Change to new shared key of SCTP-Auth, will be ignored if
+             * no SCTP used.
+             */
+            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY,
+                     0, NULL);
+        }
+#endif
+        if (statem_flush(s) != 1)
+            return WORK_MORE_B;
+
+        if (s->hit && tls_finish_handshake(s, WORK_MORE_A) != 1)
+                return WORK_ERROR;
+        break;
+
+    default:
+        /* No post work to be done */
+        break;
+    }
+
+    return WORK_FINISHED_CONTINUE;
+}
+
+/*
+ * Construct a message to be sent from the client to the server.
+ *
+ * Valid return values are:
+ *   1: Success
+ *   0: Error
+ */
+static int client_construct_message(SSL *s)
+{
+    STATEM *st = &s->statem;
+
+    switch(st->hand_state) {
+    case TLS_ST_CW_CLNT_HELLO:
+        return tls_construct_client_hello(s);
+
+    case TLS_ST_CW_CERT:
+        return tls_construct_client_certificate(s);
+
+    case TLS_ST_CW_KEY_EXCH:
+        return tls_construct_client_key_exchange(s);
+
+    case TLS_ST_CW_CERT_VRFY:
+        return tls_construct_client_verify(s);
+
+    case TLS_ST_CW_CHANGE:
+        if (SSL_IS_DTLS(s))
+            return dtls_construct_change_cipher_spec(s);
+        else
+            return tls_construct_change_cipher_spec(s);
+
+#if !defined(OPENSSL_NO_NEXTPROTONEG)
+    case TLS_ST_CW_NEXT_PROTO:
+        return tls_construct_next_proto(s);
+#endif
+    case TLS_ST_CW_FINISHED:
+        return tls_construct_finished(s,
+                                      s->method->
+                                      ssl3_enc->client_finished_label,
+                                      s->method->
+                                      ssl3_enc->client_finished_label_len);
+
+    default:
+        /* Shouldn't happen */
+        break;
+    }
+
+    return 0;
+}
+
+/* The spec allows for a longer length than this, but we limit it */
+#define HELLO_VERIFY_REQUEST_MAX_LENGTH 258
+#define SERVER_HELLO_MAX_LENGTH         20000
+#define SERVER_KEY_EXCH_MAX_LENGTH      102400
+#define SERVER_HELLO_DONE_MAX_LENGTH    0
+#define CCS_MAX_LENGTH                  1
+/* Max should actually be 36 but we are generous */
+#define FINISHED_MAX_LENGTH             64
+
+/*
+ * Returns the maximum allowed length for the current message that we are
+ * reading. Excludes the message header.
+ */
+static unsigned long client_max_message_size(SSL *s)
+{
+    STATEM *st = &s->statem;
+
+    switch(st->hand_state) {
+        case TLS_ST_CR_SRVR_HELLO:
+            return SERVER_HELLO_MAX_LENGTH;
+
+        case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
+            return HELLO_VERIFY_REQUEST_MAX_LENGTH;
+
+        case TLS_ST_CR_CERT:
+            return s->max_cert_list;
+
+        case TLS_ST_CR_CERT_STATUS:
+            return SSL3_RT_MAX_PLAIN_LENGTH;
+
+        case TLS_ST_CR_KEY_EXCH:
+            return SERVER_KEY_EXCH_MAX_LENGTH;
+
+        case TLS_ST_CR_CERT_REQ:
+            return SSL3_RT_MAX_PLAIN_LENGTH;
+
+        case TLS_ST_CR_SRVR_DONE:
+            return SERVER_HELLO_DONE_MAX_LENGTH;
+
+        case TLS_ST_CR_CHANGE:
+            return CCS_MAX_LENGTH;
+
+        case TLS_ST_CR_SESSION_TICKET:
+            return SSL3_RT_MAX_PLAIN_LENGTH;
+
+        case TLS_ST_CR_FINISHED:
+            return FINISHED_MAX_LENGTH;
+
+        default:
+            /* Shouldn't happen */
+            break;
+    }
+
+    return 0;
+}
+
+/*
+ * Process a message that the client has been received from the server.
+ */
+static enum MSG_PROCESS_RETURN client_process_message(SSL *s, PACKET *pkt)
+{
+    STATEM *st = &s->statem;
+
+    switch(st->hand_state) {
+        case TLS_ST_CR_SRVR_HELLO:
+            return tls_process_server_hello(s, pkt);
+
+        case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
+            return dtls_process_hello_verify(s, pkt);
+
+        case TLS_ST_CR_CERT:
+            return tls_process_server_certificate(s, pkt);
+
+        case TLS_ST_CR_CERT_STATUS:
+            return tls_process_cert_status(s, pkt);
+
+        case TLS_ST_CR_KEY_EXCH:
+            return tls_process_key_exchange(s, pkt);
+
+        case TLS_ST_CR_CERT_REQ:
+            return tls_process_certificate_request(s, pkt);
+
+        case TLS_ST_CR_SRVR_DONE:
+            return tls_process_server_done(s, pkt);
+
+        case TLS_ST_CR_CHANGE:
+            return tls_process_change_cipher_spec(s, pkt);
+
+        case TLS_ST_CR_SESSION_TICKET:
+            return tls_process_new_session_ticket(s, pkt);
+
+        case TLS_ST_CR_FINISHED:
+            return tls_process_finished(s, pkt);
+
+        default:
+            /* Shouldn't happen */
+            break;
+    }
+
+    return MSG_PROCESS_ERROR;
+}
+
+/*
+ * Perform any further processing required following the receipt of a message
+ * from the server
+ */
+static enum WORK_STATE client_post_process_message(SSL *s, enum WORK_STATE wst)
+{
+    STATEM *st = &s->statem;
+
+    switch(st->hand_state) {
+#ifndef OPENSSL_NO_SCTP
+    case TLS_ST_CR_SRVR_DONE:
+        /* We only get here if we are using SCTP and we are renegotiating */
+        if (BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s))) {
+            s->s3->in_read_app_data = 2;
+            s->rwstate = SSL_READING;
+            BIO_clear_retry_flags(SSL_get_rbio(s));
+            BIO_set_retry_read(SSL_get_rbio(s));
+            statem_set_sctp_read_sock(s, 1);
+            return WORK_MORE_A;
+        }
+        statem_set_sctp_read_sock(s, 0);
+        return WORK_FINISHED_STOP;
+#endif
+
+    case TLS_ST_CR_FINISHED:
+        if (!s->hit)
+            return tls_finish_handshake(s, wst);
+        else
+            return WORK_FINISHED_STOP;
+    default:
+        break;
+    }
+
+    /* Shouldn't happen */
+    return WORK_ERROR;
+}
+
+
+/*
+ * server_read_transition() encapsulates the logic for the allowed handshake
+ * state transitions when the server is reading messages from the client. The
+ * message type that the client has sent is provided in |mt|. The current state
+ * is in |s->statem.hand_state|.
+ *
+ *  Valid return values are:
+ *  1: Success (transition allowed)
+ *  0: Error (transition not allowed)
+ */
+static int server_read_transition(SSL *s, int mt)
+{
+    STATEM *st = &s->statem;
+
+    switch(st->hand_state) {
+    case TLS_ST_BEFORE:
+    case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
+        if (mt == SSL3_MT_CLIENT_HELLO) {
+            st->hand_state = TLS_ST_SR_CLNT_HELLO;
+            return 1;
+        }
+        break;
+
+    case TLS_ST_SW_SRVR_DONE:
+        /*
+         * If we get a CKE message after a ServerDone then either
+         * 1) We didn't request a Certificate
+         * OR
+         * 2) If we did request one then
+         *      a) We allow no Certificate to be returned
+         *      AND
+         *      b) We are running SSL3 (in TLS1.0+ the client must return a 0
+         *         list if we requested a certificate)
+         */
+        if (mt == SSL3_MT_CLIENT_KEY_EXCHANGE
+                && (!s->s3->tmp.cert_request
+                    || (!((s->verify_mode & SSL_VERIFY_PEER) &&
+                          (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT))
+                        && (s->version == SSL3_VERSION)))) {
+            st->hand_state = TLS_ST_SR_KEY_EXCH;
+            return 1;
+        } else if (s->s3->tmp.cert_request) {
+            if (mt == SSL3_MT_CERTIFICATE) {
+                st->hand_state = TLS_ST_SR_CERT;
+                return 1;
+            } 
+        }
+        break;
+
+    case TLS_ST_SR_CERT:
+        if (mt == SSL3_MT_CLIENT_KEY_EXCHANGE) {
+            st->hand_state = TLS_ST_SR_KEY_EXCH;
+            return 1;
+        }
+        break;
+
+    case TLS_ST_SR_KEY_EXCH:
+        /*
+         * We should only process a CertificateVerify message if we have
+         * received a Certificate from the client. If so then |s->session->peer|
+         * will be non NULL. In some instances a CertificateVerify message is
+         * not required even if the peer has sent a Certificate (e.g. such as in
+         * the case of static DH). In that case |s->no_cert_verify| should be
+         * set.
+         */
+        if (s->session->peer == NULL || s->no_cert_verify) {
+            if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+                /*
+                 * For the ECDH ciphersuites when the client sends its ECDH
+                 * pub key in a certificate, the CertificateVerify message is
+                 * not sent. Also for GOST ciphersuites when the client uses
+                 * its key from the certificate for key exchange.
+                 */
+                st->hand_state = TLS_ST_SR_CHANGE;
+                return 1;
+            }
+        } else {
+            if (mt == SSL3_MT_CERTIFICATE_VERIFY) {
+                st->hand_state = TLS_ST_SR_CERT_VRFY;
+                return 1;
+            }
+        }
+        break;
+
+    case TLS_ST_SR_CERT_VRFY:
+        if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+            st->hand_state = TLS_ST_SR_CHANGE;
+            return 1;
+        }
+        break;
+
+    case TLS_ST_SR_CHANGE:
+#ifndef OPENSSL_NO_NEXTPROTONEG
+        if (s->s3->next_proto_neg_seen) {
+            if (mt == SSL3_MT_NEXT_PROTO) {
+                st->hand_state = TLS_ST_SR_NEXT_PROTO;
+                return 1;
+            }
+        } else {
+#endif
+            if (mt == SSL3_MT_FINISHED) {
+                st->hand_state = TLS_ST_SR_FINISHED;
+                return 1;
+            }
+#ifndef OPENSSL_NO_NEXTPROTONEG
+        }
+#endif
+        break;
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+    case TLS_ST_SR_NEXT_PROTO:
+        if (mt == SSL3_MT_FINISHED) {
+            st->hand_state = TLS_ST_SR_FINISHED;
+            return 1;
+        }
+        break;
+#endif
+
+    case TLS_ST_SW_FINISHED:
+        if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+            st->hand_state = TLS_ST_SR_CHANGE;
+            return 1;
+        }
+        break;
+
+    default:
+        break;
+    }
+
+    /* No valid transition found */
+    return 0;
+}
+
+/*
+ * Should we send a ServerKeyExchange message?
+ *
+ * Valid return values are:
+ *   1: Yes
+ *   0: No
+ */
+static inline int send_server_key_exchange(SSL *s)
+{
+    unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+
+    /*
+     * only send a ServerKeyExchange if DH, fortezza or RSA but we have a
+     * sign only certificate PSK: may send PSK identity hints For
+     * ECC ciphersuites, we send a serverKeyExchange message only if
+     * the cipher suite is either ECDH-anon or ECDHE. In other cases,
+     * the server certificate contains the server's public key for
+     * key exchange.
+     */
+    if (   (alg_k & SSL_kDHE)
+        || (alg_k & SSL_kECDHE)
+        || ((alg_k & SSL_kRSA)
+            && (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL
+                || (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)
+                    && EVP_PKEY_size(s->cert->pkeys
+                                     [SSL_PKEY_RSA_ENC].privatekey) *
+                    8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)
+                   )
+               )
+           )
+        /*
+         * PSK: send ServerKeyExchange if PSK identity hint if
+         * provided
+         */
+#ifndef OPENSSL_NO_PSK
+        /* Only send SKE if we have identity hint for plain PSK */
+        || ((alg_k & (SSL_kPSK | SSL_kRSAPSK))
+            && s->cert->psk_identity_hint)
+        /* For other PSK always send SKE */
+        || (alg_k & (SSL_PSK & (SSL_kDHEPSK | SSL_kECDHEPSK)))
+#endif
+#ifndef OPENSSL_NO_SRP
+        /* SRP: send ServerKeyExchange */
+        || (alg_k & SSL_kSRP)
+#endif
+       ) {
+        return 1;
+    }
+
+    return 0;
+}
+
+/*
+ * Should we send a CertificateRequest message?
+ *
+ * Valid return values are:
+ *   1: Yes
+ *   0: No
+ */
+static inline int send_certificate_request(SSL *s)
+{
+    if (
+           /* don't request cert unless asked for it: */
+           s->verify_mode & SSL_VERIFY_PEER
+           /*
+            * if SSL_VERIFY_CLIENT_ONCE is set, don't request cert
+            * during re-negotiation:
+            */
+           && ((s->session->peer == NULL) ||
+               !(s->verify_mode & SSL_VERIFY_CLIENT_ONCE))
+           /*
+            * never request cert in anonymous ciphersuites (see
+            * section "Certificate request" in SSL 3 drafts and in
+            * RFC 2246):
+            */
+           && (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
+           /*
+            * ... except when the application insists on
+            * verification (against the specs, but s3_clnt.c accepts
+            * this for SSL 3)
+            */
+               || (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT))
+           /* don't request certificate for SRP auth */
+           && !(s->s3->tmp.new_cipher->algorithm_auth & SSL_aSRP)
+           /*
+            * With normal PSK Certificates and Certificate Requests
+            * are omitted
+            */
+           && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_PSK)) {
+        return 1;
+    }
+
+    return 0;
+}
+
+/*
+ * server_write_transition() works out what handshake state to move to next
+ * when the server is writing messages to be sent to the client.
+ */
+static enum WRITE_TRAN server_write_transition(SSL *s)
+{
+    STATEM *st = &s->statem;
+
+    switch(st->hand_state) {
+        case TLS_ST_BEFORE:
+            /* Just go straight to trying to read from the client */;
+            return WRITE_TRAN_FINISHED;
+
+        case TLS_ST_OK:
+            /* We must be trying to renegotiate */
+            st->hand_state = TLS_ST_SW_HELLO_REQ;
+            return WRITE_TRAN_CONTINUE;
+
+        case TLS_ST_SW_HELLO_REQ:
+            st->hand_state = TLS_ST_OK;
+            statem_set_in_init(s, 0);
+            return WRITE_TRAN_CONTINUE;
+
+        case TLS_ST_SR_CLNT_HELLO:
+            if (SSL_IS_DTLS(s) && !s->d1->cookie_verified
+                    && (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE))
+                st->hand_state = DTLS_ST_SW_HELLO_VERIFY_REQUEST;
+            else
+                st->hand_state = TLS_ST_SW_SRVR_HELLO;
+            return WRITE_TRAN_CONTINUE;
+
+        case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
+            return WRITE_TRAN_FINISHED;
+
+        case TLS_ST_SW_SRVR_HELLO:
+            if (s->hit) {
+                if (s->tlsext_ticket_expected)
+                    st->hand_state = TLS_ST_SW_SESSION_TICKET;
+                else
+                    st->hand_state = TLS_ST_SW_CHANGE;
+            } else {
+                /* Check if it is anon DH or anon ECDH, */
+                /* normal PSK or SRP */
+                if (!(s->s3->tmp.new_cipher->algorithm_auth &
+                     (SSL_aNULL | SSL_aSRP | SSL_aPSK))) {
+                    st->hand_state = TLS_ST_SW_CERT;
+                } else if (send_server_key_exchange(s)) {
+                    st->hand_state = TLS_ST_SW_KEY_EXCH;
+                } else if (send_certificate_request(s)) {
+                    st->hand_state = TLS_ST_SW_CERT_REQ;
+                } else {
+                    st->hand_state = TLS_ST_SW_SRVR_DONE;
+                }
+            }
+            return WRITE_TRAN_CONTINUE;
+
+        case TLS_ST_SW_CERT:
+            if (s->tlsext_status_expected) {
+                st->hand_state = TLS_ST_SW_CERT_STATUS;
+                return WRITE_TRAN_CONTINUE;
+            }
+            /* Fall through */
+
+        case TLS_ST_SW_CERT_STATUS:
+            if (send_server_key_exchange(s)) {
+                st->hand_state = TLS_ST_SW_KEY_EXCH;
+                return WRITE_TRAN_CONTINUE;
+            }
+            /* Fall through */
+
+        case TLS_ST_SW_KEY_EXCH:
+            if (send_certificate_request(s)) {
+                st->hand_state = TLS_ST_SW_CERT_REQ;
+                return WRITE_TRAN_CONTINUE;
+            }
+            /* Fall through */
+
+        case TLS_ST_SW_CERT_REQ:
+            st->hand_state = TLS_ST_SW_SRVR_DONE;
+            return WRITE_TRAN_CONTINUE;
+
+        case TLS_ST_SW_SRVR_DONE:
+            return WRITE_TRAN_FINISHED;
+
+        case TLS_ST_SR_FINISHED:
+            if (s->hit) {
+                st->hand_state = TLS_ST_OK;
+                statem_set_in_init(s, 0);
+                return WRITE_TRAN_CONTINUE;
+            } else if (s->tlsext_ticket_expected) {
+                st->hand_state = TLS_ST_SW_SESSION_TICKET;
+            } else {
+                st->hand_state = TLS_ST_SW_CHANGE;
+            }
+            return WRITE_TRAN_CONTINUE;
+
+        case TLS_ST_SW_SESSION_TICKET:
+            st->hand_state = TLS_ST_SW_CHANGE;
+            return WRITE_TRAN_CONTINUE;
+
+        case TLS_ST_SW_CHANGE:
+            st->hand_state = TLS_ST_SW_FINISHED;
+            return WRITE_TRAN_CONTINUE;
+
+        case TLS_ST_SW_FINISHED:
+            if (s->hit) {
+                return WRITE_TRAN_FINISHED;
+            }
+            st->hand_state = TLS_ST_OK;
+            statem_set_in_init(s, 0);
+            return WRITE_TRAN_CONTINUE;
+
+        default:
+            /* Shouldn't happen */
+            return WRITE_TRAN_ERROR;
+    }
+}
+
+/*
+ * Perform any pre work that needs to be done prior to sending a message from
+ * the server to the client.
+ */
+static enum WORK_STATE server_pre_work(SSL *s, enum WORK_STATE wst)
+{
+    STATEM *st = &s->statem;
+
+    switch(st->hand_state) {
+    case TLS_ST_SW_HELLO_REQ:
+        s->shutdown = 0;
+        if (SSL_IS_DTLS(s))
+            dtls1_clear_record_buffer(s);
+        break;
+
+    case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
+        s->shutdown = 0;
+        if (SSL_IS_DTLS(s)) {
+            dtls1_clear_record_buffer(s);
+            /* We don't buffer this message so don't use the timer */
+            st->use_timer = 0;
+        }
+        break;
+
+    case TLS_ST_SW_SRVR_HELLO:
+        if (SSL_IS_DTLS(s)) {
+            /*
+             * Messages we write from now on should be bufferred and
+             * retransmitted if necessary, so we need to use the timer now
+             */
+            st->use_timer = 1;
+        }
+        break;
+
+    case TLS_ST_SW_SRVR_DONE:
+#ifndef OPENSSL_NO_SCTP
+        if (SSL_IS_DTLS(s) && BIO_dgram_is_sctp(SSL_get_wbio(s)))
+            return dtls_wait_for_dry(s);
+#endif
+        return WORK_FINISHED_CONTINUE;
+
+    case TLS_ST_SW_SESSION_TICKET:
+        if (SSL_IS_DTLS(s)) {
+            /*
+             * We're into the last flight. We don't retransmit the last flight
+             * unless we need to, so we don't use the timer
+             */
+            st->use_timer = 0;
+        }
+        break;
+
+    case TLS_ST_SW_CHANGE:
+        s->session->cipher = s->s3->tmp.new_cipher;
+        if (!s->method->ssl3_enc->setup_key_block(s)) {
+            statem_set_error(s);
+            return WORK_ERROR;
+        }
+        if (SSL_IS_DTLS(s)) {
+            /*
+             * We're into the last flight. We don't retransmit the last flight
+             * unless we need to, so we don't use the timer. This might have
+             * already been set to 0 if we sent a NewSessionTicket message,
+             * but we'll set it again here in case we didn't.
+             */
+            st->use_timer = 0;
+        }
+        return WORK_FINISHED_CONTINUE;
+
+    case TLS_ST_OK:
+        return tls_finish_handshake(s, wst);
+
+    default:
+        /* No pre work to be done */
+        break;
+    }
+
+    return WORK_FINISHED_CONTINUE;
+}
+
+/*
+ * Perform any work that needs to be done after sending a message from the
+ * server to the client.
+ */
+static enum WORK_STATE server_post_work(SSL *s, enum WORK_STATE wst)
+{
+    STATEM *st = &s->statem;
+
+    s->init_num = 0;
+
+    switch(st->hand_state) {
+    case TLS_ST_SW_HELLO_REQ:
+        if (statem_flush(s) != 1)
+            return WORK_MORE_A;
+        ssl3_init_finished_mac(s);
+        break;
+
+    case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
+        if (statem_flush(s) != 1)
+            return WORK_MORE_A;
+        /* HelloVerifyRequest resets Finished MAC */
+        if (s->version != DTLS1_BAD_VER)
+            ssl3_init_finished_mac(s);
+        /*
+         * The next message should be another ClientHello which we need to
+         * treat like it was the first packet
+         */
+        s->first_packet = 1;
+        break;
+
+    case TLS_ST_SW_SRVR_HELLO:
+#ifndef OPENSSL_NO_SCTP
+        if (SSL_IS_DTLS(s) && s->hit) {
+            unsigned char sctpauthkey[64];
+            char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
+
+            /*
+             * Add new shared key for SCTP-Auth, will be ignored if no
+             * SCTP used.
+             */
+            snprintf((char *)labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL),
+                     DTLS1_SCTP_AUTH_LABEL);
+
+            if (SSL_export_keying_material(s, sctpauthkey,
+                    sizeof(sctpauthkey), labelbuffer,
+                    sizeof(labelbuffer), NULL, 0, 0) <= 0) {
+                statem_set_error(s);
+                return WORK_ERROR;
+            }
+
+            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
+                     sizeof(sctpauthkey), sctpauthkey);
+        }
+#endif
+        break;
+
+    case TLS_ST_SW_CHANGE:
+#ifndef OPENSSL_NO_SCTP
+        if (SSL_IS_DTLS(s) && !s->hit) {
+            /*
+             * Change to new shared key of SCTP-Auth, will be ignored if
+             * no SCTP used.
+             */
+            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY,
+                     0, NULL);
+        }
+#endif
+        if (!s->method->ssl3_enc->change_cipher_state(s,
+                SSL3_CHANGE_CIPHER_SERVER_WRITE)) {
+            statem_set_error(s);
+            return WORK_ERROR;
+        }
+
+        if (SSL_IS_DTLS(s))
+            dtls1_reset_seq_numbers(s, SSL3_CC_WRITE);
+        break;
+
+    case TLS_ST_SW_SRVR_DONE:
+        if (statem_flush(s) != 1)
+            return WORK_MORE_A;
+        break;
+
+    case TLS_ST_SW_FINISHED:
+        if (statem_flush(s) != 1)
+            return WORK_MORE_A;
+#ifndef OPENSSL_NO_SCTP
+        if (SSL_IS_DTLS(s) && s->hit) {
+            /*
+             * Change to new shared key of SCTP-Auth, will be ignored if
+             * no SCTP used.
+             */
+            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY,
+                     0, NULL);
+        }
+#endif
+        break;
+
+    default:
+        /* No post work to be done */
+        break;
+    }
+
+    return WORK_FINISHED_CONTINUE;
+}
+
+/*
+ * Construct a message to be sent from the server to the client.
+ *
+ * Valid return values are:
+ *   1: Success
+ *   0: Error
+ */
+static int server_construct_message(SSL *s)
+{
+    STATEM *st = &s->statem;
+
+    switch(st->hand_state) {
+    case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
+        return dtls_construct_hello_verify_request(s);
+
+    case TLS_ST_SW_HELLO_REQ:
+        return tls_construct_hello_request(s);
+
+    case TLS_ST_SW_SRVR_HELLO:
+        return tls_construct_server_hello(s);
+
+    case TLS_ST_SW_CERT:
+        return tls_construct_server_certificate(s);
+
+    case TLS_ST_SW_KEY_EXCH:
+        return tls_construct_server_key_exchange(s);
+
+    case TLS_ST_SW_CERT_REQ:
+        return tls_construct_certificate_request(s);
+
+    case TLS_ST_SW_SRVR_DONE:
+        return tls_construct_server_done(s);
+
+    case TLS_ST_SW_SESSION_TICKET:
+        return tls_construct_new_session_ticket(s);
+
+    case TLS_ST_SW_CERT_STATUS:
+        return tls_construct_cert_status(s);
+
+    case TLS_ST_SW_CHANGE:
+        if (SSL_IS_DTLS(s))
+            return dtls_construct_change_cipher_spec(s);
+        else
+            return tls_construct_change_cipher_spec(s);
+
+    case TLS_ST_SW_FINISHED:
+        return tls_construct_finished(s,
+                                      s->method->
+                                      ssl3_enc->server_finished_label,
+                                      s->method->
+                                      ssl3_enc->server_finished_label_len);
+
+    default:
+        /* Shouldn't happen */
+        break;
+    }
+
+    return 0;
+}
+
+#define CLIENT_KEY_EXCH_MAX_LENGTH      2048
+#define NEXT_PROTO_MAX_LENGTH           514
+
+/*
+ * Returns the maximum allowed length for the current message that we are
+ * reading. Excludes the message header.
+ */
+static unsigned long server_max_message_size(SSL *s)
+{
+    STATEM *st = &s->statem;
+
+    switch(st->hand_state) {
+    case TLS_ST_SR_CLNT_HELLO:
+        return SSL3_RT_MAX_PLAIN_LENGTH;
+
+    case TLS_ST_SR_CERT:
+        return s->max_cert_list;
+
+    case TLS_ST_SR_KEY_EXCH:
+        return CLIENT_KEY_EXCH_MAX_LENGTH;
+
+    case TLS_ST_SR_CERT_VRFY:
+        return SSL3_RT_MAX_PLAIN_LENGTH;
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+    case TLS_ST_SR_NEXT_PROTO:
+        return NEXT_PROTO_MAX_LENGTH;
+#endif
+
+    case TLS_ST_SR_CHANGE:
+        return CCS_MAX_LENGTH;
+
+    case TLS_ST_SR_FINISHED:
+        return FINISHED_MAX_LENGTH;
+
+    default:
+        /* Shouldn't happen */
+        break;
+    }
+
+    return 0;
+}
+
+/*
+ * Process a message that the server has received from the client.
+ */
+static enum MSG_PROCESS_RETURN  server_process_message(SSL *s, PACKET *pkt)
+{
+    STATEM *st = &s->statem;
+
+    switch(st->hand_state) {
+    case TLS_ST_SR_CLNT_HELLO:
+        return tls_process_client_hello(s, pkt);
+
+    case TLS_ST_SR_CERT:
+        return tls_process_client_certificate(s, pkt);
+
+    case TLS_ST_SR_KEY_EXCH:
+        return tls_process_client_key_exchange(s, pkt);
+
+    case TLS_ST_SR_CERT_VRFY:
+        return tls_process_cert_verify(s, pkt);
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+    case TLS_ST_SR_NEXT_PROTO:
+        return tls_process_next_proto(s, pkt);
+#endif
+
+    case TLS_ST_SR_CHANGE:
+        return tls_process_change_cipher_spec(s, pkt);
+
+    case TLS_ST_SR_FINISHED:
+        return tls_process_finished(s, pkt);
+
+    default:
+        /* Shouldn't happen */
+        break;
+    }
+
+    return MSG_PROCESS_ERROR;
+}
+
+/*
+ * Perform any further processing required following the receipt of a message
+ * from the client
+ */
+static enum WORK_STATE server_post_process_message(SSL *s, enum WORK_STATE wst)
+{
+    STATEM *st = &s->statem;
+
+    switch(st->hand_state) {
+    case TLS_ST_SR_CLNT_HELLO:
+        return tls_post_process_client_hello(s, wst);
+
+    case TLS_ST_SR_KEY_EXCH:
+        return tls_post_process_client_key_exchange(s, wst);
+
+    case TLS_ST_SR_CERT_VRFY:
+#ifndef OPENSSL_NO_SCTP
+        if (    /* Is this SCTP? */
+                BIO_dgram_is_sctp(SSL_get_wbio(s))
+                /* Are we renegotiating? */
+                && s->renegotiate
+                && BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s))) {
+            s->s3->in_read_app_data = 2;
+            s->rwstate = SSL_READING;
+            BIO_clear_retry_flags(SSL_get_rbio(s));
+            BIO_set_retry_read(SSL_get_rbio(s));
+            statem_set_sctp_read_sock(s, 1);
+            return WORK_MORE_A;
+        } else {
+            statem_set_sctp_read_sock(s, 0);
+        }
+#endif
+        return WORK_FINISHED_CONTINUE;
+
+
+    case TLS_ST_SR_FINISHED:
+        if (s->hit)
+            return tls_finish_handshake(s, wst);
+        else
+            return WORK_FINISHED_STOP;
+    default:
+        break;
+    }
+
+    /* Shouldn't happen */
+    return WORK_ERROR;
+}
diff --git a/ssl/statem/statem.h b/ssl/statem/statem.h
new file mode 100644 (file)
index 0000000..b6256f9
--- /dev/null
@@ -0,0 +1,174 @@
+/* ssl/statem/statem.h */
+/* ====================================================================
+ * Copyright (c) 1998-2015 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+/*****************************************************************************
+ *                                                                           *
+ * These emums should be considered PRIVATE to the state machine. No         *
+ * non-state machine code should need to use these                           *
+ *                                                                           *
+ *****************************************************************************/
+/*
+ * Valid return codes used for functions performing work prior to or after
+ * sending or receiving a message
+ */
+enum WORK_STATE {
+    /* Something went wrong */
+    WORK_ERROR,
+    /* We're done working and there shouldn't be anything else to do after */
+    WORK_FINISHED_STOP,
+    /* We're done working move onto the next thing */
+    WORK_FINISHED_CONTINUE,
+    /* We're working on phase A */
+    WORK_MORE_A,
+    /* We're working on phase B */
+    WORK_MORE_B
+};
+
+/* Write transition return codes */
+enum WRITE_TRAN {
+    /* Something went wrong */
+    WRITE_TRAN_ERROR,
+    /* A transition was successfully completed and we should continue */
+    WRITE_TRAN_CONTINUE,
+    /* There is no more write work to be done */
+    WRITE_TRAN_FINISHED
+};
+
+/* Message processing return codes */
+enum MSG_PROCESS_RETURN {
+    MSG_PROCESS_ERROR,
+    MSG_PROCESS_FINISHED_READING,
+    MSG_PROCESS_CONTINUE_PROCESSING,
+    MSG_PROCESS_CONTINUE_READING
+};
+
+/* Message flow states */
+enum MSG_FLOW_STATE {
+    /* No handshake in progress */
+    MSG_FLOW_UNINITED,
+    /* A permanent error with this connection */
+    MSG_FLOW_ERROR,
+    /* We are about to renegotiate */
+    MSG_FLOW_RENEGOTIATE,
+    /* We are reading messages */
+    MSG_FLOW_READING,
+    /* We are writing messages */
+    MSG_FLOW_WRITING,
+    /* Handshake has finished */
+    MSG_FLOW_FINISHED
+};
+
+/* Read states */
+enum READ_STATE {
+    READ_STATE_HEADER,
+    READ_STATE_BODY,
+    READ_STATE_POST_PROCESS
+};
+
+/* Write states */
+enum WRITE_STATE {
+    WRITE_STATE_TRANSITION,
+    WRITE_STATE_PRE_WORK,
+    WRITE_STATE_SEND,
+    WRITE_STATE_POST_WORK
+};
+
+
+/*****************************************************************************
+ *                                                                           *
+ * This structure should be considered "opaque" to anything outside of the   *
+ * state machine. No non-state machine code should be accessing the members  *
+ * of this structure.                                                        *
+ *                                                                           *
+ *****************************************************************************/
+
+struct statem_st {
+    enum MSG_FLOW_STATE state;
+    enum WRITE_STATE write_state;
+    enum WORK_STATE write_state_work;
+    enum READ_STATE read_state;
+    enum WORK_STATE read_state_work;
+    enum HANDSHAKE_STATE hand_state;
+    int in_init;
+    int read_state_first_init;
+    int use_timer;
+#ifndef OPENSSL_NO_SCTP
+    int in_sctp_read_sock;
+#endif
+};
+typedef struct statem_st STATEM;
+
+
+/*****************************************************************************
+ *                                                                           *
+ * The following macros/functions represent the libssl internal API to the   *
+ * state machine. Any libssl code may call these functions/macros            *
+ *                                                                           *
+ *****************************************************************************/
+
+__owur int statem_accept(SSL *s);
+__owur int statem_connect(SSL *s);
+void statem_clear(SSL *s);
+void statem_set_renegotiate(SSL *s);
+void statem_set_error(SSL *s);
+int statem_in_error(const SSL *s);
+void statem_set_in_init(SSL *s, int init);
+__owur int statem_app_data_allowed(SSL *s);
+#ifndef OPENSSL_NO_SCTP
+void statem_set_sctp_read_sock(SSL *s, int read_sock);
+__owur int statem_in_sctp_read_sock(SSL *s);
+#endif
+
+
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
new file mode 100644 (file)
index 0000000..3ff4276
--- /dev/null
@@ -0,0 +1,2853 @@
+/* ssl/statem/statem_clnt.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2007 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ *
+ * Portions of the attached software ("Contribution") are developed by
+ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
+ *
+ * The Contribution is licensed pursuant to the OpenSSL open source
+ * license provided above.
+ *
+ * ECC cipher suite support in OpenSSL originally written by
+ * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories.
+ *
+ */
+/* ====================================================================
+ * Copyright 2005 Nokia. All rights reserved.
+ *
+ * The portions of the attached software ("Contribution") is developed by
+ * Nokia Corporation and is licensed pursuant to the OpenSSL open source
+ * license.
+ *
+ * The Contribution, originally written by Mika Kousa and Pasi Eronen of
+ * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
+ * support (see RFC 4279) to OpenSSL.
+ *
+ * No patent licenses or other rights except those expressly stated in
+ * the OpenSSL open source license shall be deemed granted or received
+ * expressly, by implication, estoppel, or otherwise.
+ *
+ * No assurances are provided by Nokia that the Contribution does not
+ * infringe the patent or other intellectual property rights of any third
+ * party or that the license provides you with all the necessary rights
+ * to make use of the Contribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
+ * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
+ * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
+ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
+ * OTHERWISE.
+ */
+
+#include <stdio.h>
+#include "../ssl_locl.h"
+#include <openssl/buffer.h>
+#include <openssl/rand.h>
+#include <openssl/objects.h>
+#include <openssl/evp.h>
+#include <openssl/md5.h>
+#ifndef OPENSSL_NO_DH
+# include <openssl/dh.h>
+#endif
+#include <openssl/bn.h>
+#ifndef OPENSSL_NO_ENGINE
+# include <openssl/engine.h>
+#endif
+
+static int ssl_set_version(SSL *s);
+static int ca_dn_cmp(const X509_NAME *const *a, const X509_NAME *const *b);
+static int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk,
+                                    unsigned char *p);
+
+/*
+ * Work out what version we should be using for the initial ClientHello if
+ * the version is currently set to (D)TLS_ANY_VERSION.
+ * Returns 1 on success
+ * Returns 0 on error
+ */
+static int ssl_set_version(SSL *s)
+{
+    unsigned long mask, options = s->options;
+
+    if (s->method->version == TLS_ANY_VERSION) {
+        /*
+         * SSL_OP_NO_X disables all protocols above X *if* there are
+         * some protocols below X enabled. This is required in order
+         * to maintain "version capability" vector contiguous. So
+         * that if application wants to disable TLS1.0 in favour of
+         * TLS1>=1, it would be insufficient to pass SSL_NO_TLSv1, the
+         * answer is SSL_OP_NO_TLSv1|SSL_OP_NO_SSLv3.
+         */
+        mask = SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1
+#if !defined(OPENSSL_NO_SSL3)
+            | SSL_OP_NO_SSLv3
+#endif
+            ;
+#if !defined(OPENSSL_NO_TLS1_2_CLIENT)
+        if (options & SSL_OP_NO_TLSv1_2) {
+            if ((options & mask) != mask) {
+                s->version = TLS1_1_VERSION;
+            } else {
+                SSLerr(SSL_F_SSL_SET_VERSION, SSL_R_NO_PROTOCOLS_AVAILABLE);
+                return 0;
+            }
+        } else {
+            s->version = TLS1_2_VERSION;
+        }
+#else
+        if ((options & mask) == mask) {
+            SSLerr(SSL_F_SSL_SET_VERSION, SSL_R_NO_PROTOCOLS_AVAILABLE);
+            return 0;
+        }
+        s->version = TLS1_1_VERSION;
+#endif
+
+        mask &= ~SSL_OP_NO_TLSv1_1;
+        if ((options & SSL_OP_NO_TLSv1_1) && (options & mask) != mask)
+            s->version = TLS1_VERSION;
+        mask &= ~SSL_OP_NO_TLSv1;
+#if !defined(OPENSSL_NO_SSL3)
+        if ((options & SSL_OP_NO_TLSv1) && (options & mask) != mask)
+            s->version = SSL3_VERSION;
+#endif
+
+        if (s->version != TLS1_2_VERSION && tls1_suiteb(s)) {
+            SSLerr(SSL_F_SSL_SET_VERSION,
+                   SSL_R_ONLY_TLS_1_2_ALLOWED_IN_SUITEB_MODE);
+            return 0;
+        }
+
+        if (s->version == SSL3_VERSION && FIPS_mode()) {
+            SSLerr(SSL_F_SSL_SET_VERSION, SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE);
+            return 0;
+        }
+
+    } else if (s->method->version == DTLS_ANY_VERSION) {
+        /* Determine which DTLS version to use */
+        /* If DTLS 1.2 disabled correct the version number */
+        if (options & SSL_OP_NO_DTLSv1_2) {
+            if (tls1_suiteb(s)) {
+                SSLerr(SSL_F_SSL_SET_VERSION,
+                       SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE);
+                return 0;
+            }
+            /*
+             * Disabling all versions is silly: return an error.
+             */
+            if (options & SSL_OP_NO_DTLSv1) {
+                SSLerr(SSL_F_SSL_SET_VERSION, SSL_R_WRONG_SSL_VERSION);
+                return 0;
+            }
+            /*
+             * Update method so we don't use any DTLS 1.2 features.
+             */
+            s->method = DTLSv1_client_method();
+            s->version = DTLS1_VERSION;
+        } else {
+            /*
+             * We only support one version: update method
+             */
+            if (options & SSL_OP_NO_DTLSv1)
+                s->method = DTLSv1_2_client_method();
+            s->version = DTLS1_2_VERSION;
+        }
+    }
+
+    s->client_version = s->version;
+
+    return 1;
+}
+
+int tls_construct_client_hello(SSL *s)
+{
+    unsigned char *buf;
+    unsigned char *p, *d;
+    int i;
+    unsigned long l;
+    int al = 0;
+#ifndef OPENSSL_NO_COMP
+    int j;
+    SSL_COMP *comp;
+#endif
+    SSL_SESSION *sess = s->session;
+
+    buf = (unsigned char *)s->init_buf->data;
+
+    /* Work out what SSL/TLS/DTLS version to use */
+    if (ssl_set_version(s) == 0)
+        goto err;
+
+    if ((sess == NULL) || (sess->ssl_version != s->version) ||
+        /*
+         * In the case of EAP-FAST, we can have a pre-shared
+         * "ticket" without a session ID.
+         */
+        (!sess->session_id_length && !sess->tlsext_tick) ||
+        (sess->not_resumable)) {
+        if (!ssl_get_new_session(s, 0))
+            goto err;
+    }
+    /* else use the pre-loaded session */
+
+    p = s->s3->client_random;
+
+    /*
+     * for DTLS if client_random is initialized, reuse it, we are
+     * required to use same upon reply to HelloVerify
+     */
+    if (SSL_IS_DTLS(s)) {
+        size_t idx;
+        i = 1;
+        for (idx = 0; idx < sizeof(s->s3->client_random); idx++) {
+            if (p[idx]) {
+                i = 0;
+                break;
+            }
+        }
+    } else
+        i = 1;
+
+    if (i && ssl_fill_hello_random(s, 0, p,
+                                   sizeof(s->s3->client_random)) <= 0)
+        goto err;
+
+    /* Do the message type and length last */
+    d = p = ssl_handshake_start(s);
+
+    /*-
+     * version indicates the negotiated version: for example from
+     * an SSLv2/v3 compatible client hello). The client_version
+     * field is the maximum version we permit and it is also
+     * used in RSA encrypted premaster secrets. Some servers can
+     * choke if we initially report a higher version then
+     * renegotiate to a lower one in the premaster secret. This
+     * didn't happen with TLS 1.0 as most servers supported it
+     * but it can with TLS 1.1 or later if the server only supports
+     * 1.0.
+     *
+     * Possible scenario with previous logic:
+     *      1. Client hello indicates TLS 1.2
+     *      2. Server hello says TLS 1.0
+     *      3. RSA encrypted premaster secret uses 1.2.
+     *      4. Handhaked proceeds using TLS 1.0.
+     *      5. Server sends hello request to renegotiate.
+     *      6. Client hello indicates TLS v1.0 as we now
+     *         know that is maximum server supports.
+     *      7. Server chokes on RSA encrypted premaster secret
+     *         containing version 1.0.
+     *
+     * For interoperability it should be OK to always use the
+     * maximum version we support in client hello and then rely
+     * on the checking of version to ensure the servers isn't
+     * being inconsistent: for example initially negotiating with
+     * TLS 1.0 and renegotiating with TLS 1.2. We do this by using
+     * client_version in client hello and not resetting it to
+     * the negotiated version.
+     */
+    *(p++) = s->client_version >> 8;
+    *(p++) = s->client_version & 0xff;
+
+    /* Random stuff */
+    memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE);
+    p += SSL3_RANDOM_SIZE;
+
+    /* Session ID */
+    if (s->new_session)
+        i = 0;
+    else
+        i = s->session->session_id_length;
+    *(p++) = i;
+    if (i != 0) {
+        if (i > (int)sizeof(s->session->session_id)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        memcpy(p, s->session->session_id, i);
+        p += i;
+    }
+
+    /* cookie stuff for DTLS */
+    if (SSL_IS_DTLS(s)) {
+        if (s->d1->cookie_len > sizeof(s->d1->cookie)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        *(p++) = s->d1->cookie_len;
+        memcpy(p, s->d1->cookie, s->d1->cookie_len);
+        p += s->d1->cookie_len;
+    }
+
+    /* Ciphers supported */
+    i = ssl_cipher_list_to_bytes(s, SSL_get_ciphers(s), &(p[2]));
+    if (i == 0) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, SSL_R_NO_CIPHERS_AVAILABLE);
+        goto err;
+    }
+#ifdef OPENSSL_MAX_TLS1_2_CIPHER_LENGTH
+    /*
+     * Some servers hang if client hello > 256 bytes as hack workaround
+     * chop number of supported ciphers to keep it well below this if we
+     * use TLS v1.2
+     */
+    if (TLS1_get_version(s) >= TLS1_2_VERSION
+        && i > OPENSSL_MAX_TLS1_2_CIPHER_LENGTH)
+        i = OPENSSL_MAX_TLS1_2_CIPHER_LENGTH & ~1;
+#endif
+    s2n(i, p);
+    p += i;
+
+    /* COMPRESSION */
+#ifdef OPENSSL_NO_COMP
+    *(p++) = 1;
+#else
+
+    if (!ssl_allow_compression(s) || !s->ctx->comp_methods)
+        j = 0;
+    else
+        j = sk_SSL_COMP_num(s->ctx->comp_methods);
+    *(p++) = 1 + j;
+    for (i = 0; i < j; i++) {
+        comp = sk_SSL_COMP_value(s->ctx->comp_methods, i);
+        *(p++) = comp->id;
+    }
+#endif
+    *(p++) = 0;             /* Add the NULL method */
+
+    /* TLS extensions */
+    if (ssl_prepare_clienthello_tlsext(s) <= 0) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT);
+        goto err;
+    }
+    if ((p =
+         ssl_add_clienthello_tlsext(s, p, buf + SSL3_RT_MAX_PLAIN_LENGTH,
+                                    &al)) == NULL) {
+        ssl3_send_alert(s, SSL3_AL_FATAL, al);
+        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    l = p - d;
+    if (!ssl_set_handshake_header(s, SSL3_MT_CLIENT_HELLO, l)) {
+        ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    return 1;
+ err:
+    statem_set_error(s);
+    return 0;
+}
+
+enum MSG_PROCESS_RETURN dtls_process_hello_verify(SSL *s, PACKET *pkt)
+{
+    int al;
+    unsigned int cookie_len;
+    PACKET cookiepkt;
+
+    if (!PACKET_forward(pkt, 2)
+            || !PACKET_get_length_prefixed_1(pkt, &cookiepkt)) {
+        al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_DTLS_PROCESS_HELLO_VERIFY, SSL_R_LENGTH_MISMATCH);
+        goto f_err;
+    }
+
+    cookie_len = PACKET_remaining(&cookiepkt);
+    if (cookie_len > sizeof(s->d1->cookie)) {
+        al = SSL_AD_ILLEGAL_PARAMETER;
+        SSLerr(SSL_F_DTLS_PROCESS_HELLO_VERIFY, SSL_R_LENGTH_TOO_LONG);
+        goto f_err;
+    }
+
+    if (!PACKET_copy_bytes(&cookiepkt, s->d1->cookie, cookie_len)) {
+        al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_DTLS_PROCESS_HELLO_VERIFY, SSL_R_LENGTH_MISMATCH);
+        goto f_err;
+    }
+    s->d1->cookie_len = cookie_len;
+
+    return MSG_PROCESS_FINISHED_READING;
+ f_err:
+    ssl3_send_alert(s, SSL3_AL_FATAL, al);
+    statem_set_error(s);
+    return MSG_PROCESS_ERROR;
+}
+
+enum MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
+{
+    STACK_OF(SSL_CIPHER) *sk;
+    const SSL_CIPHER *c;
+    PACKET session_id;
+    size_t session_id_len;
+    unsigned char *cipherchars;
+    int i, al = SSL_AD_INTERNAL_ERROR;
+    unsigned int compression;
+#ifndef OPENSSL_NO_COMP
+    SSL_COMP *comp;
+#endif
+
+    if (s->method->version == TLS_ANY_VERSION) {
+        unsigned int sversion;
+
+        if (!PACKET_get_net_2(pkt, &sversion)) {
+            al = SSL_AD_DECODE_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
+            goto f_err;
+        }
+
+#if TLS_MAX_VERSION != TLS1_2_VERSION
+#error Code needs updating for new TLS version
+#endif
+#ifndef OPENSSL_NO_SSL3
+        if ((sversion == SSL3_VERSION) && !(s->options & SSL_OP_NO_SSLv3)) {
+            if (FIPS_mode()) {
+                SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO,
+                       SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE);
+                al = SSL_AD_PROTOCOL_VERSION;
+                goto f_err;
+            }
+            s->method = SSLv3_client_method();
+        } else
+#endif
+        if ((sversion == TLS1_VERSION) && !(s->options & SSL_OP_NO_TLSv1)) {
+            s->method = TLSv1_client_method();
+        } else if ((sversion == TLS1_1_VERSION) &&
+                   !(s->options & SSL_OP_NO_TLSv1_1)) {
+            s->method = TLSv1_1_client_method();
+        } else if ((sversion == TLS1_2_VERSION) &&
+                   !(s->options & SSL_OP_NO_TLSv1_2)) {
+            s->method = TLSv1_2_client_method();
+        } else {
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_UNSUPPORTED_PROTOCOL);
+            al = SSL_AD_PROTOCOL_VERSION;
+            goto f_err;
+        }
+        s->session->ssl_version = s->version = s->method->version;
+
+        if (!ssl_security(s, SSL_SECOP_VERSION, 0, s->version, NULL)) {
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_VERSION_TOO_LOW);
+            al = SSL_AD_PROTOCOL_VERSION;
+            goto f_err;
+        }
+    } else if (s->method->version == DTLS_ANY_VERSION) {
+        /* Work out correct protocol version to use */
+        unsigned int hversion;
+        int options;
+
+        if (!PACKET_get_net_2(pkt, &hversion)) {
+            al = SSL_AD_DECODE_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
+            goto f_err;
+        }
+
+        options = s->options;
+        if (hversion == DTLS1_2_VERSION && !(options & SSL_OP_NO_DTLSv1_2))
+            s->method = DTLSv1_2_client_method();
+        else if (tls1_suiteb(s)) {
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO,
+                   SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE);
+            s->version = hversion;
+            al = SSL_AD_PROTOCOL_VERSION;
+            goto f_err;
+        } else if (hversion == DTLS1_VERSION && !(options & SSL_OP_NO_DTLSv1))
+            s->method = DTLSv1_client_method();
+        else {
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_WRONG_SSL_VERSION);
+            s->version = hversion;
+            al = SSL_AD_PROTOCOL_VERSION;
+            goto f_err;
+        }
+        s->session->ssl_version = s->version = s->method->version;
+    } else {
+        unsigned char *vers;
+
+        if (!PACKET_get_bytes(pkt, &vers, 2)) {
+            al = SSL_AD_DECODE_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
+            goto f_err;
+        }
+        if ((vers[0] != (s->version >> 8))
+                || (vers[1] != (s->version & 0xff))) {
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_WRONG_SSL_VERSION);
+            s->version = (s->version & 0xff00) | vers[1];
+            al = SSL_AD_PROTOCOL_VERSION;
+            goto f_err;
+        }
+    }
+
+    /* load the server hello data */
+    /* load the server random */
+    if (!PACKET_copy_bytes(pkt, s->s3->server_random, SSL3_RANDOM_SIZE)) {
+        al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
+        goto f_err;
+    }
+
+    s->hit = 0;
+
+    /* Get the session-id. */
+    if (!PACKET_get_length_prefixed_1(pkt, &session_id)) {
+        al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
+        goto f_err;
+    }
+    session_id_len = PACKET_remaining(&session_id);
+    if (session_id_len > sizeof s->session->session_id
+        || session_id_len > SSL3_SESSION_ID_SIZE) {
+        al = SSL_AD_ILLEGAL_PARAMETER;
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_SSL3_SESSION_ID_TOO_LONG);
+        goto f_err;
+    }
+
+    if (!PACKET_get_bytes(pkt, &cipherchars, TLS_CIPHER_LEN)) {
+        SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
+        al = SSL_AD_DECODE_ERROR;
+        goto f_err;
+    }
+
+    /*
+     * Check if we can resume the session based on external pre-shared secret.
+     * EAP-FAST (RFC 4851) supports two types of session resumption.
+     * Resumption based on server-side state works with session IDs.
+     * Resumption based on pre-shared Protected Access Credentials (PACs)
+     * works by overriding the SessionTicket extension at the application
+     * layer, and does not send a session ID. (We do not know whether EAP-FAST
+     * servers would honour the session ID.) Therefore, the session ID alone
+     * is not a reliable indicator of session resumption, so we first check if
+     * we can resume, and later peek at the next handshake message to see if the
+     * server wants to resume.
+     */
+    if (s->version >= TLS1_VERSION && s->tls_session_secret_cb &&
+        s->session->tlsext_tick) {
+        SSL_CIPHER *pref_cipher = NULL;
+        s->session->master_key_length = sizeof(s->session->master_key);
+        if (s->tls_session_secret_cb(s, s->session->master_key,
+                                     &s->session->master_key_length,
+                                     NULL, &pref_cipher,
+                                     s->tls_session_secret_cb_arg)) {
+            s->session->cipher = pref_cipher ?
+                pref_cipher : ssl_get_cipher_by_char(s, cipherchars);
+        } else {
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
+            al = SSL_AD_INTERNAL_ERROR;
+            goto f_err;
+        }
+    }
+
+    if (session_id_len != 0 && session_id_len == s->session->session_id_length
+        && memcmp(PACKET_data(&session_id), s->session->session_id,
+                  session_id_len) == 0) {
+        if (s->sid_ctx_length != s->session->sid_ctx_length
+            || memcmp(s->session->sid_ctx, s->sid_ctx, s->sid_ctx_length)) {
+            /* actually a client application bug */
+            al = SSL_AD_ILLEGAL_PARAMETER;
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO,
+                   SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT);
+            goto f_err;
+        }
+        s->hit = 1;
+    } else {
+        /*
+         * If we were trying for session-id reuse but the server
+         * didn't echo the ID, make a new SSL_SESSION.
+         * In the case of EAP-FAST and PAC, we do not send a session ID,
+         * so the PAC-based session secret is always preserved. It'll be
+         * overwritten if the server refuses resumption.
+         */
+        if (s->session->session_id_length > 0) {
+            if (!ssl_get_new_session(s, 0)) {
+                goto f_err;
+            }
+        }
+
+        s->session->session_id_length = session_id_len;
+        /* session_id_len could be 0 */
+        memcpy(s->session->session_id, PACKET_data(&session_id),
+               session_id_len);
+    }
+
+    c = ssl_get_cipher_by_char(s, cipherchars);
+    if (c == NULL) {
+        /* unknown cipher */
+        al = SSL_AD_ILLEGAL_PARAMETER;
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_UNKNOWN_CIPHER_RETURNED);
+        goto f_err;
+    }
+    /* Set version disabled mask now we know version */
+    if (!SSL_USE_TLS1_2_CIPHERS(s))
+        s->s3->tmp.mask_ssl = SSL_TLSV1_2;
+    else
+        s->s3->tmp.mask_ssl = 0;
+    /*
+     * If it is a disabled cipher we didn't send it in client hello, so
+     * return an error.
+     */
+    if (ssl_cipher_disabled(s, c, SSL_SECOP_CIPHER_CHECK)) {
+        al = SSL_AD_ILLEGAL_PARAMETER;
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_WRONG_CIPHER_RETURNED);
+        goto f_err;
+    }
+
+    sk = ssl_get_ciphers_by_id(s);
+    i = sk_SSL_CIPHER_find(sk, c);
+    if (i < 0) {
+        /* we did not say we would use this cipher */
+        al = SSL_AD_ILLEGAL_PARAMETER;
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_WRONG_CIPHER_RETURNED);
+        goto f_err;
+    }
+
+    /*
+     * Depending on the session caching (internal/external), the cipher
+     * and/or cipher_id values may not be set. Make sure that cipher_id is
+     * set and use it for comparison.
+     */
+    if (s->session->cipher)
+        s->session->cipher_id = s->session->cipher->id;
+    if (s->hit && (s->session->cipher_id != c->id)) {
+        al = SSL_AD_ILLEGAL_PARAMETER;
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO,
+               SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED);
+        goto f_err;
+    }
+    s->s3->tmp.new_cipher = c;
+    /*
+     * Don't digest cached records if no sigalgs: we may need them for client
+     * authentication.
+     */
+    if (!SSL_USE_SIGALGS(s) && !ssl3_digest_cached_records(s, 0))
+        goto f_err;
+    /* lets get the compression algorithm */
+    /* COMPRESSION */
+    if (!PACKET_get_1(pkt, &compression)) {
+        SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
+        al = SSL_AD_DECODE_ERROR;
+        goto f_err;
+    }
+#ifdef OPENSSL_NO_COMP
+    if (compression != 0) {
+        al = SSL_AD_ILLEGAL_PARAMETER;
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO,
+               SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
+        goto f_err;
+    }
+    /*
+     * If compression is disabled we'd better not try to resume a session
+     * using compression.
+     */
+    if (s->session->compress_meth != 0) {
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_INCONSISTENT_COMPRESSION);
+        goto f_err;
+    }
+#else
+    if (s->hit && compression != s->session->compress_meth) {
+        al = SSL_AD_ILLEGAL_PARAMETER;
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO,
+               SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED);
+        goto f_err;
+    }
+    if (compression == 0)
+        comp = NULL;
+    else if (!ssl_allow_compression(s)) {
+        al = SSL_AD_ILLEGAL_PARAMETER;
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_COMPRESSION_DISABLED);
+        goto f_err;
+    } else {
+        comp = ssl3_comp_find(s->ctx->comp_methods, compression);
+    }
+
+    if (compression != 0 && comp == NULL) {
+        al = SSL_AD_ILLEGAL_PARAMETER;
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO,
+               SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
+        goto f_err;
+    } else {
+        s->s3->tmp.new_compression = comp;
+    }
+#endif
+
+    /* TLS extensions */
+    if (!ssl_parse_serverhello_tlsext(s, pkt)) {
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_PARSE_TLSEXT);
+        goto err;
+    }
+
+    if (PACKET_remaining(pkt) != 0) {
+        /* wrong packet length */
+        al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_BAD_PACKET_LENGTH);
+        goto f_err;
+    }
+
+#ifndef OPENSSL_NO_SCTP
+    if (SSL_IS_DTLS(s) && s->hit) {
+        unsigned char sctpauthkey[64];
+        char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
+
+        /*
+         * Add new shared key for SCTP-Auth, will be ignored if
+         * no SCTP used.
+         */
+        snprintf((char *)labelbuffer,
+                 sizeof(DTLS1_SCTP_AUTH_LABEL),
+                 DTLS1_SCTP_AUTH_LABEL);
+
+        if (SSL_export_keying_material(s, sctpauthkey,
+                                   sizeof(sctpauthkey),
+                                   labelbuffer,
+                                   sizeof(labelbuffer), NULL, 0,
+                                   0) <= 0)
+            goto err;
+
+        BIO_ctrl(SSL_get_wbio(s),
+                 BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
+                 sizeof(sctpauthkey), sctpauthkey);
+    }
+#endif
+
+    return MSG_PROCESS_CONTINUE_READING;
+ f_err:
+    ssl3_send_alert(s, SSL3_AL_FATAL, al);
+ err:
+    statem_set_error(s);
+    return MSG_PROCESS_ERROR;
+}
+
+enum MSG_PROCESS_RETURN tls_process_server_certificate(SSL *s, PACKET *pkt)
+{
+    int al, i, ret = MSG_PROCESS_ERROR, exp_idx;
+    unsigned long cert_list_len, cert_len;
+    X509 *x = NULL;
+    unsigned char *certstart, *certbytes;
+    STACK_OF(X509) *sk = NULL;
+    EVP_PKEY *pkey = NULL;
+
+    if ((sk = sk_X509_new_null()) == NULL) {
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    if (!PACKET_get_net_3(pkt, &cert_list_len)
+            || PACKET_remaining(pkt) != cert_list_len) {
+        al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE, SSL_R_LENGTH_MISMATCH);
+        goto f_err;
+    }
+    while (PACKET_remaining(pkt)) {
+        if (!PACKET_get_net_3(pkt, &cert_len)
+                || !PACKET_get_bytes(pkt, &certbytes, cert_len)) {
+            al = SSL_AD_DECODE_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE,
+                   SSL_R_CERT_LENGTH_MISMATCH);
+            goto f_err;
+        }
+
+        certstart = certbytes;
+        x = d2i_X509(NULL, (const unsigned char **)&certbytes, cert_len);
+        if (x == NULL) {
+            al = SSL_AD_BAD_CERTIFICATE;
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE, ERR_R_ASN1_LIB);
+            goto f_err;
+        }
+        if (certbytes != (certstart + cert_len)) {
+            al = SSL_AD_DECODE_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE,
+                   SSL_R_CERT_LENGTH_MISMATCH);
+            goto f_err;
+        }
+        if (!sk_X509_push(sk, x)) {
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE, ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+        x = NULL;
+    }
+
+    i = ssl_verify_cert_chain(s, sk);
+    if (s->verify_mode != SSL_VERIFY_NONE && i <= 0) {
+        al = ssl_verify_alarm_type(s->verify_result);
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE,
+               SSL_R_CERTIFICATE_VERIFY_FAILED);
+        goto f_err;
+    }
+    ERR_clear_error();          /* but we keep s->verify_result */
+    if (i > 1) {
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE, i);
+        al = SSL_AD_HANDSHAKE_FAILURE;
+        goto f_err;
+    }
+
+    s->session->peer_chain = sk;
+    /*
+     * Inconsistency alert: cert_chain does include the peer's certificate,
+     * which we don't include in s3_srvr.c
+     */
+    x = sk_X509_value(sk, 0);
+    sk = NULL;
+    /*
+     * VRS 19990621: possible memory leak; sk=null ==> !sk_pop_free() @end
+     */
+
+    pkey = X509_get_pubkey(x);
+
+    if (pkey == NULL || EVP_PKEY_missing_parameters(pkey)) {
+        x = NULL;
+        al = SSL3_AL_FATAL;
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE,
+               SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS);
+        goto f_err;
+    }
+
+    i = ssl_cert_type(x, pkey);
+    if (i < 0) {
+        x = NULL;
+        al = SSL3_AL_FATAL;
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE,
+               SSL_R_UNKNOWN_CERTIFICATE_TYPE);
+        goto f_err;
+    }
+
+    exp_idx = ssl_cipher_get_cert_index(s->s3->tmp.new_cipher);
+    if (exp_idx >= 0 && i != exp_idx) {
+        x = NULL;
+        al = SSL_AD_ILLEGAL_PARAMETER;
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE,
+               SSL_R_WRONG_CERTIFICATE_TYPE);
+        goto f_err;
+    }
+    s->session->peer_type = i;
+
+    X509_free(s->session->peer);
+    X509_up_ref(x);
+    s->session->peer = x;
+    s->session->verify_result = s->verify_result;
+
+    x = NULL;
+    ret = MSG_PROCESS_CONTINUE_READING;
+    goto done;
+
+ f_err:
+    ssl3_send_alert(s, SSL3_AL_FATAL, al);
+ err:
+    statem_set_error(s);
+ done:
+    EVP_PKEY_free(pkey);
+    X509_free(x);
+    sk_X509_pop_free(sk, X509_free);
+    return ret;
+}
+
+enum MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
+{
+#ifndef OPENSSL_NO_RSA
+    unsigned char *q, md_buf[EVP_MAX_MD_SIZE * 2];
+#endif
+    EVP_MD_CTX md_ctx;
+    int al, j, verify_ret;
+    long alg_k, alg_a;
+    EVP_PKEY *pkey = NULL;
+    const EVP_MD *md = NULL;
+#ifndef OPENSSL_NO_RSA
+    RSA *rsa = NULL;
+#endif
+#ifndef OPENSSL_NO_DH
+    DH *dh = NULL;
+#endif
+#ifndef OPENSSL_NO_EC
+    EC_KEY *ecdh = NULL;
+    BN_CTX *bn_ctx = NULL;
+    EC_POINT *srvr_ecpoint = NULL;
+    int curve_nid = 0;
+#endif
+    PACKET save_param_start, signature;
+
+    EVP_MD_CTX_init(&md_ctx);
+
+    alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+
+    save_param_start = *pkt;
+
+#ifndef OPENSSL_NO_RSA
+    RSA_free(s->s3->peer_rsa_tmp);
+    s->s3->peer_rsa_tmp = NULL;
+#endif
+#ifndef OPENSSL_NO_DH
+    DH_free(s->s3->peer_dh_tmp);
+    s->s3->peer_dh_tmp = NULL;
+#endif
+#ifndef OPENSSL_NO_EC
+    EC_KEY_free(s->s3->peer_ecdh_tmp);
+    s->s3->peer_ecdh_tmp = NULL;
+#endif
+
+    alg_a = s->s3->tmp.new_cipher->algorithm_auth;
+
+    al = SSL_AD_DECODE_ERROR;
+
+#ifndef OPENSSL_NO_PSK
+    /* PSK ciphersuites are preceded by an identity hint */
+    if (alg_k & SSL_PSK) {
+        PACKET psk_identity_hint;
+        if (!PACKET_get_length_prefixed_2(pkt, &psk_identity_hint)) {
+            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
+            goto f_err;
+        }
+
+        /*
+         * Store PSK identity hint for later use, hint is used in
+         * ssl3_send_client_key_exchange.  Assume that the maximum length of
+         * a PSK identity hint can be as long as the maximum length of a PSK
+         * identity.
+         */
+        if (PACKET_remaining(&psk_identity_hint) > PSK_MAX_IDENTITY_LEN) {
+            al = SSL_AD_HANDSHAKE_FAILURE;
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_DATA_LENGTH_TOO_LONG);
+            goto f_err;
+        }
+
+        if (!PACKET_strndup(&psk_identity_hint,
+                            &s->session->psk_identity_hint)) {
+            al = SSL_AD_INTERNAL_ERROR;
+            goto f_err;
+        }
+    }
+
+    /* Nothing else to do for plain PSK or RSAPSK */
+    if (alg_k & (SSL_kPSK | SSL_kRSAPSK)) {
+    } else
+#endif                          /* !OPENSSL_NO_PSK */
+#ifndef OPENSSL_NO_SRP
+    if (alg_k & SSL_kSRP) {
+        PACKET prime, generator, salt, server_pub;
+        if (!PACKET_get_length_prefixed_2(pkt, &prime)
+            || !PACKET_get_length_prefixed_2(pkt, &generator)
+            || !PACKET_get_length_prefixed_1(pkt, &salt)
+            || !PACKET_get_length_prefixed_2(pkt, &server_pub)) {
+            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
+            goto f_err;
+        }
+
+        if ((s->srp_ctx.N =
+             BN_bin2bn(PACKET_data(&prime),
+                       PACKET_remaining(&prime), NULL)) == NULL
+            || (s->srp_ctx.g =
+                BN_bin2bn(PACKET_data(&generator),
+                          PACKET_remaining(&generator), NULL)) == NULL
+            || (s->srp_ctx.s =
+                BN_bin2bn(PACKET_data(&salt),
+                          PACKET_remaining(&salt), NULL)) == NULL
+            || (s->srp_ctx.B =
+                BN_bin2bn(PACKET_data(&server_pub),
+                          PACKET_remaining(&server_pub), NULL)) == NULL) {
+            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_BN_LIB);
+            goto err;
+        }
+
+        if (!srp_verify_server_param(s, &al)) {
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_BAD_SRP_PARAMETERS);
+            goto f_err;
+        }
+
+/* We must check if there is a certificate */
+        if (alg_a & (SSL_aRSA|SSL_aDSS))
+            pkey = X509_get_pubkey(s->session->peer);
+    } else
+#endif                          /* !OPENSSL_NO_SRP */
+#ifndef OPENSSL_NO_RSA
+    if (alg_k & SSL_kRSA) {
+        PACKET mod, exp;
+        /* Temporary RSA keys only allowed in export ciphersuites */
+        if (!SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)) {
+            al = SSL_AD_UNEXPECTED_MESSAGE;
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_UNEXPECTED_MESSAGE);
+            goto f_err;
+        }
+
+        if (!PACKET_get_length_prefixed_2(pkt, &mod)
+            || !PACKET_get_length_prefixed_2(pkt, &exp)) {
+            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
+            goto f_err;
+        }
+
+        if ((rsa = RSA_new()) == NULL) {
+            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+
+        if ((rsa->n = BN_bin2bn(PACKET_data(&mod), PACKET_remaining(&mod),
+                                rsa->n)) == NULL
+            || (rsa->e = BN_bin2bn(PACKET_data(&exp), PACKET_remaining(&exp),
+                                   rsa->e)) == NULL) {
+            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_BN_LIB);
+            goto err;
+        }
+
+        /* this should be because we are using an export cipher */
+        if (alg_a & SSL_aRSA)
+            pkey = X509_get_pubkey(s->session->peer);
+        else {
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+
+        if (EVP_PKEY_bits(pkey) <= SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) {
+            al = SSL_AD_UNEXPECTED_MESSAGE;
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_UNEXPECTED_MESSAGE);
+            goto f_err;
+        }
+
+        s->s3->peer_rsa_tmp = rsa;
+        rsa = NULL;
+    }
+#else                           /* OPENSSL_NO_RSA */
+    if (0) ;
+#endif
+#ifndef OPENSSL_NO_DH
+    else if (alg_k & (SSL_kDHE | SSL_kDHEPSK)) {
+        PACKET prime, generator, pub_key;
+
+        if (!PACKET_get_length_prefixed_2(pkt, &prime)
+            || !PACKET_get_length_prefixed_2(pkt, &generator)
+            || !PACKET_get_length_prefixed_2(pkt, &pub_key)) {
+            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
+            goto f_err;
+        }
+
+        if ((dh = DH_new()) == NULL) {
+            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_DH_LIB);
+            goto err;
+        }
+
+        if ((dh->p = BN_bin2bn(PACKET_data(&prime),
+                               PACKET_remaining(&prime), NULL)) == NULL
+            || (dh->g = BN_bin2bn(PACKET_data(&generator),
+                                  PACKET_remaining(&generator), NULL)) == NULL
+            || (dh->pub_key =
+                BN_bin2bn(PACKET_data(&pub_key),
+                          PACKET_remaining(&pub_key), NULL)) == NULL) {
+            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_BN_LIB);
+            goto err;
+        }
+
+        if (BN_is_zero(dh->p) || BN_is_zero(dh->g) || BN_is_zero(dh->pub_key)) {
+            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_DH_VALUE);
+            goto f_err;
+        }
+
+        if (!ssl_security(s, SSL_SECOP_TMP_DH, DH_security_bits(dh), 0, dh)) {
+            al = SSL_AD_HANDSHAKE_FAILURE;
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_DH_KEY_TOO_SMALL);
+            goto f_err;
+        }
+        if (alg_a & (SSL_aRSA|SSL_aDSS))
+            pkey = X509_get_pubkey(s->session->peer);
+        /* else anonymous DH, so no certificate or pkey. */
+
+        s->s3->peer_dh_tmp = dh;
+        dh = NULL;
+    }
+#endif                          /* !OPENSSL_NO_DH */
+
+#ifndef OPENSSL_NO_EC
+    else if (alg_k & (SSL_kECDHE | SSL_kECDHEPSK)) {
+        EC_GROUP *ngroup;
+        const EC_GROUP *group;
+        PACKET encoded_pt;
+        unsigned char *ecparams;
+
+        if ((ecdh = EC_KEY_new()) == NULL) {
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+
+        /*
+         * Extract elliptic curve parameters and the server's ephemeral ECDH
+         * public key. For now we only support named (not generic) curves and
+         * ECParameters in this case is just three bytes.
+         */
+        if (!PACKET_get_bytes(pkt, &ecparams, 3)) {
+            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_TOO_SHORT);
+            goto f_err;
+        }
+        /*
+         * Check curve is one of our preferences, if not server has sent an
+         * invalid curve. ECParameters is 3 bytes.
+         */
+        if (!tls1_check_curve(s, ecparams, 3)) {
+            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_WRONG_CURVE);
+            goto f_err;
+        }
+
+        if ((curve_nid = tls1_ec_curve_id2nid(*(ecparams + 2))) == 0) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE,
+                   SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS);
+            goto f_err;
+        }
+
+        ngroup = EC_GROUP_new_by_curve_name(curve_nid);
+        if (ngroup == NULL) {
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_EC_LIB);
+            goto err;
+        }
+        if (EC_KEY_set_group(ecdh, ngroup) == 0) {
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_EC_LIB);
+            goto err;
+        }
+        EC_GROUP_free(ngroup);
+
+        group = EC_KEY_get0_group(ecdh);
+
+        if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) &&
+            (EC_GROUP_get_degree(group) > 163)) {
+            al = SSL_AD_EXPORT_RESTRICTION;
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE,
+                   SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER);
+            goto f_err;
+        }
+
+        /* Next, get the encoded ECPoint */
+        if (((srvr_ecpoint = EC_POINT_new(group)) == NULL) ||
+            ((bn_ctx = BN_CTX_new()) == NULL)) {
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+
+        if (!PACKET_get_length_prefixed_1(pkt, &encoded_pt)) {
+            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
+            goto f_err;
+        }
+
+        if (EC_POINT_oct2point(group, srvr_ecpoint, PACKET_data(&encoded_pt),
+                               PACKET_remaining(&encoded_pt), bn_ctx) == 0) {
+            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_ECPOINT);
+            goto f_err;
+        }
+
+        /*
+         * The ECC/TLS specification does not mention the use of DSA to sign
+         * ECParameters in the server key exchange message. We do support RSA
+         * and ECDSA.
+         */
+        if (0) ;
+# ifndef OPENSSL_NO_RSA
+        else if (alg_a & SSL_aRSA)
+            pkey = X509_get_pubkey(s->session->peer);
+# endif
+# ifndef OPENSSL_NO_EC
+        else if (alg_a & SSL_aECDSA)
+            pkey = X509_get_pubkey(s->session->peer);
+# endif
+        /* else anonymous ECDH, so no certificate or pkey. */
+        EC_KEY_set_public_key(ecdh, srvr_ecpoint);
+        s->s3->peer_ecdh_tmp = ecdh;
+        ecdh = NULL;
+        BN_CTX_free(bn_ctx);
+        bn_ctx = NULL;
+        EC_POINT_free(srvr_ecpoint);
+        srvr_ecpoint = NULL;
+    } else if (alg_k) {
+        al = SSL_AD_UNEXPECTED_MESSAGE;
+        SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_UNEXPECTED_MESSAGE);
+        goto f_err;
+    }
+#endif                          /* !OPENSSL_NO_EC */
+
+    /* if it was signed, check the signature */
+    if (pkey != NULL) {
+        PACKET params;
+        /*
+         * |pkt| now points to the beginning of the signature, so the difference
+         * equals the length of the parameters.
+         */
+        if (!PACKET_get_sub_packet(&save_param_start, &params,
+                                   PACKET_remaining(&save_param_start) -
+                                   PACKET_remaining(pkt))) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            goto f_err;
+        }
+
+        if (SSL_USE_SIGALGS(s)) {
+            unsigned char *sigalgs;
+            int rv;
+            if (!PACKET_get_bytes(pkt, &sigalgs, 2)) {
+                SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_TOO_SHORT);
+                goto f_err;
+            }
+            rv = tls12_check_peer_sigalg(&md, s, sigalgs, pkey);
+            if (rv == -1)
+                goto err;
+            else if (rv == 0) {
+                goto f_err;
+            }
+#ifdef SSL_DEBUG
+            fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md));
+#endif
+        } else {
+            md = EVP_sha1();
+        }
+
+        if (!PACKET_get_length_prefixed_2(pkt, &signature)
+            || PACKET_remaining(pkt) != 0) {
+            SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
+            goto f_err;
+        }
+        j = EVP_PKEY_size(pkey);
+        if (j < 0) {
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            goto f_err;
+        }
+
+        /*
+         * Check signature length
+         */
+        if (PACKET_remaining(&signature) > (size_t)j) {
+            /* wrong packet length */
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_WRONG_SIGNATURE_LENGTH);
+            goto f_err;
+        }
+#ifndef OPENSSL_NO_RSA
+        if (pkey->type == EVP_PKEY_RSA && !SSL_USE_SIGALGS(s)) {
+            int num;
+            unsigned int size;
+
+            j = 0;
+            q = md_buf;
+            for (num = 2; num > 0; num--) {
+                EVP_MD_CTX_set_flags(&md_ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
+                EVP_DigestInit_ex(&md_ctx, (num == 2)
+                                  ? s->ctx->md5 : s->ctx->sha1, NULL);
+                EVP_DigestUpdate(&md_ctx, &(s->s3->client_random[0]),
+                                 SSL3_RANDOM_SIZE);
+                EVP_DigestUpdate(&md_ctx, &(s->s3->server_random[0]),
+                                 SSL3_RANDOM_SIZE);
+                EVP_DigestUpdate(&md_ctx, PACKET_data(&params),
+                                 PACKET_remaining(&params));
+                EVP_DigestFinal_ex(&md_ctx, q, &size);
+                q += size;
+                j += size;
+            }
+            verify_ret =
+                RSA_verify(NID_md5_sha1, md_buf, j, PACKET_data(&signature),
+                           PACKET_remaining(&signature), pkey->pkey.rsa);
+            if (verify_ret < 0) {
+                al = SSL_AD_DECRYPT_ERROR;
+                SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_BAD_RSA_DECRYPT);
+                goto f_err;
+            }
+            if (verify_ret == 0) {
+                /* bad signature */
+                al = SSL_AD_DECRYPT_ERROR;
+                SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_BAD_SIGNATURE);
+                goto f_err;
+            }
+        } else
+#endif
+        {
+            EVP_VerifyInit_ex(&md_ctx, md, NULL);
+            EVP_VerifyUpdate(&md_ctx, &(s->s3->client_random[0]),
+                             SSL3_RANDOM_SIZE);
+            EVP_VerifyUpdate(&md_ctx, &(s->s3->server_random[0]),
+                             SSL3_RANDOM_SIZE);
+            EVP_VerifyUpdate(&md_ctx, PACKET_data(&params),
+                             PACKET_remaining(&params));
+            if (EVP_VerifyFinal(&md_ctx, PACKET_data(&signature),
+                                PACKET_remaining(&signature), pkey) <= 0) {
+                /* bad signature */
+                al = SSL_AD_DECRYPT_ERROR;
+                SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_BAD_SIGNATURE);
+                goto f_err;
+            }
+        }
+    } else {
+        /* aNULL, aSRP or PSK do not need public keys */
+        if (!(alg_a & (SSL_aNULL | SSL_aSRP)) && !(alg_k & SSL_PSK)) {
+            /* Might be wrong key type, check it */
+            if (ssl3_check_cert_and_algorithm(s))
+                /* Otherwise this shouldn't happen */
+                SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        /* still data left over */
+        if (PACKET_remaining(pkt) != 0) {
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_EXTRA_DATA_IN_MESSAGE);
+            goto f_err;
+        }
+    }
+    EVP_PKEY_free(pkey);
+    EVP_MD_CTX_cleanup(&md_ctx);
+    return MSG_PROCESS_CONTINUE_READING;
+ f_err:
+    ssl3_send_alert(s, SSL3_AL_FATAL, al);
+ err:
+    EVP_PKEY_free(pkey);
+#ifndef OPENSSL_NO_RSA
+    RSA_free(rsa);
+#endif
+#ifndef OPENSSL_NO_DH
+    DH_free(dh);
+#endif
+#ifndef OPENSSL_NO_EC
+    BN_CTX_free(bn_ctx);
+    EC_POINT_free(srvr_ecpoint);
+    EC_KEY_free(ecdh);
+#endif
+    EVP_MD_CTX_cleanup(&md_ctx);
+    statem_set_error(s);
+    return MSG_PROCESS_ERROR;
+}
+
+enum MSG_PROCESS_RETURN tls_process_certificate_request(SSL *s, PACKET *pkt)
+{
+    int ret = MSG_PROCESS_ERROR;
+    unsigned int list_len, ctype_num, i, name_len;
+    X509_NAME *xn = NULL;
+    unsigned char *data;
+    unsigned char *namestart, *namebytes;
+    STACK_OF(X509_NAME) *ca_sk = NULL;
+
+    if ((ca_sk = sk_X509_NAME_new(ca_dn_cmp)) == NULL) {
+        SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    /* get the certificate types */
+    if (!PACKET_get_1(pkt, &ctype_num)
+            || !PACKET_get_bytes(pkt, &data, ctype_num)) {
+        ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+        SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, SSL_R_LENGTH_MISMATCH);
+        goto err;
+    }
+    OPENSSL_free(s->cert->ctypes);
+    s->cert->ctypes = NULL;
+    if (ctype_num > SSL3_CT_NUMBER) {
+        /* If we exceed static buffer copy all to cert structure */
+        s->cert->ctypes = OPENSSL_malloc(ctype_num);
+        if (s->cert->ctypes == NULL) {
+            SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+        memcpy(s->cert->ctypes, data, ctype_num);
+        s->cert->ctype_num = (size_t)ctype_num;
+        ctype_num = SSL3_CT_NUMBER;
+    }
+    for (i = 0; i < ctype_num; i++)
+        s->s3->tmp.ctype[i] = data[i];
+
+    if (SSL_USE_SIGALGS(s)) {
+        if (!PACKET_get_net_2(pkt, &list_len)
+                || !PACKET_get_bytes(pkt, &data, list_len)) {
+            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+            SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST,
+                   SSL_R_LENGTH_MISMATCH);
+            goto err;
+        }
+
+        /* Clear certificate digests and validity flags */
+        for (i = 0; i < SSL_PKEY_NUM; i++) {
+            s->s3->tmp.md[i] = NULL;
+            s->s3->tmp.valid_flags[i] = 0;
+        }
+        if ((list_len & 1) || !tls1_save_sigalgs(s, data, list_len)) {
+            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+            SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST,
+                   SSL_R_SIGNATURE_ALGORITHMS_ERROR);
+            goto err;
+        }
+        if (!tls1_process_sigalgs(s)) {
+            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+            SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+    }
+
+    /* get the CA RDNs */
+    if (!PACKET_get_net_2(pkt, &list_len)
+            || PACKET_remaining(pkt) != list_len) {
+        ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+        SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, SSL_R_LENGTH_MISMATCH);
+        goto err;
+    }
+
+    while (PACKET_remaining(pkt)) {
+        if (!PACKET_get_net_2(pkt, &name_len)
+                || !PACKET_get_bytes(pkt, &namebytes, name_len)) {
+            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+            SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST,
+                   SSL_R_LENGTH_MISMATCH);
+            goto err;
+        }
+
+        namestart = namebytes;
+
+        if ((xn = d2i_X509_NAME(NULL, (const unsigned char **)&namebytes,
+                                name_len)) == NULL) {
+            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+            SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, ERR_R_ASN1_LIB);
+            goto err;
+        }
+
+        if (namebytes != (namestart + name_len)) {
+            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+            SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST,
+                   SSL_R_CA_DN_LENGTH_MISMATCH);
+            goto err;
+        }
+        if (!sk_X509_NAME_push(ca_sk, xn)) {
+            SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST, ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+    }
+
+    /* we should setup a certificate to return.... */
+    s->s3->tmp.cert_req = 1;
+    s->s3->tmp.ctype_num = ctype_num;
+    sk_X509_NAME_pop_free(s->s3->tmp.ca_names, X509_NAME_free);
+    s->s3->tmp.ca_names = ca_sk;
+    ca_sk = NULL;
+
+    ret = MSG_PROCESS_CONTINUE_READING;
+    goto done;
+ err:
+    statem_set_error(s);
+ done:
+    sk_X509_NAME_pop_free(ca_sk, X509_NAME_free);
+    return ret;
+}
+
+static int ca_dn_cmp(const X509_NAME *const *a, const X509_NAME *const *b)
+{
+    return (X509_NAME_cmp(*a, *b));
+}
+
+enum MSG_PROCESS_RETURN tls_process_new_session_ticket(SSL *s, PACKET *pkt)
+{
+    int al;
+    unsigned int ticklen;
+    unsigned long ticket_lifetime_hint;
+
+    if (!PACKET_get_net_4(pkt, &ticket_lifetime_hint)
+            || !PACKET_get_net_2(pkt, &ticklen)
+            || PACKET_remaining(pkt) != ticklen) {
+        al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET, SSL_R_LENGTH_MISMATCH);
+        goto f_err;
+    }
+
+    /* Server is allowed to change its mind and send an empty ticket. */
+    if (ticklen == 0)
+        return 1;
+
+    if (s->session->session_id_length > 0) {
+        int i = s->session_ctx->session_cache_mode;
+        SSL_SESSION *new_sess;
+        /*
+         * We reused an existing session, so we need to replace it with a new
+         * one
+         */
+        if (i & SSL_SESS_CACHE_CLIENT) {
+            /*
+             * Remove the old session from the cache
+             */
+            if (i & SSL_SESS_CACHE_NO_INTERNAL_STORE) {
+                if (s->session_ctx->remove_session_cb != NULL)
+                    s->session_ctx->remove_session_cb(s->session_ctx,
+                                                      s->session);
+            } else {
+                /* We carry on if this fails */
+                SSL_CTX_remove_session(s->session_ctx, s->session);
+            }
+        }
+
+        if ((new_sess = ssl_session_dup(s->session, 0)) == 0) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_NEW_SESSION_TICKET, ERR_R_MALLOC_FAILURE);
+            goto f_err;
+        }
+
+        SSL_SESSION_free(s->session);
+        s->session = new_sess;
+    }
+
+    OPENSSL_free(s->session->tlsext_tick);
+    s->session->tlsext_ticklen = 0;
+
+    s->session->tlsext_tick = OPENSSL_malloc(ticklen);
+    if (!s->session->tlsext_tick) {
+        SSLerr(SSL_F_TLS_PROCESS_NEW_SESSION_TICKET, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+    if (!PACKET_copy_bytes(pkt, s->session->tlsext_tick, ticklen)) {
+        al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_NEW_SESSION_TICKET, SSL_R_LENGTH_MISMATCH);
+        goto f_err;
+    }
+
+    s->session->tlsext_tick_lifetime_hint = ticket_lifetime_hint;
+    s->session->tlsext_ticklen = ticklen;
+    /*
+     * There are two ways to detect a resumed ticket session. 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(s->session->tlsext_tick, ticklen,
+               s->session->session_id, &s->session->session_id_length,
+               EVP_sha256(), NULL);
+    return MSG_PROCESS_CONTINUE_READING;
+ f_err:
+    ssl3_send_alert(s, SSL3_AL_FATAL, al);
+ err:
+    statem_set_error(s);
+    return MSG_PROCESS_ERROR;
+}
+
+enum MSG_PROCESS_RETURN tls_process_cert_status(SSL *s, PACKET *pkt)
+{
+    int al;
+    unsigned long resplen;
+    unsigned int type;
+
+    if (!PACKET_get_1(pkt, &type)
+            || type != TLSEXT_STATUSTYPE_ocsp) {
+        al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_CERT_STATUS, SSL_R_UNSUPPORTED_STATUS_TYPE);
+        goto f_err;
+    }
+    if (!PACKET_get_net_3(pkt, &resplen)
+            || PACKET_remaining(pkt) != resplen) {
+        al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_CERT_STATUS, SSL_R_LENGTH_MISMATCH);
+        goto f_err;
+    }
+    OPENSSL_free(s->tlsext_ocsp_resp);
+    s->tlsext_ocsp_resp = OPENSSL_malloc(resplen);
+    if (!s->tlsext_ocsp_resp) {
+        al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_CERT_STATUS, ERR_R_MALLOC_FAILURE);
+        goto f_err;
+    }
+    if (!PACKET_copy_bytes(pkt, s->tlsext_ocsp_resp, resplen)) {
+        al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_CERT_STATUS, SSL_R_LENGTH_MISMATCH);
+        goto f_err;
+    }
+    s->tlsext_ocsp_resplen = resplen;
+    if (s->ctx->tlsext_status_cb) {
+        int ret;
+        ret = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
+        if (ret == 0) {
+            al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE;
+            SSLerr(SSL_F_TLS_PROCESS_CERT_STATUS, SSL_R_INVALID_STATUS_RESPONSE);
+            goto f_err;
+        }
+        if (ret < 0) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CERT_STATUS, ERR_R_MALLOC_FAILURE);
+            goto f_err;
+        }
+    }
+    return MSG_PROCESS_CONTINUE_READING;
+ f_err:
+    ssl3_send_alert(s, SSL3_AL_FATAL, al);
+    statem_set_error(s);
+    return MSG_PROCESS_ERROR;
+}
+
+enum MSG_PROCESS_RETURN tls_process_server_done(SSL *s, PACKET *pkt)
+{
+    if (PACKET_remaining(pkt) > 0) {
+        /* should contain no data */
+        ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+        SSLerr(SSL_F_TLS_PROCESS_SERVER_DONE, SSL_R_LENGTH_MISMATCH);
+        statem_set_error(s);
+        return MSG_PROCESS_ERROR;
+    }
+
+#ifndef OPENSSL_NO_SRP
+    if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP) {
+        if (SRP_Calc_A_param(s) <= 0) {
+            SSLerr(SSL_F_TLS_PROCESS_SERVER_DONE, SSL_R_SRP_A_CALC);
+            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+            statem_set_error(s);
+            return MSG_PROCESS_ERROR;
+        }
+    }
+#endif
+
+#ifndef OPENSSL_NO_SCTP
+    /* Only applies to renegotiation */
+    if (SSL_IS_DTLS(s) && BIO_dgram_is_sctp(SSL_get_wbio(s))
+            && s->renegotiate != 0)
+        return MSG_PROCESS_CONTINUE_PROCESSING;
+    else
+#endif
+        return MSG_PROCESS_FINISHED_READING;
+}
+
+int tls_construct_client_key_exchange(SSL *s)
+{
+    unsigned char *p;
+    int n;
+#ifndef OPENSSL_NO_PSK
+    size_t pskhdrlen = 0;
+#endif
+    unsigned long alg_k;
+#ifndef OPENSSL_NO_RSA
+    unsigned char *q;
+    EVP_PKEY *pkey = NULL;
+#endif
+#ifndef OPENSSL_NO_EC
+    EC_KEY *clnt_ecdh = NULL;
+    const EC_POINT *srvr_ecpoint = NULL;
+    EVP_PKEY *srvr_pub_pkey = NULL;
+    unsigned char *encodedPoint = NULL;
+    int encoded_pt_len = 0;
+    BN_CTX *bn_ctx = NULL;
+#endif
+    unsigned char *pms = NULL;
+    size_t pmslen = 0;
+    alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+
+    p = ssl_handshake_start(s);
+
+
+#ifndef OPENSSL_NO_PSK
+    if (alg_k & SSL_PSK) {
+        int psk_err = 1;
+        /*
+         * The callback needs PSK_MAX_IDENTITY_LEN + 1 bytes to return a
+         * \0-terminated identity. The last byte is for us for simulating
+         * strnlen.
+         */
+        char identity[PSK_MAX_IDENTITY_LEN + 1];
+        size_t identitylen;
+        unsigned char psk[PSK_MAX_PSK_LEN];
+        size_t psklen;
+
+        if (s->psk_client_callback == NULL) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                   SSL_R_PSK_NO_CLIENT_CB);
+            goto err;
+        }
+
+        memset(identity, 0, sizeof(identity));
+
+        psklen = s->psk_client_callback(s, s->session->psk_identity_hint,
+                                        identity, sizeof(identity) - 1,
+                                        psk, sizeof(psk));
+
+        if (psklen > PSK_MAX_PSK_LEN) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                   ERR_R_INTERNAL_ERROR);
+            goto psk_err;
+        } else if (psklen == 0) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                   SSL_R_PSK_IDENTITY_NOT_FOUND);
+            goto psk_err;
+        }
+
+        OPENSSL_free(s->s3->tmp.psk);
+        s->s3->tmp.psk = BUF_memdup(psk, psklen);
+        OPENSSL_cleanse(psk, psklen);
+
+        if (s->s3->tmp.psk == NULL) {
+            OPENSSL_cleanse(identity, sizeof(identity));
+            goto memerr;
+        }
+
+        s->s3->tmp.psklen = psklen;
+
+        identitylen = strlen(identity);
+        if (identitylen > PSK_MAX_IDENTITY_LEN) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                   ERR_R_INTERNAL_ERROR);
+            goto psk_err;
+        }
+        OPENSSL_free(s->session->psk_identity);
+        s->session->psk_identity = BUF_strdup(identity);
+        if (s->session->psk_identity == NULL) {
+            OPENSSL_cleanse(identity, sizeof(identity));
+            goto memerr;
+        }
+
+        s2n(identitylen, p);
+        memcpy(p, identity, identitylen);
+        pskhdrlen = 2 + identitylen;
+        p += identitylen;
+        psk_err = 0;
+psk_err:
+        OPENSSL_cleanse(identity, sizeof(identity));
+        if (psk_err != 0) {
+            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+            goto err;
+        }
+    }
+    if (alg_k & SSL_kPSK) {
+        n = 0;
+    } else
+#endif
+
+    /* Fool emacs indentation */
+    if (0) {
+    }
+#ifndef OPENSSL_NO_RSA
+    else if (alg_k & (SSL_kRSA | SSL_kRSAPSK)) {
+        RSA *rsa;
+        pmslen = SSL_MAX_MASTER_KEY_LENGTH;
+        pms = OPENSSL_malloc(pmslen);
+        if (!pms)
+            goto memerr;
+
+        if (s->session->peer == NULL) {
+            /*
+             * We should always have a server certificate with SSL_kRSA.
+             */
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                   ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+
+        if (s->s3->peer_rsa_tmp != NULL)
+            rsa = s->s3->peer_rsa_tmp;
+        else {
+            pkey = X509_get_pubkey(s->session->peer);
+            if ((pkey == NULL) || (pkey->type != EVP_PKEY_RSA)
+                || (pkey->pkey.rsa == NULL)) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                       ERR_R_INTERNAL_ERROR);
+                EVP_PKEY_free(pkey);
+                goto err;
+            }
+            rsa = pkey->pkey.rsa;
+            EVP_PKEY_free(pkey);
+        }
+
+        pms[0] = s->client_version >> 8;
+        pms[1] = s->client_version & 0xff;
+        if (RAND_bytes(pms + 2, pmslen - 2) <= 0)
+            goto err;
+
+        q = p;
+        /* Fix buf for TLS and beyond */
+        if (s->version > SSL3_VERSION)
+            p += 2;
+        n = RSA_public_encrypt(pmslen, pms, p, rsa, RSA_PKCS1_PADDING);
+# ifdef PKCS1_CHECK
+        if (s->options & SSL_OP_PKCS1_CHECK_1)
+            p[1]++;
+        if (s->options & SSL_OP_PKCS1_CHECK_2)
+            tmp_buf[0] = 0x70;
+# endif
+        if (n <= 0) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                   SSL_R_BAD_RSA_ENCRYPT);
+            goto err;
+        }
+
+        /* Fix buf for TLS and beyond */
+        if (s->version > SSL3_VERSION) {
+            s2n(n, q);
+            n += 2;
+        }
+    }
+#endif
+#ifndef OPENSSL_NO_DH
+    else if (alg_k & (SSL_kDHE | SSL_kDHr | SSL_kDHd | SSL_kDHEPSK)) {
+        DH *dh_srvr, *dh_clnt;
+        if (s->s3->peer_dh_tmp != NULL)
+            dh_srvr = s->s3->peer_dh_tmp;
+        else {
+            /* we get them from the cert */
+            EVP_PKEY *spkey = NULL;
+            dh_srvr = NULL;
+            spkey = X509_get_pubkey(s->session->peer);
+            if (spkey) {
+                dh_srvr = EVP_PKEY_get1_DH(spkey);
+                EVP_PKEY_free(spkey);
+            }
+            if (dh_srvr == NULL) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                       ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
+        }
+        if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY) {
+            /* Use client certificate key */
+            EVP_PKEY *clkey = s->cert->key->privatekey;
+            dh_clnt = NULL;
+            if (clkey)
+                dh_clnt = EVP_PKEY_get1_DH(clkey);
+            if (dh_clnt == NULL) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                       ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
+        } else {
+            /* generate a new random key */
+            if ((dh_clnt = DHparams_dup(dh_srvr)) == NULL) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB);
+                goto err;
+            }
+            if (!DH_generate_key(dh_clnt)) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB);
+                DH_free(dh_clnt);
+                goto err;
+            }
+        }
+
+        pmslen = DH_size(dh_clnt);
+        pms = OPENSSL_malloc(pmslen);
+        if (!pms)
+            goto memerr;
+
+        /*
+         * use the 'p' output buffer for the DH key, but make sure to
+         * clear it out afterwards
+         */
+
+        n = DH_compute_key(pms, dh_srvr->pub_key, dh_clnt);
+        if (s->s3->peer_dh_tmp == NULL)
+            DH_free(dh_srvr);
+
+        if (n <= 0) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB);
+            DH_free(dh_clnt);
+            goto err;
+        }
+        pmslen = n;
+
+        if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY)
+            n = 0;
+        else {
+            /* send off the data */
+            n = BN_num_bytes(dh_clnt->pub_key);
+            s2n(n, p);
+            BN_bn2bin(dh_clnt->pub_key, p);
+            n += 2;
+        }
+
+        DH_free(dh_clnt);
+    }
+#endif
+
+#ifndef OPENSSL_NO_EC
+    else if (alg_k & (SSL_kECDHE | SSL_kECDHr | SSL_kECDHe | SSL_kECDHEPSK)) {
+        const EC_GROUP *srvr_group = NULL;
+        EC_KEY *tkey;
+        int ecdh_clnt_cert = 0;
+        int field_size = 0;
+        /*
+         * Did we send out the client's ECDH share for use in premaster
+         * computation as part of client certificate? If so, set
+         * ecdh_clnt_cert to 1.
+         */
+        if ((alg_k & (SSL_kECDHr | SSL_kECDHe)) && (s->cert != NULL)) {
+            /*-
+             * XXX: For now, we do not support client
+             * authentication using ECDH certificates.
+             * To add such support, one needs to add
+             * code that checks for appropriate
+             * conditions and sets ecdh_clnt_cert to 1.
+             * For example, the cert have an ECC
+             * key on the same curve as the server's
+             * and the key should be authorized for
+             * key agreement.
+             *
+             * One also needs to add code in ssl3_connect
+             * to skip sending the certificate verify
+             * message.
+             *
+             * if ((s->cert->key->privatekey != NULL) &&
+             *     (s->cert->key->privatekey->type ==
+             *      EVP_PKEY_EC) && ...)
+             * ecdh_clnt_cert = 1;
+             */
+        }
+
+        if (s->s3->peer_ecdh_tmp != NULL) {
+            tkey = s->s3->peer_ecdh_tmp;
+        } else {
+            /* Get the Server Public Key from Cert */
+            srvr_pub_pkey = X509_get_pubkey(s->session->peer);
+            if ((srvr_pub_pkey == NULL)
+                || (srvr_pub_pkey->type != EVP_PKEY_EC)
+                || (srvr_pub_pkey->pkey.ec == NULL)) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                       ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
+
+            tkey = srvr_pub_pkey->pkey.ec;
+        }
+
+        srvr_group = EC_KEY_get0_group(tkey);
+        srvr_ecpoint = EC_KEY_get0_public_key(tkey);
+
+        if ((srvr_group == NULL) || (srvr_ecpoint == NULL)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                   ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+
+        if ((clnt_ecdh = EC_KEY_new()) == NULL) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                   ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+
+        if (!EC_KEY_set_group(clnt_ecdh, srvr_group)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
+            goto err;
+        }
+        if (ecdh_clnt_cert) {
+            /*
+             * Reuse key info from our certificate We only need our
+             * private key to perform the ECDH computation.
+             */
+            const BIGNUM *priv_key;
+            tkey = s->cert->key->privatekey->pkey.ec;
+            priv_key = EC_KEY_get0_private_key(tkey);
+            if (priv_key == NULL) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                       ERR_R_MALLOC_FAILURE);
+                goto err;
+            }
+            if (!EC_KEY_set_private_key(clnt_ecdh, priv_key)) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
+                goto err;
+            }
+        } else {
+            /* Generate a new ECDH key pair */
+            if (!(EC_KEY_generate_key(clnt_ecdh))) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                       ERR_R_ECDH_LIB);
+                goto err;
+            }
+        }
+
+        /*
+         * use the 'p' output buffer for the ECDH key, but make sure to
+         * clear it out afterwards
+         */
+
+        field_size = EC_GROUP_get_degree(srvr_group);
+        if (field_size <= 0) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
+            goto err;
+        }
+        pmslen = (field_size + 7) / 8;
+        pms = OPENSSL_malloc(pmslen);
+        if (!pms)
+            goto memerr;
+        n = ECDH_compute_key(pms, pmslen, srvr_ecpoint, clnt_ecdh, NULL);
+        if (n <= 0 || pmslen != (size_t)n) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
+            goto err;
+        }
+
+        if (ecdh_clnt_cert) {
+            /* Send empty client key exch message */
+            n = 0;
+        } else {
+            /*
+             * First check the size of encoding and allocate memory
+             * accordingly.
+             */
+            encoded_pt_len =
+                EC_POINT_point2oct(srvr_group,
+                                   EC_KEY_get0_public_key(clnt_ecdh),
+                                   POINT_CONVERSION_UNCOMPRESSED,
+                                   NULL, 0, NULL);
+
+            encodedPoint = (unsigned char *)
+                OPENSSL_malloc(encoded_pt_len * sizeof(unsigned char));
+            bn_ctx = BN_CTX_new();
+            if ((encodedPoint == NULL) || (bn_ctx == NULL)) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                       ERR_R_MALLOC_FAILURE);
+                goto err;
+            }
+
+            /* Encode the public key */
+            n = EC_POINT_point2oct(srvr_group,
+                                   EC_KEY_get0_public_key(clnt_ecdh),
+                                   POINT_CONVERSION_UNCOMPRESSED,
+                                   encodedPoint, encoded_pt_len, bn_ctx);
+
+            *p = n;         /* length of encoded point */
+            /* Encoded point will be copied here */
+            p += 1;
+            /* copy the point */
+            memcpy(p, encodedPoint, n);
+            /* increment n to account for length field */
+            n += 1;
+        }
+
+        /* Free allocated memory */
+        BN_CTX_free(bn_ctx);
+        OPENSSL_free(encodedPoint);
+        EC_KEY_free(clnt_ecdh);
+        EVP_PKEY_free(srvr_pub_pkey);
+    }
+#endif                          /* !OPENSSL_NO_EC */
+    else if (alg_k & SSL_kGOST) {
+        /* GOST key exchange message creation */
+        EVP_PKEY_CTX *pkey_ctx;
+        X509 *peer_cert;
+        size_t msglen;
+        unsigned int md_len;
+        unsigned char shared_ukm[32], tmp[256];
+        EVP_MD_CTX *ukm_hash;
+        EVP_PKEY *pub_key;
+
+        pmslen = 32;
+        pms = OPENSSL_malloc(pmslen);
+        if (!pms)
+            goto memerr;
+
+        /*
+         * Get server sertificate PKEY and create ctx from it
+         */
+        peer_cert = s->session->peer;
+        if (!peer_cert) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                   SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER);
+            goto err;
+        }
+
+        pkey_ctx = EVP_PKEY_CTX_new(pub_key =
+                                    X509_get_pubkey(peer_cert), NULL);
+        /*
+         * If we have send a certificate, and certificate key
+         *
+         * * parameters match those of server certificate, use
+         * certificate key for key exchange
+         */
+
+        /* Otherwise, generate ephemeral key pair */
+
+        EVP_PKEY_encrypt_init(pkey_ctx);
+        /* Generate session key */
+        if (RAND_bytes(pms, pmslen) <= 0) {
+            EVP_PKEY_CTX_free(pkey_ctx);
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                   ERR_R_INTERNAL_ERROR);
+            goto err;
+        };
+        /*
+         * If we have client certificate, use its secret as peer key
+         */
+        if (s->s3->tmp.cert_req && s->cert->key->privatekey) {
+            if (EVP_PKEY_derive_set_peer
+                (pkey_ctx, s->cert->key->privatekey) <= 0) {
+                /*
+                 * If there was an error - just ignore it. Ephemeral key
+                 * * would be used
+                 */
+                ERR_clear_error();
+            }
+        }
+        /*
+         * Compute shared IV and store it in algorithm-specific context
+         * data
+         */
+        ukm_hash = EVP_MD_CTX_create();
+        EVP_DigestInit(ukm_hash,
+                       EVP_get_digestbynid(NID_id_GostR3411_94));
+        EVP_DigestUpdate(ukm_hash, s->s3->client_random,
+                         SSL3_RANDOM_SIZE);
+        EVP_DigestUpdate(ukm_hash, s->s3->server_random,
+                         SSL3_RANDOM_SIZE);
+        EVP_DigestFinal_ex(ukm_hash, shared_ukm, &md_len);
+        EVP_MD_CTX_destroy(ukm_hash);
+        if (EVP_PKEY_CTX_ctrl
+            (pkey_ctx, -1, EVP_PKEY_OP_ENCRYPT, EVP_PKEY_CTRL_SET_IV, 8,
+             shared_ukm) < 0) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                   SSL_R_LIBRARY_BUG);
+            goto err;
+        }
+        /* Make GOST keytransport blob message */
+        /*
+         * Encapsulate it into sequence
+         */
+        *(p++) = V_ASN1_SEQUENCE | V_ASN1_CONSTRUCTED;
+        msglen = 255;
+        if (EVP_PKEY_encrypt(pkey_ctx, tmp, &msglen, pms, pmslen) < 0) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                   SSL_R_LIBRARY_BUG);
+            goto err;
+        }
+        if (msglen >= 0x80) {
+            *(p++) = 0x81;
+            *(p++) = msglen & 0xff;
+            n = msglen + 3;
+        } else {
+            *(p++) = msglen & 0xff;
+            n = msglen + 2;
+        }
+        memcpy(p, tmp, msglen);
+        /* Check if pubkey from client certificate was used */
+        if (EVP_PKEY_CTX_ctrl
+            (pkey_ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 2, NULL) > 0) {
+            /* Set flag "skip certificate verify" */
+            s->s3->flags |= TLS1_FLAGS_SKIP_CERT_VERIFY;
+        }
+        EVP_PKEY_CTX_free(pkey_ctx);
+        EVP_PKEY_free(pub_key);
+
+    }
+#ifndef OPENSSL_NO_SRP
+    else if (alg_k & SSL_kSRP) {
+        if (s->srp_ctx.A != NULL) {
+            /* send off the data */
+            n = BN_num_bytes(s->srp_ctx.A);
+            s2n(n, p);
+            BN_bn2bin(s->srp_ctx.A, p);
+            n += 2;
+        } else {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                   ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        OPENSSL_free(s->session->srp_username);
+        s->session->srp_username = BUF_strdup(s->srp_ctx.login);
+        if (s->session->srp_username == NULL) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+                   ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+    }
+#endif
+    else {
+        ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+#ifndef OPENSSL_NO_PSK
+    n += pskhdrlen;
+#endif
+
+    if (!ssl_set_handshake_header(s, SSL3_MT_CLIENT_KEY_EXCHANGE, n)) {
+        ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    s->s3->tmp.pms = pms;
+    s->s3->tmp.pmslen = pmslen;
+
+    return 1;
+ memerr:
+    ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+    SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+ err:
+    OPENSSL_clear_free(pms, pmslen);
+    s->s3->tmp.pms = NULL;
+#ifndef OPENSSL_NO_EC
+    BN_CTX_free(bn_ctx);
+    OPENSSL_free(encodedPoint);
+    EC_KEY_free(clnt_ecdh);
+    EVP_PKEY_free(srvr_pub_pkey);
+#endif
+#ifndef OPENSSL_NO_PSK
+    OPENSSL_clear_free(s->s3->tmp.psk, s->s3->tmp.psklen);
+    s->s3->tmp.psk = NULL;
+#endif
+    statem_set_error(s);
+    return 0;
+}
+
+int tls_client_key_exchange_post_work(SSL *s)
+{
+    unsigned char *pms = NULL;
+    size_t pmslen = 0;
+
+#ifndef OPENSSL_NO_SRP
+    /* Check for SRP */
+    if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP) {
+        if (!srp_generate_client_master_secret(s)) {
+            SSLerr(SSL_F_TLS_CLIENT_KEY_EXCHANGE_POST_WORK,
+                   ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        return 1;
+    }
+#endif
+    pms = s->s3->tmp.pms;
+    pmslen = s->s3->tmp.pmslen;
+
+    if (pms == NULL && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) {
+        ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+        SSLerr(SSL_F_TLS_CLIENT_KEY_EXCHANGE_POST_WORK, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+    if (!ssl_generate_master_secret(s, pms, pmslen, 1)) {
+        ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+        SSLerr(SSL_F_TLS_CLIENT_KEY_EXCHANGE_POST_WORK, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+#ifndef OPENSSL_NO_SCTP
+    if (SSL_IS_DTLS(s)) {
+        unsigned char sctpauthkey[64];
+        char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
+
+        /*
+         * Add new shared key for SCTP-Auth, will be ignored if no SCTP
+         * used.
+         */
+        snprintf((char *)labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL),
+                 DTLS1_SCTP_AUTH_LABEL);
+
+        if (SSL_export_keying_material(s, sctpauthkey,
+                                   sizeof(sctpauthkey), labelbuffer,
+                                   sizeof(labelbuffer), NULL, 0, 0) <= 0)
+            goto err;
+
+        BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
+                 sizeof(sctpauthkey), sctpauthkey);
+    }
+#endif
+
+    return 1;
+ err:
+    OPENSSL_clear_free(pms, pmslen);
+    s->s3->tmp.pms = NULL;
+    return 0;
+}
+
+int tls_construct_client_verify(SSL *s)
+{
+    unsigned char *p;
+    unsigned char data[MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH];
+    EVP_PKEY *pkey;
+    EVP_PKEY_CTX *pctx = NULL;
+    EVP_MD_CTX mctx;
+    unsigned u = 0;
+    unsigned long n;
+    int j;
+
+    EVP_MD_CTX_init(&mctx);
+
+    p = ssl_handshake_start(s);
+    pkey = s->cert->key->privatekey;
+/* Create context from key and test if sha1 is allowed as digest */
+    pctx = EVP_PKEY_CTX_new(pkey, NULL);
+    EVP_PKEY_sign_init(pctx);
+    if (EVP_PKEY_CTX_set_signature_md(pctx, EVP_sha1()) > 0) {
+        if (!SSL_USE_SIGALGS(s))
+            s->method->ssl3_enc->cert_verify_mac(s,
+                                                 NID_sha1,
+                                                 &(data
+                                                   [MD5_DIGEST_LENGTH]));
+    } else {
+        ERR_clear_error();
+    }
+    /*
+     * For TLS v1.2 send signature algorithm and signature using agreed
+     * digest and cached handshake records.
+     */
+    if (SSL_USE_SIGALGS(s)) {
+        long hdatalen = 0;
+        void *hdata;
+        const EVP_MD *md = s->s3->tmp.md[s->cert->key - s->cert->pkeys];
+        hdatalen = BIO_get_mem_data(s->s3->handshake_buffer, &hdata);
+        if (hdatalen <= 0 || !tls12_get_sigandhash(p, pkey, md)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        p += 2;
+#ifdef SSL_DEBUG
+        fprintf(stderr, "Using TLS 1.2 with client alg %s\n",
+                EVP_MD_name(md));
+#endif
+        if (!EVP_SignInit_ex(&mctx, md, NULL)
+            || !EVP_SignUpdate(&mctx, hdata, hdatalen)
+            || !EVP_SignFinal(&mctx, p + 2, &u, pkey)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_EVP_LIB);
+            goto err;
+        }
+        s2n(u, p);
+        n = u + 4;
+        /* Digest cached records and discard handshake buffer */
+        if (!ssl3_digest_cached_records(s, 0))
+            goto err;
+    } else
+#ifndef OPENSSL_NO_RSA
+    if (pkey->type == EVP_PKEY_RSA) {
+        s->method->ssl3_enc->cert_verify_mac(s, NID_md5, &(data[0]));
+        if (RSA_sign(NID_md5_sha1, data,
+                     MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH,
+                     &(p[2]), &u, pkey->pkey.rsa) <= 0) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_RSA_LIB);
+            goto err;
+        }
+        s2n(u, p);
+        n = u + 2;
+    } else
+#endif
+#ifndef OPENSSL_NO_DSA
+    if (pkey->type == EVP_PKEY_DSA) {
+        if (!DSA_sign(pkey->save_type,
+                      &(data[MD5_DIGEST_LENGTH]),
+                      SHA_DIGEST_LENGTH, &(p[2]),
+                      (unsigned int *)&j, pkey->pkey.dsa)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_DSA_LIB);
+            goto err;
+        }
+        s2n(j, p);
+        n = j + 2;
+    } else
+#endif
+#ifndef OPENSSL_NO_EC
+    if (pkey->type == EVP_PKEY_EC) {
+        if (!ECDSA_sign(pkey->save_type,
+                        &(data[MD5_DIGEST_LENGTH]),
+                        SHA_DIGEST_LENGTH, &(p[2]),
+                        (unsigned int *)&j, pkey->pkey.ec)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_ECDSA_LIB);
+            goto err;
+        }
+        s2n(j, p);
+        n = j + 2;
+    } else
+#endif
+    if (pkey->type == NID_id_GostR3410_2001) {
+        unsigned char signbuf[64];
+        int i;
+        size_t sigsize = 64;
+        s->method->ssl3_enc->cert_verify_mac(s,
+                                             NID_id_GostR3411_94, data);
+        if (EVP_PKEY_sign(pctx, signbuf, &sigsize, data, 32) <= 0) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        for (i = 63, j = 0; i >= 0; j++, i--) {
+            p[2 + j] = signbuf[i];
+        }
+        s2n(j, p);
+        n = j + 2;
+    } else {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+    if (!ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE_VERIFY, n)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    EVP_MD_CTX_cleanup(&mctx);
+    EVP_PKEY_CTX_free(pctx);
+    return 1;
+ err:
+    EVP_MD_CTX_cleanup(&mctx);
+    EVP_PKEY_CTX_free(pctx);
+    return 0;
+}
+
+/*
+ * Check a certificate can be used for client authentication. Currently check
+ * cert exists, if we have a suitable digest for TLS 1.2 if static DH client
+ * certificates can be used and optionally checks suitability for Suite B.
+ */
+static int ssl3_check_client_certificate(SSL *s)
+{
+    unsigned long alg_k;
+    if (!s->cert || !s->cert->key->x509 || !s->cert->key->privatekey)
+        return 0;
+    /* If no suitable signature algorithm can't use certificate */
+    if (SSL_USE_SIGALGS(s) && !s->s3->tmp.md[s->cert->key - s->cert->pkeys])
+        return 0;
+    /*
+     * If strict mode check suitability of chain before using it. This also
+     * adjusts suite B digest if necessary.
+     */
+    if (s->cert->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT &&
+        !tls1_check_chain(s, NULL, NULL, NULL, -2))
+        return 0;
+    alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+    /* See if we can use client certificate for fixed DH */
+    if (alg_k & (SSL_kDHr | SSL_kDHd)) {
+        int i = s->session->peer_type;
+        EVP_PKEY *clkey = NULL, *spkey = NULL;
+        clkey = s->cert->key->privatekey;
+        /* If client key not DH assume it can be used */
+        if (EVP_PKEY_id(clkey) != EVP_PKEY_DH)
+            return 1;
+        if (i >= 0)
+            spkey = X509_get_pubkey(s->session->peer);
+        if (spkey) {
+            /* Compare server and client parameters */
+            i = EVP_PKEY_cmp_parameters(clkey, spkey);
+            EVP_PKEY_free(spkey);
+            if (i != 1)
+                return 0;
+        }
+        s->s3->flags |= TLS1_FLAGS_SKIP_CERT_VERIFY;
+    }
+    return 1;
+}
+
+enum WORK_STATE tls_prepare_client_certificate(SSL *s, enum WORK_STATE wst)
+{
+    X509 *x509 = NULL;
+    EVP_PKEY *pkey = NULL;
+    int i;
+
+    if (wst == WORK_MORE_A) {
+        /* Let cert callback update client certificates if required */
+        if (s->cert->cert_cb) {
+            i = s->cert->cert_cb(s, s->cert->cert_cb_arg);
+            if (i < 0) {
+                s->rwstate = SSL_X509_LOOKUP;
+                return WORK_MORE_A;
+            }
+            if (i == 0) {
+                ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+                statem_set_error(s);
+                return 0;
+            }
+            s->rwstate = SSL_NOTHING;
+        }
+        if (ssl3_check_client_certificate(s))
+            return WORK_FINISHED_CONTINUE;
+
+        /* Fall through to WORK_MORE_B */
+        wst = WORK_MORE_B;
+    }
+
+    /* We need to get a client cert */
+    if (wst == WORK_MORE_B) {
+        /*
+         * If we get an error, we need to ssl->rwstate=SSL_X509_LOOKUP;
+         * return(-1); We then get retied later
+         */
+        i = ssl_do_client_cert_cb(s, &x509, &pkey);
+        if (i < 0) {
+            s->rwstate = SSL_X509_LOOKUP;
+            return WORK_MORE_B;
+        }
+        s->rwstate = SSL_NOTHING;
+        if ((i == 1) && (pkey != NULL) && (x509 != NULL)) {
+            if (!SSL_use_certificate(s, x509) || !SSL_use_PrivateKey(s, pkey))
+                i = 0;
+        } else if (i == 1) {
+            i = 0;
+            SSLerr(SSL_F_TLS_PREPARE_CLIENT_CERTIFICATE,
+                   SSL_R_BAD_DATA_RETURNED_BY_CALLBACK);
+        }
+
+        X509_free(x509);
+        EVP_PKEY_free(pkey);
+        if (i && !ssl3_check_client_certificate(s))
+            i = 0;
+        if (i == 0) {
+            if (s->version == SSL3_VERSION) {
+                s->s3->tmp.cert_req = 0;
+                ssl3_send_alert(s, SSL3_AL_WARNING, SSL_AD_NO_CERTIFICATE);
+                return WORK_FINISHED_CONTINUE;
+            } else {
+                s->s3->tmp.cert_req = 2;
+                if (!ssl3_digest_cached_records(s, 0)) {
+                    ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+                    statem_set_error(s);
+                    return 0;
+                }
+            }
+        }
+
+        return WORK_FINISHED_CONTINUE;
+    }
+
+    /* Shouldn't ever get here */
+    return WORK_ERROR;
+}
+
+int tls_construct_client_certificate(SSL *s)
+{
+    if (!ssl3_output_cert_chain(s,
+                                (s->s3->tmp.cert_req ==
+                                 2) ? NULL : s->cert->key)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_CERTIFICATE, ERR_R_INTERNAL_ERROR);
+        ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+        statem_set_error(s);
+        return 0;
+    }
+
+    return 1;
+}
+
+#define has_bits(i,m)   (((i)&(m)) == (m))
+
+int ssl3_check_cert_and_algorithm(SSL *s)
+{
+    int i, idx;
+    long alg_k, alg_a;
+    EVP_PKEY *pkey = NULL;
+    int pkey_bits;
+#ifndef OPENSSL_NO_RSA
+    RSA *rsa;
+#endif
+#ifndef OPENSSL_NO_DH
+    DH *dh;
+#endif
+    int al = SSL_AD_HANDSHAKE_FAILURE;
+
+    alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+    alg_a = s->s3->tmp.new_cipher->algorithm_auth;
+
+    /* we don't have a certificate */
+    if ((alg_a & SSL_aNULL) || (alg_k & SSL_kPSK))
+        return (1);
+#ifndef OPENSSL_NO_RSA
+    rsa = s->s3->peer_rsa_tmp;
+#endif
+#ifndef OPENSSL_NO_DH
+    dh = s->s3->peer_dh_tmp;
+#endif
+
+    /* This is the passed certificate */
+
+    idx = s->session->peer_type;
+#ifndef OPENSSL_NO_EC
+    if (idx == SSL_PKEY_ECC) {
+        if (ssl_check_srvr_ecc_cert_and_alg(s->session->peer, s) == 0) {
+            /* check failed */
+            SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, SSL_R_BAD_ECC_CERT);
+            goto f_err;
+        } else {
+            return 1;
+        }
+    } else if (alg_a & SSL_aECDSA) {
+        SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
+               SSL_R_MISSING_ECDSA_SIGNING_CERT);
+        goto f_err;
+    } else if (alg_k & (SSL_kECDHr | SSL_kECDHe)) {
+        SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, SSL_R_MISSING_ECDH_CERT);
+        goto f_err;
+    }
+#endif
+    pkey = X509_get_pubkey(s->session->peer);
+    pkey_bits = EVP_PKEY_bits(pkey);
+    i = X509_certificate_type(s->session->peer, pkey);
+    EVP_PKEY_free(pkey);
+
+    /* Check that we have a certificate if we require one */
+    if ((alg_a & SSL_aRSA) && !has_bits(i, EVP_PK_RSA | EVP_PKT_SIGN)) {
+        SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
+               SSL_R_MISSING_RSA_SIGNING_CERT);
+        goto f_err;
+    }
+#ifndef OPENSSL_NO_DSA
+    else if ((alg_a & SSL_aDSS) && !has_bits(i, EVP_PK_DSA | EVP_PKT_SIGN)) {
+        SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
+               SSL_R_MISSING_DSA_SIGNING_CERT);
+        goto f_err;
+    }
+#endif
+#ifndef OPENSSL_NO_RSA
+    if (alg_k & (SSL_kRSA | SSL_kRSAPSK)) {
+        if (!SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) &&
+            !has_bits(i, EVP_PK_RSA | EVP_PKT_ENC)) {
+            SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
+                   SSL_R_MISSING_RSA_ENCRYPTING_CERT);
+            goto f_err;
+        } else if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)) {
+            if (pkey_bits <= SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) {
+                if (!has_bits(i, EVP_PK_RSA | EVP_PKT_ENC)) {
+                    SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
+                           SSL_R_MISSING_RSA_ENCRYPTING_CERT);
+                    goto f_err;
+                }
+                if (rsa != NULL) {
+                    /* server key exchange is not allowed. */
+                    al = SSL_AD_INTERNAL_ERROR;
+                    SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, ERR_R_INTERNAL_ERROR);
+                    goto f_err;
+                }
+            }
+        }
+    }
+#endif
+#ifndef OPENSSL_NO_DH
+    if ((alg_k & SSL_kDHE) && (dh == NULL)) {
+        al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, ERR_R_INTERNAL_ERROR);
+        goto f_err;
+    } else if ((alg_k & SSL_kDHr) && !SSL_USE_SIGALGS(s) &&
+               !has_bits(i, EVP_PK_DH | EVP_PKS_RSA)) {
+        SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
+               SSL_R_MISSING_DH_RSA_CERT);
+        goto f_err;
+    }
+# ifndef OPENSSL_NO_DSA
+    else if ((alg_k & SSL_kDHd) && !SSL_USE_SIGALGS(s) &&
+             !has_bits(i, EVP_PK_DH | EVP_PKS_DSA)) {
+        SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
+               SSL_R_MISSING_DH_DSA_CERT);
+        goto f_err;
+    }
+# endif
+#endif
+
+    if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) &&
+        pkey_bits > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) {
+#ifndef OPENSSL_NO_RSA
+        if (alg_k & SSL_kRSA) {
+            if (rsa == NULL) {
+                SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
+                       SSL_R_MISSING_EXPORT_TMP_RSA_KEY);
+                goto f_err;
+            } else if (RSA_bits(rsa) >
+                SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) {
+                /* We have a temporary RSA key but it's too large. */
+                al = SSL_AD_EXPORT_RESTRICTION;
+                SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
+                       SSL_R_MISSING_EXPORT_TMP_RSA_KEY);
+                goto f_err;
+            }
+        } else
+#endif
+#ifndef OPENSSL_NO_DH
+        if (alg_k & SSL_kDHE) {
+            if (DH_bits(dh) >
+                SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) {
+                /* We have a temporary DH key but it's too large. */
+                al = SSL_AD_EXPORT_RESTRICTION;
+                SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
+                       SSL_R_MISSING_EXPORT_TMP_DH_KEY);
+                goto f_err;
+            }
+        } else if (alg_k & (SSL_kDHr | SSL_kDHd)) {
+            /* The cert should have had an export DH key. */
+            al = SSL_AD_EXPORT_RESTRICTION;
+            SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
+                   SSL_R_MISSING_EXPORT_TMP_DH_KEY);
+                goto f_err;
+        } else
+#endif
+        {
+            SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
+                   SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE);
+            goto f_err;
+        }
+    }
+    return (1);
+ f_err:
+    ssl3_send_alert(s, SSL3_AL_FATAL, al);
+    return (0);
+}
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+int tls_construct_next_proto(SSL *s)
+{
+    unsigned int len, padding_len;
+    unsigned char *d;
+
+    len = s->next_proto_negotiated_len;
+    padding_len = 32 - ((len + 2) % 32);
+    d = (unsigned char *)s->init_buf->data;
+    d[4] = len;
+    memcpy(d + 5, s->next_proto_negotiated, len);
+    d[5 + len] = padding_len;
+    memset(d + 6 + len, 0, padding_len);
+    *(d++) = SSL3_MT_NEXT_PROTO;
+    l2n3(2 + len + padding_len, d);
+    s->init_num = 4 + 2 + len + padding_len;
+    s->init_off = 0;
+
+    return 1;
+}
+#endif
+
+int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey)
+{
+    int i = 0;
+#ifndef OPENSSL_NO_ENGINE
+    if (s->ctx->client_cert_engine) {
+        i = ENGINE_load_ssl_client_cert(s->ctx->client_cert_engine, s,
+                                        SSL_get_client_CA_list(s),
+                                        px509, ppkey, NULL, NULL, NULL);
+        if (i != 0)
+            return i;
+    }
+#endif
+    if (s->ctx->client_cert_cb)
+        i = s->ctx->client_cert_cb(s, px509, ppkey);
+    return i;
+}
+
+int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk,
+                             unsigned char *p)
+{
+    int i, j = 0;
+    SSL_CIPHER *c;
+    unsigned char *q;
+    int empty_reneg_info_scsv = !s->renegotiate;
+    /* Set disabled masks for this session */
+    ssl_set_client_disabled(s);
+
+    if (sk == NULL)
+        return (0);
+    q = p;
+
+    for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) {
+        c = sk_SSL_CIPHER_value(sk, i);
+        /* Skip disabled ciphers */
+        if (ssl_cipher_disabled(s, c, SSL_SECOP_CIPHER_SUPPORTED))
+            continue;
+#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL
+        if (c->id == SSL3_CK_SCSV) {
+            if (!empty_reneg_info_scsv)
+                continue;
+            else
+                empty_reneg_info_scsv = 0;
+        }
+#endif
+        j = s->method->put_cipher_by_char(c, p);
+        p += j;
+    }
+    /*
+     * If p == q, no ciphers; caller indicates an error. Otherwise, add
+     * applicable SCSVs.
+     */
+    if (p != q) {
+        if (empty_reneg_info_scsv) {
+            static SSL_CIPHER scsv = {
+                0, NULL, SSL3_CK_SCSV, 0, 0, 0, 0, 0, 0, 0, 0, 0
+            };
+            j = s->method->put_cipher_by_char(&scsv, p);
+            p += j;
+#ifdef OPENSSL_RI_DEBUG
+            fprintf(stderr,
+                    "TLS_EMPTY_RENEGOTIATION_INFO_SCSV sent by client\n");
+#endif
+        }
+        if (s->mode & SSL_MODE_SEND_FALLBACK_SCSV) {
+            static SSL_CIPHER scsv = {
+                0, NULL, SSL3_CK_FALLBACK_SCSV, 0, 0, 0, 0, 0, 0, 0, 0, 0
+            };
+            j = s->method->put_cipher_by_char(&scsv, p);
+            p += j;
+        }
+    }
+
+    return (p - q);
+}
diff --git a/ssl/statem/statem_dtls.c b/ssl/statem/statem_dtls.c
new file mode 100644 (file)
index 0000000..e13ed8d
--- /dev/null
@@ -0,0 +1,1283 @@
+/* ssl/statem/statem_dtls.c */
+/*
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2005 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include "../ssl_locl.h"
+#include <openssl/buffer.h>
+#include <openssl/rand.h>
+#include <openssl/objects.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+#define RSMBLY_BITMASK_SIZE(msg_len) (((msg_len) + 7) / 8)
+
+#define RSMBLY_BITMASK_MARK(bitmask, start, end) { \
+                        if ((end) - (start) <= 8) { \
+                                long ii; \
+                                for (ii = (start); ii < (end); ii++) bitmask[((ii) >> 3)] |= (1 << ((ii) & 7)); \
+                        } else { \
+                                long ii; \
+                                bitmask[((start) >> 3)] |= bitmask_start_values[((start) & 7)]; \
+                                for (ii = (((start) >> 3) + 1); ii < ((((end) - 1)) >> 3); ii++) bitmask[ii] = 0xff; \
+                                bitmask[(((end) - 1) >> 3)] |= bitmask_end_values[((end) & 7)]; \
+                        } }
+
+#define RSMBLY_BITMASK_IS_COMPLETE(bitmask, msg_len, is_complete) { \
+                        long ii; \
+                        OPENSSL_assert((msg_len) > 0); \
+                        is_complete = 1; \
+                        if (bitmask[(((msg_len) - 1) >> 3)] != bitmask_end_values[((msg_len) & 7)]) is_complete = 0; \
+                        if (is_complete) for (ii = (((msg_len) - 1) >> 3) - 1; ii >= 0 ; ii--) \
+                                if (bitmask[ii] != 0xff) { is_complete = 0; break; } }
+
+static unsigned char bitmask_start_values[] =
+    { 0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80 };
+static unsigned char bitmask_end_values[] =
+    { 0xff, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f };
+
+static void dtls1_fix_message_header(SSL *s, unsigned long frag_off,
+                                     unsigned long frag_len);
+static unsigned char *dtls1_write_message_header(SSL *s, unsigned char *p);
+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 dtls_get_reassembled_message(SSL *s, long *len);
+
+static hm_fragment *dtls1_hm_fragment_new(unsigned long frag_len,
+                                          int reassembly)
+{
+    hm_fragment *frag = NULL;
+    unsigned char *buf = NULL;
+    unsigned char *bitmask = NULL;
+
+    frag = OPENSSL_malloc(sizeof(*frag));
+    if (frag == NULL)
+        return NULL;
+
+    if (frag_len) {
+        buf = OPENSSL_malloc(frag_len);
+        if (buf == NULL) {
+            OPENSSL_free(frag);
+            return NULL;
+        }
+    }
+
+    /* zero length fragment gets zero frag->fragment */
+    frag->fragment = buf;
+
+    /* Initialize reassembly bitmask if necessary */
+    if (reassembly) {
+        bitmask = OPENSSL_zalloc(RSMBLY_BITMASK_SIZE(frag_len));
+        if (bitmask == NULL) {
+            OPENSSL_free(buf);
+            OPENSSL_free(frag);
+            return NULL;
+        }
+    }
+
+    frag->reassembly = bitmask;
+
+    return frag;
+}
+
+void dtls1_hm_fragment_free(hm_fragment *frag)
+{
+    if (!frag)
+        return;
+    if (frag->msg_header.is_ccs) {
+        EVP_CIPHER_CTX_free(frag->msg_header.
+                            saved_retransmit_state.enc_write_ctx);
+        EVP_MD_CTX_destroy(frag->msg_header.
+                           saved_retransmit_state.write_hash);
+    }
+    OPENSSL_free(frag->fragment);
+    OPENSSL_free(frag->reassembly);
+    OPENSSL_free(frag);
+}
+
+/*
+ * send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or
+ * SSL3_RT_CHANGE_CIPHER_SPEC)
+ */
+int dtls1_do_write(SSL *s, int type)
+{
+    int ret;
+    unsigned int curr_mtu;
+    int retry = 1;
+    unsigned int len, frag_off, mac_size, blocksize, used_len;
+
+    if (!dtls1_query_mtu(s))
+        return -1;
+
+    OPENSSL_assert(s->d1->mtu >= dtls1_min_mtu(s)); /* should have something
+                                                     * reasonable now */
+
+    if (s->init_off == 0 && type == SSL3_RT_HANDSHAKE)
+        OPENSSL_assert(s->init_num ==
+                       (int)s->d1->w_msg_hdr.msg_len +
+                       DTLS1_HM_HEADER_LENGTH);
+
+    if (s->write_hash) {
+        if (s->enc_write_ctx
+            && ((EVP_CIPHER_CTX_mode(s->enc_write_ctx) == EVP_CIPH_GCM_MODE) ||
+                (EVP_CIPHER_CTX_mode(s->enc_write_ctx) == EVP_CIPH_CCM_MODE)))
+            mac_size = 0;
+        else
+            mac_size = EVP_MD_CTX_size(s->write_hash);
+    } else
+        mac_size = 0;
+
+    if (s->enc_write_ctx &&
+        (EVP_CIPHER_CTX_mode(s->enc_write_ctx) == EVP_CIPH_CBC_MODE))
+        blocksize = 2 * EVP_CIPHER_block_size(s->enc_write_ctx->cipher);
+    else
+        blocksize = 0;
+
+    frag_off = 0;
+    /* s->init_num shouldn't ever be < 0...but just in case */
+    while (s->init_num > 0) {
+        used_len = BIO_wpending(SSL_get_wbio(s)) + DTLS1_RT_HEADER_LENGTH
+            + mac_size + blocksize;
+        if (s->d1->mtu > used_len)
+            curr_mtu = s->d1->mtu - used_len;
+        else
+            curr_mtu = 0;
+
+        if (curr_mtu <= DTLS1_HM_HEADER_LENGTH) {
+            /*
+             * grr.. we could get an error if MTU picked was wrong
+             */
+            ret = BIO_flush(SSL_get_wbio(s));
+            if (ret <= 0)
+                return ret;
+            used_len = DTLS1_RT_HEADER_LENGTH + mac_size + blocksize;
+            if (s->d1->mtu > used_len + DTLS1_HM_HEADER_LENGTH) {
+                curr_mtu = s->d1->mtu - used_len;
+            } else {
+                /* Shouldn't happen */
+                return -1;
+            }
+        }
+
+        /*
+         * We just checked that s->init_num > 0 so this cast should be safe
+         */
+        if (((unsigned int)s->init_num) > curr_mtu)
+            len = curr_mtu;
+        else
+            len = s->init_num;
+
+        /* Shouldn't ever happen */
+        if (len > INT_MAX)
+            len = INT_MAX;
+
+        /*
+         * XDTLS: this function is too long.  split out the CCS part
+         */
+        if (type == SSL3_RT_HANDSHAKE) {
+            if (s->init_off != 0) {
+                OPENSSL_assert(s->init_off > DTLS1_HM_HEADER_LENGTH);
+                s->init_off -= DTLS1_HM_HEADER_LENGTH;
+                s->init_num += DTLS1_HM_HEADER_LENGTH;
+
+                /*
+                 * We just checked that s->init_num > 0 so this cast should
+                 * be safe
+                 */
+                if (((unsigned int)s->init_num) > curr_mtu)
+                    len = curr_mtu;
+                else
+                    len = s->init_num;
+            }
+
+            /* Shouldn't ever happen */
+            if (len > INT_MAX)
+                len = INT_MAX;
+
+            if (len < DTLS1_HM_HEADER_LENGTH) {
+                /*
+                 * len is so small that we really can't do anything sensible
+                 * so fail
+                 */
+                return -1;
+            }
+            dtls1_fix_message_header(s, frag_off,
+                                     len - DTLS1_HM_HEADER_LENGTH);
+
+            dtls1_write_message_header(s,
+                                       (unsigned char *)&s->init_buf->
+                                       data[s->init_off]);
+        }
+
+        ret = dtls1_write_bytes(s, type, &s->init_buf->data[s->init_off],
+                                len);
+        if (ret < 0) {
+            /*
+             * might need to update MTU here, but we don't know which
+             * previous packet caused the failure -- so can't really
+             * retransmit anything.  continue as if everything is fine and
+             * wait for an alert to handle the retransmit
+             */
+            if (retry && BIO_ctrl(SSL_get_wbio(s),
+                                  BIO_CTRL_DGRAM_MTU_EXCEEDED, 0, NULL) > 0) {
+                if (!(SSL_get_options(s) & SSL_OP_NO_QUERY_MTU)) {
+                    if (!dtls1_query_mtu(s))
+                        return -1;
+                    /* Have one more go */
+                    retry = 0;
+                } else
+                    return -1;
+            } else {
+                return (-1);
+            }
+        } else {
+
+            /*
+             * bad if this assert fails, only part of the handshake message
+             * got sent.  but why would this happen?
+             */
+            OPENSSL_assert(len == (unsigned int)ret);
+
+            if (type == SSL3_RT_HANDSHAKE && !s->d1->retransmitting) {
+                /*
+                 * should not be done for 'Hello Request's, but in that case
+                 * we'll ignore the result anyway
+                 */
+                unsigned char *p =
+                    (unsigned char *)&s->init_buf->data[s->init_off];
+                const struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
+                int xlen;
+
+                if (frag_off == 0 && s->version != DTLS1_BAD_VER) {
+                    /*
+                     * reconstruct message header is if it is being sent in
+                     * single fragment
+                     */
+                    *p++ = msg_hdr->type;
+                    l2n3(msg_hdr->msg_len, p);
+                    s2n(msg_hdr->seq, p);
+                    l2n3(0, p);
+                    l2n3(msg_hdr->msg_len, p);
+                    p -= DTLS1_HM_HEADER_LENGTH;
+                    xlen = ret;
+                } else {
+                    p += DTLS1_HM_HEADER_LENGTH;
+                    xlen = ret - DTLS1_HM_HEADER_LENGTH;
+                }
+
+                ssl3_finish_mac(s, p, xlen);
+            }
+
+            if (ret == s->init_num) {
+                if (s->msg_callback)
+                    s->msg_callback(1, s->version, type, s->init_buf->data,
+                                    (size_t)(s->init_off + s->init_num), s,
+                                    s->msg_callback_arg);
+
+                s->init_off = 0; /* done writing this message */
+                s->init_num = 0;
+
+                return (1);
+            }
+            s->init_off += ret;
+            s->init_num -= ret;
+            frag_off += (ret -= DTLS1_HM_HEADER_LENGTH);
+        }
+    }
+    return (0);
+}
+
+int dtls_get_message(SSL *s, int *mt, unsigned long *len)
+{
+    struct hm_header_st *msg_hdr;
+    unsigned char *p;
+    unsigned long msg_len;
+    int ok;
+    long tmplen;
+
+    msg_hdr = &s->d1->r_msg_hdr;
+    memset(msg_hdr, 0, sizeof(*msg_hdr));
+
+ again:
+    ok = dtls_get_reassembled_message(s, &tmplen);
+    if (tmplen == DTLS1_HM_BAD_FRAGMENT
+        || tmplen == DTLS1_HM_FRAGMENT_RETRY) {
+        /* bad fragment received */
+        goto again;
+    } else if (tmplen <= 0 && !ok) {
+        return 0;
+    }
+
+    *mt = s->s3->tmp.message_type;
+
+    p = (unsigned char *)s->init_buf->data;
+
+    if (*mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+        if (s->msg_callback) {
+            s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC,
+                            p, 1, s, s->msg_callback_arg);
+        }
+        /*
+         * This isn't a real handshake message so skip the processing below.
+         */
+        *len = (unsigned long)tmplen;
+        return 1;
+    }
+
+    msg_len = msg_hdr->msg_len;
+
+    /* reconstruct message header */
+    *(p++) = msg_hdr->type;
+    l2n3(msg_len, p);
+    s2n(msg_hdr->seq, p);
+    l2n3(0, p);
+    l2n3(msg_len, p);
+    if (s->version != DTLS1_BAD_VER) {
+        p -= DTLS1_HM_HEADER_LENGTH;
+        msg_len += DTLS1_HM_HEADER_LENGTH;
+    }
+
+    ssl3_finish_mac(s, p, msg_len);
+    if (s->msg_callback)
+        s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
+                        p, msg_len, s, s->msg_callback_arg);
+
+    memset(msg_hdr, 0, sizeof(*msg_hdr));
+
+    s->d1->handshake_read_seq++;
+
+
+    s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
+    *len = s->init_num;
+
+    return 1;
+}
+
+static int dtls1_preprocess_fragment(SSL *s, struct hm_header_st *msg_hdr)
+{
+    size_t frag_off, frag_len, msg_len;
+
+    msg_len = msg_hdr->msg_len;
+    frag_off = msg_hdr->frag_off;
+    frag_len = msg_hdr->frag_len;
+
+    /* sanity checking */
+    if ((frag_off + frag_len) > msg_len) {
+        SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT, SSL_R_EXCESSIVE_MESSAGE_SIZE);
+        return SSL_AD_ILLEGAL_PARAMETER;
+    }
+
+    if (s->d1->r_msg_hdr.frag_off == 0) { /* first fragment */
+        /*
+         * msg_len is limited to 2^24, but is effectively checked against max
+         * above
+         */
+        if (!BUF_MEM_grow_clean
+            (s->init_buf, msg_len + DTLS1_HM_HEADER_LENGTH)) {
+            SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT, ERR_R_BUF_LIB);
+            return SSL_AD_INTERNAL_ERROR;
+        }
+
+        s->s3->tmp.message_size = msg_len;
+        s->d1->r_msg_hdr.msg_len = msg_len;
+        s->s3->tmp.message_type = msg_hdr->type;
+        s->d1->r_msg_hdr.type = msg_hdr->type;
+        s->d1->r_msg_hdr.seq = msg_hdr->seq;
+    } else if (msg_len != s->d1->r_msg_hdr.msg_len) {
+        /*
+         * They must be playing with us! BTW, failure to enforce upper limit
+         * would open possibility for buffer overrun.
+         */
+        SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT, SSL_R_EXCESSIVE_MESSAGE_SIZE);
+        return SSL_AD_ILLEGAL_PARAMETER;
+    }
+
+    return 0;                   /* no error */
+}
+
+static int dtls1_retrieve_buffered_fragment(SSL *s, int *ok)
+{
+    /*-
+     * (0) check whether the desired fragment is available
+     * if so:
+     * (1) copy over the fragment to s->init_buf->data[]
+     * (2) update s->init_num
+     */
+    pitem *item;
+    hm_fragment *frag;
+    int al;
+
+    *ok = 0;
+    item = pqueue_peek(s->d1->buffered_messages);
+    if (item == NULL)
+        return 0;
+
+    frag = (hm_fragment *)item->data;
+
+    /* Don't return if reassembly still in progress */
+    if (frag->reassembly != NULL)
+        return 0;
+
+    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);
+
+        if (al == 0) {          /* no alert */
+            unsigned char *p =
+                (unsigned char *)s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
+            memcpy(&p[frag->msg_header.frag_off], frag->fragment,
+                   frag->msg_header.frag_len);
+        }
+
+        dtls1_hm_fragment_free(frag);
+        pitem_free(item);
+
+        if (al == 0) {
+            *ok = 1;
+            return frag_len;
+        }
+
+        ssl3_send_alert(s, SSL3_AL_FATAL, al);
+        s->init_num = 0;
+        *ok = 0;
+        return -1;
+    } else
+        return 0;
+}
+
+/*
+ * dtls1_max_handshake_message_len returns the maximum number of bytes
+ * permitted in a DTLS handshake message for |s|. The minimum is 16KB, but
+ * may be greater if the maximum certificate list size requires it.
+ */
+static unsigned long dtls1_max_handshake_message_len(const SSL *s)
+{
+    unsigned long max_len =
+        DTLS1_HM_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH;
+    if (max_len < (unsigned long)s->max_cert_list)
+        return s->max_cert_list;
+    return max_len;
+}
+
+static int
+dtls1_reassemble_fragment(SSL *s, const struct hm_header_st *msg_hdr, int *ok)
+{
+    hm_fragment *frag = NULL;
+    pitem *item = NULL;
+    int i = -1, is_complete;
+    unsigned char seq64be[8];
+    unsigned long frag_len = msg_hdr->frag_len;
+
+    if ((msg_hdr->frag_off + frag_len) > msg_hdr->msg_len ||
+        msg_hdr->msg_len > dtls1_max_handshake_message_len(s))
+        goto err;
+
+    if (frag_len == 0)
+        return DTLS1_HM_FRAGMENT_RETRY;
+
+    /* Try to find item in queue */
+    memset(seq64be, 0, sizeof(seq64be));
+    seq64be[6] = (unsigned char)(msg_hdr->seq >> 8);
+    seq64be[7] = (unsigned char)msg_hdr->seq;
+    item = pqueue_find(s->d1->buffered_messages, seq64be);
+
+    if (item == NULL) {
+        frag = dtls1_hm_fragment_new(msg_hdr->msg_len, 1);
+        if (frag == NULL)
+            goto err;
+        memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr));
+        frag->msg_header.frag_len = frag->msg_header.msg_len;
+        frag->msg_header.frag_off = 0;
+    } else {
+        frag = (hm_fragment *)item->data;
+        if (frag->msg_header.msg_len != msg_hdr->msg_len) {
+            item = NULL;
+            frag = NULL;
+            goto err;
+        }
+    }
+
+    /*
+     * If message is already reassembled, this must be a retransmit and can
+     * be dropped. In this case item != NULL and so frag does not need to be
+     * freed.
+     */
+    if (frag->reassembly == NULL) {
+        unsigned char devnull[256];
+
+        while (frag_len) {
+            i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL,
+                                          devnull,
+                                          frag_len >
+                                          sizeof(devnull) ? sizeof(devnull) :
+                                          frag_len, 0);
+            if (i <= 0)
+                goto err;
+            frag_len -= i;
+        }
+        return DTLS1_HM_FRAGMENT_RETRY;
+    }
+
+    /* read the body of the fragment (header has already been read */
+    i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL,
+                                  frag->fragment + msg_hdr->frag_off,
+                                  frag_len, 0);
+    if ((unsigned long)i != frag_len)
+        i = -1;
+    if (i <= 0)
+        goto err;
+
+    RSMBLY_BITMASK_MARK(frag->reassembly, (long)msg_hdr->frag_off,
+                        (long)(msg_hdr->frag_off + frag_len));
+
+    RSMBLY_BITMASK_IS_COMPLETE(frag->reassembly, (long)msg_hdr->msg_len,
+                               is_complete);
+
+    if (is_complete) {
+        OPENSSL_free(frag->reassembly);
+        frag->reassembly = NULL;
+    }
+
+    if (item == NULL) {
+        item = pitem_new(seq64be, frag);
+        if (item == NULL) {
+            i = -1;
+            goto err;
+        }
+
+        item = pqueue_insert(s->d1->buffered_messages, item);
+        /*
+         * pqueue_insert fails iff a duplicate item is inserted. However,
+         * |item| cannot be a duplicate. If it were, |pqueue_find|, above,
+         * would have returned it and control would never have reached this
+         * branch.
+         */
+        OPENSSL_assert(item != NULL);
+    }
+
+    return DTLS1_HM_FRAGMENT_RETRY;
+
+ err:
+    if (item == NULL)
+        dtls1_hm_fragment_free(frag);
+    *ok = 0;
+    return i;
+}
+
+static int
+dtls1_process_out_of_seq_message(SSL *s, const struct hm_header_st *msg_hdr,
+                                 int *ok)
+{
+    int i = -1;
+    hm_fragment *frag = NULL;
+    pitem *item = NULL;
+    unsigned char seq64be[8];
+    unsigned long frag_len = msg_hdr->frag_len;
+
+    if ((msg_hdr->frag_off + frag_len) > msg_hdr->msg_len)
+        goto err;
+
+    /* Try to find item in queue, to prevent duplicate entries */
+    memset(seq64be, 0, sizeof(seq64be));
+    seq64be[6] = (unsigned char)(msg_hdr->seq >> 8);
+    seq64be[7] = (unsigned char)msg_hdr->seq;
+    item = pqueue_find(s->d1->buffered_messages, seq64be);
+
+    /*
+     * If we already have an entry and this one is a fragment, don't discard
+     * it and rather try to reassemble it.
+     */
+    if (item != NULL && frag_len != msg_hdr->msg_len)
+        item = NULL;
+
+    /*
+     * 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];
+
+        while (frag_len) {
+            i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL,
+                                          devnull,
+                                          frag_len >
+                                          sizeof(devnull) ? sizeof(devnull) :
+                                          frag_len, 0);
+            if (i <= 0)
+                goto err;
+            frag_len -= i;
+        }
+    } else {
+        if (frag_len != msg_hdr->msg_len)
+            return dtls1_reassemble_fragment(s, msg_hdr, ok);
+
+        if (frag_len > dtls1_max_handshake_message_len(s))
+            goto err;
+
+        frag = dtls1_hm_fragment_new(frag_len, 0);
+        if (frag == NULL)
+            goto err;
+
+        memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr));
+
+        if (frag_len) {
+            /*
+             * read the body of the fragment (header has already been read
+             */
+            i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL,
+                                          frag->fragment, frag_len, 0);
+            if ((unsigned long)i != frag_len)
+                i = -1;
+            if (i <= 0)
+                goto err;
+        }
+
+        item = pitem_new(seq64be, frag);
+        if (item == NULL)
+            goto err;
+
+        item = pqueue_insert(s->d1->buffered_messages, item);
+        /*
+         * pqueue_insert fails iff a duplicate item is inserted. However,
+         * |item| cannot be a duplicate. If it were, |pqueue_find|, above,
+         * would have returned it. Then, either |frag_len| !=
+         * |msg_hdr->msg_len| in which case |item| is set to NULL and it will
+         * have been processed with |dtls1_reassemble_fragment|, above, or
+         * the record will have been discarded.
+         */
+        OPENSSL_assert(item != NULL);
+    }
+
+    return DTLS1_HM_FRAGMENT_RETRY;
+
+ err:
+    if (item == NULL)
+        dtls1_hm_fragment_free(frag);
+    *ok = 0;
+    return i;
+}
+
+static int dtls_get_reassembled_message(SSL *s, long *len)
+{
+    unsigned char wire[DTLS1_HM_HEADER_LENGTH];
+    unsigned long mlen, frag_off, frag_len;
+    int i, al, recvd_type;
+    struct hm_header_st msg_hdr;
+    int ok;
+
+ redo:
+    /* see if we have the required fragment already */
+    if ((frag_len = dtls1_retrieve_buffered_fragment(s, &ok)) || ok) {
+        if (ok)
+            s->init_num = frag_len;
+        *len = frag_len;
+        return ok;
+    }
+
+    /* read handshake message header */
+    i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, &recvd_type, wire,
+                                  DTLS1_HM_HEADER_LENGTH, 0);
+    if (i <= 0) {               /* nbio, or an error */
+        s->rwstate = SSL_READING;
+        *len = i;
+        return 0;
+    }
+    if(recvd_type == SSL3_RT_CHANGE_CIPHER_SPEC) {
+        if (wire[0] != SSL3_MT_CCS) {
+            al = SSL_AD_UNEXPECTED_MESSAGE;
+            SSLerr(SSL_F_DTLS_GET_REASSEMBLED_MESSAGE,
+                   SSL_R_BAD_CHANGE_CIPHER_SPEC);
+            goto f_err;
+        }
+
+        memcpy(s->init_buf->data, wire, i);
+        s->init_num = i - 1;
+        s->init_msg = s->init_buf->data + 1;
+        s->s3->tmp.message_type = SSL3_MT_CHANGE_CIPHER_SPEC;
+        s->s3->tmp.message_size = i - 1;
+        *len = i - 1;
+        return 1;
+    }
+
+    /* Handshake fails if message header is incomplete */
+    if (i != DTLS1_HM_HEADER_LENGTH) {
+        al = SSL_AD_UNEXPECTED_MESSAGE;
+        SSLerr(SSL_F_DTLS_GET_REASSEMBLED_MESSAGE, SSL_R_UNEXPECTED_MESSAGE);
+        goto f_err;
+    }
+
+    /* parse the message fragment header */
+    dtls1_get_message_header(wire, &msg_hdr);
+
+    mlen = msg_hdr.msg_len;
+    frag_off = msg_hdr.frag_off;
+    frag_len = msg_hdr.frag_len;
+
+    /*
+     * We must have at least frag_len bytes left in the record to be read.
+     * Fragments must not span records.
+     */
+    if (frag_len > RECORD_LAYER_get_rrec_length(&s->rlayer)) {
+        al = SSL3_AD_ILLEGAL_PARAMETER;
+        SSLerr(SSL_F_DTLS_GET_REASSEMBLED_MESSAGE, SSL_R_BAD_LENGTH);
+        goto f_err;
+    }
+
+    /*
+     * if this is a future (or stale) message it gets buffered
+     * (or dropped)--no further processing at this time
+     * While listening, we accept seq 1 (ClientHello with cookie)
+     * although we're still expecting seq 0 (ClientHello)
+     */
+    if (msg_hdr.seq != s->d1->handshake_read_seq) {
+        *len = dtls1_process_out_of_seq_message(s, &msg_hdr, &ok);
+        return ok;
+    }
+
+    if (frag_len && frag_len < mlen) {
+        *len = dtls1_reassemble_fragment(s, &msg_hdr, &ok);
+        return ok;
+    }
+
+    if (!s->server && s->d1->r_msg_hdr.frag_off == 0 &&
+        wire[0] == SSL3_MT_HELLO_REQUEST) {
+        /*
+         * The server may always send 'Hello Request' messages -- we are
+         * doing a handshake anyway now, so ignore them if their format is
+         * correct. Does not count for 'Finished' MAC.
+         */
+        if (wire[1] == 0 && wire[2] == 0 && wire[3] == 0) {
+            if (s->msg_callback)
+                s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
+                                wire, DTLS1_HM_HEADER_LENGTH, s,
+                                s->msg_callback_arg);
+
+            s->init_num = 0;
+            goto redo;
+        } else {                /* Incorrectly formated Hello request */
+
+            al = SSL_AD_UNEXPECTED_MESSAGE;
+            SSLerr(SSL_F_DTLS_GET_REASSEMBLED_MESSAGE,
+                   SSL_R_UNEXPECTED_MESSAGE);
+            goto f_err;
+        }
+    }
+
+    if ((al = dtls1_preprocess_fragment(s, &msg_hdr)))
+        goto f_err;
+
+    if (frag_len > 0) {
+        unsigned char *p =
+            (unsigned char *)s->init_buf->data + DTLS1_HM_HEADER_LENGTH;
+
+        i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL,
+                                      &p[frag_off], frag_len, 0);
+
+        /*
+         * This shouldn't ever fail due to NBIO because we already checked
+         * that we have enough data in the record
+         */
+        if (i <= 0) {
+            s->rwstate = SSL_READING;
+            *len = i;
+            return 0;
+        }
+    } else
+        i = 0;
+
+    /*
+     * XDTLS: an incorrectly formatted fragment should cause the handshake
+     * to fail
+     */
+    if (i != (int)frag_len) {
+        al = SSL3_AD_ILLEGAL_PARAMETER;
+        SSLerr(SSL_F_DTLS_GET_REASSEMBLED_MESSAGE, SSL3_AD_ILLEGAL_PARAMETER);
+        goto f_err;
+    }
+
+    /*
+     * Note that s->init_num is *not* used as current offset in
+     * s->init_buf->data, but as a counter summing up fragments' lengths: as
+     * soon as they sum up to handshake packet length, we assume we have got
+     * all the fragments.
+     */
+    *len = s->init_num = frag_len;
+    return 1;
+
+ f_err:
+    ssl3_send_alert(s, SSL3_AL_FATAL, al);
+    s->init_num = 0;
+    *len = -1;
+    return 0;
+}
+
+/*-
+ * for these 2 messages, we need to
+ * ssl->enc_read_ctx                    re-init
+ * ssl->rlayer.read_sequence            zero
+ * ssl->s3->read_mac_secret             re-init
+ * ssl->session->read_sym_enc           assign
+ * ssl->session->read_compression       assign
+ * ssl->session->read_hash              assign
+ */
+int dtls_construct_change_cipher_spec(SSL *s)
+{
+    unsigned char *p;
+
+    p = (unsigned char *)s->init_buf->data;
+    *p++ = SSL3_MT_CCS;
+    s->d1->handshake_write_seq = s->d1->next_handshake_write_seq;
+    s->init_num = DTLS1_CCS_HEADER_LENGTH;
+
+    if (s->version == DTLS1_BAD_VER) {
+        s->d1->next_handshake_write_seq++;
+        s2n(s->d1->handshake_write_seq, p);
+        s->init_num += 2;
+    }
+
+    s->init_off = 0;
+
+    dtls1_set_message_header_int(s, SSL3_MT_CCS, 0,
+                                 s->d1->handshake_write_seq, 0, 0);
+
+    /* buffer the message to handle re-xmits */
+    if (!dtls1_buffer_message(s, 1)) {
+        SSLerr(SSL_F_DTLS_CONSTRUCT_CHANGE_CIPHER_SPEC, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_SCTP
+enum WORK_STATE dtls_wait_for_dry(SSL *s)
+{
+    int ret;
+
+    /* read app data until dry event */
+    ret = BIO_dgram_sctp_wait_for_dry(SSL_get_wbio(s));
+    if (ret < 0)
+        return WORK_ERROR;
+
+    if (ret == 0) {
+        s->s3->in_read_app_data = 2;
+        s->rwstate = SSL_READING;
+        BIO_clear_retry_flags(SSL_get_rbio(s));
+        BIO_set_retry_read(SSL_get_rbio(s));
+        return WORK_MORE_A;
+    }
+    return WORK_FINISHED_CONTINUE;
+}
+#endif
+
+int dtls1_read_failed(SSL *s, int code)
+{
+    if (code > 0) {
+        fprintf(stderr, "invalid state reached %s:%d", __FILE__, __LINE__);
+        return 1;
+    }
+
+    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
+         */
+        return code;
+    }
+#ifndef OPENSSL_NO_HEARTBEATS
+    /* done, no need to send a retransmit */
+    if (!SSL_in_init(s) && !s->tlsext_hb_pending)
+#else
+    /* done, no need to send a retransmit */
+    if (!SSL_in_init(s))
+#endif
+    {
+        BIO_set_flags(SSL_get_rbio(s), BIO_FLAGS_READ);
+        return code;
+    }
+
+    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;
+}
+
+int dtls1_retransmit_buffered_messages(SSL *s)
+{
+    pqueue sent = s->d1->sent_messages;
+    piterator iter;
+    pitem *item;
+    hm_fragment *frag;
+    int found = 0;
+
+    iter = pqueue_iterator(sent);
+
+    for (item = pqueue_next(&iter); item != NULL; item = pqueue_next(&iter)) {
+        frag = (hm_fragment *)item->data;
+        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;
+        }
+    }
+
+    return 1;
+}
+
+int dtls1_buffer_message(SSL *s, int is_ccs)
+{
+    pitem *item;
+    hm_fragment *frag;
+    unsigned char seq64be[8];
+
+    /*
+     * this function is called immediately after a message has been
+     * serialized
+     */
+    OPENSSL_assert(s->init_off == 0);
+
+    frag = dtls1_hm_fragment_new(s->init_num, 0);
+    if (!frag)
+        return 0;
+
+    memcpy(frag->fragment, s->init_buf->data, s->init_num);
+
+    if (is_ccs) {
+        /* For DTLS1_BAD_VER the header length is non-standard */
+        OPENSSL_assert(s->d1->w_msg_hdr.msg_len +
+                       ((s->version==DTLS1_BAD_VER)?3:DTLS1_CCS_HEADER_LENGTH)
+                       == (unsigned int)s->init_num);
+    } else {
+        OPENSSL_assert(s->d1->w_msg_hdr.msg_len +
+                       DTLS1_HM_HEADER_LENGTH == (unsigned int)s->init_num);
+    }
+
+    frag->msg_header.msg_len = s->d1->w_msg_hdr.msg_len;
+    frag->msg_header.seq = s->d1->w_msg_hdr.seq;
+    frag->msg_header.type = s->d1->w_msg_hdr.type;
+    frag->msg_header.frag_off = 0;
+    frag->msg_header.frag_len = s->d1->w_msg_hdr.msg_len;
+    frag->msg_header.is_ccs = is_ccs;
+
+    /* save current state */
+    frag->msg_header.saved_retransmit_state.enc_write_ctx = s->enc_write_ctx;
+    frag->msg_header.saved_retransmit_state.write_hash = s->write_hash;
+    frag->msg_header.saved_retransmit_state.compress = s->compress;
+    frag->msg_header.saved_retransmit_state.session = s->session;
+    frag->msg_header.saved_retransmit_state.epoch =
+        DTLS_RECORD_LAYER_get_w_epoch(&s->rlayer);
+
+    memset(seq64be, 0, sizeof(seq64be));
+    seq64be[6] =
+        (unsigned
+         char)(dtls1_get_queue_priority(frag->msg_header.seq,
+                                        frag->msg_header.is_ccs) >> 8);
+    seq64be[7] =
+        (unsigned
+         char)(dtls1_get_queue_priority(frag->msg_header.seq,
+                                        frag->msg_header.is_ccs));
+
+    item = pitem_new(seq64be, frag);
+    if (item == NULL) {
+        dtls1_hm_fragment_free(frag);
+        return 0;
+    }
+
+    pqueue_insert(s->d1->sent_messages, item);
+    return 1;
+}
+
+int
+dtls1_retransmit_message(SSL *s, unsigned short seq, unsigned long frag_off,
+                         int *found)
+{
+    int ret;
+    /* XDTLS: for now assuming that read/writes are blocking */
+    pitem *item;
+    hm_fragment *frag;
+    unsigned long header_length;
+    unsigned char seq64be[8];
+    struct dtls1_retransmit_state saved_state;
+
+    /*-
+      OPENSSL_assert(s->init_num == 0);
+      OPENSSL_assert(s->init_off == 0);
+     */
+
+    /* XDTLS:  the requested message ought to be found, otherwise error */
+    memset(seq64be, 0, sizeof(seq64be));
+    seq64be[6] = (unsigned char)(seq >> 8);
+    seq64be[7] = (unsigned char)seq;
+
+    item = pqueue_find(s->d1->sent_messages, seq64be);
+    if (item == NULL) {
+        fprintf(stderr, "retransmit:  message %d non-existant\n", seq);
+        *found = 0;
+        return 0;
+    }
+
+    *found = 1;
+    frag = (hm_fragment *)item->data;
+
+    if (frag->msg_header.is_ccs)
+        header_length = DTLS1_CCS_HEADER_LENGTH;
+    else
+        header_length = DTLS1_HM_HEADER_LENGTH;
+
+    memcpy(s->init_buf->data, frag->fragment,
+           frag->msg_header.msg_len + header_length);
+    s->init_num = frag->msg_header.msg_len + header_length;
+
+    dtls1_set_message_header_int(s, frag->msg_header.type,
+                                 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 = DTLS_RECORD_LAYER_get_w_epoch(&s->rlayer);
+
+    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;
+    DTLS_RECORD_LAYER_set_saved_w_epoch(&s->rlayer,
+        frag->msg_header.saved_retransmit_state.epoch);
+
+    ret = dtls1_do_write(s, frag->msg_header.is_ccs ?
+                         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;
+    DTLS_RECORD_LAYER_set_saved_w_epoch(&s->rlayer, saved_state.epoch);
+
+    s->d1->retransmitting = 0;
+
+    (void)BIO_flush(SSL_get_wbio(s));
+    return ret;
+}
+
+/* call this function when the buffered messages are no longer needed */
+void dtls1_clear_record_buffer(SSL *s)
+{
+    pitem *item;
+
+    for (item = pqueue_pop(s->d1->sent_messages);
+         item != NULL; item = pqueue_pop(s->d1->sent_messages)) {
+        dtls1_hm_fragment_free((hm_fragment *)item->data);
+        pitem_free(item);
+    }
+}
+
+void dtls1_set_message_header(SSL *s, unsigned char *p,
+                                        unsigned char mt, unsigned long len,
+                                        unsigned long frag_off,
+                                        unsigned long frag_len)
+{
+    if (frag_off == 0) {
+        s->d1->handshake_write_seq = s->d1->next_handshake_write_seq;
+        s->d1->next_handshake_write_seq++;
+    }
+
+    dtls1_set_message_header_int(s, mt, len, s->d1->handshake_write_seq,
+                                 frag_off, frag_len);
+}
+
+/* don't actually do the writing, wait till the MTU has been retrieved */
+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)
+{
+    struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
+
+    msg_hdr->type = mt;
+    msg_hdr->msg_len = len;
+    msg_hdr->seq = seq_num;
+    msg_hdr->frag_off = frag_off;
+    msg_hdr->frag_len = frag_len;
+}
+
+static void
+dtls1_fix_message_header(SSL *s, unsigned long frag_off,
+                         unsigned long frag_len)
+{
+    struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
+
+    msg_hdr->frag_off = frag_off;
+    msg_hdr->frag_len = frag_len;
+}
+
+static unsigned char *dtls1_write_message_header(SSL *s, unsigned char *p)
+{
+    struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
+
+    *p++ = msg_hdr->type;
+    l2n3(msg_hdr->msg_len, p);
+
+    s2n(msg_hdr->seq, p);
+    l2n3(msg_hdr->frag_off, p);
+    l2n3(msg_hdr->frag_len, p);
+
+    return p;
+}
+
+void
+dtls1_get_message_header(unsigned char *data, struct hm_header_st *msg_hdr)
+{
+    memset(msg_hdr, 0, sizeof(*msg_hdr));
+    msg_hdr->type = *(data++);
+    n2l3(data, msg_hdr->msg_len);
+
+    n2s(data, msg_hdr->seq);
+    n2l3(data, msg_hdr->frag_off);
+    n2l3(data, msg_hdr->frag_len);
+}
+
+
diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c
new file mode 100644 (file)
index 0000000..75d151e
--- /dev/null
@@ -0,0 +1,712 @@
+/* ssl/statem/statem_lib.c */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2002 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECC cipher suite support in OpenSSL originally developed by
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
+ */
+
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include "../ssl_locl.h"
+#include <openssl/buffer.h>
+#include <openssl/rand.h>
+#include <openssl/objects.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+/*
+ * send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or
+ * SSL3_RT_CHANGE_CIPHER_SPEC)
+ */
+int ssl3_do_write(SSL *s, int type)
+{
+    int ret;
+
+    ret = ssl3_write_bytes(s, type, &s->init_buf->data[s->init_off],
+                           s->init_num);
+    if (ret < 0)
+        return (-1);
+    if (type == SSL3_RT_HANDSHAKE)
+        /*
+         * should not be done for 'Hello Request's, but in that case we'll
+         * ignore the result anyway
+         */
+        ssl3_finish_mac(s, (unsigned char *)&s->init_buf->data[s->init_off],
+                        ret);
+
+    if (ret == s->init_num) {
+        if (s->msg_callback)
+            s->msg_callback(1, s->version, type, s->init_buf->data,
+                            (size_t)(s->init_off + s->init_num), s,
+                            s->msg_callback_arg);
+        return (1);
+    }
+    s->init_off += ret;
+    s->init_num -= ret;
+    return (0);
+}
+
+int tls_construct_finished(SSL *s, const char *sender, int slen)
+{
+    unsigned char *p;
+    int i;
+    unsigned long l;
+
+    p = ssl_handshake_start(s);
+
+    i = s->method->ssl3_enc->final_finish_mac(s,
+                                              sender, slen,
+                                              s->s3->tmp.finish_md);
+    if (i <= 0)
+        return 0;
+    s->s3->tmp.finish_md_len = i;
+    memcpy(p, s->s3->tmp.finish_md, i);
+    l = i;
+
+    /*
+     * Copy the finished so we can use it for renegotiation checks
+     */
+    if (!s->server) {
+        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;
+    }
+
+    if (!ssl_set_handshake_header(s, SSL3_MT_FINISHED, l)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_FINISHED, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+/*
+ * ssl3_take_mac calculates the Finished MAC for the handshakes messages seen
+ * to far.
+ */
+static void ssl3_take_mac(SSL *s)
+{
+    const char *sender;
+    int slen;
+    /*
+     * If no new cipher setup return immediately: other functions will set
+     * the appropriate error.
+     */
+    if (s->s3->tmp.new_cipher == NULL)
+        return;
+    if (!s->server) {
+        sender = s->method->ssl3_enc->server_finished_label;
+        slen = s->method->ssl3_enc->server_finished_label_len;
+    } else {
+        sender = s->method->ssl3_enc->client_finished_label;
+        slen = s->method->ssl3_enc->client_finished_label_len;
+    }
+
+    s->s3->tmp.peer_finish_md_len = s->method->ssl3_enc->final_finish_mac(s,
+                                                                          sender,
+                                                                          slen,
+                                                                          s->s3->tmp.peer_finish_md);
+}
+#endif
+
+enum MSG_PROCESS_RETURN tls_process_change_cipher_spec(SSL *s, PACKET *pkt)
+{
+    int al;
+    long remain;
+    
+    remain = PACKET_remaining(pkt);
+    /*
+     * 'Change Cipher Spec' is just a single byte, which should already have
+     * been consumed by ssl_get_message() so there should be no bytes left,
+     * unless we're using DTLS1_BAD_VER, which has an extra 2 bytes
+     */
+    if (SSL_IS_DTLS(s)) {
+        if ((s->version == DTLS1_BAD_VER
+                        && remain != DTLS1_CCS_HEADER_LENGTH + 1)
+                    || (s->version != DTLS1_BAD_VER
+                        && remain != DTLS1_CCS_HEADER_LENGTH - 1)) {
+                al = SSL_AD_ILLEGAL_PARAMETER;
+                SSLerr(SSL_F_TLS_PROCESS_CHANGE_CIPHER_SPEC,
+                       SSL_R_BAD_CHANGE_CIPHER_SPEC);
+                goto f_err;
+        }
+    } else {
+        if (remain != 0) {
+            al = SSL_AD_ILLEGAL_PARAMETER;
+            SSLerr(SSL_F_TLS_PROCESS_CHANGE_CIPHER_SPEC,
+                   SSL_R_BAD_CHANGE_CIPHER_SPEC);
+            goto f_err;
+        }
+    }
+
+    /* Check we have a cipher to change to */
+    if (s->s3->tmp.new_cipher == NULL) {
+        al = SSL_AD_UNEXPECTED_MESSAGE;
+        SSLerr(SSL_F_TLS_PROCESS_CHANGE_CIPHER_SPEC, SSL_R_CCS_RECEIVED_EARLY);
+        goto f_err;
+    }
+
+    s->s3->change_cipher_spec = 1;
+    if (!ssl3_do_change_cipher_spec(s)) {
+        al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_CHANGE_CIPHER_SPEC, ERR_R_INTERNAL_ERROR);
+        goto f_err;
+    }
+
+    if (SSL_IS_DTLS(s)) {
+        dtls1_reset_seq_numbers(s, SSL3_CC_READ);
+
+        if (s->version == DTLS1_BAD_VER)
+            s->d1->handshake_read_seq++;
+
+#ifndef OPENSSL_NO_SCTP
+        /*
+         * Remember that a CCS has been received, so that an old key of
+         * SCTP-Auth can be deleted when a CCS is sent. Will be ignored if no
+         * SCTP is used
+         */
+        BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD, 1, NULL);
+#endif
+    }
+
+    return MSG_PROCESS_CONTINUE_READING;
+ f_err:
+    ssl3_send_alert(s, SSL3_AL_FATAL, al);
+    statem_set_error(s);
+    return MSG_PROCESS_ERROR;
+}
+
+enum MSG_PROCESS_RETURN tls_process_finished(SSL *s, PACKET *pkt)
+{
+    int al, i;
+
+    /* If this occurs, we have missed a message */
+    if (!s->s3->change_cipher_spec) {
+        al = SSL_AD_UNEXPECTED_MESSAGE;
+        SSLerr(SSL_F_TLS_PROCESS_FINISHED, SSL_R_GOT_A_FIN_BEFORE_A_CCS);
+        goto f_err;
+    }
+    s->s3->change_cipher_spec = 0;
+
+    i = s->s3->tmp.peer_finish_md_len;
+
+    if (i < 0 || (unsigned long)i != PACKET_remaining(pkt)) {
+        al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_FINISHED, SSL_R_BAD_DIGEST_LENGTH);
+        goto f_err;
+    }
+
+    if (CRYPTO_memcmp(PACKET_data(pkt), s->s3->tmp.peer_finish_md, i) != 0) {
+        al = SSL_AD_DECRYPT_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_FINISHED, SSL_R_DIGEST_CHECK_FAILED);
+        goto f_err;
+    }
+
+    /*
+     * Copy the finished so we can use it for renegotiation checks
+     */
+    if (s->server) {
+        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 MSG_PROCESS_CONTINUE_PROCESSING;
+ f_err:
+    ssl3_send_alert(s, SSL3_AL_FATAL, al);
+    statem_set_error(s);
+    return MSG_PROCESS_ERROR;
+}
+
+int tls_construct_change_cipher_spec(SSL *s)
+{
+    unsigned char *p;
+
+    p = (unsigned char *)s->init_buf->data;
+    *p = SSL3_MT_CCS;
+    s->init_num = 1;
+    s->init_off = 0;
+
+    return 1;
+}
+
+unsigned long ssl3_output_cert_chain(SSL *s, CERT_PKEY *cpk)
+{
+    unsigned char *p;
+    unsigned long l = 3 + SSL_HM_HEADER_LENGTH(s);
+
+    if (!ssl_add_cert_chain(s, cpk, &l))
+        return 0;
+
+    l -= 3 + SSL_HM_HEADER_LENGTH(s);
+    p = ssl_handshake_start(s);
+    l2n3(l, p);
+    l += 3;
+
+    if (!ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE, l)) {
+        SSLerr(SSL_F_SSL3_OUTPUT_CERT_CHAIN, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+    return l + SSL_HM_HEADER_LENGTH(s);
+}
+
+enum WORK_STATE tls_finish_handshake(SSL *s, enum WORK_STATE wst)
+{
+    void (*cb) (const SSL *ssl, int type, int val) = NULL;
+
+#ifndef OPENSSL_NO_SCTP
+    if (SSL_IS_DTLS(s) && BIO_dgram_is_sctp(SSL_get_wbio(s))) {
+        enum WORK_STATE ret;
+        ret = dtls_wait_for_dry(s);
+        if (ret != WORK_FINISHED_CONTINUE)
+            return ret;
+    }
+#endif
+
+    /* clean a few things up */
+    ssl3_cleanup_key_block(s);
+
+    if (!SSL_IS_DTLS(s)) {
+        /*
+         * We don't do this in DTLS because we may still need the init_buf
+         * in case there are any unexpected retransmits
+         */
+        BUF_MEM_free(s->init_buf);
+        s->init_buf = NULL;
+    }
+
+    ssl_free_wbio_buffer(s);
+
+    s->init_num = 0;
+
+    if (!s->server || s->renegotiate == 2) {
+        /* skipped if we just sent a HelloRequest */
+        s->renegotiate = 0;
+        s->new_session = 0;
+
+        if (s->server) {
+            s->renegotiate = 0;
+            s->new_session = 0;
+
+            ssl_update_cache(s, SSL_SESS_CACHE_SERVER);
+
+            s->ctx->stats.sess_accept_good++;
+            s->handshake_func = statem_accept;
+        } else {
+            ssl_update_cache(s, SSL_SESS_CACHE_CLIENT);
+            if (s->hit)
+                s->ctx->stats.sess_hit++;
+
+            s->handshake_func = statem_connect;
+            s->ctx->stats.sess_connect_good++;
+        }
+
+        if (s->info_callback != NULL)
+            cb = s->info_callback;
+        else if (s->ctx->info_callback != NULL)
+            cb = s->ctx->info_callback;
+
+        if (cb != NULL)
+            cb(s, SSL_CB_HANDSHAKE_DONE, 1);
+
+        if (SSL_IS_DTLS(s)) {
+            /* done with handshaking */
+            s->d1->handshake_read_seq = 0;
+            s->d1->handshake_write_seq = 0;
+            s->d1->next_handshake_write_seq = 0;
+        }
+    }
+
+    return WORK_FINISHED_STOP;
+}
+
+int tls_get_message_header(SSL *s, int *mt)
+{
+    /* s->init_num < SSL3_HM_HEADER_LENGTH */
+    int skip_message, i, recvd_type, al;
+    unsigned char *p;
+    unsigned long l;
+
+    p = (unsigned char *)s->init_buf->data;
+
+    do {
+        while (s->init_num < SSL3_HM_HEADER_LENGTH) {
+            i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, &recvd_type,
+                &p[s->init_num], SSL3_HM_HEADER_LENGTH - s->init_num, 0);
+            if (i <= 0) {
+                s->rwstate = SSL_READING;
+                return 0;
+            }
+            if (recvd_type == SSL3_RT_CHANGE_CIPHER_SPEC) {
+                s->s3->tmp.message_type = *mt = SSL3_MT_CHANGE_CIPHER_SPEC;
+                s->init_num = i - 1;
+                s->s3->tmp.message_size = i;
+                return 1;
+            } else if (recvd_type != SSL3_RT_HANDSHAKE) {
+                al = SSL_AD_UNEXPECTED_MESSAGE;
+                SSLerr(SSL_F_TLS_GET_MESSAGE_HEADER, SSL_R_CCS_RECEIVED_EARLY);
+                goto f_err;
+            }
+            s->init_num += i;
+        }
+
+        skip_message = 0;
+        if (!s->server)
+            if (p[0] == SSL3_MT_HELLO_REQUEST)
+                /*
+                 * The server may always send 'Hello Request' messages --
+                 * we are doing a handshake anyway now, so ignore them if
+                 * their format is correct. Does not count for 'Finished'
+                 * MAC.
+                 */
+                if (p[1] == 0 && p[2] == 0 && p[3] == 0) {
+                    s->init_num = 0;
+                    skip_message = 1;
+
+                    if (s->msg_callback)
+                        s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
+                                        p, SSL3_HM_HEADER_LENGTH, s,
+                                        s->msg_callback_arg);
+                }
+    } while (skip_message);
+    /* s->init_num == SSL3_HM_HEADER_LENGTH */
+
+    *mt = *p;
+    s->s3->tmp.message_type = *(p++);
+
+    if(RECORD_LAYER_is_sslv2_record(&s->rlayer)) {
+        /*
+         * Only happens with SSLv3+ in an SSLv2 backward compatible
+         * ClientHello
+         */
+         /*
+          * Total message size is the remaining record bytes to read
+          * plus the SSL3_HM_HEADER_LENGTH bytes that we already read
+          */
+        l = RECORD_LAYER_get_rrec_length(&s->rlayer)
+            + SSL3_HM_HEADER_LENGTH;
+        if (l && !BUF_MEM_grow_clean(s->init_buf, (int)l)) {
+            SSLerr(SSL_F_TLS_GET_MESSAGE_HEADER, ERR_R_BUF_LIB);
+            goto err;
+        }
+        s->s3->tmp.message_size = l;
+
+        s->init_msg = s->init_buf->data;
+        s->init_num = SSL3_HM_HEADER_LENGTH;
+    } else {
+        n2l3(p, l);
+        /* BUF_MEM_grow takes an 'int' parameter */
+        if (l > (INT_MAX - SSL3_HM_HEADER_LENGTH)) {
+            al = SSL_AD_ILLEGAL_PARAMETER;
+            SSLerr(SSL_F_TLS_GET_MESSAGE_HEADER, SSL_R_EXCESSIVE_MESSAGE_SIZE);
+            goto f_err;
+        }
+        if (l && !BUF_MEM_grow_clean(s->init_buf,
+                                    (int)l + SSL3_HM_HEADER_LENGTH)) {
+            SSLerr(SSL_F_TLS_GET_MESSAGE_HEADER, ERR_R_BUF_LIB);
+            goto err;
+        }
+        s->s3->tmp.message_size = l;
+
+        s->init_msg = s->init_buf->data + SSL3_HM_HEADER_LENGTH;
+        s->init_num = 0;
+    }
+
+    return 1;
+ f_err:
+    ssl3_send_alert(s, SSL3_AL_FATAL, al);
+ err:
+    return 0;
+}
+
+int tls_get_message_body(SSL *s, unsigned long *len)
+{
+    long n;
+    unsigned char *p;
+    int i;
+
+    if (s->s3->tmp.message_type == SSL3_MT_CHANGE_CIPHER_SPEC) {
+        /* We've already read everything in */
+        *len = (unsigned long)s->init_num;
+        return 1;
+    }
+
+    p = s->init_msg;
+    n = s->s3->tmp.message_size - s->init_num;
+    while (n > 0) {
+        i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, NULL,
+                                      &p[s->init_num], n, 0);
+        if (i <= 0) {
+            s->rwstate = SSL_READING;
+            *len = 0;
+            return 0;
+        }
+        s->init_num += i;
+        n -= i;
+    }
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+    /*
+     * If receiving Finished, record MAC of prior handshake messages for
+     * Finished verification.
+     */
+    if (*s->init_buf->data == SSL3_MT_FINISHED)
+        ssl3_take_mac(s);
+#endif
+
+    /* Feed this message into MAC computation. */
+    if(RECORD_LAYER_is_sslv2_record(&s->rlayer)) {
+        ssl3_finish_mac(s, (unsigned char *)s->init_buf->data, s->init_num);
+        if (s->msg_callback)
+            s->msg_callback(0, SSL2_VERSION, 0,  s->init_buf->data,
+                            (size_t)s->init_num, s, s->msg_callback_arg);
+    } else {
+        ssl3_finish_mac(s, (unsigned char *)s->init_buf->data,
+            s->init_num + SSL3_HM_HEADER_LENGTH);
+        if (s->msg_callback)
+            s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->init_buf->data,
+                            (size_t)s->init_num + SSL3_HM_HEADER_LENGTH, s,
+                            s->msg_callback_arg);
+    }
+
+    /*
+     * init_num should never be negative...should probably be declared
+     * unsigned
+     */
+    if (s->init_num < 0) {
+        SSLerr(SSL_F_TLS_GET_MESSAGE_BODY, ERR_R_INTERNAL_ERROR);
+        ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+        *len = 0;
+        return 0;
+    }
+    *len = (unsigned long)s->init_num;
+    return 1;
+}
+
+int ssl_cert_type(X509 *x, EVP_PKEY *pkey)
+{
+    EVP_PKEY *pk;
+    int ret = -1, i;
+
+    if (pkey == NULL)
+        pk = X509_get_pubkey(x);
+    else
+        pk = pkey;
+    if (pk == NULL)
+        goto err;
+
+    i = pk->type;
+    if (i == EVP_PKEY_RSA) {
+        ret = SSL_PKEY_RSA_ENC;
+    } else if (i == EVP_PKEY_DSA) {
+        ret = SSL_PKEY_DSA_SIGN;
+    }
+#ifndef OPENSSL_NO_EC
+    else if (i == EVP_PKEY_EC) {
+        ret = SSL_PKEY_ECC;
+    }
+#endif
+    else if (i == NID_id_GostR3410_2001) {
+        ret = SSL_PKEY_GOST01;
+    } else if (x && (i == EVP_PKEY_DH || i == EVP_PKEY_DHX)) {
+        /*
+         * For DH two cases: DH certificate signed with RSA and DH
+         * certificate signed with DSA.
+         */
+        i = X509_certificate_type(x, pk);
+        if (i & EVP_PKS_RSA)
+            ret = SSL_PKEY_DH_RSA;
+        else if (i & EVP_PKS_DSA)
+            ret = SSL_PKEY_DH_DSA;
+    }
+
+ err:
+    if (!pkey)
+        EVP_PKEY_free(pk);
+    return (ret);
+}
+
+int ssl_verify_alarm_type(long type)
+{
+    int al;
+
+    switch (type) {
+    case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+    case X509_V_ERR_UNABLE_TO_GET_CRL:
+    case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
+        al = SSL_AD_UNKNOWN_CA;
+        break;
+    case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
+    case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
+    case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
+    case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+    case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+    case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
+    case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
+    case X509_V_ERR_CERT_NOT_YET_VALID:
+    case X509_V_ERR_CRL_NOT_YET_VALID:
+    case X509_V_ERR_CERT_UNTRUSTED:
+    case X509_V_ERR_CERT_REJECTED:
+        al = SSL_AD_BAD_CERTIFICATE;
+        break;
+    case X509_V_ERR_CERT_SIGNATURE_FAILURE:
+    case X509_V_ERR_CRL_SIGNATURE_FAILURE:
+        al = SSL_AD_DECRYPT_ERROR;
+        break;
+    case X509_V_ERR_CERT_HAS_EXPIRED:
+    case X509_V_ERR_CRL_HAS_EXPIRED:
+        al = SSL_AD_CERTIFICATE_EXPIRED;
+        break;
+    case X509_V_ERR_CERT_REVOKED:
+        al = SSL_AD_CERTIFICATE_REVOKED;
+        break;
+    case X509_V_ERR_OUT_OF_MEM:
+        al = SSL_AD_INTERNAL_ERROR;
+        break;
+    case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+    case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+    case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
+    case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
+    case X509_V_ERR_CERT_CHAIN_TOO_LONG:
+    case X509_V_ERR_PATH_LENGTH_EXCEEDED:
+    case X509_V_ERR_INVALID_CA:
+        al = SSL_AD_UNKNOWN_CA;
+        break;
+    case X509_V_ERR_APPLICATION_VERIFICATION:
+        al = SSL_AD_HANDSHAKE_FAILURE;
+        break;
+    case X509_V_ERR_INVALID_PURPOSE:
+        al = SSL_AD_UNSUPPORTED_CERTIFICATE;
+        break;
+    default:
+        al = SSL_AD_CERTIFICATE_UNKNOWN;
+        break;
+    }
+    return (al);
+}
+
+int ssl_allow_compression(SSL *s)
+{
+    if (s->options & SSL_OP_NO_COMPRESSION)
+        return 0;
+    return ssl_security(s, SSL_SECOP_COMPRESSION, 0, 0, NULL);
+}
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
new file mode 100644 (file)
index 0000000..5f85a8c
--- /dev/null
@@ -0,0 +1,2929 @@
+/* ssl/statem/statem_srvr.c -*- mode:C; c-file-style: "eay" -*- */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2007 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ *
+ * Portions of the attached software ("Contribution") are developed by
+ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
+ *
+ * The Contribution is licensed pursuant to the OpenSSL open source
+ * license provided above.
+ *
+ * ECC cipher suite support in OpenSSL originally written by
+ * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories.
+ *
+ */
+/* ====================================================================
+ * Copyright 2005 Nokia. All rights reserved.
+ *
+ * The portions of the attached software ("Contribution") is developed by
+ * Nokia Corporation and is licensed pursuant to the OpenSSL open source
+ * license.
+ *
+ * The Contribution, originally written by Mika Kousa and Pasi Eronen of
+ * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites
+ * support (see RFC 4279) to OpenSSL.
+ *
+ * No patent licenses or other rights except those expressly stated in
+ * the OpenSSL open source license shall be deemed granted or received
+ * expressly, by implication, estoppel, or otherwise.
+ *
+ * No assurances are provided by Nokia that the Contribution does not
+ * infringe the patent or other intellectual property rights of any third
+ * party or that the license provides you with all the necessary rights
+ * to make use of the Contribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN
+ * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA
+ * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY
+ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR
+ * OTHERWISE.
+ */
+
+
+#include <stdio.h>
+#include "../ssl_locl.h"
+#include "internal/constant_time_locl.h"
+#include <openssl/buffer.h>
+#include <openssl/rand.h>
+#include <openssl/objects.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/x509.h>
+#ifndef OPENSSL_NO_DH
+# include <openssl/dh.h>
+#endif
+#include <openssl/bn.h>
+#include <openssl/md5.h>
+
+static STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s,
+                                                      PACKET *cipher_suites,
+                                                      STACK_OF(SSL_CIPHER) **skp,
+                                                      int sslv2format, int *al);
+
+#ifndef OPENSSL_NO_SRP
+static int ssl_check_srp_ext_ClientHello(SSL *s, int *al)
+{
+    int ret = SSL_ERROR_NONE;
+
+    *al = SSL_AD_UNRECOGNIZED_NAME;
+
+    if ((s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP) &&
+        (s->srp_ctx.TLS_ext_srp_username_callback != NULL)) {
+        if (s->srp_ctx.login == NULL) {
+            /*
+             * RFC 5054 says SHOULD reject, we do so if There is no srp
+             * login name
+             */
+            ret = SSL3_AL_FATAL;
+            *al = SSL_AD_UNKNOWN_PSK_IDENTITY;
+        } else {
+            ret = SSL_srp_server_param_with_username(s, al);
+        }
+    }
+    return ret;
+}
+#endif
+
+int tls_construct_hello_request(SSL *s)
+{
+    if (!ssl_set_handshake_header(s, SSL3_MT_HELLO_REQUEST, 0)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_HELLO_REQUEST, ERR_R_INTERNAL_ERROR);
+        statem_set_error(s);
+        return 0;
+    }
+
+    return 1;
+}
+
+unsigned int dtls_raw_hello_verify_request(unsigned char *buf,
+                                            unsigned char *cookie,
+                                            unsigned char cookie_len)
+{
+    unsigned int msg_len;
+    unsigned char *p;
+
+    p = buf;
+    /* Always use DTLS 1.0 version: see RFC 6347 */
+    *(p++) = DTLS1_VERSION >> 8;
+    *(p++) = DTLS1_VERSION & 0xFF;
+
+    *(p++) = (unsigned char)cookie_len;
+    memcpy(p, cookie, cookie_len);
+    p += cookie_len;
+    msg_len = p - buf;
+
+    return msg_len;
+}
+
+int dtls_construct_hello_verify_request(SSL *s)
+{
+    unsigned int len;
+    unsigned char *buf;
+
+    buf = (unsigned char *)s->init_buf->data;
+
+    if (s->ctx->app_gen_cookie_cb == NULL ||
+        s->ctx->app_gen_cookie_cb(s, s->d1->cookie,
+                                  &(s->d1->cookie_len)) == 0 ||
+        s->d1->cookie_len > 255) {
+        SSLerr(SSL_F_DTLS1_SEND_HELLO_VERIFY_REQUEST,
+               SSL_R_COOKIE_GEN_CALLBACK_FAILURE);
+        statem_set_error(s);
+        return 0;
+    }
+
+    len = dtls_raw_hello_verify_request(&buf[DTLS1_HM_HEADER_LENGTH],
+                                         s->d1->cookie, s->d1->cookie_len);
+
+    dtls1_set_message_header(s, buf, DTLS1_MT_HELLO_VERIFY_REQUEST, len, 0,
+                             len);
+    len += DTLS1_HM_HEADER_LENGTH;
+
+    /* number of bytes to write */
+    s->init_num = len;
+    s->init_off = 0;
+
+    return 1;
+}
+
+enum MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt)
+{
+    int i, al = SSL_AD_INTERNAL_ERROR;
+    unsigned int j, complen = 0;
+    unsigned long id;
+    SSL_CIPHER *c;
+#ifndef OPENSSL_NO_COMP
+    SSL_COMP *comp = NULL;
+#endif
+    STACK_OF(SSL_CIPHER) *ciphers = NULL;
+    int protverr = 1;
+    /* |cookie| will only be initialized for DTLS. */
+    PACKET session_id, cipher_suites, compression, extensions, cookie;
+    int is_v2_record;
+
+    is_v2_record = RECORD_LAYER_is_sslv2_record(&s->rlayer);
+
+    PACKET_null_init(&cookie);
+    /* First lets get s->client_version set correctly */
+    if (is_v2_record) {
+        unsigned int version;
+        unsigned int mt;
+        /*-
+         * An SSLv3/TLSv1 backwards-compatible CLIENT-HELLO in an SSLv2
+         * header is sent directly on the wire, not wrapped as a TLS
+         * record. Our record layer just processes the message length and passes
+         * the rest right through. Its format is:
+         * Byte  Content
+         * 0-1   msg_length - decoded by the record layer
+         * 2     msg_type - s->init_msg points here
+         * 3-4   version
+         * 5-6   cipher_spec_length
+         * 7-8   session_id_length
+         * 9-10  challenge_length
+         * ...   ...
+         */
+
+        if (!PACKET_get_1(pkt, &mt)
+                || mt != SSL2_MT_CLIENT_HELLO) {
+            /*
+             * Should never happen. We should have tested this in the record
+             * layer in order to have determined that this is a SSLv2 record
+             * in the first place
+             */
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+
+        if (!PACKET_get_net_2(pkt, &version)) {
+            /* No protocol version supplied! */
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL);
+            goto err;
+        }
+        if (version == 0x0002) {
+            /* This is real SSLv2. We don't support it. */
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL);
+            goto err;
+        } else if ((version & 0xff00) == (SSL3_VERSION_MAJOR << 8)) {
+            /* SSLv3/TLS */
+            s->client_version = version;
+        } else {
+            /* No idea what protocol this is */
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL);
+            goto err;
+        }
+    } else {
+        /*
+         * use version from inside client hello, not from record header (may
+         * differ: see RFC 2246, Appendix E, second paragraph)
+         */
+        if(!PACKET_get_net_2(pkt, (unsigned int *)&s->client_version)) {
+            al = SSL_AD_DECODE_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_LENGTH_TOO_SHORT);
+            goto f_err;
+        }
+    }
+
+    /* Do SSL/TLS version negotiation if applicable */
+    if (!SSL_IS_DTLS(s)) {
+        if (s->version != TLS_ANY_VERSION) {
+            if (s->client_version >= s->version) {
+                protverr = 0;
+            }
+        } else if (s->client_version >= SSL3_VERSION) {
+            switch(s->client_version) {
+            default:
+            case TLS1_2_VERSION:
+                if(!(s->options & SSL_OP_NO_TLSv1_2)) {
+                    s->version = TLS1_2_VERSION;
+                    s->method = TLSv1_2_server_method();
+                    protverr = 0;
+                    break;
+                }
+                /* Deliberately fall through */
+            case TLS1_1_VERSION:
+                if(!(s->options & SSL_OP_NO_TLSv1_1)) {
+                    s->version = TLS1_1_VERSION;
+                    s->method = TLSv1_1_server_method();
+                    protverr = 0;
+                    break;
+                }
+                /* Deliberately fall through */
+            case TLS1_VERSION:
+                if(!(s->options & SSL_OP_NO_TLSv1)) {
+                    s->version = TLS1_VERSION;
+                    s->method = TLSv1_server_method();
+                    protverr = 0;
+                    break;
+                }
+                /* Deliberately fall through */
+            case SSL3_VERSION:
+#ifndef OPENSSL_NO_SSL3
+                if(!(s->options & SSL_OP_NO_SSLv3)) {
+                    s->version = SSL3_VERSION;
+                    s->method = SSLv3_server_method();
+                    protverr = 0;
+                    break;
+                }
+#else
+                break;
+#endif
+            }
+        }
+    } else if (s->client_version <= s->version
+                || s->method->version == DTLS_ANY_VERSION) {
+        /*
+         * For DTLS we just check versions are potentially compatible. Version
+         * negotiation comes later.
+         */
+        protverr = 0;
+    }
+
+    if (protverr) {
+        SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL);
+        if ((!s->enc_write_ctx && !s->write_hash)) {
+            /*
+             * similar to ssl3_get_record, send alert using remote version
+             * number
+             */
+            s->version = s->client_version;
+        }
+        al = SSL_AD_PROTOCOL_VERSION;
+        goto f_err;
+    }
+
+    /* Parse the message and load client random. */
+    if (is_v2_record) {
+        /*
+         * Handle an SSLv2 backwards compatible ClientHello
+         * Note, this is only for SSLv3+ using the backward compatible format.
+         * Real SSLv2 is not supported, and is rejected above.
+         */
+        unsigned int cipher_len, session_id_len, challenge_len;
+        PACKET challenge;
+
+        if (!PACKET_get_net_2(pkt, &cipher_len)
+                || !PACKET_get_net_2(pkt, &session_id_len)
+                || !PACKET_get_net_2(pkt, &challenge_len)) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO,
+                   SSL_R_RECORD_LENGTH_MISMATCH);
+            al = SSL_AD_DECODE_ERROR;
+            goto f_err;
+        }
+
+        if (!PACKET_get_sub_packet(pkt, &cipher_suites, cipher_len)
+            || !PACKET_get_sub_packet(pkt, &session_id, session_id_len)
+            || !PACKET_get_sub_packet(pkt, &challenge, challenge_len)
+            /* No extensions. */
+            || PACKET_remaining(pkt) != 0) {
+            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_RECORD_LENGTH_MISMATCH);
+            al = SSL_AD_DECODE_ERROR;
+            goto f_err;
+        }
+
+        /* Load the client random */
+        challenge_len = challenge_len > SSL3_RANDOM_SIZE ? SSL3_RANDOM_SIZE :
+            challenge_len;
+        memset(s->s3->client_random, 0, SSL3_RANDOM_SIZE);
+        if (!PACKET_copy_bytes(&challenge,
+                               s->s3->client_random + SSL3_RANDOM_SIZE -
+                               challenge_len, challenge_len)) {
+            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+            al = SSL_AD_INTERNAL_ERROR;
+            goto f_err;
+        }
+
+        PACKET_null_init(&compression);
+        PACKET_null_init(&extensions);
+    } else {
+        /* Regular ClientHello. */
+        if (!PACKET_copy_bytes(pkt, s->s3->client_random, SSL3_RANDOM_SIZE)
+            || !PACKET_get_length_prefixed_1(pkt, &session_id)) {
+            al = SSL_AD_DECODE_ERROR;
+            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH);
+            goto f_err;
+        }
+
+        if (SSL_IS_DTLS(s)) {
+            if (!PACKET_get_length_prefixed_1(pkt, &cookie)) {
+                al = SSL_AD_DECODE_ERROR;
+                SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH);
+                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) {
+                if (PACKET_remaining(&cookie) == 0)
+                return 1;
+            }
+        }
+
+        if (!PACKET_get_length_prefixed_2(pkt, &cipher_suites)
+            || !PACKET_get_length_prefixed_1(pkt, &compression)) {
+                al = SSL_AD_DECODE_ERROR;
+                SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH);
+                goto f_err;
+        }
+        /* Could be empty. */
+        extensions = *pkt;
+    }
+
+    s->hit = 0;
+
+    /*
+     * We don't allow resumption in a backwards compatible ClientHello.
+     * TODO(openssl-team): in TLS1.1+, session_id MUST be empty.
+     *
+     * Versions before 0.9.7 always allow clients to resume sessions in
+     * renegotiation. 0.9.7 and later allow this by default, but optionally
+     * ignore resumption requests with flag
+     * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION (it's a new flag rather
+     * than a change to default behavior so that applications relying on
+     * this for security won't even compile against older library versions).
+     * 1.0.1 and later also have a function SSL_renegotiate_abbreviated() to
+     * request renegotiation but not a new session (s->new_session remains
+     * unset): for servers, this essentially just means that the
+     * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION setting will be
+     * ignored.
+     */
+    if (is_v2_record ||
+        (s->new_session &&
+         (s->options & SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION))) {
+        if (!ssl_get_new_session(s, 1))
+            goto err;
+    } else {
+        i = ssl_get_prev_session(s, &extensions, &session_id);
+        /*
+         * Only resume if the session's version matches the negotiated
+         * version.
+         * RFC 5246 does not provide much useful advice on resumption
+         * with a different protocol version. It doesn't forbid it but
+         * the sanity of such behaviour would be questionable.
+         * In practice, clients do not accept a version mismatch and
+         * will abort the handshake with an error.
+         */
+        if (i == 1 && s->version == s->session->ssl_version) {
+            /* previous session */
+            s->hit = 1;
+        } else if (i == -1) {
+            goto err;
+        } else {
+            /* i == 0 */
+            if (!ssl_get_new_session(s, 1))
+                goto err;
+        }
+    }
+
+    if (SSL_IS_DTLS(s)) {
+        /* Empty cookie was already handled above by returning early. */
+        if (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) {
+            if (s->ctx->app_verify_cookie_cb != NULL) {
+                if (s->ctx->app_verify_cookie_cb(s, PACKET_data(&cookie),
+                                                 PACKET_remaining(&cookie)) == 0) {
+                    al = SSL_AD_HANDSHAKE_FAILURE;
+                    SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,
+                           SSL_R_COOKIE_MISMATCH);
+                    goto f_err;
+                    /* else cookie verification succeeded */
+                }
+            /* default verification */
+            } else if (!PACKET_equal(&cookie, s->d1->cookie,
+                                     s->d1->cookie_len)) {
+                al = SSL_AD_HANDSHAKE_FAILURE;
+                SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_COOKIE_MISMATCH);
+                goto f_err;
+            }
+            s->d1->cookie_verified = 1;
+        }
+        if (s->method->version == DTLS_ANY_VERSION) {
+            /* Select version to use */
+            if (s->client_version <= DTLS1_2_VERSION &&
+                !(s->options & SSL_OP_NO_DTLSv1_2)) {
+                s->version = DTLS1_2_VERSION;
+                s->method = DTLSv1_2_server_method();
+            } else if (tls1_suiteb(s)) {
+                SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,
+                       SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE);
+                s->version = s->client_version;
+                al = SSL_AD_PROTOCOL_VERSION;
+                goto f_err;
+            } else if (s->client_version <= DTLS1_VERSION &&
+                       !(s->options & SSL_OP_NO_DTLSv1)) {
+                s->version = DTLS1_VERSION;
+                s->method = DTLSv1_server_method();
+            } else {
+                SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,
+                       SSL_R_WRONG_VERSION_NUMBER);
+                s->version = s->client_version;
+                al = SSL_AD_PROTOCOL_VERSION;
+                goto f_err;
+            }
+            s->session->ssl_version = s->version;
+        }
+    }
+
+    if (ssl_bytes_to_cipher_list(s, &cipher_suites, &(ciphers),
+                                 is_v2_record, &al) == NULL) {
+        goto f_err;
+    }
+
+    /* If it is a hit, check that the cipher is in the list */
+    if (s->hit) {
+        j = 0;
+        id = s->session->cipher->id;
+
+#ifdef CIPHER_DEBUG
+        fprintf(stderr, "client sent %d ciphers\n",
+                sk_SSL_CIPHER_num(ciphers));
+#endif
+        for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) {
+            c = sk_SSL_CIPHER_value(ciphers, i);
+#ifdef CIPHER_DEBUG
+            fprintf(stderr, "client [%2d of %2d]:%s\n",
+                    i, sk_SSL_CIPHER_num(ciphers), SSL_CIPHER_get_name(c));
+#endif
+            if (c->id == id) {
+                j = 1;
+                break;
+            }
+        }
+        if (j == 0) {
+            /*
+             * we need to have the cipher in the cipher list if we are asked
+             * to reuse it
+             */
+            al = SSL_AD_ILLEGAL_PARAMETER;
+            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,
+                   SSL_R_REQUIRED_CIPHER_MISSING);
+            goto f_err;
+        }
+    }
+
+    complen = PACKET_remaining(&compression);
+    for (j = 0; j < complen; j++) {
+        if (PACKET_data(&compression)[j] == 0)
+            break;
+    }
+
+    if (j >= complen) {
+        /* no compress */
+        al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_NO_COMPRESSION_SPECIFIED);
+        goto f_err;
+    }
+    
+    /* TLS extensions */
+    if (s->version >= SSL3_VERSION) {
+        if (!ssl_parse_clienthello_tlsext(s, &extensions)) {
+            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_PARSE_TLSEXT);
+            goto err;
+        }
+    }
+
+    /*
+     * Check if we want to use external pre-shared secret for this handshake
+     * for not reused session only. We need to generate server_random before
+     * calling tls_session_secret_cb in order to allow SessionTicket
+     * processing to use it in key derivation.
+     */
+    {
+        unsigned char *pos;
+        pos = s->s3->server_random;
+        if (ssl_fill_hello_random(s, 1, pos, SSL3_RANDOM_SIZE) <= 0) {
+            goto f_err;
+        }
+    }
+
+    if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb) {
+        SSL_CIPHER *pref_cipher = NULL;
+
+        s->session->master_key_length = sizeof(s->session->master_key);
+        if (s->tls_session_secret_cb(s, s->session->master_key,
+                                     &s->session->master_key_length, ciphers,
+                                     &pref_cipher,
+                                     s->tls_session_secret_cb_arg)) {
+            s->hit = 1;
+            s->session->ciphers = ciphers;
+            s->session->verify_result = X509_V_OK;
+
+            ciphers = NULL;
+
+            /* check if some cipher was preferred by call back */
+            pref_cipher =
+                pref_cipher ? pref_cipher : ssl3_choose_cipher(s,
+                                                               s->
+                                                               session->ciphers,
+                                                               SSL_get_ciphers
+                                                               (s));
+            if (pref_cipher == NULL) {
+                al = SSL_AD_HANDSHAKE_FAILURE;
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_NO_SHARED_CIPHER);
+                goto f_err;
+            }
+
+            s->session->cipher = pref_cipher;
+            sk_SSL_CIPHER_free(s->cipher_list);
+            s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
+            sk_SSL_CIPHER_free(s->cipher_list_by_id);
+            s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
+        }
+    }
+
+    /*
+     * Worst case, we will use the NULL compression, but if we have other
+     * options, we will now look for them.  We have complen-1 compression
+     * algorithms from the client, starting at q.
+     */
+    s->s3->tmp.new_compression = NULL;
+#ifndef OPENSSL_NO_COMP
+    /* This only happens if we have a cache hit */
+    if (s->session->compress_meth != 0) {
+        int m, comp_id = s->session->compress_meth;
+        unsigned int k;
+        /* Perform sanity checks on resumed compression algorithm */
+        /* Can't disable compression */
+        if (!ssl_allow_compression(s)) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO,
+                   SSL_R_INCONSISTENT_COMPRESSION);
+            goto f_err;
+        }
+        /* Look for resumed compression method */
+        for (m = 0; m < sk_SSL_COMP_num(s->ctx->comp_methods); m++) {
+            comp = sk_SSL_COMP_value(s->ctx->comp_methods, m);
+            if (comp_id == comp->id) {
+                s->s3->tmp.new_compression = comp;
+                break;
+            }
+        }
+        if (s->s3->tmp.new_compression == NULL) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO,
+                   SSL_R_INVALID_COMPRESSION_ALGORITHM);
+            goto f_err;
+        }
+        /* Look for resumed method in compression list */
+        for (k = 0; k < complen; k++) {
+            if (PACKET_data(&compression)[k] == comp_id)
+                break;
+        }
+        if (k >= complen) {
+            al = SSL_AD_ILLEGAL_PARAMETER;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO,
+                   SSL_R_REQUIRED_COMPRESSSION_ALGORITHM_MISSING);
+            goto f_err;
+        }
+    } else if (s->hit)
+        comp = NULL;
+    else if (ssl_allow_compression(s) && s->ctx->comp_methods) {
+        /* See if we have a match */
+        int m, nn, v, done = 0;
+        unsigned int o;
+
+        nn = sk_SSL_COMP_num(s->ctx->comp_methods);
+        for (m = 0; m < nn; m++) {
+            comp = sk_SSL_COMP_value(s->ctx->comp_methods, m);
+            v = comp->id;
+            for (o = 0; o < complen; o++) {
+                if (v == PACKET_data(&compression)[o]) {
+                    done = 1;
+                    break;
+                }
+            }
+            if (done)
+                break;
+        }
+        if (done)
+            s->s3->tmp.new_compression = comp;
+        else
+            comp = NULL;
+    }
+#else
+    /*
+     * If compression is disabled we'd better not try to resume a session
+     * using compression.
+     */
+    if (s->session->compress_meth != 0) {
+        SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_INCONSISTENT_COMPRESSION);
+        goto f_err;
+    }
+#endif
+
+    /*
+     * Given s->session->ciphers and SSL_get_ciphers, we must pick a cipher
+     */
+
+    if (!s->hit) {
+#ifdef OPENSSL_NO_COMP
+        s->session->compress_meth = 0;
+#else
+        s->session->compress_meth = (comp == NULL) ? 0 : comp->id;
+#endif
+        sk_SSL_CIPHER_free(s->session->ciphers);
+        s->session->ciphers = ciphers;
+        if (ciphers == NULL) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+            goto f_err;
+        }
+        ciphers = NULL;
+        if (!tls1_set_server_sigalgs(s)) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT);
+            goto err;
+        }
+    }
+
+    sk_SSL_CIPHER_free(ciphers);
+    return MSG_PROCESS_CONTINUE_PROCESSING;
+ f_err:
+    ssl3_send_alert(s, SSL3_AL_FATAL, al);
+ err:
+    statem_set_error(s);
+
+    sk_SSL_CIPHER_free(ciphers);
+    return MSG_PROCESS_ERROR;
+
+}
+
+enum WORK_STATE tls_post_process_client_hello(SSL *s, enum WORK_STATE wst)
+{
+    int al;
+    SSL_CIPHER *cipher;
+
+    if (wst == WORK_MORE_A) {
+        if (!s->hit) {
+            /* Let cert callback update server certificates if required */
+            if (s->cert->cert_cb) {
+                int rv = s->cert->cert_cb(s, s->cert->cert_cb_arg);
+                if (rv == 0) {
+                    al = SSL_AD_INTERNAL_ERROR;
+                    SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO, SSL_R_CERT_CB_ERROR);
+                    goto f_err;
+                }
+                if (rv < 0) {
+                    s->rwstate = SSL_X509_LOOKUP;
+                    return WORK_MORE_A;
+                }
+                s->rwstate = SSL_NOTHING;
+            }
+            cipher = ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
+
+            if (cipher == NULL) {
+                al = SSL_AD_HANDSHAKE_FAILURE;
+                SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO, SSL_R_NO_SHARED_CIPHER);
+                goto f_err;
+            }
+            s->s3->tmp.new_cipher = cipher;
+            /* check whether we should disable session resumption */
+            if (s->not_resumable_session_cb != NULL)
+                s->session->not_resumable = s->not_resumable_session_cb(s,
+                    ((cipher->algorithm_mkey & (SSL_kDHE | SSL_kECDHE)) != 0));
+            if (s->session->not_resumable)
+                /* do not send a session ticket */
+                s->tlsext_ticket_expected = 0;
+        } else {
+            /* Session-id reuse */
+            s->s3->tmp.new_cipher = s->session->cipher;
+        }
+
+        if (!SSL_USE_SIGALGS(s) || !(s->verify_mode & SSL_VERIFY_PEER)) {
+            if (!ssl3_digest_cached_records(s, 0))
+                goto f_err;
+        }
+
+        /*-
+         * we now have the following setup.
+         * client_random
+         * cipher_list          - our prefered list of ciphers
+         * ciphers              - the clients prefered list of ciphers
+         * compression          - basically ignored right now
+         * ssl version is set   - sslv3
+         * s->session           - The ssl session has been setup.
+         * s->hit               - session reuse flag
+         * s->s3->tmp.new_cipher- the new cipher to use.
+         */
+
+        /* Handles TLS extensions that we couldn't check earlier */
+        if (s->version >= SSL3_VERSION) {
+            if (ssl_check_clienthello_tlsext_late(s) <= 0) {
+                SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT);
+                goto f_err;
+            }
+        }
+
+        wst = WORK_MORE_B;
+    }
+#ifndef OPENSSL_NO_SRP
+    if (wst == WORK_MORE_B) {
+        int ret;
+        if ((ret = ssl_check_srp_ext_ClientHello(s, &al)) < 0) {
+            /*
+             * callback indicates further work to be done
+             */
+            s->rwstate = SSL_X509_LOOKUP;
+            return WORK_MORE_B;
+        }
+        if (ret != SSL_ERROR_NONE) {
+            /*
+             * This is not really an error but the only means to for
+             * a client to detect whether srp is supported.
+             */
+            if (al != TLS1_AD_UNKNOWN_PSK_IDENTITY)
+                SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO,
+                           SSL_R_CLIENTHELLO_TLSEXT);
+            goto f_err;
+        }
+    }
+#endif
+    s->renegotiate = 2;
+
+    return WORK_FINISHED_STOP;
+ f_err:
+    ssl3_send_alert(s, SSL3_AL_FATAL, al);
+    statem_set_error(s);
+    return WORK_ERROR;
+}
+
+int tls_construct_server_hello(SSL *s)
+{
+    unsigned char *buf;
+    unsigned char *p, *d;
+    int i, sl;
+    int al = 0;
+    unsigned long l;
+
+    buf = (unsigned char *)s->init_buf->data;
+
+    /* Do the message type and length last */
+    d = p = ssl_handshake_start(s);
+
+    *(p++) = s->version >> 8;
+    *(p++) = s->version & 0xff;
+
+    /*
+     * Random stuff. Filling of the server_random takes place in
+     * tls_process_client_hello()
+     */
+    memcpy(p, s->s3->server_random, SSL3_RANDOM_SIZE);
+    p += SSL3_RANDOM_SIZE;
+
+    /*-
+     * There are several cases for the session ID to send
+     * back in the server hello:
+     * - For session reuse from the session cache,
+     *   we send back the old session ID.
+     * - If stateless session reuse (using a session ticket)
+     *   is successful, we send back the client's "session ID"
+     *   (which doesn't actually identify the session).
+     * - If it is a new session, we send back the new
+     *   session ID.
+     * - However, if we want the new session to be single-use,
+     *   we send back a 0-length session ID.
+     * s->hit is non-zero in either case of session reuse,
+     * so the following won't overwrite an ID that we're supposed
+     * to send back.
+     */
+    if (s->session->not_resumable ||
+        (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER)
+         && !s->hit))
+        s->session->session_id_length = 0;
+
+    sl = s->session->session_id_length;
+    if (sl > (int)sizeof(s->session->session_id)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
+        statem_set_error(s);
+        return 0;
+    }
+    *(p++) = sl;
+    memcpy(p, s->session->session_id, sl);
+    p += sl;
+
+    /* put the cipher */
+    i = ssl3_put_cipher_by_char(s->s3->tmp.new_cipher, p);
+    p += i;
+
+    /* put the compression method */
+#ifdef OPENSSL_NO_COMP
+    *(p++) = 0;
+#else
+    if (s->s3->tmp.new_compression == NULL)
+        *(p++) = 0;
+    else
+        *(p++) = s->s3->tmp.new_compression->id;
+#endif
+
+    if (ssl_prepare_serverhello_tlsext(s) <= 0) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_HELLO, SSL_R_SERVERHELLO_TLSEXT);
+        statem_set_error(s);
+        return 0;
+    }
+    if ((p =
+         ssl_add_serverhello_tlsext(s, p, buf + SSL3_RT_MAX_PLAIN_LENGTH,
+                                    &al)) == NULL) {
+        ssl3_send_alert(s, SSL3_AL_FATAL, al);
+        SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
+        statem_set_error(s);
+        return 0;
+    }
+
+    /* do the header */
+    l = (p - d);
+    if (!ssl_set_handshake_header(s, SSL3_MT_SERVER_HELLO, l)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
+        statem_set_error(s);
+        return 0;
+    }
+
+    return 1;
+}
+
+int tls_construct_server_done(SSL *s)
+{
+    if (!ssl_set_handshake_header(s, SSL3_MT_SERVER_DONE, 0)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_DONE, ERR_R_INTERNAL_ERROR);
+        statem_set_error(s);
+        return 0;
+    }
+
+    if (!s->s3->tmp.cert_request) {
+        if (!ssl3_digest_cached_records(s, 0)) {
+            statem_set_error(s);
+        }
+    }
+
+    return 1;
+}
+
+int tls_construct_server_key_exchange(SSL *s)
+{
+#ifndef OPENSSL_NO_RSA
+    unsigned char *q;
+    int j, num;
+    RSA *rsa;
+    unsigned char md_buf[MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH];
+    unsigned int u;
+#endif
+#ifndef OPENSSL_NO_DH
+    DH *dh = NULL, *dhp;
+#endif
+#ifndef OPENSSL_NO_EC
+    EC_KEY *ecdh = NULL, *ecdhp;
+    unsigned char *encodedPoint = NULL;
+    int encodedlen = 0;
+    int curve_id = 0;
+    BN_CTX *bn_ctx = NULL;
+#endif
+    EVP_PKEY *pkey;
+    const EVP_MD *md = NULL;
+    unsigned char *p, *d;
+    int al, i;
+    unsigned long type;
+    int n;
+    CERT *cert;
+    BIGNUM *r[4];
+    int nr[4], kn;
+    BUF_MEM *buf;
+    EVP_MD_CTX md_ctx;
+
+    EVP_MD_CTX_init(&md_ctx);
+
+    type = s->s3->tmp.new_cipher->algorithm_mkey;
+    cert = s->cert;
+
+    buf = s->init_buf;
+
+    r[0] = r[1] = r[2] = r[3] = NULL;
+    n = 0;
+#ifndef OPENSSL_NO_PSK
+    if (type & SSL_PSK) {
+        /*
+         * reserve size for record length and PSK identity hint
+         */
+        n += 2;
+        if (s->cert->psk_identity_hint)
+            n += strlen(s->cert->psk_identity_hint);
+    }
+    /* Plain PSK or RSAPSK nothing to do */
+    if (type & (SSL_kPSK | SSL_kRSAPSK)) {
+    } else
+#endif                          /* !OPENSSL_NO_PSK */
+#ifndef OPENSSL_NO_RSA
+    if (type & SSL_kRSA) {
+        rsa = cert->rsa_tmp;
+        if ((rsa == NULL) && (s->cert->rsa_tmp_cb != NULL)) {
+            rsa = s->cert->rsa_tmp_cb(s,
+                                      SSL_C_IS_EXPORT(s->s3->
+                                                      tmp.new_cipher),
+                                      SSL_C_EXPORT_PKEYLENGTH(s->s3->
+                                                              tmp.new_cipher));
+            if (rsa == NULL) {
+                al = SSL_AD_HANDSHAKE_FAILURE;
+                SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                       SSL_R_ERROR_GENERATING_TMP_RSA_KEY);
+                goto f_err;
+            }
+            RSA_up_ref(rsa);
+            cert->rsa_tmp = rsa;
+        }
+        if (rsa == NULL) {
+            al = SSL_AD_HANDSHAKE_FAILURE;
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                   SSL_R_MISSING_TMP_RSA_KEY);
+            goto f_err;
+        }
+        r[0] = rsa->n;
+        r[1] = rsa->e;
+        s->s3->tmp.use_rsa_tmp = 1;
+    } else
+#endif
+#ifndef OPENSSL_NO_DH
+    if (type & (SSL_kDHE | SSL_kDHEPSK)) {
+        if (s->cert->dh_tmp_auto) {
+            dhp = ssl_get_auto_dh(s);
+            if (dhp == NULL) {
+                al = SSL_AD_INTERNAL_ERROR;
+                SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                       ERR_R_INTERNAL_ERROR);
+                goto f_err;
+            }
+        } else
+            dhp = cert->dh_tmp;
+        if ((dhp == NULL) && (s->cert->dh_tmp_cb != NULL))
+            dhp = s->cert->dh_tmp_cb(s,
+                                     SSL_C_IS_EXPORT(s->s3->
+                                                     tmp.new_cipher),
+                                     SSL_C_EXPORT_PKEYLENGTH(s->s3->
+                                                             tmp.new_cipher));
+        if (dhp == NULL) {
+            al = SSL_AD_HANDSHAKE_FAILURE;
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                   SSL_R_MISSING_TMP_DH_KEY);
+            goto f_err;
+        }
+        if (!ssl_security(s, SSL_SECOP_TMP_DH,
+                          DH_security_bits(dhp), 0, dhp)) {
+            al = SSL_AD_HANDSHAKE_FAILURE;
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                   SSL_R_DH_KEY_TOO_SMALL);
+            goto f_err;
+        }
+        if (s->s3->tmp.dh != NULL) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                   ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+
+        if (s->cert->dh_tmp_auto)
+            dh = dhp;
+        else if ((dh = DHparams_dup(dhp)) == NULL) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_DH_LIB);
+            goto err;
+        }
+
+        s->s3->tmp.dh = dh;
+        if ((dhp->pub_key == NULL ||
+             dhp->priv_key == NULL ||
+             (s->options & SSL_OP_SINGLE_DH_USE))) {
+            if (!DH_generate_key(dh)) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_DH_LIB);
+                goto err;
+            }
+        } else {
+            dh->pub_key = BN_dup(dhp->pub_key);
+            dh->priv_key = BN_dup(dhp->priv_key);
+            if ((dh->pub_key == NULL) || (dh->priv_key == NULL)) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_DH_LIB);
+                goto err;
+            }
+        }
+        r[0] = dh->p;
+        r[1] = dh->g;
+        r[2] = dh->pub_key;
+    } else
+#endif
+#ifndef OPENSSL_NO_EC
+    if (type & (SSL_kECDHE | SSL_kECDHEPSK)) {
+        const EC_GROUP *group;
+
+        ecdhp = cert->ecdh_tmp;
+        if (s->cert->ecdh_tmp_auto) {
+            /* Get NID of appropriate shared curve */
+            int nid = tls1_shared_curve(s, -2);
+            if (nid != NID_undef)
+                ecdhp = EC_KEY_new_by_curve_name(nid);
+        } else if ((ecdhp == NULL) && s->cert->ecdh_tmp_cb) {
+            ecdhp = s->cert->ecdh_tmp_cb(s,
+                                         SSL_C_IS_EXPORT(s->s3->
+                                                         tmp.new_cipher),
+                                         SSL_C_EXPORT_PKEYLENGTH(s->
+                                                                 s3->tmp.new_cipher));
+        }
+        if (ecdhp == NULL) {
+            al = SSL_AD_HANDSHAKE_FAILURE;
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                   SSL_R_MISSING_TMP_ECDH_KEY);
+            goto f_err;
+        }
+
+        if (s->s3->tmp.ecdh != NULL) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                   ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+
+        /* Duplicate the ECDH structure. */
+        if (ecdhp == NULL) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_ECDH_LIB);
+            goto err;
+        }
+        if (s->cert->ecdh_tmp_auto)
+            ecdh = ecdhp;
+        else if ((ecdh = EC_KEY_dup(ecdhp)) == NULL) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_ECDH_LIB);
+            goto err;
+        }
+
+        s->s3->tmp.ecdh = ecdh;
+        if ((EC_KEY_get0_public_key(ecdh) == NULL) ||
+            (EC_KEY_get0_private_key(ecdh) == NULL) ||
+            (s->options & SSL_OP_SINGLE_ECDH_USE)) {
+            if (!EC_KEY_generate_key(ecdh)) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                       ERR_R_ECDH_LIB);
+                goto err;
+            }
+        }
+
+        if (((group = EC_KEY_get0_group(ecdh)) == NULL) ||
+            (EC_KEY_get0_public_key(ecdh) == NULL) ||
+            (EC_KEY_get0_private_key(ecdh) == NULL)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_ECDH_LIB);
+            goto err;
+        }
+
+        if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) &&
+            (EC_GROUP_get_degree(group) > 163)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                   SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER);
+            goto err;
+        }
+
+        /*
+         * XXX: For now, we only support ephemeral ECDH keys over named
+         * (not generic) curves. For supported named curves, curve_id is
+         * non-zero.
+         */
+        if ((curve_id =
+             tls1_ec_nid2curve_id(EC_GROUP_get_curve_name(group)))
+            == 0) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                   SSL_R_UNSUPPORTED_ELLIPTIC_CURVE);
+            goto err;
+        }
+
+        /*
+         * Encode the public key. First check the size of encoding and
+         * allocate memory accordingly.
+         */
+        encodedlen = EC_POINT_point2oct(group,
+                                        EC_KEY_get0_public_key(ecdh),
+                                        POINT_CONVERSION_UNCOMPRESSED,
+                                        NULL, 0, NULL);
+
+        encodedPoint = (unsigned char *)
+            OPENSSL_malloc(encodedlen * sizeof(unsigned char));
+        bn_ctx = BN_CTX_new();
+        if ((encodedPoint == NULL) || (bn_ctx == NULL)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                   ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+
+        encodedlen = EC_POINT_point2oct(group,
+                                        EC_KEY_get0_public_key(ecdh),
+                                        POINT_CONVERSION_UNCOMPRESSED,
+                                        encodedPoint, encodedlen, bn_ctx);
+
+        if (encodedlen == 0) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_ECDH_LIB);
+            goto err;
+        }
+
+        BN_CTX_free(bn_ctx);
+        bn_ctx = NULL;
+
+        /*
+         * XXX: For now, we only support named (not generic) curves in
+         * ECDH ephemeral key exchanges. In this situation, we need four
+         * additional bytes to encode the entire ServerECDHParams
+         * structure.
+         */
+        n += 4 + encodedlen;
+
+        /*
+         * We'll generate the serverKeyExchange message explicitly so we
+         * can set these to NULLs
+         */
+        r[0] = NULL;
+        r[1] = NULL;
+        r[2] = NULL;
+        r[3] = NULL;
+    } else
+#endif                          /* !OPENSSL_NO_EC */
+#ifndef OPENSSL_NO_SRP
+    if (type & SSL_kSRP) {
+        if ((s->srp_ctx.N == NULL) ||
+            (s->srp_ctx.g == NULL) ||
+            (s->srp_ctx.s == NULL) || (s->srp_ctx.B == NULL)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                   SSL_R_MISSING_SRP_PARAM);
+            goto err;
+        }
+        r[0] = s->srp_ctx.N;
+        r[1] = s->srp_ctx.g;
+        r[2] = s->srp_ctx.s;
+        r[3] = s->srp_ctx.B;
+    } else
+#endif
+    {
+        al = SSL_AD_HANDSHAKE_FAILURE;
+        SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+               SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE);
+        goto f_err;
+    }
+    for (i = 0; i < 4 && r[i] != NULL; i++) {
+        nr[i] = BN_num_bytes(r[i]);
+#ifndef OPENSSL_NO_SRP
+        if ((i == 2) && (type & SSL_kSRP))
+            n += 1 + nr[i];
+        else
+#endif
+            n += 2 + nr[i];
+    }
+
+    if (!(s->s3->tmp.new_cipher->algorithm_auth & (SSL_aNULL|SSL_aSRP))
+        && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_PSK)) {
+        if ((pkey = ssl_get_sign_pkey(s, s->s3->tmp.new_cipher, &md))
+            == NULL) {
+            al = SSL_AD_DECODE_ERROR;
+            goto f_err;
+        }
+        kn = EVP_PKEY_size(pkey);
+    } else {
+        pkey = NULL;
+        kn = 0;
+    }
+
+    if (!BUF_MEM_grow_clean(buf, n + SSL_HM_HEADER_LENGTH(s) + kn)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_LIB_BUF);
+        goto err;
+    }
+    d = p = ssl_handshake_start(s);
+
+#ifndef OPENSSL_NO_PSK
+    if (type & SSL_PSK) {
+        /* copy PSK identity hint */
+        if (s->cert->psk_identity_hint) {
+            s2n(strlen(s->cert->psk_identity_hint), p);
+            strncpy((char *)p, s->cert->psk_identity_hint,
+                    strlen(s->cert->psk_identity_hint));
+            p += strlen(s->cert->psk_identity_hint);
+        } else {
+            s2n(0, p);
+        }
+    }
+#endif
+
+    for (i = 0; i < 4 && r[i] != NULL; i++) {
+#ifndef OPENSSL_NO_SRP
+        if ((i == 2) && (type & SSL_kSRP)) {
+            *p = nr[i];
+            p++;
+        } else
+#endif
+            s2n(nr[i], p);
+        BN_bn2bin(r[i], p);
+        p += nr[i];
+    }
+
+#ifndef OPENSSL_NO_EC
+    if (type & (SSL_kECDHE | SSL_kECDHEPSK)) {
+        /*
+         * XXX: For now, we only support named (not generic) curves. In
+         * this situation, the serverKeyExchange message has: [1 byte
+         * CurveType], [2 byte CurveName] [1 byte length of encoded
+         * point], followed by the actual encoded point itself
+         */
+        *p = NAMED_CURVE_TYPE;
+        p += 1;
+        *p = 0;
+        p += 1;
+        *p = curve_id;
+        p += 1;
+        *p = encodedlen;
+        p += 1;
+        memcpy(p, encodedPoint, encodedlen);
+        OPENSSL_free(encodedPoint);
+        encodedPoint = NULL;
+        p += encodedlen;
+    }
+#endif
+
+    /* not anonymous */
+    if (pkey != NULL) {
+        /*
+         * n is the length of the params, they start at &(d[4]) and p
+         * points to the space at the end.
+         */
+#ifndef OPENSSL_NO_RSA
+        if (pkey->type == EVP_PKEY_RSA && !SSL_USE_SIGALGS(s)) {
+            q = md_buf;
+            j = 0;
+            for (num = 2; num > 0; num--) {
+                EVP_MD_CTX_set_flags(&md_ctx,
+                                     EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
+                EVP_DigestInit_ex(&md_ctx, (num == 2)
+                                  ? s->ctx->md5 : s->ctx->sha1, NULL);
+                EVP_DigestUpdate(&md_ctx, &(s->s3->client_random[0]),
+                                 SSL3_RANDOM_SIZE);
+                EVP_DigestUpdate(&md_ctx, &(s->s3->server_random[0]),
+                                 SSL3_RANDOM_SIZE);
+                EVP_DigestUpdate(&md_ctx, d, n);
+                EVP_DigestFinal_ex(&md_ctx, q, (unsigned int *)&i);
+                q += i;
+                j += i;
+            }
+            if (RSA_sign(NID_md5_sha1, md_buf, j,
+                         &(p[2]), &u, pkey->pkey.rsa) <= 0) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_LIB_RSA);
+                goto err;
+            }
+            s2n(u, p);
+            n += u + 2;
+        } else
+#endif
+        if (md) {
+            /* send signature algorithm */
+            if (SSL_USE_SIGALGS(s)) {
+                if (!tls12_get_sigandhash(p, pkey, md)) {
+                    /* Should never happen */
+                    al = SSL_AD_INTERNAL_ERROR;
+                    SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                           ERR_R_INTERNAL_ERROR);
+                    goto f_err;
+                }
+                p += 2;
+            }
+#ifdef SSL_DEBUG
+            fprintf(stderr, "Using hash %s\n", EVP_MD_name(md));
+#endif
+            EVP_SignInit_ex(&md_ctx, md, NULL);
+            EVP_SignUpdate(&md_ctx, &(s->s3->client_random[0]),
+                           SSL3_RANDOM_SIZE);
+            EVP_SignUpdate(&md_ctx, &(s->s3->server_random[0]),
+                           SSL3_RANDOM_SIZE);
+            EVP_SignUpdate(&md_ctx, d, n);
+            if (!EVP_SignFinal(&md_ctx, &(p[2]),
+                               (unsigned int *)&i, pkey)) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_LIB_EVP);
+                goto err;
+            }
+            s2n(i, p);
+            n += i + 2;
+            if (SSL_USE_SIGALGS(s))
+                n += 2;
+        } else {
+            /* Is this error check actually needed? */
+            al = SSL_AD_HANDSHAKE_FAILURE;
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                   SSL_R_UNKNOWN_PKEY_TYPE);
+            goto f_err;
+        }
+    }
+
+    if (!ssl_set_handshake_header(s, SSL3_MT_SERVER_KEY_EXCHANGE, n)) {
+        al = SSL_AD_HANDSHAKE_FAILURE;
+        SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+        goto f_err;
+    }
+
+    EVP_MD_CTX_cleanup(&md_ctx);
+    return 1;
+ f_err:
+    ssl3_send_alert(s, SSL3_AL_FATAL, al);
+ err:
+#ifndef OPENSSL_NO_EC
+    OPENSSL_free(encodedPoint);
+    BN_CTX_free(bn_ctx);
+#endif
+    EVP_MD_CTX_cleanup(&md_ctx);
+    statem_set_error(s);
+    return 0;
+}
+
+int tls_construct_certificate_request(SSL *s)
+{
+    unsigned char *p, *d;
+    int i, j, nl, off, n;
+    STACK_OF(X509_NAME) *sk = NULL;
+    X509_NAME *name;
+    BUF_MEM *buf;
+
+    buf = s->init_buf;
+
+    d = p = ssl_handshake_start(s);
+
+    /* get the list of acceptable cert types */
+    p++;
+    n = ssl3_get_req_cert_type(s, p);
+    d[0] = n;
+    p += n;
+    n++;
+
+    if (SSL_USE_SIGALGS(s)) {
+        const unsigned char *psigs;
+        unsigned char *etmp = p;
+        nl = tls12_get_psigalgs(s, &psigs);
+        /* Skip over length for now */
+        p += 2;
+        nl = tls12_copy_sigalgs(s, p, psigs, nl);
+        /* Now fill in length */
+        s2n(nl, etmp);
+        p += nl;
+        n += nl + 2;
+    }
+
+    off = n;
+    p += 2;
+    n += 2;
+
+    sk = SSL_get_client_CA_list(s);
+    nl = 0;
+    if (sk != NULL) {
+        for (i = 0; i < sk_X509_NAME_num(sk); i++) {
+            name = sk_X509_NAME_value(sk, i);
+            j = i2d_X509_NAME(name, NULL);
+            if (!BUF_MEM_grow_clean
+                (buf, SSL_HM_HEADER_LENGTH(s) + n + j + 2)) {
+                SSLerr(SSL_F_TLS_CONSTRUCT_CERTIFICATE_REQUEST,
+                       ERR_R_BUF_LIB);
+                goto err;
+            }
+            p = ssl_handshake_start(s) + n;
+            s2n(j, p);
+            i2d_X509_NAME(name, &p);
+            n += 2 + j;
+            nl += 2 + j;
+        }
+    }
+    /* else no CA names */
+    p = ssl_handshake_start(s) + off;
+    s2n(nl, p);
+
+    if (!ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE_REQUEST, n)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CERTIFICATE_REQUEST, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    s->s3->tmp.cert_request = 1;
+
+    return 1;
+ err:
+    statem_set_error(s);
+    return 0;
+}
+
+enum MSG_PROCESS_RETURN tls_process_client_key_exchange(SSL *s, PACKET *pkt)
+{
+    int al;
+    unsigned int i;
+    unsigned long alg_k;
+#ifndef OPENSSL_NO_RSA
+    RSA *rsa = NULL;
+    EVP_PKEY *pkey = NULL;
+#endif
+#ifndef OPENSSL_NO_DH
+    BIGNUM *pub = NULL;
+    DH *dh_srvr, *dh_clnt = NULL;
+#endif
+#ifndef OPENSSL_NO_EC
+    EC_KEY *srvr_ecdh = NULL;
+    EVP_PKEY *clnt_pub_pkey = NULL;
+    EC_POINT *clnt_ecpoint = NULL;
+    BN_CTX *bn_ctx = NULL;
+#endif
+    PACKET enc_premaster;
+    unsigned char *data, *rsa_decrypt = NULL;
+
+    alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+
+#ifndef OPENSSL_NO_PSK
+    /* For PSK parse and retrieve identity, obtain PSK key */
+    if (alg_k & SSL_PSK) {
+        unsigned char psk[PSK_MAX_PSK_LEN];
+        size_t psklen;
+        PACKET psk_identity;
+
+        if (!PACKET_get_length_prefixed_2(pkt, &psk_identity)) {
+            al = SSL_AD_DECODE_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
+            goto f_err;
+        }
+        if (PACKET_remaining(&psk_identity) > PSK_MAX_IDENTITY_LEN) {
+            al = SSL_AD_DECODE_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                   SSL_R_DATA_LENGTH_TOO_LONG);
+            goto f_err;
+        }
+        if (s->psk_server_callback == NULL) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                   SSL_R_PSK_NO_SERVER_CB);
+            goto f_err;
+        }
+
+        if (!PACKET_strndup(&psk_identity, &s->session->psk_identity)) {
+            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            al = SSL_AD_INTERNAL_ERROR;
+            goto f_err;
+        }
+
+        psklen = s->psk_server_callback(s, s->session->psk_identity,
+                                         psk, sizeof(psk));
+
+        if (psklen > PSK_MAX_PSK_LEN) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            goto f_err;
+        } else if (psklen == 0) {
+            /*
+             * PSK related to the given identity not found
+             */
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                   SSL_R_PSK_IDENTITY_NOT_FOUND);
+            al = SSL_AD_UNKNOWN_PSK_IDENTITY;
+            goto f_err;
+        }
+
+        OPENSSL_free(s->s3->tmp.psk);
+        s->s3->tmp.psk = BUF_memdup(psk, psklen);
+        OPENSSL_cleanse(psk, psklen);
+
+        if (s->s3->tmp.psk == NULL) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+            goto f_err;
+        }
+
+        s->s3->tmp.psklen = psklen;
+    }
+    if (alg_k & SSL_kPSK) {
+        /* Identity extracted earlier: should be nothing left */
+        if (PACKET_remaining(pkt) != 0) {
+            al = SSL_AD_HANDSHAKE_FAILURE;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
+            goto f_err;
+        }
+        /* PSK handled by ssl_generate_master_secret */
+        if (!ssl_generate_master_secret(s, NULL, 0, 0)) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            goto f_err;
+        }
+    } else
+#endif
+#ifndef OPENSSL_NO_RSA
+    if (alg_k & (SSL_kRSA | SSL_kRSAPSK)) {
+        unsigned char rand_premaster_secret[SSL_MAX_MASTER_KEY_LENGTH];
+        int decrypt_len;
+        unsigned char decrypt_good, version_good;
+        size_t j;
+
+        /* FIX THIS UP EAY EAY EAY EAY */
+        if (s->s3->tmp.use_rsa_tmp) {
+            if ((s->cert != NULL) && (s->cert->rsa_tmp != NULL))
+                rsa = s->cert->rsa_tmp;
+            /*
+             * Don't do a callback because rsa_tmp should be sent already
+             */
+            if (rsa == NULL) {
+                al = SSL_AD_HANDSHAKE_FAILURE;
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                       SSL_R_MISSING_TMP_RSA_PKEY);
+                goto f_err;
+
+            }
+        } else {
+            pkey = s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey;
+            if ((pkey == NULL) ||
+                (pkey->type != EVP_PKEY_RSA) || (pkey->pkey.rsa == NULL)) {
+                al = SSL_AD_HANDSHAKE_FAILURE;
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                       SSL_R_MISSING_RSA_CERTIFICATE);
+                goto f_err;
+            }
+            rsa = pkey->pkey.rsa;
+        }
+
+        /* SSLv3 and pre-standard DTLS omit the length bytes. */
+        if (s->version == SSL3_VERSION || s->version == DTLS1_BAD_VER) {
+            enc_premaster = *pkt;
+        } else {
+            PACKET orig = *pkt;
+            if (!PACKET_get_length_prefixed_2(pkt, &enc_premaster)
+                || PACKET_remaining(pkt) != 0) {
+                /* Try SSLv3 behaviour for TLS. */
+                if (s->options & SSL_OP_TLS_D5_BUG) {
+                    enc_premaster = orig;
+                } else {
+                    al = SSL_AD_DECODE_ERROR;
+                    SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
+                    goto f_err;
+                }
+            }
+        }
+
+        /*
+         * We want to be sure that the plaintext buffer size makes it safe to
+         * iterate over the entire size of a premaster secret
+         * (SSL_MAX_MASTER_KEY_LENGTH). Reject overly short RSA keys because
+         * their ciphertext cannot accommodate a premaster secret anyway.
+         */
+        if (RSA_size(rsa) < SSL_MAX_MASTER_KEY_LENGTH) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+                   RSA_R_KEY_SIZE_TOO_SMALL);
+            goto f_err;
+        }
+
+        rsa_decrypt = OPENSSL_malloc(RSA_size(rsa));
+        if (rsa_decrypt == NULL) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+            goto f_err;
+        }
+
+        /*
+         * We must not leak whether a decryption failure occurs because of
+         * Bleichenbacher's attack on PKCS #1 v1.5 RSA padding (see RFC 2246,
+         * section 7.4.7.1). The code follows that advice of the TLS RFC and
+         * generates a random premaster secret for the case that the decrypt
+         * fails. See https://tools.ietf.org/html/rfc5246#section-7.4.7.1
+         */
+
+        if (RAND_bytes(rand_premaster_secret,
+                       sizeof(rand_premaster_secret)) <= 0) {
+            goto err;
+        }
+
+        decrypt_len = RSA_private_decrypt(PACKET_remaining(&enc_premaster),
+                                          PACKET_data(&enc_premaster),
+                                          rsa_decrypt, rsa, RSA_PKCS1_PADDING);
+        ERR_clear_error();
+
+        /*
+         * decrypt_len should be SSL_MAX_MASTER_KEY_LENGTH. decrypt_good will
+         * be 0xff if so and zero otherwise.
+         */
+        decrypt_good =
+            constant_time_eq_int_8(decrypt_len, SSL_MAX_MASTER_KEY_LENGTH);
+
+        /*
+         * If the version in the decrypted pre-master secret is correct then
+         * version_good will be 0xff, otherwise it'll be zero. The
+         * Klima-Pokorny-Rosa extension of Bleichenbacher's attack
+         * (http://eprint.iacr.org/2003/052/) exploits the version number
+         * check as a "bad version oracle". Thus version checks are done in
+         * constant time and are treated like any other decryption error.
+         */
+        version_good =
+            constant_time_eq_8(rsa_decrypt[0],
+                               (unsigned)(s->client_version >> 8));
+        version_good &=
+            constant_time_eq_8(rsa_decrypt[1],
+                               (unsigned)(s->client_version & 0xff));
+
+        /*
+         * The premaster secret must contain the same version number as the
+         * ClientHello to detect version rollback attacks (strangely, the
+         * protocol does not offer such protection for DH ciphersuites).
+         * However, buggy clients exist that send the negotiated protocol
+         * version instead if the server does not support the requested
+         * protocol version. If SSL_OP_TLS_ROLLBACK_BUG is set, tolerate such
+         * clients.
+         */
+        if (s->options & SSL_OP_TLS_ROLLBACK_BUG) {
+            unsigned char workaround_good;
+            workaround_good =
+                constant_time_eq_8(rsa_decrypt[0], (unsigned)(s->version >> 8));
+            workaround_good &=
+                constant_time_eq_8(rsa_decrypt[1],
+                                   (unsigned)(s->version & 0xff));
+            version_good |= workaround_good;
+        }
+
+        /*
+         * Both decryption and version must be good for decrypt_good to
+         * remain non-zero (0xff).
+         */
+        decrypt_good &= version_good;
+
+        /*
+         * Now copy rand_premaster_secret over from p using
+         * decrypt_good_mask. If decryption failed, then p does not
+         * contain valid plaintext, however, a check above guarantees
+         * it is still sufficiently large to read from.
+         */
+        for (j = 0; j < sizeof(rand_premaster_secret); j++) {
+            rsa_decrypt[j] =
+                constant_time_select_8(decrypt_good, rsa_decrypt[j],
+                                       rand_premaster_secret[j]);
+        }
+
+        if (!ssl_generate_master_secret(s, rsa_decrypt,
+                                        sizeof(rand_premaster_secret), 0)) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            goto f_err;
+        }
+        OPENSSL_free(rsa_decrypt);
+        rsa_decrypt = NULL;
+    } else
+#endif
+#ifndef OPENSSL_NO_DH
+    if (alg_k & (SSL_kDHE | SSL_kDHr | SSL_kDHd | SSL_kDHEPSK)) {
+        int idx = -1;
+        EVP_PKEY *skey = NULL;
+        PACKET bookmark = *pkt;
+        unsigned char shared[(OPENSSL_DH_MAX_MODULUS_BITS + 7) / 8];
+
+        if (!PACKET_get_net_2(pkt, &i)) {
+            if (alg_k & (SSL_kDHE | SSL_kDHEPSK)) {
+                al = SSL_AD_HANDSHAKE_FAILURE;
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                       SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG);
+                goto f_err;
+            }
+            i = 0;
+        }
+        if (PACKET_remaining(pkt) != i) {
+            if (!(s->options & SSL_OP_SSLEAY_080_CLIENT_DH_BUG)) {
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                       SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG);
+                goto err;
+            } else {
+                *pkt = bookmark;
+                i = PACKET_remaining(pkt);
+            }
+        }
+        if (alg_k & SSL_kDHr)
+            idx = SSL_PKEY_DH_RSA;
+        else if (alg_k & SSL_kDHd)
+            idx = SSL_PKEY_DH_DSA;
+        if (idx >= 0) {
+            skey = s->cert->pkeys[idx].privatekey;
+            if ((skey == NULL) ||
+                (skey->type != EVP_PKEY_DH) || (skey->pkey.dh == NULL)) {
+                al = SSL_AD_HANDSHAKE_FAILURE;
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                       SSL_R_MISSING_RSA_CERTIFICATE);
+                goto f_err;
+            }
+            dh_srvr = skey->pkey.dh;
+        } else if (s->s3->tmp.dh == NULL) {
+            al = SSL_AD_HANDSHAKE_FAILURE;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                   SSL_R_MISSING_TMP_DH_KEY);
+            goto f_err;
+        } else
+            dh_srvr = s->s3->tmp.dh;
+
+        if (PACKET_remaining(pkt) == 0L) {
+            /* Get pubkey from cert */
+            EVP_PKEY *clkey = X509_get_pubkey(s->session->peer);
+            if (clkey) {
+                if (EVP_PKEY_cmp_parameters(clkey, skey) == 1)
+                    dh_clnt = EVP_PKEY_get1_DH(clkey);
+            }
+            if (dh_clnt == NULL) {
+                al = SSL_AD_HANDSHAKE_FAILURE;
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                       SSL_R_MISSING_TMP_DH_KEY);
+                goto f_err;
+            }
+            EVP_PKEY_free(clkey);
+            pub = dh_clnt->pub_key;
+        } else {
+            if (!PACKET_get_bytes(pkt, &data, i)) {
+                /* We already checked we have enough data */
+                al = SSL_AD_INTERNAL_ERROR;
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                       ERR_R_INTERNAL_ERROR);
+                goto f_err;
+            }
+            pub = BN_bin2bn(data, i, NULL);
+        }
+        if (pub == NULL) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, SSL_R_BN_LIB);
+            goto err;
+        }
+
+        i = DH_compute_key(shared, pub, dh_srvr);
+
+        if (i <= 0) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB);
+            BN_clear_free(pub);
+            goto err;
+        }
+
+        DH_free(s->s3->tmp.dh);
+        s->s3->tmp.dh = NULL;
+        if (dh_clnt)
+            DH_free(dh_clnt);
+        else
+            BN_clear_free(pub);
+        pub = NULL;
+        if (!ssl_generate_master_secret(s, shared, i, 0)) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            goto f_err;
+        }
+        if (dh_clnt) {
+            s->no_cert_verify = 1;
+            return MSG_PROCESS_CONTINUE_PROCESSING;
+        }
+    } else
+#endif
+
+#ifndef OPENSSL_NO_EC
+    if (alg_k & (SSL_kECDHE | SSL_kECDHr | SSL_kECDHe | SSL_kECDHEPSK)) {
+        int field_size = 0;
+        const EC_KEY *tkey;
+        const EC_GROUP *group;
+        const BIGNUM *priv_key;
+        unsigned char *shared;
+
+        /* initialize structures for server's ECDH key pair */
+        if ((srvr_ecdh = EC_KEY_new()) == NULL) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+
+        /* Let's get server private key and group information */
+        if (alg_k & (SSL_kECDHr | SSL_kECDHe)) {
+            /* use the certificate */
+            tkey = s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec;
+        } else {
+            /*
+             * use the ephermeral values we saved when generating the
+             * ServerKeyExchange msg.
+             */
+            tkey = s->s3->tmp.ecdh;
+        }
+
+        group = EC_KEY_get0_group(tkey);
+        priv_key = EC_KEY_get0_private_key(tkey);
+
+        if (!EC_KEY_set_group(srvr_ecdh, group) ||
+            !EC_KEY_set_private_key(srvr_ecdh, priv_key)) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
+            goto err;
+        }
+
+        /* Let's get client's public key */
+        if ((clnt_ecpoint = EC_POINT_new(group)) == NULL) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+
+        if (PACKET_remaining(pkt) == 0L) {
+            /* Client Publickey was in Client Certificate */
+
+            if (alg_k & (SSL_kECDHE | SSL_kECDHEPSK)) {
+                al = SSL_AD_HANDSHAKE_FAILURE;
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                       SSL_R_MISSING_TMP_ECDH_KEY);
+                goto f_err;
+            }
+            if (((clnt_pub_pkey = X509_get_pubkey(s->session->peer))
+                 == NULL) || (clnt_pub_pkey->type != EVP_PKEY_EC)) {
+                /*
+                 * XXX: For now, we do not support client authentication
+                 * using ECDH certificates so this branch (n == 0L) of the
+                 * code is never executed. When that support is added, we
+                 * ought to ensure the key received in the certificate is
+                 * authorized for key agreement. ECDH_compute_key implicitly
+                 * checks that the two ECDH shares are for the same group.
+                 */
+                al = SSL_AD_HANDSHAKE_FAILURE;
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                       SSL_R_UNABLE_TO_DECODE_ECDH_CERTS);
+                goto f_err;
+            }
+
+            if (EC_POINT_copy(clnt_ecpoint,
+                              EC_KEY_get0_public_key(clnt_pub_pkey->
+                                                     pkey.ec)) == 0) {
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
+                goto err;
+            }
+            s->no_cert_verify = 1;
+        } else {
+            /*
+             * Get client's public key from encoded point in the
+             * ClientKeyExchange message.
+             */
+            if ((bn_ctx = BN_CTX_new()) == NULL) {
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                       ERR_R_MALLOC_FAILURE);
+                goto err;
+            }
+
+            /* Get encoded point length */
+            if (!PACKET_get_1(pkt, &i)) {
+                al = SSL_AD_DECODE_ERROR;
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                       SSL_R_LENGTH_MISMATCH);
+                goto f_err;
+            }
+            if (!PACKET_get_bytes(pkt, &data, i)
+                    || PACKET_remaining(pkt) != 0) {
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
+                goto err;
+            }
+            if (EC_POINT_oct2point(group, clnt_ecpoint, data, i, bn_ctx) == 0) {
+                SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
+                goto err;
+            }
+        }
+
+        /* Compute the shared pre-master secret */
+        field_size = EC_GROUP_get_degree(group);
+        if (field_size <= 0) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
+            goto err;
+        }
+        shared = OPENSSL_malloc((field_size + 7) / 8);
+        if (shared == NULL) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+        i = ECDH_compute_key(shared, (field_size + 7) / 8, clnt_ecpoint,
+                             srvr_ecdh, NULL);
+        if (i <= 0) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
+            OPENSSL_free(shared);
+            goto err;
+        }
+
+        EVP_PKEY_free(clnt_pub_pkey);
+        EC_POINT_free(clnt_ecpoint);
+        EC_KEY_free(srvr_ecdh);
+        BN_CTX_free(bn_ctx);
+        EC_KEY_free(s->s3->tmp.ecdh);
+        s->s3->tmp.ecdh = NULL;
+
+        if (!ssl_generate_master_secret(s, shared, i, 1)) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            goto f_err;
+        }
+        return MSG_PROCESS_CONTINUE_PROCESSING;
+    } else
+#endif
+#ifndef OPENSSL_NO_SRP
+    if (alg_k & SSL_kSRP) {
+        if (!PACKET_get_net_2(pkt, &i)
+                || !PACKET_get_bytes(pkt, &data, i)) {
+            al = SSL_AD_DECODE_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, SSL_R_BAD_SRP_A_LENGTH);
+            goto f_err;
+        }
+        if ((s->srp_ctx.A = BN_bin2bn(data, i, NULL)) == NULL) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_BN_LIB);
+            goto err;
+        }
+        if (BN_ucmp(s->srp_ctx.A, s->srp_ctx.N) >= 0
+            || BN_is_zero(s->srp_ctx.A)) {
+            al = SSL_AD_ILLEGAL_PARAMETER;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                   SSL_R_BAD_SRP_PARAMETERS);
+            goto f_err;
+        }
+        OPENSSL_free(s->session->srp_username);
+        s->session->srp_username = BUF_strdup(s->srp_ctx.login);
+        if (s->session->srp_username == NULL) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+
+        if (!srp_generate_server_master_secret(s)) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+    } else
+#endif                          /* OPENSSL_NO_SRP */
+    if (alg_k & SSL_kGOST) {
+        EVP_PKEY_CTX *pkey_ctx;
+        EVP_PKEY *client_pub_pkey = NULL, *pk = NULL;
+        unsigned char premaster_secret[32], *start;
+        size_t outlen = 32, inlen;
+        unsigned long alg_a;
+        int Ttag, Tclass;
+        long Tlen;
+        long sess_key_len;
+
+        /* Get our certificate private key */
+        alg_a = s->s3->tmp.new_cipher->algorithm_auth;
+        if (alg_a & SSL_aGOST01)
+            pk = s->cert->pkeys[SSL_PKEY_GOST01].privatekey;
+
+        pkey_ctx = EVP_PKEY_CTX_new(pk, NULL);
+        EVP_PKEY_decrypt_init(pkey_ctx);
+        /*
+         * If client certificate is present and is of the same type, maybe
+         * use it for key exchange.  Don't mind errors from
+         * EVP_PKEY_derive_set_peer, because it is completely valid to use a
+         * client certificate for authorization only.
+         */
+        client_pub_pkey = X509_get_pubkey(s->session->peer);
+        if (client_pub_pkey) {
+            if (EVP_PKEY_derive_set_peer(pkey_ctx, client_pub_pkey) <= 0)
+                ERR_clear_error();
+        }
+        /* Decrypt session key */
+        sess_key_len = PACKET_remaining(pkt);
+        if (!PACKET_get_bytes(pkt, &data, sess_key_len)) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            goto f_err;
+        }
+        if (ASN1_get_object ((const unsigned char **)&data, &Tlen, &Ttag,
+                             &Tclass, sess_key_len) != V_ASN1_CONSTRUCTED
+            || Ttag != V_ASN1_SEQUENCE
+            || Tclass != V_ASN1_UNIVERSAL) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                   SSL_R_DECRYPTION_FAILED);
+            goto gerr;
+        }
+        start = data;
+        inlen = Tlen;
+        if (EVP_PKEY_decrypt
+            (pkey_ctx, premaster_secret, &outlen, start, inlen) <= 0) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE,
+                   SSL_R_DECRYPTION_FAILED);
+            goto gerr;
+        }
+        /* Generate master secret */
+        if (!ssl_generate_master_secret(s, premaster_secret,
+                                        sizeof(premaster_secret), 0)) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            goto f_err;
+        }
+        /* Check if pubkey from client certificate was used */
+        if (EVP_PKEY_CTX_ctrl
+            (pkey_ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 2, NULL) > 0)
+            s->no_cert_verify = 1;
+
+        EVP_PKEY_free(client_pub_pkey);
+        EVP_PKEY_CTX_free(pkey_ctx);
+        return MSG_PROCESS_CONTINUE_PROCESSING;
+ gerr:
+        EVP_PKEY_free(client_pub_pkey);
+        EVP_PKEY_CTX_free(pkey_ctx);
+        goto err;
+    } else {
+        al = SSL_AD_HANDSHAKE_FAILURE;
+        SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, SSL_R_UNKNOWN_CIPHER_TYPE);
+        goto f_err;
+    }
+
+    return MSG_PROCESS_CONTINUE_PROCESSING;
+ f_err:
+    ssl3_send_alert(s, SSL3_AL_FATAL, al);
+#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_RSA) || !defined(OPENSSL_NO_EC) || defined(OPENSSL_NO_SRP)
+ err:
+#endif
+#ifndef OPENSSL_NO_EC
+    EVP_PKEY_free(clnt_pub_pkey);
+    EC_POINT_free(clnt_ecpoint);
+    EC_KEY_free(srvr_ecdh);
+    BN_CTX_free(bn_ctx);
+    OPENSSL_free(rsa_decrypt);
+#endif
+#ifndef OPENSSL_NO_PSK
+    OPENSSL_clear_free(s->s3->tmp.psk, s->s3->tmp.psklen);
+    s->s3->tmp.psk = NULL;
+#endif
+    statem_set_error(s);
+    return MSG_PROCESS_ERROR;
+}
+
+enum WORK_STATE tls_post_process_client_key_exchange(SSL *s,
+                                                      enum WORK_STATE wst)
+{
+#ifndef OPENSSL_NO_SCTP
+    if (wst == WORK_MORE_A) {
+        if (SSL_IS_DTLS(s)) {
+            unsigned char sctpauthkey[64];
+            char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
+            /*
+             * Add new shared key for SCTP-Auth, will be ignored if no SCTP
+             * used.
+             */
+            snprintf((char *)labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL),
+                     DTLS1_SCTP_AUTH_LABEL);
+
+            if (SSL_export_keying_material(s, sctpauthkey,
+                                       sizeof(sctpauthkey), labelbuffer,
+                                       sizeof(labelbuffer), NULL, 0, 0) <= 0) {
+                statem_set_error(s);
+                return WORK_ERROR;;
+            }
+
+            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
+                     sizeof(sctpauthkey), sctpauthkey);
+        }
+        wst = WORK_MORE_B;
+    }
+
+    if ((wst == WORK_MORE_B)
+            /* Is this SCTP? */
+            && BIO_dgram_is_sctp(SSL_get_wbio(s))
+            /* Are we renegotiating? */
+            && s->renegotiate
+            /* Are we going to skip the CertificateVerify? */
+            && (s->session->peer == NULL || s->no_cert_verify)
+            && BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s))) {
+        s->s3->in_read_app_data = 2;
+        s->rwstate = SSL_READING;
+        BIO_clear_retry_flags(SSL_get_rbio(s));
+        BIO_set_retry_read(SSL_get_rbio(s));
+        statem_set_sctp_read_sock(s, 1);
+        return WORK_MORE_B;
+    } else {
+        statem_set_sctp_read_sock(s, 0);
+    }
+#endif
+
+    if (s->no_cert_verify) {
+        /* No certificate verify so we no longer need the handshake_buffer */
+        BIO_free(s->s3->handshake_buffer);
+        return WORK_FINISHED_CONTINUE;
+    } else if (SSL_USE_SIGALGS(s)) {
+        if (!s->session->peer) {
+            /* No peer certificate so we no longer need the handshake_buffer */
+            BIO_free(s->s3->handshake_buffer);
+            return WORK_FINISHED_CONTINUE;
+        }
+        if (!s->s3->handshake_buffer) {
+            SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_KEY_EXCHANGE,
+                   ERR_R_INTERNAL_ERROR);
+            statem_set_error(s);
+            return WORK_ERROR;
+        }
+        /*
+         * For sigalgs freeze the handshake buffer. If we support
+         * extms we've done this already so this is a no-op
+         */
+        if (!ssl3_digest_cached_records(s, 1)) {
+            statem_set_error(s);
+            return WORK_ERROR;
+        }
+    } else {
+        int offset = 0;
+        int dgst_num;
+
+        /*
+         * We need to get hashes here so if there is a client cert,
+         * it can be verified FIXME - digest processing for
+         * CertificateVerify should be generalized. But it is next
+         * step
+         */
+        if (!ssl3_digest_cached_records(s, 0)) {
+            statem_set_error(s);
+            return WORK_ERROR;
+        }
+        for (dgst_num = 0; dgst_num < SSL_MAX_DIGEST; dgst_num++) {
+            if (s->s3->handshake_dgst[dgst_num]) {
+                int dgst_size;
+
+                s->method->ssl3_enc->cert_verify_mac(s,
+                                                     EVP_MD_CTX_type
+                                                     (s->
+                                                      s3->handshake_dgst
+                                                      [dgst_num]),
+                                                     &(s->s3->
+                                                       tmp.cert_verify_md
+                                                       [offset]));
+                dgst_size =
+                    EVP_MD_CTX_size(s->s3->handshake_dgst[dgst_num]);
+                if (dgst_size < 0) {
+                    statem_set_error(s);
+                return WORK_ERROR;
+                }
+                offset += dgst_size;
+            }
+        }
+    }
+
+    return WORK_FINISHED_CONTINUE;
+}
+
+enum MSG_PROCESS_RETURN tls_process_cert_verify(SSL *s, PACKET *pkt)
+{
+    EVP_PKEY *pkey = NULL;
+    unsigned char *sig, *data;
+    int al, ret = MSG_PROCESS_ERROR;
+    int type = 0, i, j;
+    unsigned int len;
+    X509 *peer;
+    const EVP_MD *md = NULL;
+    EVP_MD_CTX mctx;
+    EVP_MD_CTX_init(&mctx);
+
+    peer = s->session->peer;
+    pkey = X509_get_pubkey(peer);
+    type = X509_certificate_type(peer, pkey);
+
+    if (!(type & EVP_PKT_SIGN)) {
+        SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY,
+               SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE);
+        al = SSL_AD_ILLEGAL_PARAMETER;
+        goto f_err;
+    }
+
+    /* Check for broken implementations of GOST ciphersuites */
+    /*
+     * If key is GOST and n is exactly 64, it is bare signature without
+     * length field
+     */
+    if (PACKET_remaining(pkt) == 64 && pkey->type == NID_id_GostR3410_2001) {
+        len = 64;
+    } else {
+        if (SSL_USE_SIGALGS(s)) {
+            int rv;
+
+            if (!PACKET_get_bytes(pkt, &sig, 2)) {
+                al = SSL_AD_DECODE_ERROR;
+                goto f_err;
+            }
+            rv = tls12_check_peer_sigalg(&md, s, sig, pkey);
+            if (rv == -1) {
+                al = SSL_AD_INTERNAL_ERROR;
+                goto f_err;
+            } else if (rv == 0) {
+                al = SSL_AD_DECODE_ERROR;
+                goto f_err;
+            }
+#ifdef SSL_DEBUG
+            fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md));
+#endif
+        }
+        if (!PACKET_get_net_2(pkt, &len)) {
+            SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_LENGTH_MISMATCH);
+            al = SSL_AD_DECODE_ERROR;
+            goto f_err;
+        }
+    }
+    j = EVP_PKEY_size(pkey);
+    if (((int)len > j) || ((int)PACKET_remaining(pkt) > j)
+            || (PACKET_remaining(pkt) == 0)) {
+        SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_WRONG_SIGNATURE_SIZE);
+        al = SSL_AD_DECODE_ERROR;
+        goto f_err;
+    }
+    if (!PACKET_get_bytes(pkt, &data, len)) {
+        SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_LENGTH_MISMATCH);
+        al = SSL_AD_DECODE_ERROR;
+        goto f_err;
+    }
+
+    if (SSL_USE_SIGALGS(s)) {
+        long hdatalen = 0;
+        void *hdata;
+        hdatalen = BIO_get_mem_data(s->s3->handshake_buffer, &hdata);
+        if (hdatalen <= 0) {
+            SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, ERR_R_INTERNAL_ERROR);
+            al = SSL_AD_INTERNAL_ERROR;
+            goto f_err;
+        }
+#ifdef SSL_DEBUG
+        fprintf(stderr, "Using TLS 1.2 with client verify alg %s\n",
+                EVP_MD_name(md));
+#endif
+        if (!EVP_VerifyInit_ex(&mctx, md, NULL)
+            || !EVP_VerifyUpdate(&mctx, hdata, hdatalen)) {
+            SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, ERR_R_EVP_LIB);
+            al = SSL_AD_INTERNAL_ERROR;
+            goto f_err;
+        }
+
+        if (EVP_VerifyFinal(&mctx, data, len, pkey) <= 0) {
+            al = SSL_AD_DECRYPT_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_BAD_SIGNATURE);
+            goto f_err;
+        }
+    } else
+#ifndef OPENSSL_NO_RSA
+    if (pkey->type == EVP_PKEY_RSA) {
+        i = RSA_verify(NID_md5_sha1, s->s3->tmp.cert_verify_md,
+                       MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH, data, len,
+                       pkey->pkey.rsa);
+        if (i < 0) {
+            al = SSL_AD_DECRYPT_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_BAD_RSA_DECRYPT);
+            goto f_err;
+        }
+        if (i == 0) {
+            al = SSL_AD_DECRYPT_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_BAD_RSA_SIGNATURE);
+            goto f_err;
+        }
+    } else
+#endif
+#ifndef OPENSSL_NO_DSA
+    if (pkey->type == EVP_PKEY_DSA) {
+        j = DSA_verify(pkey->save_type,
+                       &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]),
+                       SHA_DIGEST_LENGTH, data, len, pkey->pkey.dsa);
+        if (j <= 0) {
+            /* bad signature */
+            al = SSL_AD_DECRYPT_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_BAD_DSA_SIGNATURE);
+            goto f_err;
+        }
+    } else
+#endif
+#ifndef OPENSSL_NO_EC
+    if (pkey->type == EVP_PKEY_EC) {
+        j = ECDSA_verify(pkey->save_type,
+                         &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]),
+                         SHA_DIGEST_LENGTH, data, len, pkey->pkey.ec);
+        if (j <= 0) {
+            /* bad signature */
+            al = SSL_AD_DECRYPT_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_BAD_ECDSA_SIGNATURE);
+            goto f_err;
+        }
+    } else
+#endif
+    if (pkey->type == NID_id_GostR3410_2001) {
+        unsigned char signature[64];
+        int idx;
+        EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(pkey, NULL);
+        EVP_PKEY_verify_init(pctx);
+        if (len != 64) {
+            fprintf(stderr, "GOST signature length is %d", len);
+        }
+        for (idx = 0; idx < 64; idx++) {
+            signature[63 - idx] = data[idx];
+        }
+        j = EVP_PKEY_verify(pctx, signature, 64, s->s3->tmp.cert_verify_md,
+                            32);
+        EVP_PKEY_CTX_free(pctx);
+        if (j <= 0) {
+            al = SSL_AD_DECRYPT_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, SSL_R_BAD_ECDSA_SIGNATURE);
+            goto f_err;
+        }
+    } else {
+        SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, ERR_R_INTERNAL_ERROR);
+        al = SSL_AD_UNSUPPORTED_CERTIFICATE;
+        goto f_err;
+    }
+
+    ret = MSG_PROCESS_CONTINUE_PROCESSING;
+    if (0) {
+ f_err:
+        ssl3_send_alert(s, SSL3_AL_FATAL, al);
+        statem_set_error(s);
+    }
+    BIO_free(s->s3->handshake_buffer);
+    s->s3->handshake_buffer = NULL;
+    EVP_MD_CTX_cleanup(&mctx);
+    EVP_PKEY_free(pkey);
+    return ret;
+}
+
+enum MSG_PROCESS_RETURN tls_process_client_certificate(SSL *s, PACKET *pkt)
+{
+    int i, al, ret = MSG_PROCESS_ERROR;
+    X509 *x = NULL;
+    unsigned long l, llen;
+    const unsigned char *certstart;
+    unsigned char *certbytes;
+    STACK_OF(X509) *sk = NULL;
+    PACKET spkt;
+
+    if ((sk = sk_X509_new_null()) == NULL) {
+        SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, ERR_R_MALLOC_FAILURE);
+        goto f_err;
+    }
+
+    if (!PACKET_get_net_3(pkt, &llen)
+            || !PACKET_get_sub_packet(pkt, &spkt, llen)
+            || PACKET_remaining(pkt) != 0) {
+        al = SSL_AD_DECODE_ERROR;
+        SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, SSL_R_LENGTH_MISMATCH);
+        goto f_err;
+    }
+
+    while (PACKET_remaining(&spkt) > 0) {
+        if (!PACKET_get_net_3(&spkt, &l)
+                || !PACKET_get_bytes(&spkt, &certbytes, l)) {
+            al = SSL_AD_DECODE_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
+                   SSL_R_CERT_LENGTH_MISMATCH);
+            goto f_err;
+        }
+
+        certstart = certbytes;
+        x = d2i_X509(NULL, (const unsigned char **)&certbytes, l);
+        if (x == NULL) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, ERR_R_ASN1_LIB);
+            goto f_err;
+        }
+        if (certbytes != (certstart + l)) {
+            al = SSL_AD_DECODE_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
+                   SSL_R_CERT_LENGTH_MISMATCH);
+            goto f_err;
+        }
+        if (!sk_X509_push(sk, x)) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, ERR_R_MALLOC_FAILURE);
+            goto f_err;
+        }
+        x = NULL;
+    }
+
+    if (sk_X509_num(sk) <= 0) {
+        /* TLS does not mind 0 certs returned */
+        if (s->version == SSL3_VERSION) {
+            al = SSL_AD_HANDSHAKE_FAILURE;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
+                   SSL_R_NO_CERTIFICATES_RETURNED);
+            goto f_err;
+        }
+        /* Fail for TLS only if we required a certificate */
+        else if ((s->verify_mode & SSL_VERIFY_PEER) &&
+                 (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
+                   SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
+            al = SSL_AD_HANDSHAKE_FAILURE;
+            goto f_err;
+        }
+        /* No client certificate so digest cached records */
+        if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s, 0)) {
+            al = SSL_AD_INTERNAL_ERROR;
+            goto f_err;
+        }
+    } else {
+        EVP_PKEY *pkey;
+        i = ssl_verify_cert_chain(s, sk);
+        if (i <= 0) {
+            al = ssl_verify_alarm_type(s->verify_result);
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
+                   SSL_R_CERTIFICATE_VERIFY_FAILED);
+            goto f_err;
+        }
+        if (i > 1) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, i);
+            al = SSL_AD_HANDSHAKE_FAILURE;
+            goto f_err;
+        }
+        pkey = X509_get_pubkey(sk_X509_value(sk, 0));
+        if (pkey == NULL) {
+            al = SSL3_AD_HANDSHAKE_FAILURE;
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE,
+                   SSL_R_UNKNOWN_CERTIFICATE_TYPE);
+            goto f_err;
+        }
+        EVP_PKEY_free(pkey);
+    }
+
+    X509_free(s->session->peer);
+    s->session->peer = sk_X509_shift(sk);
+    s->session->verify_result = s->verify_result;
+
+    sk_X509_pop_free(s->session->peer_chain, X509_free);
+    s->session->peer_chain = sk;
+    /*
+     * Inconsistency alert: cert_chain does *not* include the peer's own
+     * certificate, while we do include it in s3_clnt.c
+     */
+    sk = NULL;
+    ret = MSG_PROCESS_CONTINUE_READING;
+    goto done;
+
+ f_err:
+    ssl3_send_alert(s, SSL3_AL_FATAL, al);
+    statem_set_error(s);
+ done:
+    X509_free(x);
+    sk_X509_pop_free(sk, X509_free);
+    return ret;
+}
+
+int tls_construct_server_certificate(SSL *s)
+{
+    CERT_PKEY *cpk;
+
+    cpk = ssl_get_server_send_pkey(s);
+    if (cpk == NULL) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_CERTIFICATE, ERR_R_INTERNAL_ERROR);
+        statem_set_error(s);
+        return 0;
+    }
+
+    if (!ssl3_output_cert_chain(s, cpk)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_CERTIFICATE, ERR_R_INTERNAL_ERROR);
+        statem_set_error(s);
+        return 0;
+    }
+
+    return 1;
+}
+
+int tls_construct_new_session_ticket(SSL *s)
+{
+    unsigned char *senc = NULL;
+    EVP_CIPHER_CTX ctx;
+    HMAC_CTX hctx;
+    unsigned char *p, *macstart;
+    const unsigned char *const_p;
+    int len, slen_full, slen;
+    SSL_SESSION *sess;
+    unsigned int hlen;
+    SSL_CTX *tctx = s->initial_ctx;
+    unsigned char iv[EVP_MAX_IV_LENGTH];
+    unsigned char key_name[16];
+
+    /* get session encoding length */
+    slen_full = i2d_SSL_SESSION(s->session, NULL);
+    /*
+     * Some length values are 16 bits, so forget it if session is too
+     * long
+     */
+    if (slen_full == 0 || slen_full > 0xFF00) {
+        statem_set_error(s);
+        return 0;
+    }
+    senc = OPENSSL_malloc(slen_full);
+    if (!senc) {
+        statem_set_error(s);
+        return 0;
+    }
+
+    EVP_CIPHER_CTX_init(&ctx);
+    HMAC_CTX_init(&hctx);
+
+    p = senc;
+    if (!i2d_SSL_SESSION(s->session, &p))
+        goto err;
+
+    /*
+     * create a fresh copy (not shared with other threads) to clean up
+     */
+    const_p = senc;
+    sess = d2i_SSL_SESSION(NULL, &const_p, slen_full);
+    if (sess == NULL)
+        goto err;
+    sess->session_id_length = 0; /* ID is irrelevant for the ticket */
+
+    slen = i2d_SSL_SESSION(sess, NULL);
+    if (slen == 0 || slen > slen_full) { /* shouldn't ever happen */
+        SSL_SESSION_free(sess);
+        goto err;
+    }
+    p = senc;
+    if (!i2d_SSL_SESSION(sess, &p)) {
+        SSL_SESSION_free(sess);
+        goto err;
+    }
+    SSL_SESSION_free(sess);
+
+    /*-
+     * Grow buffer if need be: the length calculation is as
+     * follows handshake_header_length +
+     * 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,
+                      SSL_HM_HEADER_LENGTH(s) + 22 + EVP_MAX_IV_LENGTH +
+                      EVP_MAX_BLOCK_LENGTH + EVP_MAX_MD_SIZE + slen))
+        goto err;
+
+    p = ssl_handshake_start(s);
+    /*
+     * 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)
+            goto err;
+    } else {
+        if (RAND_bytes(iv, 16) <= 0)
+            goto err;
+        if (!EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL,
+                                tctx->tlsext_tick_aes_key, iv))
+            goto err;
+        if (!HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16,
+                          EVP_sha256(), NULL))
+            goto err;
+        memcpy(key_name, tctx->tlsext_tick_key_name, 16);
+    }
+
+    /*
+     * Ticket lifetime hint (advisory only): We leave this unspecified
+     * for resumed session (for simplicity), and guess that tickets for
+     * new sessions will live as long as their sessions.
+     */
+    l2n(s->hit ? 0 : s->session->timeout, 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 */
+    if (!EVP_EncryptUpdate(&ctx, p, &len, senc, slen))
+        goto err;
+    p += len;
+    if (!EVP_EncryptFinal(&ctx, p, &len))
+        goto err;
+    p += len;
+
+    if (!HMAC_Update(&hctx, macstart, p - macstart))
+        goto err;
+    if (!HMAC_Final(&hctx, p, &hlen))
+        goto err;
+
+    EVP_CIPHER_CTX_cleanup(&ctx);
+    HMAC_CTX_cleanup(&hctx);
+
+    p += hlen;
+    /* Now write out lengths: p points to end of data written */
+    /* Total length */
+    len = p - ssl_handshake_start(s);
+    /* Skip ticket lifetime hint */
+    p = ssl_handshake_start(s) + 4;
+    s2n(len - 6, p);
+    if (!ssl_set_handshake_header(s, SSL3_MT_NEWSESSION_TICKET, len))
+        goto err;
+    OPENSSL_free(senc);
+
+    return 1;
+ err:
+    OPENSSL_free(senc);
+    EVP_CIPHER_CTX_cleanup(&ctx);
+    HMAC_CTX_cleanup(&hctx);
+    statem_set_error(s);
+    return 0;
+}
+
+int tls_construct_cert_status(SSL *s)
+{
+    unsigned char *p;
+    /*-
+     * Grow buffer if need be: the length calculation is as
+     * follows 1 (message type) + 3 (message length) +
+     * 1 (ocsp response type) + 3 (ocsp response length)
+     * + (ocsp response)
+     */
+    if (!BUF_MEM_grow(s->init_buf, 8 + s->tlsext_ocsp_resplen)) {
+        statem_set_error(s);
+        return 0;
+    }
+
+    p = (unsigned char *)s->init_buf->data;
+
+    /* do the header */
+    *(p++) = SSL3_MT_CERTIFICATE_STATUS;
+    /* message length */
+    l2n3(s->tlsext_ocsp_resplen + 4, p);
+    /* status type */
+    *(p++) = s->tlsext_status_type;
+    /* length of OCSP response */
+    l2n3(s->tlsext_ocsp_resplen, p);
+    /* actual response */
+    memcpy(p, s->tlsext_ocsp_resp, s->tlsext_ocsp_resplen);
+    /* number of bytes to write */
+    s->init_num = 8 + s->tlsext_ocsp_resplen;
+    s->init_off = 0;
+
+    return 1;
+}
+
+#ifndef OPENSSL_NO_NEXTPROTONEG
+/*
+ * tls_process_next_proto reads a Next Protocol Negotiation handshake message.
+ * It sets the next_proto member in s if found
+ */
+enum MSG_PROCESS_RETURN tls_process_next_proto(SSL *s, PACKET *pkt)
+{
+    PACKET next_proto, padding;
+    size_t next_proto_len;
+
+    /*-
+     * The payload looks like:
+     *   uint8 proto_len;
+     *   uint8 proto[proto_len];
+     *   uint8 padding_len;
+     *   uint8 padding[padding_len];
+     */
+    if (!PACKET_get_length_prefixed_1(pkt, &next_proto)
+        || !PACKET_get_length_prefixed_1(pkt, &padding)
+        || PACKET_remaining(pkt) > 0) {
+        SSLerr(SSL_F_TLS_PROCESS_NEXT_PROTO, SSL_R_LENGTH_MISMATCH);
+        goto err;
+    }
+
+    if (!PACKET_memdup(&next_proto, &s->next_proto_negotiated,
+                       &next_proto_len)) {
+        s->next_proto_negotiated_len = 0;
+        goto err;
+    }
+
+    s->next_proto_negotiated_len = (unsigned char)next_proto_len;
+
+    return MSG_PROCESS_CONTINUE_READING;
+err:
+    statem_set_error(s);
+    return MSG_PROCESS_ERROR;
+}
+#endif
+
+#define SSLV2_CIPHER_LEN    3
+
+STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s,
+                                               PACKET *cipher_suites,
+                                               STACK_OF(SSL_CIPHER) **skp,
+                                               int sslv2format, int *al
+                                               )
+{
+    const SSL_CIPHER *c;
+    STACK_OF(SSL_CIPHER) *sk;
+    int n;
+    /* 3 = SSLV2_CIPHER_LEN > TLS_CIPHER_LEN = 2. */
+    unsigned char cipher[SSLV2_CIPHER_LEN];
+
+    s->s3->send_connection_binding = 0;
+
+    n = sslv2format ? SSLV2_CIPHER_LEN : TLS_CIPHER_LEN;
+
+    if (PACKET_remaining(cipher_suites) == 0) {
+        SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST, SSL_R_NO_CIPHERS_SPECIFIED);
+        *al = SSL_AD_ILLEGAL_PARAMETER;
+        return NULL;
+    }
+
+    if (PACKET_remaining(cipher_suites) % n != 0) {
+        SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST,
+               SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST);
+        *al = SSL_AD_DECODE_ERROR;
+        return NULL;
+    }
+
+    if ((skp == NULL) || (*skp == NULL)) {
+        sk = sk_SSL_CIPHER_new_null(); /* change perhaps later */
+        if(sk == NULL) {
+            SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST, ERR_R_MALLOC_FAILURE);
+            *al = SSL_AD_INTERNAL_ERROR;
+            return NULL;
+        }
+    } else {
+        sk = *skp;
+        sk_SSL_CIPHER_zero(sk);
+    }
+
+    if (!PACKET_memdup(cipher_suites, &s->s3->tmp.ciphers_raw,
+                       &s->s3->tmp.ciphers_rawlen)) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        goto err;
+    }
+
+    while (PACKET_copy_bytes(cipher_suites, cipher, n)) {
+        /*
+         * SSLv3 ciphers wrapped in an SSLv2-compatible ClientHello have the
+         * first byte set to zero, while true SSLv2 ciphers have a non-zero
+         * first byte. We don't support any true SSLv2 ciphers, so skip them.
+         */
+        if (sslv2format && cipher[0] != '\0')
+                continue;
+
+        /* Check for TLS_EMPTY_RENEGOTIATION_INFO_SCSV */
+        if ((cipher[n - 2] == ((SSL3_CK_SCSV >> 8) & 0xff)) &&
+            (cipher[n - 1] == (SSL3_CK_SCSV & 0xff))) {
+            /* SCSV fatal if renegotiating */
+            if (s->renegotiate) {
+                SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST,
+                       SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING);
+                *al = SSL_AD_HANDSHAKE_FAILURE;
+                goto err;
+            }
+            s->s3->send_connection_binding = 1;
+#ifdef OPENSSL_RI_DEBUG
+            fprintf(stderr, "SCSV received by server\n");
+#endif
+            continue;
+        }
+
+        /* Check for TLS_FALLBACK_SCSV */
+        if ((cipher[n - 2] == ((SSL3_CK_FALLBACK_SCSV >> 8) & 0xff)) &&
+            (cipher[n - 1] == (SSL3_CK_FALLBACK_SCSV & 0xff))) {
+            /*
+             * The SCSV indicates that the client previously tried a higher
+             * version. Fail if the current version is an unexpected
+             * downgrade.
+             */
+            if (!SSL_ctrl(s, SSL_CTRL_CHECK_PROTO_VERSION, 0, NULL)) {
+                SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST,
+                       SSL_R_INAPPROPRIATE_FALLBACK);
+                *al = SSL_AD_INAPPROPRIATE_FALLBACK;
+                goto err;
+            }
+            continue;
+        }
+
+        /* For SSLv2-compat, ignore leading 0-byte. */
+        c = ssl_get_cipher_by_char(s, sslv2format ? &cipher[1] : cipher);
+        if (c != NULL) {
+            if (!sk_SSL_CIPHER_push(sk, c)) {
+                SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST, ERR_R_MALLOC_FAILURE);
+                *al = SSL_AD_INTERNAL_ERROR;
+                goto err;
+            }
+        }
+    }
+    if (PACKET_remaining(cipher_suites) > 0) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    if (skp != NULL)
+        *skp = sk;
+    return (sk);
+ err:
+    if ((skp == NULL) || (*skp == NULL))
+        sk_SSL_CIPHER_free(sk);
+    return NULL;
+}
diff --git a/ssl/t1_clnt.c b/ssl/t1_clnt.c
deleted file mode 100644 (file)
index 9e117e9..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/* ssl/t1_clnt.c */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to.  The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *    "This product includes cryptographic software written by
- *     Eric Young (eay@cryptsoft.com)"
- *    The word 'cryptographic' can be left out if the rouines from the library
- *    being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- *    the apps directory (application code) you must include an acknowledgement:
- *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed.  i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#include <stdio.h>
-#include "ssl_locl.h"
-#include <openssl/buffer.h>
-#include <openssl/rand.h>
-#include <openssl/objects.h>
-#include <openssl/evp.h>
-
-static const SSL_METHOD *tls1_get_client_method(int ver);
-static const SSL_METHOD *tls1_get_client_method(int ver)
-{
-    if (ver == TLS_ANY_VERSION)
-        return TLS_client_method();
-    if (ver == TLS1_2_VERSION)
-        return TLSv1_2_client_method();
-    if (ver == TLS1_1_VERSION)
-        return TLSv1_1_client_method();
-    if (ver == TLS1_VERSION)
-        return TLSv1_client_method();
-#ifndef OPENSSL_NO_SSL3
-    if (ver == SSL3_VERSION)
-        return (SSLv3_client_method());
-#endif
-    return NULL;
-}
-
-IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, TLS_client_method,
-                        ssl_undefined_function,
-                        ssl3_connect,
-                        tls1_get_client_method, TLSv1_2_enc_data)
-
-IMPLEMENT_tls_meth_func(TLS1_2_VERSION, TLSv1_2_client_method,
-                        ssl_undefined_function,
-                        ssl3_connect,
-                        tls1_get_client_method, TLSv1_2_enc_data)
-
-IMPLEMENT_tls_meth_func(TLS1_1_VERSION, TLSv1_1_client_method,
-                        ssl_undefined_function,
-                        ssl3_connect,
-                        tls1_get_client_method, TLSv1_1_enc_data)
-
-IMPLEMENT_tls_meth_func(TLS1_VERSION, TLSv1_client_method,
-                        ssl_undefined_function,
-                        ssl3_connect, tls1_get_client_method, TLSv1_enc_data)
-
-#ifndef OPENSSL_NO_SSL3_METHOD
-IMPLEMENT_ssl3_meth_func(SSLv3_client_method,
-                         ssl_undefined_function,
-                         ssl3_connect, tls1_get_client_method)
-#endif
diff --git a/ssl/t1_meth.c b/ssl/t1_meth.c
deleted file mode 100644 (file)
index aa16d3f..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/* ssl/t1_meth.c */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to.  The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *    "This product includes cryptographic software written by
- *     Eric Young (eay@cryptsoft.com)"
- *    The word 'cryptographic' can be left out if the rouines from the library
- *    being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- *    the apps directory (application code) you must include an acknowledgement:
- *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed.  i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#include <stdio.h>
-#include <openssl/objects.h>
-#include "ssl_locl.h"
-
-static const SSL_METHOD *tls1_get_method(int ver)
-{
-    if (ver == TLS_ANY_VERSION)
-        return TLS_method();
-    if (ver == TLS1_2_VERSION)
-        return TLSv1_2_method();
-    if (ver == TLS1_1_VERSION)
-        return TLSv1_1_method();
-    if (ver == TLS1_VERSION)
-        return TLSv1_method();
-#ifndef OPENSSL_NO_SSL3
-    if (ver == SSL3_VERSION)
-        return (SSLv3_method());
-    else
-#endif
-    return NULL;
-}
-
-IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, TLS_method,
-                        ssl3_accept,
-                        ssl3_connect, tls1_get_method, TLSv1_2_enc_data)
-
-IMPLEMENT_tls_meth_func(TLS1_2_VERSION, TLSv1_2_method,
-                        ssl3_accept,
-                        ssl3_connect, tls1_get_method, TLSv1_2_enc_data)
-
-IMPLEMENT_tls_meth_func(TLS1_1_VERSION, TLSv1_1_method,
-                        ssl3_accept,
-                        ssl3_connect, tls1_get_method, TLSv1_1_enc_data)
-
-IMPLEMENT_tls_meth_func(TLS1_VERSION, TLSv1_method,
-                        ssl3_accept,
-                        ssl3_connect, tls1_get_method, TLSv1_enc_data)
-
-#ifndef OPENSSL_NO_SSL3_METHOD
-IMPLEMENT_ssl3_meth_func(SSLv3_method,
-                         ssl3_accept, ssl3_connect, tls1_get_method)
-#endif
diff --git a/ssl/t1_srvr.c b/ssl/t1_srvr.c
deleted file mode 100644 (file)
index 6e54b51..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-/* ssl/t1_srvr.c */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to.  The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *    "This product includes cryptographic software written by
- *     Eric Young (eay@cryptsoft.com)"
- *    The word 'cryptographic' can be left out if the rouines from the library
- *    being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- *    the apps directory (application code) you must include an acknowledgement:
- *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed.  i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-
-#include <stdio.h>
-#include "ssl_locl.h"
-#include <openssl/buffer.h>
-#include <openssl/rand.h>
-#include <openssl/objects.h>
-#include <openssl/evp.h>
-#include <openssl/x509.h>
-
-static const SSL_METHOD *tls1_get_server_method(int ver);
-static const SSL_METHOD *tls1_get_server_method(int ver)
-{
-    if (ver == TLS_ANY_VERSION)
-        return TLS_server_method();
-    if (ver == TLS1_2_VERSION)
-        return TLSv1_2_server_method();
-    if (ver == TLS1_1_VERSION)
-        return TLSv1_1_server_method();
-    if (ver == TLS1_VERSION)
-        return TLSv1_server_method();
-#ifndef OPENSSL_NO_SSL3
-    if (ver == SSL3_VERSION)
-        return (SSLv3_server_method());
-#endif
-    return NULL;
-}
-
-IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, TLS_server_method,
-                        ssl3_accept,
-                        ssl_undefined_function,
-                        tls1_get_server_method, TLSv1_2_enc_data)
-
-IMPLEMENT_tls_meth_func(TLS1_2_VERSION, TLSv1_2_server_method,
-                        ssl3_accept,
-                        ssl_undefined_function,
-                        tls1_get_server_method, TLSv1_2_enc_data)
-
-IMPLEMENT_tls_meth_func(TLS1_1_VERSION, TLSv1_1_server_method,
-                        ssl3_accept,
-                        ssl_undefined_function,
-                        tls1_get_server_method, TLSv1_1_enc_data)
-
-IMPLEMENT_tls_meth_func(TLS1_VERSION, TLSv1_server_method,
-                        ssl3_accept,
-                        ssl_undefined_function,
-                        tls1_get_server_method, TLSv1_enc_data)
-
-#ifndef OPENSSL_NO_SSL3_METHOD
-IMPLEMENT_ssl3_meth_func(SSLv3_server_method,
-                         ssl3_accept,
-                         ssl_undefined_function, tls1_get_server_method)
-#endif
index 6f32758074165a851c8ea9fae8d1f8c525004583..ffeba40fb6a95ec22b836d177f31eecf74e9221f 100644 (file)
@@ -559,7 +559,7 @@ heartbeat_test.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
 heartbeat_test.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
 heartbeat_test.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
 heartbeat_test.o: ../ssl/packet_locl.h ../ssl/record/record.h ../ssl/ssl_locl.h
-heartbeat_test.o: heartbeat_test.c testutil.h
+heartbeat_test.o: ../ssl/statem/statem.h heartbeat_test.c testutil.h
 hmactest.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h
 hmactest.o: ../include/openssl/crypto.h ../include/openssl/e_os2.h
 hmactest.o: ../include/openssl/evp.h ../include/openssl/hmac.h
@@ -681,7 +681,8 @@ ssltest.o: ../include/openssl/ssl3.h ../include/openssl/stack.h
 ssltest.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h
 ssltest.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
 ssltest.o: ../include/openssl/x509v3.h ../ssl/packet_locl.h
-ssltest.o: ../ssl/record/record.h ../ssl/ssl_locl.h ssltest.c
+ssltest.o: ../ssl/record/record.h ../ssl/ssl_locl.h ../ssl/statem/statem.h
+ssltest.o: ssltest.c
 testutil.o: ../e_os.h ../include/openssl/e_os2.h
 testutil.o: ../include/openssl/opensslconf.h testutil.c testutil.h
 v3nametest.o: ../e_os.h ../include/openssl/asn1.h ../include/openssl/bio.h