From c2b78c31d631f45cd43c2d04c5ae490b8e9f21ab Mon Sep 17 00:00:00 2001 From: Ben Laurie Date: Sun, 8 Nov 2009 14:51:54 +0000 Subject: [PATCH] First cut of renegotiation extension. --- CHANGES | 29 +++-- Configure | 3 +- apps/s_cb.c | 3 + apps/s_client.c | 3 + apps/s_server.c | 3 + ssl/Makefile | 4 +- ssl/s3_both.c | 35 ++++++ ssl/s3_srvr.c | 9 -- ssl/ssl.h | 7 ++ ssl/ssl3.h | 6 ++ ssl/ssl_err.c | 7 +- ssl/ssl_locl.h | 9 ++ ssl/t1_lib.c | 104 +++++++++++++++++- ssl/t1_reneg.c | 275 ++++++++++++++++++++++++++++++++++++++++++++++++ ssl/tls1.h | 3 + 15 files changed, 476 insertions(+), 24 deletions(-) create mode 100644 ssl/t1_reneg.c diff --git a/CHANGES b/CHANGES index 73cc1dec30..c45b286f4a 100644 --- a/CHANGES +++ b/CHANGES @@ -2,14 +2,17 @@ OpenSSL CHANGES _______________ - Changes between 0.9.8k and 0.9.8l [xx XXX xxxx] - - *) Disable renegotiation completely - this fixes a severe security - problem at the cost of breaking all renegotiation. Renegotiation - can be re-enabled by setting - OPENSSL_ENABLE_UNSAFE_LEGACY_SESSION_RENEGOTATION at - compile-time. This is really not recommended. - [Ben Laurie] + Changes between 0.9.8l and 0.9.8m [xx XXX xxxx] + + *) Implement + https://svn.resiprocate.org/rep/ietf-drafts/ekr/draft-rescorla-tls-renegotiate.txt. Re-enable + renegotiation but require the extension as needed. Unfortunately, + SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION turns out to be a + bad idea. It has been replaced by + SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION which can be set with + SSL_CTX_set_options(). This is really not recommended unless you + know what you are doing. + [Eric Rescorla and Ben Laurie] *) Fixes to stateless session resumption handling. Use initial_ctx when issuing and attempting to decrypt tickets in case it has changed during @@ -95,6 +98,16 @@ *) Add 2.5.4.* OIDs [Ilya O. ] + Changes between 0.9.8k and 0.9.8l [5 Nov 2009] + + *) Disable renegotiation completely - this fixes a severe security + problem (CVE-2009-3555) at the cost of breaking all + renegotiation. Renegotiation can be re-enabled by setting + SSL3_FLAGS_ALLOW_UNSAFE_LEGACY_RENEGOTIATION in s3->flags at + run-time. This is really not recommended unless you know what + you're doing. + [Ben Laurie] + Changes between 0.9.8j and 0.9.8k [25 Mar 2009] *) Don't set val to NULL when freeing up structures, it is freed up by diff --git a/Configure b/Configure index 6fdd8550f4..006e5a5b4f 100755 --- a/Configure +++ b/Configure @@ -161,7 +161,8 @@ my %table=( "debug-ben", "gcc:-DBN_DEBUG -DREF_CHECK -DCONF_DEBUG -DBN_CTX_DEBUG -DCRYPTO_MDEBUG -DPEDANTIC -DDEBUG_SAFESTACK -O2 -pedantic -Wall -Wshadow -Werror -pipe::(unknown):::::bn86-elf.o co86-elf.o", "debug-ben-openbsd","gcc:-DBN_DEBUG -DREF_CHECK -DCONF_DEBUG -DBN_CTX_DEBUG -DCRYPTO_MDEBUG -DPEDANTIC -DDEBUG_SAFESTACK -DOPENSSL_OPENBSD_DEV_CRYPTO -DOPENSSL_NO_ASM -O2 -pedantic -Wall -Wshadow -Werror -pipe::(unknown)::::", "debug-ben-openbsd-debug","gcc:-DBN_DEBUG -DREF_CHECK -DCONF_DEBUG -DBN_CTX_DEBUG -DCRYPTO_MDEBUG -DPEDANTIC -DDEBUG_SAFESTACK -DOPENSSL_OPENBSD_DEV_CRYPTO -DOPENSSL_NO_ASM -g3 -O2 -pedantic -Wall -Wshadow -Werror -pipe::(unknown)::::", -"debug-ben-debug", "gcc:$gcc_devteam_warn -DBN_DEBUG -DREF_CHECK -DCONF_DEBUG -DDEBUG_SAFESTACK -g3 -O2 -pipe::(unknown)::::::", +"debug-ben-debug", "gcc:$gcc_devteam_warn -DBN_DEBUG -DREF_CHECK -DCONF_DEBUG -DDEBUG_SAFESTACK -ggdb3 -O2 -pipe::(unknown)::::::", +"debug-ben-debug-noopt", "gcc:$gcc_devteam_warn -DBN_DEBUG -DREF_CHECK -DCONF_DEBUG -DDEBUG_SAFESTACK -ggdb3 -pipe::(unknown)::::::", "debug-ben-strict", "gcc:-DBN_DEBUG -DREF_CHECK -DCONF_DEBUG -DBN_CTX_DEBUG -DCRYPTO_MDEBUG -DCONST_STRICT -O2 -Wall -Wshadow -Werror -Wpointer-arith -Wcast-qual -Wwrite-strings -pipe::(unknown)::::::", "debug-rse","cc:-DTERMIOS -DL_ENDIAN -pipe -O -g -ggdb3 -Wall::(unknown):::BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}", "debug-bodo", "gcc:-DL_ENDIAN -DBN_DEBUG -DREF_CHECK -DCONF_DEBUG -DBIO_PAIR_DEBUG -DPEDANTIC -g -march=i486 -pedantic -Wshadow -Wall -Wcast-align -Wstrict-prototypes -Wmissing-prototypes -Wno-long-long -Wundef -Wconversion -pipe::-D_REENTRANT:::BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:${x86_elf_asm}", diff --git a/apps/s_cb.c b/apps/s_cb.c index 8c388afd3f..97caffc401 100644 --- a/apps/s_cb.c +++ b/apps/s_cb.c @@ -638,6 +638,9 @@ void MS_CALLBACK tlsext_cb(SSL *s, int client_server, int type, extname = "server ticket"; break; + case TLSEXT_TYPE_renegotiate: + extname = "renegotiate"; + break; default: extname = "unknown"; diff --git a/apps/s_client.c b/apps/s_client.c index f6717f1a71..c9c654c3c8 100644 --- a/apps/s_client.c +++ b/apps/s_client.c @@ -249,6 +249,7 @@ static void sc_usage(void) BIO_printf(bio_err," -status - request certificate status from server\n"); BIO_printf(bio_err," -no_ticket - disable use of RFC4507bis session tickets\n"); #endif + BIO_printf(bio_err," -legacy_renegotiation - enable use of legacy renegotiation (dangerous)\n"); } #ifndef OPENSSL_NO_TLSEXT @@ -536,6 +537,8 @@ int MAIN(int argc, char **argv) #endif else if (strcmp(*argv,"-serverpref") == 0) off|=SSL_OP_CIPHER_SERVER_PREFERENCE; + else if (strcmp(*argv,"-legacy_renegotiation") == 0) + off|=SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION; else if (strcmp(*argv,"-cipher") == 0) { if (--argc < 1) goto bad; diff --git a/apps/s_server.c b/apps/s_server.c index cb1ebcae38..77bb6e8e91 100644 --- a/apps/s_server.c +++ b/apps/s_server.c @@ -404,6 +404,7 @@ static void sv_usage(void) BIO_printf(bio_err," not specified (default is %s)\n",TEST_CERT2); BIO_printf(bio_err," -tlsextdebug - hex dump of all TLS extensions received\n"); BIO_printf(bio_err," -no_ticket - disable use of RFC4507bis session tickets\n"); + BIO_printf(bio_err," -legacy_renegotiation - enable use of legacy renegotiation (dangerous)\n"); #endif } @@ -923,6 +924,8 @@ int MAIN(int argc, char *argv[]) } else if (strcmp(*argv,"-serverpref") == 0) { off|=SSL_OP_CIPHER_SERVER_PREFERENCE; } + else if (strcmp(*argv,"-legacy_renegotiation") == 0) + off|=SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION; else if (strcmp(*argv,"-cipher") == 0) { if (--argc < 1) goto bad; diff --git a/ssl/Makefile b/ssl/Makefile index 46c06597fa..b857ce26a1 100644 --- a/ssl/Makefile +++ b/ssl/Makefile @@ -30,7 +30,7 @@ LIBSRC= \ ssl_lib.c ssl_err2.c ssl_cert.c ssl_sess.c \ ssl_ciph.c ssl_stat.c ssl_rsa.c \ ssl_asn1.c ssl_txt.c ssl_algs.c \ - bio_ssl.c ssl_err.c kssl.c + bio_ssl.c ssl_err.c kssl.c t1_reneg.c LIBOBJ= \ s2_meth.o s2_srvr.o s2_clnt.o s2_lib.o s2_enc.o s2_pkt.o \ s3_meth.o s3_srvr.o s3_clnt.o s3_lib.o s3_enc.o s3_pkt.o s3_both.o \ @@ -41,7 +41,7 @@ LIBOBJ= \ ssl_lib.o ssl_err2.o ssl_cert.o ssl_sess.o \ ssl_ciph.o ssl_stat.o ssl_rsa.o \ ssl_asn1.o ssl_txt.o ssl_algs.o \ - bio_ssl.o ssl_err.o kssl.o + bio_ssl.o ssl_err.o kssl.o t1_reneg.o SRC= $(LIBSRC) diff --git a/ssl/s3_both.c b/ssl/s3_both.c index 4042d13274..bc3ef5a72a 100644 --- a/ssl/s3_both.c +++ b/ssl/s3_both.c @@ -116,6 +116,7 @@ #include #include +#include #include #include "ssl_locl.h" #include @@ -168,6 +169,23 @@ int ssl3_send_finished(SSL *s, int a, int b, const char *sender, int slen) p+=i; l=i; + /* Copy the finished so we can use it for + renegotiation checks */ + if(s->type == SSL_ST_CONNECT) + { + 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 + { + assert(i <= EVP_MAX_MD_SIZE); + memcpy(s->s3->previous_server_finished, + s->s3->tmp.finish_md, i); + s->s3->previous_server_finished_len=i; + } + #ifdef OPENSSL_SYS_WIN16 /* MSVC 1.5 does not clear the top bytes of the word unless * I do this. @@ -232,6 +250,23 @@ int ssl3_get_finished(SSL *s, int a, int b) goto f_err; } + /* Copy the finished so we can use it for + renegotiation checks */ + if(s->type == SSL_ST_ACCEPT) + { + 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 + { + assert(i <= EVP_MAX_MD_SIZE); + memcpy(s->s3->previous_server_finished, + s->s3->tmp.peer_finish_md, i); + s->s3->previous_server_finished_len=i; + } + return(1); f_err: ssl3_send_alert(s,SSL3_AL_FATAL,al); diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index 057a9fad62..c698513a09 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -718,15 +718,6 @@ int ssl3_get_client_hello(SSL *s) #endif STACK_OF(SSL_CIPHER) *ciphers=NULL; -#ifndef OPENSSL_ENABLE_UNSAFE_LEGACY_SESSION_RENEGOTATION - if (s->new_session) - { - al=SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_NO_RENEGOTIATION); - goto f_err; - } -#endif /* ndef OPENSSL_ENABLE_UNSAFE_LEGACY_SESSION_RENEGOTATION */ - /* We do this so that we will respond with our native type. * If we are TLSv1 and we get SSLv3, we will respond with TLSv1, * This down switching should be handled by a different method. diff --git a/ssl/ssl.h b/ssl/ssl.h index f94f0f0e94..275cf2e320 100644 --- a/ssl/ssl.h +++ b/ssl/ssl.h @@ -492,6 +492,7 @@ typedef struct ssl_session_st #define SSL_OP_SSLEAY_080_CLIENT_DH_BUG 0x00000080L #define SSL_OP_TLS_D5_BUG 0x00000100L #define SSL_OP_TLS_BLOCK_PADDING_BUG 0x00000200L +#define SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0x00000400L /* Disable SSL 3.0/TLS 1.0 CBC vulnerability workaround that was added * in OpenSSL 0.9.6d. Usually (depending on the application protocol) @@ -1694,6 +1695,8 @@ void ERR_load_SSL_strings(void); #define SSL_F_GET_SERVER_HELLO 109 #define SSL_F_GET_SERVER_VERIFY 110 #define SSL_F_I2D_SSL_SESSION 111 +#define SSL_F_PARSE_CLIENT_HELLO_RENEGOTIATE_EXT 280 +#define SSL_F_PARSE_SERVER_HELLO_RENEGOTIATE_EXT 281 #define SSL_F_READ_N 112 #define SSL_F_REQUEST_CERTIFICATE 113 #define SSL_F_SERVER_FINISH 239 @@ -1758,6 +1761,7 @@ void ERR_load_SSL_strings(void); #define SSL_F_SSL3_SETUP_KEY_BLOCK 157 #define SSL_F_SSL3_WRITE_BYTES 158 #define SSL_F_SSL3_WRITE_PENDING 159 +#define SSL_F_SSL_ADD_CLIENTHELLO_RENEGOTIATE_EXT 282 #define SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT 272 #define SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK 215 #define SSL_F_SSL_ADD_FILE_CERT_SUBJECTS_TO_STACK 216 @@ -1997,6 +2001,9 @@ void ERR_load_SSL_strings(void); #define SSL_R_RECORD_LENGTH_MISMATCH 213 #define SSL_R_RECORD_TOO_LARGE 214 #define SSL_R_RECORD_TOO_SMALL 298 +#define SSL_R_RENEGOTIATE_EXT_TOO_LONG 318 +#define SSL_R_RENEGOTIATION_ENCODING_ERR 320 +#define SSL_R_RENEGOTIATION_MISMATCH 319 #define SSL_R_REQUIRED_CIPHER_MISSING 215 #define SSL_R_REUSE_CERT_LENGTH_NOT_ZERO 216 #define SSL_R_REUSE_CERT_TYPE_NOT_ZERO 217 diff --git a/ssl/ssl3.h b/ssl/ssl3.h index 4b1e2e9834..b44498c394 100644 --- a/ssl/ssl3.h +++ b/ssl/ssl3.h @@ -440,6 +440,12 @@ typedef struct ssl3_state_st int cert_request; } tmp; + /* Connection binding to prevent renegotiation attacks */ + unsigned char previous_client_finished[EVP_MAX_MD_SIZE]; + unsigned char previous_client_finished_len; + unsigned char previous_server_finished[EVP_MAX_MD_SIZE]; + unsigned char previous_server_finished_len; + int send_connection_binding; /* TODOEKR */ } SSL3_STATE; diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index 898dc10979..49e254438b 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -110,6 +110,8 @@ static ERR_STRING_DATA SSL_str_functs[]= {ERR_FUNC(SSL_F_GET_SERVER_HELLO), "GET_SERVER_HELLO"}, {ERR_FUNC(SSL_F_GET_SERVER_VERIFY), "GET_SERVER_VERIFY"}, {ERR_FUNC(SSL_F_I2D_SSL_SESSION), "i2d_SSL_SESSION"}, +{ERR_FUNC(SSL_F_PARSE_CLIENT_HELLO_RENEGOTIATE_EXT), "PARSE_CLIENT_HELLO_RENEGOTIATE_EXT"}, +{ERR_FUNC(SSL_F_PARSE_SERVER_HELLO_RENEGOTIATE_EXT), "PARSE_SERVER_HELLO_RENEGOTIATE_EXT"}, {ERR_FUNC(SSL_F_READ_N), "READ_N"}, {ERR_FUNC(SSL_F_REQUEST_CERTIFICATE), "REQUEST_CERTIFICATE"}, {ERR_FUNC(SSL_F_SERVER_FINISH), "SERVER_FINISH"}, @@ -174,6 +176,7 @@ static ERR_STRING_DATA SSL_str_functs[]= {ERR_FUNC(SSL_F_SSL3_SETUP_KEY_BLOCK), "SSL3_SETUP_KEY_BLOCK"}, {ERR_FUNC(SSL_F_SSL3_WRITE_BYTES), "SSL3_WRITE_BYTES"}, {ERR_FUNC(SSL_F_SSL3_WRITE_PENDING), "SSL3_WRITE_PENDING"}, +{ERR_FUNC(SSL_F_SSL_ADD_CLIENTHELLO_RENEGOTIATE_EXT), "SSL_ADD_CLIENTHELLO_RENEGOTIATE_EXT"}, {ERR_FUNC(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT), "SSL_ADD_CLIENTHELLO_TLSEXT"}, {ERR_FUNC(SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK), "SSL_add_dir_cert_subjects_to_stack"}, {ERR_FUNC(SSL_F_SSL_ADD_FILE_CERT_SUBJECTS_TO_STACK), "SSL_add_file_cert_subjects_to_stack"}, @@ -388,7 +391,6 @@ static ERR_STRING_DATA SSL_str_reasons[]= {ERR_REASON(SSL_R_NO_PRIVATE_KEY_ASSIGNED),"no private key assigned"}, {ERR_REASON(SSL_R_NO_PROTOCOLS_AVAILABLE),"no protocols available"}, {ERR_REASON(SSL_R_NO_PUBLICKEY) ,"no publickey"}, -{ERR_REASON(SSL_R_NO_RENEGOTIATION) ,"no renegotiation"}, {ERR_REASON(SSL_R_NO_SHARED_CIPHER) ,"no shared cipher"}, {ERR_REASON(SSL_R_NO_VERIFY_CALLBACK) ,"no verify callback"}, {ERR_REASON(SSL_R_NULL_SSL_CTX) ,"null ssl ctx"}, @@ -416,6 +418,9 @@ static ERR_STRING_DATA SSL_str_reasons[]= {ERR_REASON(SSL_R_RECORD_LENGTH_MISMATCH),"record length mismatch"}, {ERR_REASON(SSL_R_RECORD_TOO_LARGE) ,"record too large"}, {ERR_REASON(SSL_R_RECORD_TOO_SMALL) ,"record too small"}, +{ERR_REASON(SSL_R_RENEGOTIATE_EXT_TOO_LONG),"renegotiate ext too long"}, +{ERR_REASON(SSL_R_RENEGOTIATION_ENCODING_ERR),"renegotiation encoding err"}, +{ERR_REASON(SSL_R_RENEGOTIATION_MISMATCH),"renegotiation mismatch"}, {ERR_REASON(SSL_R_REQUIRED_CIPHER_MISSING),"required cipher missing"}, {ERR_REASON(SSL_R_REUSE_CERT_LENGTH_NOT_ZERO),"reuse cert length not zero"}, {ERR_REASON(SSL_R_REUSE_CERT_TYPE_NOT_ZERO),"reuse cert type not zero"}, diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 9df2186c6f..ffb6085f3d 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -985,6 +985,15 @@ int tls1_process_ticket(SSL *s, unsigned char *session_id, int len, const unsigned char *limit, SSL_SESSION **ret); EVP_MD_CTX* ssl_replace_hash(EVP_MD_CTX **hash,const EVP_MD *md) ; void ssl_clear_hash_ctx(EVP_MD_CTX **hash); + +int ssl_add_serverhello_renegotiate_ext(SSL *s, unsigned char *p, int *len, + int maxlen); +int ssl_parse_serverhello_renegotiate_ext(SSL *s, unsigned char *d, int len, + int *al); +int ssl_add_clienthello_renegotiate_ext(SSL *s, unsigned char *p, int *len, + int maxlen); +int ssl_parse_clienthello_renegotiate_ext(SSL *s, unsigned char *d, int len, + int *al); #endif #endif diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index 247854e124..6c2085d6aa 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -173,7 +173,32 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha ret+=size_str; } - + + /* Add the renegotiation option: TODOEKR switch */ + { + int el; + + if(!ssl_add_clienthello_renegotiate_ext(s, 0, &el, 0)) + { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return NULL; + } + + if((limit - p - 4 - el) < 0) return NULL; + + s2n(TLSEXT_TYPE_renegotiate,ret); + s2n(el,ret); + + if(!ssl_add_clienthello_renegotiate_ext(s, ret, &el, el)) + { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return NULL; + } + + ret += el; + } + + if (!(SSL_get_options(s) & SSL_OP_NO_TICKET)) { int ticklen; @@ -269,6 +294,30 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha s2n(TLSEXT_TYPE_server_name,ret); s2n(0,ret); } + + if(s->s3->send_connection_binding) + { + int el; + + if(!ssl_add_serverhello_renegotiate_ext(s, 0, &el, 0)) + { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return NULL; + } + + if((limit - p - 4 - el) < 0) return NULL; + + s2n(TLSEXT_TYPE_renegotiate,ret); + s2n(el,ret); + + if(!ssl_add_serverhello_renegotiate_ext(s, ret, &el, el)) + { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return NULL; + } + + ret += el; + } if (s->tlsext_ticket_expected && !(SSL_get_options(s) & SSL_OP_NO_TICKET)) @@ -298,11 +347,23 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in unsigned short size; unsigned short len; unsigned char *data = *p; + int renegotiate_seen = 0; + s->servername_done = 0; s->tlsext_status_type = -1; + s->s3->send_connection_binding = 0; if (data >= (d+n-2)) + { + if (s->new_session + && !(s->ctx->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) + { + /* We should always see one extension: the renegotiate extension */ + *al = SSL_AD_ILLEGAL_PARAMETER; /* is this the right alert? */ + return 0; + } return 1; + } n2s(data,len); if (data > (d+n-len)) @@ -414,6 +475,12 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in return 0; } + } + else if (type == TLSEXT_TYPE_renegotiate) + { + if(!ssl_parse_clienthello_renegotiate_ext(s, data, size, al)) + return 0; + renegotiate_seen = 1; } else if (type == TLSEXT_TYPE_status_request && s->ctx->tlsext_status_cb) @@ -515,11 +582,19 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in else s->tlsext_status_type = -1; } + /* session ticket processed earlier */ data+=size; } + if (s->new_session && !renegotiate_seen + && !(s->ctx->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) + { + *al = SSL_AD_ILLEGAL_PARAMETER; /* is this the right alert? */ + return 0; + } + *p = data; return 1; } @@ -530,11 +605,22 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in unsigned short size; unsigned short len; unsigned char *data = *p; - int tlsext_servername = 0; + int renegotiate_seen = 0; if (data >= (d+n-2)) + { + /* Because the client does not see any renegotiation during an + attack, we must enforce this on all server hellos, even the + first */ + if (!(s->ctx->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) + { + /* We should always see one extension: the renegotiate extension */ + *al = SSL_AD_ILLEGAL_PARAMETER; /* is this the right alert? */ + return 0; + } return 1; + } n2s(data,len); @@ -582,7 +668,12 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in /* Set flag to expect CertificateStatus message */ s->tlsext_status_expected = 1; } - + else if (type == TLSEXT_TYPE_renegotiate) + { + if(!ssl_parse_serverhello_renegotiate_ext(s, data, size, al)) + return 0; + renegotiate_seen = 1; + } data+=size; } @@ -592,6 +683,13 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in return 0; } + if (!renegotiate_seen + && !(s->ctx->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) + { + *al = SSL_AD_ILLEGAL_PARAMETER; /* is this the right alert? */ + return 0; + } + if (!s->hit && tlsext_servername == 1) { if (s->tlsext_hostname) diff --git a/ssl/t1_reneg.c b/ssl/t1_reneg.c new file mode 100644 index 0000000000..e982dd5567 --- /dev/null +++ b/ssl/t1_reneg.c @@ -0,0 +1,275 @@ +/* ssl/t1_reneg.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2009 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +#include +#include +#include +#include "ssl_locl.h" + +/* Add the client's renegotiation binding */ +int ssl_add_clienthello_renegotiate_ext(SSL *s, unsigned char *p, int *len, + int maxlen) + { + if(p) + { + if((s->s3->previous_client_finished_len+1) > maxlen) + { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATE_EXT_TOO_LONG); + return 0; + } + + /* Length byte */ + *p = s->s3->previous_client_finished_len; + p++; + + memcpy(p, s->s3->previous_client_finished, + s->s3->previous_client_finished_len); + } + + *len=s->s3->previous_client_finished_len + 1; + + return 1; + } + +/* Parse the client's renegotiation binding and abort if it's not + right */ +int ssl_parse_clienthello_renegotiate_ext(SSL *s, unsigned char *d, int len, + int *al) + { + int ilen; + + /* Parse the length byte */ + if(len < 1) + { + SSLerr(SSL_F_PARSE_SERVER_HELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_ENCODING_ERR); + *al=SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + ilen = *d; + d++; + + /* Consistency check */ + if((ilen+1) != len) + { + SSLerr(SSL_F_PARSE_SERVER_HELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_ENCODING_ERR); + *al=SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + + /* Check that the extension matches */ + if(ilen != s->s3->previous_client_finished_len) + { + SSLerr(SSL_F_PARSE_CLIENT_HELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_MISMATCH); + *al=SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + + if(memcmp(d, s->s3->previous_client_finished, + s->s3->previous_client_finished_len)) + { + SSLerr(SSL_F_PARSE_CLIENT_HELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_MISMATCH); + *al=SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + + s->s3->send_connection_binding=1; + + return 1; + } + +/* Add the server's renegotiation binding */ +int ssl_add_serverhello_renegotiate_ext(SSL *s, unsigned char *p, int *len, + int maxlen) + { + if(p) + { + if((s->s3->previous_client_finished_len + + s->s3->previous_server_finished_len + 1) > maxlen) + { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATE_EXT_TOO_LONG); + return 0; + } + + /* Length byte */ + *p = s->s3->previous_client_finished_len + s->s3->previous_server_finished_len; + p++; + + memcpy(p, s->s3->previous_client_finished, + s->s3->previous_client_finished_len); + p += s->s3->previous_client_finished_len; + + memcpy(p, s->s3->previous_server_finished, + s->s3->previous_server_finished_len); + } + + *len=s->s3->previous_client_finished_len + + s->s3->previous_server_finished_len + 1; + + return 1; + } + +/* Parse the server's renegotiation binding and abort if it's not + right */ +int ssl_parse_serverhello_renegotiate_ext(SSL *s, unsigned char *d, int len, + int *al) + { + int expected_len=s->s3->previous_client_finished_len + + s->s3->previous_server_finished_len; + int ilen; + + /* Check for logic errors */ + assert(!expected_len || s->s3->previous_client_finished_len); + assert(!expected_len || s->s3->previous_server_finished_len); + + /* Parse the length byte */ + if(len < 1) + { + SSLerr(SSL_F_PARSE_SERVER_HELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_ENCODING_ERR); + *al=SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + ilen = *d; + d++; + + /* Consistency check */ + if(ilen+1 != len) + { + SSLerr(SSL_F_PARSE_SERVER_HELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_ENCODING_ERR); + *al=SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + + /* Check that the extension matches */ + if(ilen != expected_len) + { + SSLerr(SSL_F_PARSE_SERVER_HELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_MISMATCH); + *al=SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + + if(memcmp(d, s->s3->previous_client_finished, + s->s3->previous_client_finished_len)) + { + SSLerr(SSL_F_PARSE_CLIENT_HELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_MISMATCH); + *al=SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + d += s->s3->previous_client_finished_len; + + if(memcmp(d, s->s3->previous_server_finished, + s->s3->previous_server_finished_len)) + { + SSLerr(SSL_F_PARSE_SERVER_HELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_MISMATCH); + *al=SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + + return 1; + } diff --git a/ssl/tls1.h b/ssl/tls1.h index ebb4e50626..afe4807fa9 100644 --- a/ssl/tls1.h +++ b/ssl/tls1.h @@ -115,6 +115,9 @@ extern "C" { #define TLSEXT_TYPE_ec_point_formats 11 #define TLSEXT_TYPE_session_ticket 35 +/* Temporary extension type */ +#define TLSEXT_TYPE_renegotiate 0xff01 + /* NameType value from RFC 3546 */ #define TLSEXT_NAMETYPE_host_name 0 /* status request value from RFC 3546 */ -- 2.25.1