diff -up openssl-fips-0.9.8e/apps/s_client.c.reneg openssl-fips-0.9.8e/apps/s_client.c --- openssl-fips-0.9.8e/apps/s_client.c.reneg 2010-02-18 15:58:31.000000000 +0100 +++ openssl-fips-0.9.8e/apps/s_client.c 2010-02-18 15:58:31.000000000 +0100 @@ -231,7 +231,7 @@ static void sc_usage(void) BIO_printf(bio_err," -engine id - Initialise and use the specified engine\n"); #endif BIO_printf(bio_err," -rand file%cfile%c...\n", LIST_SEPARATOR_CHAR, LIST_SEPARATOR_CHAR); - + BIO_printf(bio_err," -legacy_renegotiation - enable use of legacy renegotiation (dangerous)\n"); } enum @@ -247,7 +247,7 @@ int MAIN(int, char **); int MAIN(int argc, char **argv) { - int off=0; + int off=0, clr = 0; SSL *con=NULL,*con2=NULL; X509_STORE *store = NULL; int s,k,width,state=0; @@ -461,6 +461,12 @@ int MAIN(int argc, char **argv) off|=SSL_OP_NO_SSLv2; 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,"-legacy_server_connect") == 0) + { off|=SSL_OP_LEGACY_SERVER_CONNECT; } + else if (strcmp(*argv,"-no_legacy_server_connect") == 0) + { clr|=SSL_OP_LEGACY_SERVER_CONNECT; } else if (strcmp(*argv,"-cipher") == 0) { if (--argc < 1) goto bad; @@ -589,6 +595,9 @@ bad: SSL_CTX_set_options(ctx,SSL_OP_ALL|off); else SSL_CTX_set_options(ctx,off); + + if (clr) + SSL_CTX_clear_options(ctx, clr); /* DTLS: partial reads end up discarding unread UDP bytes :-( * Setting read ahead solves this problem. */ @@ -1290,6 +1299,8 @@ static void print_stuff(BIO *bio, SSL *s EVP_PKEY_bits(pktmp)); EVP_PKEY_free(pktmp); } + BIO_printf(bio, "Secure Renegotiation IS%s supported\n", + SSL_get_secure_renegotiation_support(s) ? "" : " NOT"); #ifndef OPENSSL_NO_COMP comp=SSL_get_current_compression(s); expansion=SSL_get_current_expansion(s); diff -up openssl-fips-0.9.8e/apps/s_server.c.reneg openssl-fips-0.9.8e/apps/s_server.c --- openssl-fips-0.9.8e/apps/s_server.c.reneg 2010-02-18 15:58:31.000000000 +0100 +++ openssl-fips-0.9.8e/apps/s_server.c 2010-02-18 15:58:31.000000000 +0100 @@ -371,6 +371,7 @@ static void sv_usage(void) #endif BIO_printf(bio_err," -id_prefix arg - Generate SSL/TLS session IDs prefixed by 'arg'\n"); BIO_printf(bio_err," -rand file%cfile%c...\n", LIST_SEPARATOR_CHAR, LIST_SEPARATOR_CHAR); + BIO_printf(bio_err," -legacy_renegotiation - enable use of legacy renegotiation (dangerous)\n"); } static int local_argc=0; @@ -700,6 +701,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; @@ -1534,6 +1537,8 @@ static int init_ssl_connection(SSL *con) con->kssl_ctx->client_princ); } #endif /* OPENSSL_NO_KRB5 */ + BIO_printf(bio_s_out, "Secure Renegotiation IS%s supported\n", + SSL_get_secure_renegotiation_support(con) ? "" : " NOT"); return(1); } diff -up openssl-fips-0.9.8e/doc/ssl/SSL_CTX_set_options.pod.reneg openssl-fips-0.9.8e/doc/ssl/SSL_CTX_set_options.pod --- openssl-fips-0.9.8e/doc/ssl/SSL_CTX_set_options.pod.reneg 2005-10-11 12:16:09.000000000 +0200 +++ openssl-fips-0.9.8e/doc/ssl/SSL_CTX_set_options.pod 2010-02-18 16:10:52.000000000 +0100 @@ -2,7 +2,7 @@ =head1 NAME -SSL_CTX_set_options, SSL_set_options, SSL_CTX_get_options, SSL_get_options - manipulate SSL engine options +SSL_CTX_set_options, SSL_set_options, SSL_CTX_clear_options, SSL_clear_options, SSL_CTX_get_options, SSL_get_options, SSL_get_secure_renegotiation_support - manipulate SSL options =head1 SYNOPSIS @@ -11,26 +11,41 @@ SSL_CTX_set_options, SSL_set_options, SS long SSL_CTX_set_options(SSL_CTX *ctx, long options); long SSL_set_options(SSL *ssl, long options); + long SSL_CTX_clear_options(SSL_CTX *ctx, long options); + long SSL_clear_options(SSL *ssl, long options); + long SSL_CTX_get_options(SSL_CTX *ctx); long SSL_get_options(SSL *ssl); + long SSL_get_secure_renegotiation_support(SSL *ssl); + =head1 DESCRIPTION +Note: all these functions are implemented using macros. + SSL_CTX_set_options() adds the options set via bitmask in B to B. Options already set before are not cleared! SSL_set_options() adds the options set via bitmask in B to B. Options already set before are not cleared! +SSL_CTX_clear_options() clears the options set via bitmask in B +to B. + +SSL_clear_options() clears the options set via bitmask in B to B. + SSL_CTX_get_options() returns the options set for B. SSL_get_options() returns the options set for B. +SSL_get_secure_renegotiation_support() indicates whether the peer supports +secure renegotiation. + =head1 NOTES The behaviour of the SSL library can be changed by setting several options. The options are coded as bitmasks and can be combined by a logical B -operation (|). Options can only be added but can never be reset. +operation (|). SSL_CTX_set_options() and SSL_set_options() affect the (external) protocol behaviour of the SSL library. The (internal) behaviour of @@ -199,17 +214,109 @@ Do not use the TLSv1 protocol. When performing renegotiation as a server, always start a new session (i.e., session resumption requests are only accepted in the initial -handshake). This option is not needed for clients. +handshake). This option is not needed for clients. + +=item SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION + +Allow legacy insecure renegotiation between OpenSSL and unpatched clients or +servers. See the B section for more details. + +=item SSL_OP_LEGACY_SERVER_CONNECT + +Allow legacy insecure renegotiation between OpenSSL and unpatched servers +B: this option is currently set by default. See the +B section for more details. =back +=head1 SECURE RENEGOTIATION + +OpenSSL 0.9.8m and later always attempts to use secure renegotiation as +described in RFC5746. This counters the prefix attack described in +CVE-2009-3555 and elsewhere. + +The deprecated and highly broken SSLv2 protocol does not support +renegotiation at all: its use is B discouraged. + +This attack has far reaching consequences which application writers should be +aware of. In the description below an implementation supporting secure +renegotiation is referred to as I. A server not supporting secure +renegotiation is referred to as I. + +The following sections describe the operations permitted by OpenSSL's secure +renegotiation implementation. + +=head2 Patched client and server + +Connections and renegotiation are always permitted by OpenSSL implementations. + +=head2 Unpatched client and patched OpenSSL server + +The initial connection suceeds but client renegotiation is denied by the +server with a B warning alert if TLS v1.0 is used or a fatal +B alert in SSL v3.0. + +If the patched OpenSSL server attempts to renegotiate a fatal +B alert is sent. This is because the server code may be +unaware of the unpatched nature of the client. + +If the option B is set then +renegotiation B succeeds. + +B a bug in OpenSSL clients earlier than 0.9.8m (all of which are +unpatched) will result in the connection hanging if it receives a +B alert. OpenSSL versions 0.9.8m and later will regard +a B alert as fatal and respond with a fatal +B alert. This is because the OpenSSL API currently has +no provision to indicate to an application that a renegotiation attempt +was refused. + +=head2 Patched OpenSSL client and unpatched server. + +If the option B or +B is set then initial connections +and renegotiation between patched OpenSSL clients and unpatched servers +succeeds. If neither option is set then initial connections to unpatched +servers will fail. + +The option B is currently set by default even +though it has security implications: otherwise it would be impossible to +connect to unpatched servers (i.e. all of them initially) and this is clearly +not acceptable. Renegotiation is permitted because this does not add any +additional security issues: during an attack clients do not see any +renegotiations anyway. + +As more servers become patched the option B will +B be set by default in a future version of OpenSSL. + +OpenSSL client applications wishing to ensure they can connect to unpatched +servers should always B B + +OpenSSL client applications that want to ensure they can B connect to +unpatched servers (and thus avoid any security issues) should always B +B using SSL_CTX_clear_options() or +SSL_clear_options(). + +The difference between the B and +B options is that +B enables initial connections and secure +renegotiation between OpenSSL clients and unpatched servers B, while +B allows initial connections +and renegotiation between OpenSSL and unpatched clients or servers. + =head1 RETURN VALUES SSL_CTX_set_options() and SSL_set_options() return the new options bitmask after adding B. +SSL_CTX_clear_options() and SSL_clear_options() return the new options bitmask +after clearing B. + SSL_CTX_get_options() and SSL_get_options() return the current bitmask. +SSL_get_secure_renegotiation_support() returns 1 is the peer supports +secure renegotiation and 0 if it does not. + =head1 SEE ALSO L, L, L, @@ -232,4 +339,11 @@ Versions up to OpenSSL 0.9.6c do not inc can be disabled with this option (in OpenSSL 0.9.6d, it was always enabled). +SSL_CTX_clear_options() and SSL_clear_options() were first added in OpenSSL +0.9.8m. + +B, B +and the function SSL_get_secure_renegotiation_support() were first added in +OpenSSL 0.9.8m. + =cut diff -up openssl-fips-0.9.8e/ssl/d1_both.c.reneg openssl-fips-0.9.8e/ssl/d1_both.c --- openssl-fips-0.9.8e/ssl/d1_both.c.reneg 2010-02-18 15:58:31.000000000 +0100 +++ openssl-fips-0.9.8e/ssl/d1_both.c 2010-02-18 15:58:31.000000000 +0100 @@ -750,6 +750,24 @@ int dtls1_send_finished(SSL *s, int a, i p+=i; l=i; + /* Copy the finished so we can use it for + * renegotiation checks + */ + if(s->type == SSL_ST_CONNECT) + { + OPENSSL_assert(i <= EVP_MAX_MD_SIZE); + memcpy(s->s3->previous_client_finished, + s->s3->tmp.finish_md, i); + s->s3->previous_client_finished_len=i; + } + else + { + OPENSSL_assert(i <= EVP_MAX_MD_SIZE); + memcpy(s->s3->previous_server_finished, + s->s3->tmp.finish_md, i); + s->s3->previous_server_finished_len=i; + } + #ifdef OPENSSL_SYS_WIN16 /* MSVC 1.5 does not clear the top bytes of the word unless * I do this. diff -up openssl-fips-0.9.8e/ssl/d1_clnt.c.reneg openssl-fips-0.9.8e/ssl/d1_clnt.c --- openssl-fips-0.9.8e/ssl/d1_clnt.c.reneg 2010-02-18 15:58:31.000000000 +0100 +++ openssl-fips-0.9.8e/ssl/d1_clnt.c 2010-02-18 15:58:31.000000000 +0100 @@ -621,7 +621,13 @@ int dtls1_client_hello(SSL *s) *(p++)=comp->id; } *(p++)=0; /* Add the NULL method */ - + + if ((p = ssl_add_clienthello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL) + { + SSLerr(SSL_F_DTLS1_CLIENT_HELLO,ERR_R_INTERNAL_ERROR); + goto err; + } + l=(p-d); d=buf; diff -up openssl-fips-0.9.8e/ssl/d1_srvr.c.reneg openssl-fips-0.9.8e/ssl/d1_srvr.c --- openssl-fips-0.9.8e/ssl/d1_srvr.c.reneg 2010-02-18 15:58:31.000000000 +0100 +++ openssl-fips-0.9.8e/ssl/d1_srvr.c 2010-02-18 15:58:31.000000000 +0100 @@ -267,7 +267,6 @@ int dtls1_accept(SSL *s) s->shutdown=0; ret=ssl3_get_client_hello(s); if (ret <= 0) goto end; - s->new_session = 2; if ( s->d1->send_cookie) s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A; @@ -293,6 +292,7 @@ int dtls1_accept(SSL *s) case SSL3_ST_SW_SRVR_HELLO_A: case SSL3_ST_SW_SRVR_HELLO_B: + s->new_session = 2; ret=dtls1_send_server_hello(s); if (ret <= 0) goto end; @@ -713,6 +713,8 @@ int dtls1_send_server_hello(SSL *s) p+=sl; /* put the cipher */ + if (s->s3->tmp.new_cipher == NULL) + return -1; i=ssl3_put_cipher_by_char(s->s3->tmp.new_cipher,p); p+=i; @@ -726,13 +728,21 @@ int dtls1_send_server_hello(SSL *s) *(p++)=s->s3->tmp.new_compression->id; #endif +#ifndef OPENSSL_NO_TLSEXT + if ((p = ssl_add_serverhello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL) + { + SSLerr(SSL_F_DTLS1_SEND_SERVER_HELLO,ERR_R_INTERNAL_ERROR); + return -1; + } +#endif + /* do the header */ l=(p-d); d=buf; d = dtls1_set_message_header(s, d, SSL3_MT_SERVER_HELLO, l, 0, l); - s->state=SSL3_ST_CW_CLNT_HELLO_B; + s->state=SSL3_ST_SW_SRVR_HELLO_B; /* number of bytes to write */ s->init_num=p-buf; s->init_off=0; @@ -741,7 +751,7 @@ int dtls1_send_server_hello(SSL *s) dtls1_buffer_message(s, 0); } - /* SSL3_ST_CW_CLNT_HELLO_B */ + /* SSL3_ST_SW_SRVR_HELLO_B */ return(dtls1_do_write(s,SSL3_RT_HANDSHAKE)); } @@ -765,7 +775,7 @@ int dtls1_send_server_done(SSL *s) dtls1_buffer_message(s, 0); } - /* SSL3_ST_CW_CLNT_HELLO_B */ + /* SSL3_ST_SW_SRVR_DONE_B */ return(dtls1_do_write(s,SSL3_RT_HANDSHAKE)); } diff -up openssl-fips-0.9.8e/ssl/Makefile.reneg openssl-fips-0.9.8e/ssl/Makefile --- openssl-fips-0.9.8e/ssl/Makefile.reneg 2007-08-01 13:33:16.000000000 +0200 +++ openssl-fips-0.9.8e/ssl/Makefile 2010-02-18 15:58:31.000000000 +0100 @@ -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 -up openssl-fips-0.9.8e/ssl/ssl_err.c.reneg openssl-fips-0.9.8e/ssl/ssl_err.c --- openssl-fips-0.9.8e/ssl/ssl_err.c.reneg 2010-02-18 15:58:31.000000000 +0100 +++ openssl-fips-0.9.8e/ssl/ssl_err.c 2010-02-18 15:58:31.000000000 +0100 @@ -168,8 +168,12 @@ 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"}, +{ERR_FUNC(SSL_F_SSL_ADD_SERVERHELLO_RENEGOTIATE_EXT), "SSL_ADD_SERVERHELLO_RENEGOTIATE_EXT"}, +{ERR_FUNC(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT), "SSL_ADD_SERVERHELLO_TLSEXT"}, {ERR_FUNC(SSL_F_SSL_BAD_METHOD), "SSL_BAD_METHOD"}, {ERR_FUNC(SSL_F_SSL_BYTES_TO_CIPHER_LIST), "SSL_BYTES_TO_CIPHER_LIST"}, {ERR_FUNC(SSL_F_SSL_CERT_DUP), "SSL_CERT_DUP"}, @@ -208,6 +212,10 @@ static ERR_STRING_DATA SSL_str_functs[]= {ERR_FUNC(SSL_F_SSL_INIT_WBIO_BUFFER), "SSL_INIT_WBIO_BUFFER"}, {ERR_FUNC(SSL_F_SSL_LOAD_CLIENT_CA_FILE), "SSL_load_client_CA_file"}, {ERR_FUNC(SSL_F_SSL_NEW), "SSL_new"}, +{ERR_FUNC(SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT), "SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT"}, +{ERR_FUNC(SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT), "SSL_PARSE_CLIENTHELLO_TLSEXT"}, +{ERR_FUNC(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT), "SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT"}, +{ERR_FUNC(SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT), "SSL_PARSE_SERVERHELLO_TLSEXT"}, {ERR_FUNC(SSL_F_SSL_PEEK), "SSL_peek"}, {ERR_FUNC(SSL_F_SSL_READ), "SSL_read"}, {ERR_FUNC(SSL_F_SSL_RSA_PRIVATE_DECRYPT), "SSL_RSA_PRIVATE_DECRYPT"}, @@ -371,6 +379,7 @@ 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"}, @@ -378,6 +387,7 @@ static ERR_STRING_DATA SSL_str_reasons[] {ERR_REASON(SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED),"old session cipher not returned"}, {ERR_REASON(SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE),"only tls allowed in fips mode"}, {ERR_REASON(SSL_R_PACKET_LENGTH_TOO_LONG),"packet length too long"}, +{ERR_REASON(SSL_R_PARSE_TLSEXT) ,"parse tlsext"}, {ERR_REASON(SSL_R_PATH_TOO_LONG) ,"path too long"}, {ERR_REASON(SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE),"peer did not return a certificate"}, {ERR_REASON(SSL_R_PEER_ERROR) ,"peer error"}, @@ -397,10 +407,14 @@ 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"}, {ERR_REASON(SSL_R_REUSE_CIPHER_LIST_NOT_ZERO),"reuse cipher list not zero"}, +{ERR_REASON(SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING),"scsv received when renegotiating"}, {ERR_REASON(SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED),"session id context uninitialized"}, {ERR_REASON(SSL_R_SHORT_READ) ,"short read"}, {ERR_REASON(SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE),"signature for non signing certificate"}, @@ -466,6 +480,7 @@ static ERR_STRING_DATA SSL_str_reasons[] {ERR_REASON(SSL_R_UNKNOWN_REMOTE_ERROR_TYPE),"unknown remote error type"}, {ERR_REASON(SSL_R_UNKNOWN_SSL_VERSION) ,"unknown ssl version"}, {ERR_REASON(SSL_R_UNKNOWN_STATE) ,"unknown state"}, +{ERR_REASON(SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED),"unsafe legacy renegotiation disabled"}, {ERR_REASON(SSL_R_UNSUPPORTED_CIPHER) ,"unsupported cipher"}, {ERR_REASON(SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM),"unsupported compression algorithm"}, {ERR_REASON(SSL_R_UNSUPPORTED_ELLIPTIC_CURVE),"unsupported elliptic curve"}, diff -up openssl-fips-0.9.8e/ssl/ssl.h.reneg openssl-fips-0.9.8e/ssl/ssl.h --- openssl-fips-0.9.8e/ssl/ssl.h.reneg 2010-02-18 15:58:31.000000000 +0100 +++ openssl-fips-0.9.8e/ssl/ssl.h 2010-02-18 15:58:31.000000000 +0100 @@ -480,6 +480,8 @@ typedef struct ssl_session_st #define SSL_OP_MICROSOFT_SESS_ID_BUG 0x00000001L #define SSL_OP_NETSCAPE_CHALLENGE_BUG 0x00000002L +/* Allow initial connection to servers that don't support RI */ +#define SSL_OP_LEGACY_SERVER_CONNECT 0x00000004L #define SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG 0x00000008L /* can break some security expectations */ #define SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG 0x00000010L #define SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER 0x00000020L @@ -506,6 +508,8 @@ typedef struct ssl_session_st /* As server, disallow session resumption on renegotiation */ #define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION 0x00010000L +/* Permit unsafe legacy renegotiation */ +#define SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0x00040000L /* If set, always create a new key when using tmp_ecdh parameters */ #define SSL_OP_SINGLE_ECDH_USE 0x00080000L /* If set, always create a new key when using tmp_dh parameters */ @@ -554,17 +558,25 @@ typedef struct ssl_session_st #define SSL_CTX_set_options(ctx,op) \ SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,(op),NULL) +#define SSL_CTX_clear_options(ctx,op) \ + SSL_CTX_ctrl((ctx),SSL_CTRL_CLEAR_OPTIONS,(op),NULL) #define SSL_CTX_get_options(ctx) \ SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,0,NULL) #define SSL_set_options(ssl,op) \ SSL_ctrl((ssl),SSL_CTRL_OPTIONS,(op),NULL) +#define SSL_clear_options(ssl,op) \ + SSL_ctrl((ssl),SSL_CTRL_CLEAR_OPTIONS,(op),NULL) #define SSL_get_options(ssl) \ SSL_ctrl((ssl),SSL_CTRL_OPTIONS,0,NULL) #define SSL_CTX_set_mode(ctx,op) \ SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,(op),NULL) +#define SSL_CTX_clear_mode(ctx,op) \ + SSL_CTX_ctrl((ctx),SSL_CTRL_CLEAR_MODE,(op),NULL) #define SSL_CTX_get_mode(ctx) \ SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,0,NULL) +#define SSL_clear_mode(ssl,op) \ + SSL_ctrl((ssl),SSL_CTRL_CLEAR_MODE,(op),NULL) #define SSL_set_mode(ssl,op) \ SSL_ctrl((ssl),SSL_CTRL_MODE,(op),NULL) #define SSL_get_mode(ssl) \ @@ -572,6 +584,8 @@ typedef struct ssl_session_st #define SSL_set_mtu(ssl, mtu) \ SSL_ctrl((ssl),SSL_CTRL_SET_MTU,(mtu),NULL) +#define SSL_get_secure_renegotiation_support(ssl) \ + SSL_ctrl((ssl), SSL_CTRL_GET_RI_SUPPORT, 0, NULL) void SSL_CTX_set_msg_callback(SSL_CTX *ctx, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg)); void SSL_set_msg_callback(SSL *ssl, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg)); @@ -1189,6 +1203,10 @@ size_t SSL_get_peer_finished(const SSL * #define SSL_CTRL_GET_MAX_CERT_LIST 50 #define SSL_CTRL_SET_MAX_CERT_LIST 51 +#define SSL_CTRL_GET_RI_SUPPORT 76 +#define SSL_CTRL_CLEAR_OPTIONS 77 +#define SSL_CTRL_CLEAR_MODE 78 + #define SSL_session_reused(ssl) \ SSL_ctrl((ssl),SSL_CTRL_GET_SESSION_REUSED,0,NULL) #define SSL_num_renegotiations(ssl) \ @@ -1650,8 +1668,12 @@ 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 285 +#define SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT 272 #define SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK 215 #define SSL_F_SSL_ADD_FILE_CERT_SUBJECTS_TO_STACK 216 +#define SSL_F_SSL_ADD_SERVERHELLO_RENEGOTIATE_EXT 286 +#define SSL_F_SSL_ADD_SERVERHELLO_TLSEXT 273 #define SSL_F_SSL_BAD_METHOD 160 #define SSL_F_SSL_BYTES_TO_CIPHER_LIST 161 #define SSL_F_SSL_CERT_DUP 221 @@ -1690,6 +1712,10 @@ void ERR_load_SSL_strings(void); #define SSL_F_SSL_INIT_WBIO_BUFFER 184 #define SSL_F_SSL_LOAD_CLIENT_CA_FILE 185 #define SSL_F_SSL_NEW 186 +#define SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT 287 +#define SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT 290 +#define SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT 289 +#define SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT 291 #define SSL_F_SSL_PEEK 270 #define SSL_F_SSL_READ 223 #define SSL_F_SSL_RSA_PRIVATE_DECRYPT 187 @@ -1850,6 +1876,7 @@ void ERR_load_SSL_strings(void); #define SSL_R_NO_PRIVATE_KEY_ASSIGNED 190 #define SSL_R_NO_PROTOCOLS_AVAILABLE 191 #define SSL_R_NO_PUBLICKEY 192 +#define SSL_R_NO_RENEGOTIATION 319 #define SSL_R_NO_SHARED_CIPHER 193 #define SSL_R_NO_VERIFY_CALLBACK 194 #define SSL_R_NULL_SSL_CTX 195 @@ -1857,6 +1884,7 @@ void ERR_load_SSL_strings(void); #define SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED 197 #define SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE 297 #define SSL_R_PACKET_LENGTH_TOO_LONG 198 +#define SSL_R_PARSE_TLSEXT 223 #define SSL_R_PATH_TOO_LONG 270 #define SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE 199 #define SSL_R_PEER_ERROR 200 @@ -1876,10 +1904,14 @@ 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 320 +#define SSL_R_RENEGOTIATION_ENCODING_ERR 321 +#define SSL_R_RENEGOTIATION_MISMATCH 322 #define SSL_R_REQUIRED_CIPHER_MISSING 215 #define SSL_R_REUSE_CERT_LENGTH_NOT_ZERO 216 #define SSL_R_REUSE_CERT_TYPE_NOT_ZERO 217 #define SSL_R_REUSE_CIPHER_LIST_NOT_ZERO 218 +#define SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING 324 #define SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED 277 #define SSL_R_SHORT_READ 219 #define SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE 220 @@ -1945,6 +1977,7 @@ void ERR_load_SSL_strings(void); #define SSL_R_UNKNOWN_REMOTE_ERROR_TYPE 253 #define SSL_R_UNKNOWN_SSL_VERSION 254 #define SSL_R_UNKNOWN_STATE 255 +#define SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED 323 #define SSL_R_UNSUPPORTED_CIPHER 256 #define SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM 257 #define SSL_R_UNSUPPORTED_ELLIPTIC_CURVE 315 diff -up openssl-fips-0.9.8e/ssl/ssl_lib.c.reneg openssl-fips-0.9.8e/ssl/ssl_lib.c --- openssl-fips-0.9.8e/ssl/ssl_lib.c.reneg 2010-02-18 15:58:31.000000000 +0100 +++ openssl-fips-0.9.8e/ssl/ssl_lib.c 2010-02-18 16:10:30.000000000 +0100 @@ -958,8 +958,12 @@ long SSL_ctrl(SSL *s,int cmd,long larg,v case SSL_CTRL_OPTIONS: return(s->options|=larg); + case SSL_CTRL_CLEAR_OPTIONS: + return(s->options&=~larg); case SSL_CTRL_MODE: return(s->mode|=larg); + case SSL_CTRL_CLEAR_MODE: + return(s->mode &=~larg); case SSL_CTRL_GET_MAX_CERT_LIST: return(s->max_cert_list); case SSL_CTRL_SET_MAX_CERT_LIST: @@ -973,6 +977,10 @@ long SSL_ctrl(SSL *s,int cmd,long larg,v return larg; } return 0; + case SSL_CTRL_GET_RI_SUPPORT: + if (s->s3) + return s->s3->send_connection_binding; + else return 0; default: return(s->method->ssl_ctrl(s,cmd,larg,parg)); } @@ -1059,8 +1067,12 @@ long SSL_CTX_ctrl(SSL_CTX *ctx,int cmd,l return(ctx->stats.sess_cache_full); case SSL_CTRL_OPTIONS: return(ctx->options|=larg); + case SSL_CTRL_CLEAR_OPTIONS: + return(ctx->options&=~larg); case SSL_CTRL_MODE: return(ctx->mode|=larg); + case SSL_CTRL_CLEAR_MODE: + return(ctx->mode&=~larg); default: return(ctx->method->ssl_ctx_ctrl(ctx,cmd,larg,parg)); } @@ -1257,6 +1269,22 @@ int ssl_cipher_list_to_bytes(SSL *s,STAC j = put_cb ? put_cb(c,p) : ssl_put_cipher_by_char(s,c,p); p+=j; } + /* If p == q, no ciphers and caller indicates an error. Otherwise + * add SCSV if not renegotiating. + */ + if (p != q && !s->new_session) + { + static SSL_CIPHER scsv = + { + 0, NULL, SSL3_CK_SCSV, 0, 0, 0, 0, 0, 0, 0, + }; + j = put_cb ? put_cb(&scsv,p) : ssl_put_cipher_by_char(s,&scsv,p); + p+=j; +#ifdef OPENSSL_RI_DEBUG + fprintf(stderr, "SCSV sent by client\n"); +#endif + } + return(p-q); } @@ -1266,6 +1294,8 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_ciphe SSL_CIPHER *c; STACK_OF(SSL_CIPHER) *sk; int i,n; + if (s->s3) + s->s3->send_connection_binding = 0; n=ssl_put_cipher_by_char(s,NULL,NULL); if ((num%n) != 0) @@ -1283,6 +1313,26 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_ciphe for (i=0; is3 && (n != 3 || !p[0]) && + (p[n-2] == ((SSL3_CK_SCSV >> 8) & 0xff)) && + (p[n-1] == (SSL3_CK_SCSV & 0xff))) + { + /* SCSV fatal if renegotiating */ + if (s->new_session) + { + SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST,SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING); + ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE); + goto err; + } + s->s3->send_connection_binding = 1; + p += n; +#ifdef OPENSSL_RI_DEBUG + fprintf(stderr, "SCSV received by server\n"); +#endif + continue; + } + c=ssl_get_cipher_by_char(s,p); p+=n; if (c != NULL) @@ -1461,6 +1511,11 @@ SSL_CTX *SSL_CTX_new(SSL_METHOD *meth) ret->extra_certs=NULL; ret->comp_methods=SSL_COMP_get_compression_methods(); + /* Default is to connect to non-RI servers. When RI is more widely + * deployed might change this. + */ + ret->options |= SSL_OP_LEGACY_SERVER_CONNECT; + return(ret); err: SSLerr(SSL_F_SSL_CTX_NEW,ERR_R_MALLOC_FAILURE); diff -up openssl-fips-0.9.8e/ssl/ssl_locl.h.reneg openssl-fips-0.9.8e/ssl/ssl_locl.h --- openssl-fips-0.9.8e/ssl/ssl_locl.h.reneg 2010-02-18 15:58:31.000000000 +0100 +++ openssl-fips-0.9.8e/ssl/ssl_locl.h 2010-02-18 15:58:31.000000000 +0100 @@ -934,5 +934,17 @@ int check_srvr_ecc_cert_and_alg(X509 *x, SSL_COMP *ssl3_comp_find(STACK_OF(SSL_COMP) *sk, int n); +unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit); +unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned char *limit); +int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **data, unsigned char *d, int n, int *al); +int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **data, unsigned char *d, int n, int *al); +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 diff -up openssl-fips-0.9.8e/ssl/ssl3.h.reneg openssl-fips-0.9.8e/ssl/ssl3.h --- openssl-fips-0.9.8e/ssl/ssl3.h.reneg 2010-02-18 15:58:31.000000000 +0100 +++ openssl-fips-0.9.8e/ssl/ssl3.h 2010-02-18 15:58:31.000000000 +0100 @@ -129,6 +129,9 @@ extern "C" { #endif +/* Signalling cipher suite value: from draft-ietf-tls-renegotiation-03.txt */ +#define SSL3_CK_SCSV 0x030000FF + #define SSL3_CK_RSA_NULL_MD5 0x03000001 #define SSL3_CK_RSA_NULL_SHA 0x03000002 #define SSL3_CK_RSA_RC4_40_MD5 0x03000003 @@ -437,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 -up openssl-fips-0.9.8e/ssl/s23_clnt.c.reneg openssl-fips-0.9.8e/ssl/s23_clnt.c --- openssl-fips-0.9.8e/ssl/s23_clnt.c.reneg 2007-03-22 01:39:13.000000000 +0100 +++ openssl-fips-0.9.8e/ssl/s23_clnt.c 2010-02-18 16:07:51.000000000 +0100 @@ -368,6 +368,11 @@ static int ssl23_client_hello(SSL *s) *(p++)=comp->id; } *(p++)=0; /* Add the NULL method */ + if ((p = ssl_add_clienthello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL) + { + SSLerr(SSL_F_SSL23_CLIENT_HELLO,ERR_R_INTERNAL_ERROR); + return -1; + } l = p-d; *p = 42; diff -up openssl-fips-0.9.8e/ssl/s3_both.c.reneg openssl-fips-0.9.8e/ssl/s3_both.c --- openssl-fips-0.9.8e/ssl/s3_both.c.reneg 2005-04-26 18:02:39.000000000 +0200 +++ openssl-fips-0.9.8e/ssl/s3_both.c 2010-02-18 15:58:31.000000000 +0100 @@ -168,6 +168,23 @@ int ssl3_send_finished(SSL *s, int a, in p+=i; l=i; + /* Copy the finished so we can use it for + renegotiation checks */ + if(s->type == SSL_ST_CONNECT) + { + OPENSSL_assert(i <= EVP_MAX_MD_SIZE); + memcpy(s->s3->previous_client_finished, + s->s3->tmp.finish_md, i); + s->s3->previous_client_finished_len=i; + } + else + { + OPENSSL_assert(i <= EVP_MAX_MD_SIZE); + memcpy(s->s3->previous_server_finished, + s->s3->tmp.finish_md, i); + s->s3->previous_server_finished_len=i; + } + #ifdef OPENSSL_SYS_WIN16 /* MSVC 1.5 does not clear the top bytes of the word unless * I do this. @@ -232,6 +249,23 @@ int ssl3_get_finished(SSL *s, int a, int goto f_err; } + /* Copy the finished so we can use it for + renegotiation checks */ + if(s->type == SSL_ST_ACCEPT) + { + OPENSSL_assert(i <= EVP_MAX_MD_SIZE); + memcpy(s->s3->previous_client_finished, + s->s3->tmp.peer_finish_md, i); + s->s3->previous_client_finished_len=i; + } + else + { + OPENSSL_assert(i <= EVP_MAX_MD_SIZE); + memcpy(s->s3->previous_server_finished, + s->s3->tmp.peer_finish_md, i); + s->s3->previous_server_finished_len=i; + } + return(1); f_err: ssl3_send_alert(s,SSL3_AL_FATAL,al); diff -up openssl-fips-0.9.8e/ssl/s3_clnt.c.reneg openssl-fips-0.9.8e/ssl/s3_clnt.c --- openssl-fips-0.9.8e/ssl/s3_clnt.c.reneg 2010-02-18 15:58:31.000000000 +0100 +++ openssl-fips-0.9.8e/ssl/s3_clnt.c 2010-02-18 15:58:31.000000000 +0100 @@ -601,7 +601,11 @@ int ssl3_client_hello(SSL *s) } #endif *(p++)=0; /* Add the NULL method */ - + if ((p = ssl_add_clienthello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL) + { + SSLerr(SSL_F_SSL3_CLIENT_HELLO,ERR_R_INTERNAL_ERROR); + goto err; + } l=(p-d); d=buf; *(d++)=SSL3_MT_CLIENT_HELLO; @@ -635,7 +639,7 @@ int ssl3_get_server_hello(SSL *s) SSL3_ST_CR_SRVR_HELLO_A, SSL3_ST_CR_SRVR_HELLO_B, -1, - 300, /* ?? */ + 1000, /* ?? */ &ok); if (!ok) return((int)n); @@ -785,6 +789,17 @@ int ssl3_get_server_hello(SSL *s) s->s3->tmp.new_compression=comp; } #endif + /* TLS extensions - we parse renegotiate extension only */ + if (s->version >= SSL3_VERSION) + { + if (!ssl_parse_serverhello_tlsext(s,&p,d,n, &al)) + { + /* 'al' set by ssl_parse_serverhello_tlsext */ + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_PARSE_TLSEXT); + goto f_err; + } + } + if (p != (d+n)) { diff -up openssl-fips-0.9.8e/ssl/s3_pkt.c.reneg openssl-fips-0.9.8e/ssl/s3_pkt.c --- openssl-fips-0.9.8e/ssl/s3_pkt.c.reneg 2010-02-18 15:58:31.000000000 +0100 +++ openssl-fips-0.9.8e/ssl/s3_pkt.c 2010-02-18 15:58:31.000000000 +0100 @@ -1013,7 +1013,25 @@ start: * now try again to obtain the (application) data we were asked for */ goto start; } - + /* If we are a server and get a client hello when renegotiation isn't + * allowed send back a no renegotiation alert and carry on. + * WARNING: experimental code, needs reviewing (steve) + */ + if (s->server && + SSL_is_init_finished(s) && + !s->s3->send_connection_binding && + (s->version > SSL3_VERSION) && + (s->s3->handshake_fragment_len >= 4) && + (s->s3->handshake_fragment[0] == SSL3_MT_CLIENT_HELLO) && + (s->session != NULL) && (s->session->cipher != NULL) && + !(s->ctx->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) + + { + /*s->s3->handshake_fragment_len = 0;*/ + rr->length = 0; + ssl3_send_alert(s,SSL3_AL_WARNING, SSL_AD_NO_RENEGOTIATION); + goto start; + } if (s->s3->alert_fragment_len >= 2) { int alert_level = s->s3->alert_fragment[0]; @@ -1043,6 +1061,21 @@ start: s->shutdown |= SSL_RECEIVED_SHUTDOWN; return(0); } + /* This is a warning but we receive it if we requested + * renegotiation and the peer denied it. Terminate with + * a fatal alert because if application tried to + * renegotiatie it presumably had a good reason and + * expects it to succeed. + * + * In future we might have a renegotiation where we + * don't care if the peer refused it where we carry on. + */ + else if (alert_descr == SSL_AD_NO_RENEGOTIATION) + { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_NO_RENEGOTIATION); + goto f_err; + } } else if (alert_level == 2) /* fatal */ { diff -up openssl-fips-0.9.8e/ssl/s3_srvr.c.reneg openssl-fips-0.9.8e/ssl/s3_srvr.c --- openssl-fips-0.9.8e/ssl/s3_srvr.c.reneg 2010-02-18 15:58:31.000000000 +0100 +++ openssl-fips-0.9.8e/ssl/s3_srvr.c 2010-02-18 15:58:31.000000000 +0100 @@ -248,6 +248,18 @@ int ssl3_accept(SSL *s) s->state=SSL3_ST_SR_CLNT_HELLO_A; s->ctx->stats.sess_accept++; } + else if (!s->s3->send_connection_binding && + !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) + { + /* Server attempting to renegotiate with + * client that doesn't support secure + * renegotiation. + */ + SSLerr(SSL_F_SSL3_ACCEPT, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED); + ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE); + ret = -1; + goto end; + } else { /* s->state == SSL_ST_RENEGOTIATE, @@ -898,6 +910,16 @@ int ssl3_get_client_hello(SSL *s) goto f_err; } + /* TLS extensions - just parsing the renegotiation extension */ + if (s->version >= SSL3_VERSION) + { + if (!ssl_parse_clienthello_tlsext(s,&p,d,n, &al)) + { + /* 'al' set by ssl_parse_clienthello_tlsext */ + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PARSE_TLSEXT); + goto f_err; + } + } /* Worst case, we will use the NULL compression, but if we have other * options, we will now look for them. We have i-1 compression * algorithms from the client, starting at q. */ @@ -1089,20 +1111,24 @@ int ssl3_send_server_hello(SSL *s) else *(p++)=s->s3->tmp.new_compression->id; #endif - + if ((p = ssl_add_serverhello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL) + { + SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO,ERR_R_INTERNAL_ERROR); + return -1; + } /* do the header */ l=(p-d); d=buf; *(d++)=SSL3_MT_SERVER_HELLO; l2n3(l,d); - s->state=SSL3_ST_CW_CLNT_HELLO_B; + s->state=SSL3_ST_SW_SRVR_HELLO_B; /* number of bytes to write */ s->init_num=p-buf; s->init_off=0; } - /* SSL3_ST_CW_CLNT_HELLO_B */ + /* SSL3_ST_SW_SRVR_HELLO_B */ return(ssl3_do_write(s,SSL3_RT_HANDSHAKE)); } @@ -1126,7 +1152,7 @@ int ssl3_send_server_done(SSL *s) s->init_off=0; } - /* SSL3_ST_CW_CLNT_HELLO_B */ + /* SSL3_ST_SW_SRVR_DONE_B */ return(ssl3_do_write(s,SSL3_RT_HANDSHAKE)); } diff -up openssl-fips-0.9.8e/ssl/tls1.h.reneg openssl-fips-0.9.8e/ssl/tls1.h --- openssl-fips-0.9.8e/ssl/tls1.h.reneg 2010-02-18 15:58:31.000000000 +0100 +++ openssl-fips-0.9.8e/ssl/tls1.h 2010-02-18 15:58:31.000000000 +0100 @@ -97,6 +97,9 @@ extern "C" { #define TLS1_AD_USER_CANCELLED 90 #define TLS1_AD_NO_RENEGOTIATION 100 +/* Temporary extension type */ +#define TLSEXT_TYPE_renegotiate 0xff01 + /* Additional TLS ciphersuites from draft-ietf-tls-56-bit-ciphersuites-00.txt * (available if TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES is defined, see * s3_lib.c). We actually treat them like SSL 3.0 ciphers, which we probably diff -up openssl-fips-0.9.8e/ssl/t1_lib.c.reneg openssl-fips-0.9.8e/ssl/t1_lib.c --- openssl-fips-0.9.8e/ssl/t1_lib.c.reneg 2007-01-21 17:07:25.000000000 +0100 +++ openssl-fips-0.9.8e/ssl/t1_lib.c 2010-02-18 16:10:05.000000000 +0100 @@ -117,3 +117,202 @@ long tls1_callback_ctrl(SSL *s, int cmd, return(0); } #endif + +unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit) + { + int extdatalen=0; + unsigned char *ret = p; + + /* don't add extensions for SSLv3 unless doing secure renegotiation */ + if (s->client_version == SSL3_VERSION + && !s->s3->send_connection_binding) + return p; + + ret+=2; + + if (ret>=limit) return NULL; /* this really never occurs, but ... */ + + /* Add RI if renegotiating */ + if (s->new_session) + { + int el; + + if(!ssl_add_clienthello_renegotiate_ext(s, 0, &el, 0)) + { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return NULL; + } + + if((limit - p - 4 - el) < 0) return NULL; + + s2n(TLSEXT_TYPE_renegotiate,ret); + s2n(el,ret); + + if(!ssl_add_clienthello_renegotiate_ext(s, ret, &el, el)) + { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return NULL; + } + + ret += el; + } + + if ((extdatalen = ret-p-2)== 0) + return p; + + s2n(extdatalen,p); + return ret; + } + +unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned char *limit) + { + int extdatalen=0; + unsigned char *ret = p; + + /* don't add extensions for SSLv3, unless doing secure renegotiation */ + if (s->version == SSL3_VERSION && !s->s3->send_connection_binding) + return p; + + ret+=2; + if (ret>=limit) return NULL; /* this really never occurs, but ... */ + + if(s->s3->send_connection_binding) + { + int el; + + if(!ssl_add_serverhello_renegotiate_ext(s, 0, &el, 0)) + { + SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return NULL; + } + + if((limit - p - 4 - el) < 0) return NULL; + + s2n(TLSEXT_TYPE_renegotiate,ret); + s2n(el,ret); + + if(!ssl_add_serverhello_renegotiate_ext(s, ret, &el, el)) + { + SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return NULL; + } + + ret += el; + } + + if ((extdatalen = ret-p-2)== 0) + return p; + + s2n(extdatalen,p); + return ret; + } + +int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al) + { + unsigned short type; + unsigned short size; + unsigned short len; + unsigned char *data = *p; + int renegotiate_seen = 0; + + if (data >= (d+n-2)) + goto ri_check; + + n2s(data,len); + + if (data > (d+n-len)) + goto ri_check; + + while (data <= (d+n-4)) + { + n2s(data,type); + n2s(data,size); + + if (data+size > (d+n)) + goto ri_check; + + if (type == TLSEXT_TYPE_renegotiate) + { + if(!ssl_parse_clienthello_renegotiate_ext(s, data, size, al)) + return 0; + renegotiate_seen = 1; + } + + data+=size; + } + *p = data; + + ri_check: + + /* Need RI if renegotiating */ + + if (!renegotiate_seen && s->new_session && + !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) + { + *al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT, + SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED); + return 0; + } + + return 1; + } + +int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al) + { + unsigned short type; + unsigned short size; + unsigned short len; + unsigned char *data = *p; + int renegotiate_seen = 0; + + if (data >= (d+n-2)) + goto ri_check; + + n2s(data,len); + + while(data <= (d+n-4)) + { + n2s(data,type); + n2s(data,size); + + if (data+size > (d+n)) + goto ri_check; + if (type == TLSEXT_TYPE_renegotiate) + { + if(!ssl_parse_serverhello_renegotiate_ext(s, data, size, al)) + return 0; + renegotiate_seen = 1; + } + data+=size; + } + + if (data != d+n) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + *p = data; + + ri_check: + + /* Determine if we need to see RI. Strictly speaking if we want to + * avoid an attack we should *always* see RI even on initial server + * hello because the client doesn't see any renegotiation during an + * attack. However this would mean we could not connect to any server + * which doesn't support RI so for the immediate future tolerate RI + * absence on initial connect only. + */ + if (!renegotiate_seen + && !(s->options & SSL_OP_LEGACY_SERVER_CONNECT) + && !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) + { + *al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT, + SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED); + return 0; + } + + return 1; + } diff -up openssl-fips-0.9.8e/ssl/t1_reneg.c.reneg openssl-fips-0.9.8e/ssl/t1_reneg.c --- openssl-fips-0.9.8e/ssl/t1_reneg.c.reneg 2010-02-18 15:58:31.000000000 +0100 +++ openssl-fips-0.9.8e/ssl/t1_reneg.c 2010-02-18 15:58:31.000000000 +0100 @@ -0,0 +1,292 @@ +/* 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 "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); +#ifdef OPENSSL_RI_DEBUG + fprintf(stderr, "%s RI extension sent by client\n", + s->s3->previous_client_finished_len ? "Non-empty" : "Empty"); +#endif + } + + *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_SSL_PARSE_CLIENTHELLO_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_SSL_PARSE_CLIENTHELLO_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_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_MISMATCH); + *al=SSL_AD_HANDSHAKE_FAILURE; + return 0; + } + + if(memcmp(d, s->s3->previous_client_finished, + s->s3->previous_client_finished_len)) + { + SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_MISMATCH); + *al=SSL_AD_HANDSHAKE_FAILURE; + return 0; + } +#ifdef OPENSSL_RI_DEBUG + fprintf(stderr, "%s RI extension received by server\n", + ilen ? "Non-empty" : "Empty"); +#endif + + 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_SERVERHELLO_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); +#ifdef OPENSSL_RI_DEBUG + fprintf(stderr, "%s RI extension sent by server\n", + s->s3->previous_client_finished_len ? "Non-empty" : "Empty"); +#endif + } + + *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 */ + OPENSSL_assert(!expected_len || s->s3->previous_client_finished_len); + OPENSSL_assert(!expected_len || s->s3->previous_server_finished_len); + + /* Parse the length byte */ + if(len < 1) + { + SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_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_SSL_PARSE_SERVERHELLO_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_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_MISMATCH); + *al=SSL_AD_HANDSHAKE_FAILURE; + return 0; + } + + if(memcmp(d, s->s3->previous_client_finished, + s->s3->previous_client_finished_len)) + { + SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_MISMATCH); + *al=SSL_AD_HANDSHAKE_FAILURE; + 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_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_MISMATCH); + *al=SSL_AD_ILLEGAL_PARAMETER; + return 0; + } +#ifdef OPENSSL_RI_DEBUG + fprintf(stderr, "%s RI extension received by client\n", + ilen ? "Non-empty" : "Empty"); +#endif + s->s3->send_connection_binding=1; + + return 1; + }