From 637f374ad49d5f6d4f81d87d7cdd226428aa470c Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Mon, 7 Dec 2009 13:31:02 +0000 Subject: [PATCH] Initial experimental TLSv1.1 support --- CHANGES | 10 ++++++++++ apps/s_client.c | 7 ++++++- apps/s_server.c | 6 ++++++ ssl/s23_clnt.c | 21 ++++++++++++++++++--- ssl/s23_srvr.c | 22 +++++++++++++++++++--- ssl/s3_pkt.c | 29 ++++++++++++++++++++++++----- ssl/ssl.h | 6 ++++++ ssl/ssl_lib.c | 6 ++++-- ssl/ssl_locl.h | 7 ++++--- ssl/ssl_sess.c | 5 +++++ ssl/ssl_txt.c | 2 ++ ssl/t1_clnt.c | 14 ++++++++++---- ssl/t1_enc.c | 29 ++++++++++++++++++++++++++++- ssl/t1_lib.c | 2 +- ssl/t1_meth.c | 15 ++++++++++----- ssl/t1_srvr.c | 14 ++++++++++---- ssl/tls1.h | 4 ++++ 17 files changed, 167 insertions(+), 32 deletions(-) diff --git a/CHANGES b/CHANGES index 40319bcd02..60bf09a70a 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,16 @@ Changes between 1.0.0 and 1.1.0 [xx XXX xxxx] + *) Initial TLSv1.1 support. Since TLSv1.1 is very similar to TLS v1.0 only + a few changes are required: + + Add SSL_OP_NO_TLSv1_1 flag. + Add TLSv1_1 methods. + Update version checking logic to handle version 1.1. + Add explicit IV handling (ported from DTLS code). + Add command line options to s_client/s_server. + [Steve Henson] + *) Experiemental password based recipient info support for CMS library: implementing RFC3211. [Steve Henson] diff --git a/apps/s_client.c b/apps/s_client.c index a4be63a114..2f647b852d 100644 --- a/apps/s_client.c +++ b/apps/s_client.c @@ -318,10 +318,11 @@ static void sc_usage(void) #endif BIO_printf(bio_err," -ssl2 - just use SSLv2\n"); BIO_printf(bio_err," -ssl3 - just use SSLv3\n"); + BIO_printf(bio_err," -tls1_1 - just use TLSv1.1\n"); BIO_printf(bio_err," -tls1 - just use TLSv1\n"); BIO_printf(bio_err," -dtls1 - just use DTLSv1\n"); BIO_printf(bio_err," -mtu - set the link layer MTU\n"); - BIO_printf(bio_err," -no_tls1/-no_ssl3/-no_ssl2 - turn off that protocol\n"); + BIO_printf(bio_err," -no_tls1_1/-no_tls1/-no_ssl3/-no_ssl2 - turn off that protocol\n"); BIO_printf(bio_err," -bugs - Switch on all SSL implementation bug workarounds\n"); BIO_printf(bio_err," -serverpref - Use server's cipher preferences (only SSLv2)\n"); BIO_printf(bio_err," -cipher - preferred cipher to use, use the 'openssl ciphers'\n"); @@ -597,6 +598,8 @@ int MAIN(int argc, char **argv) meth=SSLv3_client_method(); #endif #ifndef OPENSSL_NO_TLS1 + else if (strcmp(*argv,"-tls1_1") == 0) + meth=TLSv1_1_client_method(); else if (strcmp(*argv,"-tls1") == 0) meth=TLSv1_client_method(); #endif @@ -645,6 +648,8 @@ int MAIN(int argc, char **argv) if (--argc < 1) goto bad; CAfile= *(++argv); } + else if (strcmp(*argv,"-no_tls1_1") == 0) + off|=SSL_OP_NO_TLSv1_1; else if (strcmp(*argv,"-no_tls1") == 0) off|=SSL_OP_NO_TLSv1; else if (strcmp(*argv,"-no_ssl3") == 0) diff --git a/apps/s_server.c b/apps/s_server.c index 8a08a30695..6f67689519 100644 --- a/apps/s_server.c +++ b/apps/s_server.c @@ -458,6 +458,7 @@ static void sv_usage(void) #endif BIO_printf(bio_err," -ssl2 - Just talk SSLv2\n"); BIO_printf(bio_err," -ssl3 - Just talk SSLv3\n"); + BIO_printf(bio_err," -tls1_1 - Just talk TLSv1_1\n"); BIO_printf(bio_err," -tls1 - Just talk TLSv1\n"); BIO_printf(bio_err," -dtls1 - Just talk DTLSv1\n"); BIO_printf(bio_err," -timeout - Enable timeouts\n"); @@ -466,6 +467,7 @@ static void sv_usage(void) BIO_printf(bio_err," -no_ssl2 - Just disable SSLv2\n"); BIO_printf(bio_err," -no_ssl3 - Just disable SSLv3\n"); BIO_printf(bio_err," -no_tls1 - Just disable TLSv1\n"); + BIO_printf(bio_err," -no_tls1_1 - Just disable TLSv1.1\n"); #ifndef OPENSSL_NO_DH BIO_printf(bio_err," -no_dhe - Disable ephemeral DH\n"); #endif @@ -1120,6 +1122,8 @@ int MAIN(int argc, char *argv[]) { off|=SSL_OP_NO_SSLv2; } else if (strcmp(*argv,"-no_ssl3") == 0) { off|=SSL_OP_NO_SSLv3; } + else if (strcmp(*argv,"-no_tls1_1") == 0) + { off|=SSL_OP_NO_TLSv1_1; } else if (strcmp(*argv,"-no_tls1") == 0) { off|=SSL_OP_NO_TLSv1; } else if (strcmp(*argv,"-no_comp") == 0) @@ -1137,6 +1141,8 @@ int MAIN(int argc, char *argv[]) { meth=SSLv3_server_method(); } #endif #ifndef OPENSSL_NO_TLS1 + else if (strcmp(*argv,"-tls1_1") == 0) + { meth=TLSv1_1_server_method(); } else if (strcmp(*argv,"-tls1") == 0) { meth=TLSv1_server_method(); } #endif diff --git a/ssl/s23_clnt.c b/ssl/s23_clnt.c index 53e080ee8e..bacf97c265 100644 --- a/ssl/s23_clnt.c +++ b/ssl/s23_clnt.c @@ -284,7 +284,11 @@ static int ssl23_client_hello(SSL *s) if (ssl2_compat && ssl23_no_ssl2_ciphers(s)) ssl2_compat = 0; - if (!(s->options & SSL_OP_NO_TLSv1)) + if (!(s->options & SSL_OP_NO_TLSv1_1)) + { + version = TLS1_1_VERSION; + } + else if (!(s->options & SSL_OP_NO_TLSv1)) { version = TLS1_VERSION; } @@ -332,7 +336,12 @@ static int ssl23_client_hello(SSL *s) if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0) return -1; - if (version == TLS1_VERSION) + if (version == TLS1_1_VERSION) + { + version_major = TLS1_1_VERSION_MAJOR; + version_minor = TLS1_1_VERSION_MINOR; + } + else if (version == TLS1_VERSION) { version_major = TLS1_VERSION_MAJOR; version_minor = TLS1_VERSION_MINOR; @@ -611,7 +620,7 @@ static int ssl23_get_server_hello(SSL *s) #endif } else if (p[1] == SSL3_VERSION_MAJOR && - (p[2] == SSL3_VERSION_MINOR || p[2] == TLS1_VERSION_MINOR) && + (p[2] >= SSL3_VERSION_MINOR && p[2] <= TLS1_1_VERSION_MINOR) && ((p[0] == SSL3_RT_HANDSHAKE && p[5] == SSL3_MT_SERVER_HELLO) || (p[0] == SSL3_RT_ALERT && p[3] == 0 && p[4] == 2))) { @@ -629,6 +638,12 @@ static int ssl23_get_server_hello(SSL *s) s->version=TLS1_VERSION; s->method=TLSv1_client_method(); } + else if ((p[2] == TLS1_1_VERSION_MINOR) && + !(s->options & SSL_OP_NO_TLSv1_1)) + { + s->version=TLS1_1_VERSION; + s->method=TLSv1_1_client_method(); + } else { SSLerr(SSL_F_SSL23_GET_SERVER_HELLO,SSL_R_UNSUPPORTED_PROTOCOL); diff --git a/ssl/s23_srvr.c b/ssl/s23_srvr.c index 773c0e38d8..03efdf74c1 100644 --- a/ssl/s23_srvr.c +++ b/ssl/s23_srvr.c @@ -128,6 +128,8 @@ static const SSL_METHOD *ssl23_get_server_method(int ver) return(SSLv3_server_method()); else if (ver == TLS1_VERSION) return(TLSv1_server_method()); + else if (ver == TLS1_1_VERSION) + return(TLSv1_1_server_method()); else return(NULL); } @@ -283,7 +285,13 @@ int ssl23_get_client_hello(SSL *s) /* SSLv3/TLSv1 */ if (p[4] >= TLS1_VERSION_MINOR) { - if (!(s->options & SSL_OP_NO_TLSv1)) + if (p[4] >= TLS1_1_VERSION_MINOR && + !(s->options & SSL_OP_NO_TLSv1_1)) + { + s->version=TLS1_1_VERSION; + s->state=SSL23_ST_SR_CLNT_HELLO_B; + } + else if (!(s->options & SSL_OP_NO_TLSv1)) { s->version=TLS1_VERSION; /* type=2; */ /* done later to survive restarts */ @@ -343,7 +351,13 @@ int ssl23_get_client_hello(SSL *s) v[1]=p[10]; /* minor version according to client_version */ if (v[1] >= TLS1_VERSION_MINOR) { - if (!(s->options & SSL_OP_NO_TLSv1)) + if (v[1] >= TLS1_1_VERSION_MINOR && + !(s->options & SSL_OP_NO_TLSv1_1)) + { + s->version=TLS1_1_VERSION; + type=3; + } + else if (!(s->options & SSL_OP_NO_TLSv1)) { s->version=TLS1_VERSION; type=3; @@ -566,7 +580,9 @@ int ssl23_get_client_hello(SSL *s) s->s3->rbuf.offset=0; } - if (s->version == TLS1_VERSION) + if (s->version == TLS1_1_VERSION) + s->method = TLSv1_1_server_method(); + else if (s->version == TLS1_VERSION) s->method = TLSv1_server_method(); else s->method = SSLv3_server_method(); diff --git a/ssl/s3_pkt.c b/ssl/s3_pkt.c index febc2860e1..d795199ead 100644 --- a/ssl/s3_pkt.c +++ b/ssl/s3_pkt.c @@ -115,6 +115,7 @@ #include "ssl_locl.h" #include #include +#include static int do_ssl3_write(SSL *s, int type, const unsigned char *buf, unsigned int len, int create_empty_fragment); @@ -629,6 +630,7 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf, unsigned char *p,*plen; int i,mac_size,clear=0; int prefix_len=0; + int eivlen; long align=0; SSL3_RECORD *wr; SSL3_BUFFER *wb=&(s->s3->wbuf); @@ -738,9 +740,18 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf, /* field where we are to write out packet length */ plen=p; p+=2; + /* Explicit IV length, block ciphers and TLS version 1.1 or later */ + if (s->enc_write_ctx && s->version >= TLS1_1_VERSION) + { + eivlen = EVP_CIPHER_CTX_iv_length(s->enc_write_ctx); + if (eivlen <= 1) + eivlen = 0; + } + else + eivlen = 0; /* lets setup the record stuff. */ - wr->data=p; + wr->data=p + eivlen; wr->length=(int)len; wr->input=(unsigned char *)buf; @@ -768,11 +779,19 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf, if (mac_size != 0) { - if (s->method->ssl3_enc->mac(s,&(p[wr->length]),1) < 0) + if (s->method->ssl3_enc->mac(s,&(p[wr->length + eivlen]),1) < 0) goto err; wr->length+=mac_size; - wr->input=p; - wr->data=p; + } + + wr->input=p; + wr->data=p; + + if (eivlen) + { + if (RAND_pseudo_bytes(p, eivlen) <= 0) + goto err; + wr->length += eivlen; } /* ssl3_enc can only have an error on read */ @@ -1262,7 +1281,7 @@ start: default: #ifndef OPENSSL_NO_TLS /* TLS just ignores unknown message types */ - if (s->version == TLS1_VERSION) + if (s->version >= TLS1_VERSION && s->version <= TLS1_1_VERSION) { rr->length = 0; goto start; diff --git a/ssl/ssl.h b/ssl/ssl.h index 1d82a6df62..e3cb2a1a02 100644 --- a/ssl/ssl.h +++ b/ssl/ssl.h @@ -298,6 +298,7 @@ extern "C" { #define SSL_TXT_SSLV2 "SSLv2" #define SSL_TXT_SSLV3 "SSLv3" #define SSL_TXT_TLSV1 "TLSv1" +#define SSL_TXT_TLSV1_1 "TLSv1.1" #define SSL_TXT_EXP "EXP" #define SSL_TXT_EXPORT "EXPORT" @@ -569,6 +570,7 @@ typedef struct ssl_session_st #define SSL_OP_NO_SSLv2 0x01000000L #define SSL_OP_NO_SSLv3 0x02000000L #define SSL_OP_NO_TLSv1 0x04000000L +#define SSL_OP_NO_TLSv1_1 0x00040000L /* The next flag deliberately changes the ciphertest, this is a check * for the PKCS#1 attack */ @@ -1630,6 +1632,10 @@ const SSL_METHOD *TLSv1_method(void); /* TLSv1.0 */ const SSL_METHOD *TLSv1_server_method(void); /* TLSv1.0 */ const SSL_METHOD *TLSv1_client_method(void); /* TLSv1.0 */ +const SSL_METHOD *TLSv1_1_method(void); /* TLSv1.1 */ +const SSL_METHOD *TLSv1_1_server_method(void); /* TLSv1.1 */ +const SSL_METHOD *TLSv1_1_client_method(void); /* TLSv1.1 */ + const SSL_METHOD *DTLSv1_method(void); /* DTLSv1.0 */ const SSL_METHOD *DTLSv1_server_method(void); /* DTLSv1.0 */ const SSL_METHOD *DTLSv1_client_method(void); /* DTLSv1.0 */ diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index b3b356d5ab..04b6bfcb1c 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -2380,8 +2380,10 @@ SSL_METHOD *ssl_bad_method(int ver) const char *SSL_get_version(const SSL *s) { - if (s->version == TLS1_VERSION) - return("TLSv1"); + if (s->version == TLS1_1_VERSION) + return("TLSv1.1"); + else if (s->version == SSL3_VERSION) + return("SSLv3"); else if (s->version == SSL3_VERSION) return("SSLv3"); else if (s->version == SSL2_VERSION) diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index c7c93ac61d..226d407023 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -591,11 +591,12 @@ extern SSL3_ENC_METHOD TLSv1_enc_data; extern SSL3_ENC_METHOD SSLv3_enc_data; extern SSL3_ENC_METHOD DTLSv1_enc_data; -#define IMPLEMENT_tls1_meth_func(func_name, s_accept, s_connect, s_get_meth) \ +#define IMPLEMENT_tls_meth_func(version, func_name, s_accept, s_connect, \ + s_get_meth) \ const SSL_METHOD *func_name(void) \ { \ static const SSL_METHOD func_name##_data= { \ - TLS1_VERSION, \ + version, \ tls1_new, \ tls1_clear, \ tls1_free, \ @@ -669,7 +670,7 @@ const SSL_METHOD *func_name(void) \ const SSL_METHOD *func_name(void) \ { \ static const SSL_METHOD func_name##_data= { \ - TLS1_VERSION, \ + TLS1_1_VERSION, \ tls1_new, \ tls1_clear, \ tls1_free, \ diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c index bebbfa099d..348410e5c3 100644 --- a/ssl/ssl_sess.c +++ b/ssl/ssl_sess.c @@ -300,6 +300,11 @@ int ssl_get_new_session(SSL *s, int session) ss->ssl_version=TLS1_VERSION; ss->session_id_length=SSL3_SSL_SESSION_ID_LENGTH; } + else if (s->version == TLS1_1_VERSION) + { + ss->ssl_version=TLS1_1_VERSION; + ss->session_id_length=SSL3_SSL_SESSION_ID_LENGTH; + } else if (s->version == DTLS1_BAD_VER) { ss->ssl_version=DTLS1_BAD_VER; diff --git a/ssl/ssl_txt.c b/ssl/ssl_txt.c index 3122440e26..cab712b9a8 100644 --- a/ssl/ssl_txt.c +++ b/ssl/ssl_txt.c @@ -115,6 +115,8 @@ int SSL_SESSION_print(BIO *bp, const SSL_SESSION *x) s="SSLv2"; else if (x->ssl_version == SSL3_VERSION) s="SSLv3"; + else if (x->ssl_version == TLS1_1_VERSION) + s="TLSv1.1"; else if (x->ssl_version == TLS1_VERSION) s="TLSv1"; else if (x->ssl_version == DTLS1_VERSION) diff --git a/ssl/t1_clnt.c b/ssl/t1_clnt.c index c87af17712..b06bada6f2 100644 --- a/ssl/t1_clnt.c +++ b/ssl/t1_clnt.c @@ -66,13 +66,19 @@ static const SSL_METHOD *tls1_get_client_method(int ver); static const SSL_METHOD *tls1_get_client_method(int ver) { + if (ver == TLS1_1_VERSION) + return TLSv1_1_client_method(); if (ver == TLS1_VERSION) - return(TLSv1_client_method()); - else - return(NULL); + return TLSv1_client_method(); + return NULL; } -IMPLEMENT_tls1_meth_func(TLSv1_client_method, +IMPLEMENT_tls_meth_func(TLS1_1_VERSION, TLSv1_1_client_method, + ssl_undefined_function, + ssl3_connect, + tls1_get_client_method) + +IMPLEMENT_tls_meth_func(TLS1_VERSION, TLSv1_client_method, ssl_undefined_function, ssl3_connect, tls1_get_client_method) diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c index d9cb059d0c..028f6493d1 100644 --- a/ssl/t1_enc.c +++ b/ssl/t1_enc.c @@ -143,6 +143,7 @@ #include #include #include +#include #ifdef KSSL_DEBUG #include #endif @@ -617,7 +618,27 @@ int tls1_enc(SSL *s, int send) if (s->enc_write_ctx == NULL) enc=NULL; else + { + int ivlen; enc=EVP_CIPHER_CTX_cipher(s->enc_write_ctx); + /* For TLSv1.1 and later explicit IV */ + if (s->version >= TLS1_1_VERSION) + ivlen = EVP_CIPHER_iv_length(enc); + else + ivlen = 0; + if (ivlen > 1) + { + if ( rec->data != rec->input) + /* we can't write into the input stream: + * Can this ever happen?? (steve) + */ + fprintf(stderr, + "%s:%d: rec->data != rec->input\n", + __FILE__, __LINE__); + else if (RAND_bytes(rec->input, ivlen) <= 0) + return -1; + } + } } else { @@ -746,7 +767,13 @@ int tls1_enc(SSL *s, int send) return -1; } } - rec->length-=i; + rec->length -=i; + if (s->version >= TLS1_1_VERSION) + { + rec->data += bs; /* skip the explicit IV */ + rec->input += bs; + rec->length -= bs; + } } } return(1); diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index 43c651f47b..ebf9c4fdae 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -166,7 +166,7 @@ void tls1_free(SSL *s) void tls1_clear(SSL *s) { ssl3_clear(s); - s->version=TLS1_VERSION; + s->version = s->method->version; } #ifndef OPENSSL_NO_EC diff --git a/ssl/t1_meth.c b/ssl/t1_meth.c index 6ce7c0bbf5..3257636425 100644 --- a/ssl/t1_meth.c +++ b/ssl/t1_meth.c @@ -60,16 +60,21 @@ #include #include "ssl_locl.h" -static const SSL_METHOD *tls1_get_method(int ver); static const SSL_METHOD *tls1_get_method(int ver) { + if (ver == TLS1_1_VERSION) + return TLSv1_1_method(); if (ver == TLS1_VERSION) - return(TLSv1_method()); - else - return(NULL); + return TLSv1_method(); + return NULL; } -IMPLEMENT_tls1_meth_func(TLSv1_method, +IMPLEMENT_tls_meth_func(TLS1_1_VERSION, TLSv1_1_method, + ssl3_accept, + ssl3_connect, + tls1_get_method) + +IMPLEMENT_tls_meth_func(TLS1_VERSION, TLSv1_method, ssl3_accept, ssl3_connect, tls1_get_method) diff --git a/ssl/t1_srvr.c b/ssl/t1_srvr.c index 42525e9e89..274a3d6738 100644 --- a/ssl/t1_srvr.c +++ b/ssl/t1_srvr.c @@ -67,13 +67,19 @@ static const SSL_METHOD *tls1_get_server_method(int ver); static const SSL_METHOD *tls1_get_server_method(int ver) { + if (ver == TLS1_1_VERSION) + return TLSv1_1_server_method(); if (ver == TLS1_VERSION) - return(TLSv1_server_method()); - else - return(NULL); + return TLSv1_server_method(); + return NULL; } -IMPLEMENT_tls1_meth_func(TLSv1_server_method, +IMPLEMENT_tls_meth_func(TLS1_1_VERSION, TLSv1_1_server_method, + ssl3_accept, + ssl_undefined_function, + tls1_get_server_method) + +IMPLEMENT_tls_meth_func(TLS1_VERSION, TLSv1_server_method, ssl3_accept, ssl_undefined_function, tls1_get_server_method) diff --git a/ssl/tls1.h b/ssl/tls1.h index b3cc8f098b..b32b713ca8 100644 --- a/ssl/tls1.h +++ b/ssl/tls1.h @@ -159,6 +159,10 @@ extern "C" { #define TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES 0 +#define TLS1_1_VERSION 0x0302 +#define TLS1_1_VERSION_MAJOR 0x03 +#define TLS1_1_VERSION_MINOR 0x02 + #define TLS1_VERSION 0x0301 #define TLS1_VERSION_MAJOR 0x03 #define TLS1_VERSION_MINOR 0x01 -- 2.25.1