From: Matt Caswell Date: Fri, 11 Sep 2015 09:48:59 +0000 (+0100) Subject: Reorganise state machine files X-Git-Tag: OpenSSL_1_1_0-pre1~361 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=8ba708e5166b02ab61f2762d36b3e7b7455e9c06;p=oweals%2Fopenssl.git Reorganise state machine files 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 Reviewed-by: Richard Levitte --- diff --git a/crypto/ct/Makefile b/crypto/ct/Makefile index 2f55a2d560..dfb0839c1e 100644 --- a/crypto/ct/Makefile +++ b/crypto/ct/Makefile @@ -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 diff --git a/ssl/Makefile b/ssl/Makefile index 536ddcc200..9f1fe8d8c2 100644 --- a/ssl/Makefile +++ b/ssl/Makefile @@ -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 index e20278b1ce..0000000000 --- a/ssl/d1_both.c +++ /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 -#include -#include -#include "ssl_locl.h" -#include -#include -#include -#include -#include - -#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 index d26e39cab5..0000000000 --- a/ssl/d1_clnt.c +++ /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 -#include "ssl_locl.h" -#include -#include -#include -#include -#include -#include -#ifndef OPENSSL_NO_DH -# include -#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; -} diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c index 3bc9fe7362..2f9609affb 100644 --- a/ssl/d1_lib.c +++ b/ssl/d1_lib.c @@ -60,6 +60,7 @@ #include #define USE_SOCKETS #include +#include #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 index 734077493f..0000000000 --- a/ssl/d1_meth.c +++ /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 -#include -#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 index 47c6203799..0000000000 --- a/ssl/d1_srvr.c +++ /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 -#include "ssl_locl.h" -#include -#include -#include -#include -#include -#include -#include -#ifndef OPENSSL_NO_DH -# include -#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 index 0000000000..4e7093ed3c --- /dev/null +++ b/ssl/methods.c @@ -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 +#include +#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 index 47f02dbf3a..0000000000 --- a/ssl/s3_both.c +++ /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 -#include -#include -#include "ssl_locl.h" -#include -#include -#include -#include -#include - -/* - * 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 index 49a9f60259..0000000000 --- a/ssl/s3_clnt.c +++ /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 -#include "ssl_locl.h" -#include -#include -#include -#include -#include -#ifndef OPENSSL_NO_DH -# include -#endif -#include -#ifndef OPENSSL_NO_ENGINE -# include -#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, ¶ms, - 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(¶ms), - PACKET_remaining(¶ms)); - 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(¶ms), - PACKET_remaining(¶ms)); - 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 index 4442223282..0000000000 --- a/ssl/s3_srvr.c +++ /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 -#include "ssl_locl.h" -#include "internal/constant_time_locl.h" -#include -#include -#include -#include -#include -#include -#ifndef OPENSSL_NO_DH -# include -#endif -#include -#include - -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; -} diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index ab095c8267..25afff8c9b 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -166,6 +166,7 @@ # include #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 index 81af75c4d5..0000000000 --- a/ssl/statem.c +++ /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 -#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 index 0000000000..7e4f524ddc --- /dev/null +++ b/ssl/statem/statem.c @@ -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 +#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 index 0000000000..b6256f9788 --- /dev/null +++ b/ssl/statem/statem.h @@ -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 index 0000000000..3ff427650b --- /dev/null +++ b/ssl/statem/statem_clnt.c @@ -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 +#include "../ssl_locl.h" +#include +#include +#include +#include +#include +#ifndef OPENSSL_NO_DH +# include +#endif +#include +#ifndef OPENSSL_NO_ENGINE +# include +#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, ¶ms, + 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(¶ms), + PACKET_remaining(¶ms)); + 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(¶ms), + PACKET_remaining(¶ms)); + 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 index 0000000000..e13ed8d247 --- /dev/null +++ b/ssl/statem/statem_dtls.c @@ -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 +#include +#include +#include "../ssl_locl.h" +#include +#include +#include +#include +#include + +#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 index 0000000000..75d151e5e0 --- /dev/null +++ b/ssl/statem/statem_lib.c @@ -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 +#include +#include +#include "../ssl_locl.h" +#include +#include +#include +#include +#include + +/* + * 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 index 0000000000..5f85a8c500 --- /dev/null +++ b/ssl/statem/statem_srvr.c @@ -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 +#include "../ssl_locl.h" +#include "internal/constant_time_locl.h" +#include +#include +#include +#include +#include +#include +#ifndef OPENSSL_NO_DH +# include +#endif +#include +#include + +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 index 9e117e9a69..0000000000 --- a/ssl/t1_clnt.c +++ /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 -#include "ssl_locl.h" -#include -#include -#include -#include - -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 index aa16d3f2a8..0000000000 --- a/ssl/t1_meth.c +++ /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 -#include -#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 index 6e54b5169c..0000000000 --- a/ssl/t1_srvr.c +++ /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 -#include "ssl_locl.h" -#include -#include -#include -#include -#include - -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 diff --git a/test/Makefile b/test/Makefile index 6f32758074..ffeba40fb6 100644 --- a/test/Makefile +++ b/test/Makefile @@ -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