saprasad / rpms / openssl

Forked from rpms/openssl 3 years ago
Clone
Blob Blame History Raw
diff -up openssl-1.0.0-beta4/apps/s_client.c.scsv openssl-1.0.0-beta4/apps/s_client.c
--- openssl-1.0.0-beta4/apps/s_client.c.scsv	2010-01-07 23:37:39.000000000 +0100
+++ openssl-1.0.0-beta4/apps/s_client.c	2010-01-07 23:37:39.000000000 +0100
@@ -382,7 +382,7 @@ int MAIN(int, char **);
 
 int MAIN(int argc, char **argv)
 	{
-	int off=0;
+	unsigned int off=0, clr=0;
 	SSL *con=NULL;
 	int s,k,width,state=0;
 	char *cbuf=NULL,*sbuf=NULL,*mbuf=NULL;
@@ -660,6 +660,10 @@ int MAIN(int argc, char **argv)
 			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;
@@ -870,6 +874,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.
 	 */
@@ -1725,6 +1732,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-1.0.0-beta4/apps/s_server.c.scsv openssl-1.0.0-beta4/apps/s_server.c
--- openssl-1.0.0-beta4/apps/s_server.c.scsv	2010-01-07 23:37:39.000000000 +0100
+++ openssl-1.0.0-beta4/apps/s_server.c	2010-01-07 23:37:39.000000000 +0100
@@ -2212,6 +2212,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-1.0.0-beta4/doc/ssl/SSL_CTX_set_options.pod.scsv openssl-1.0.0-beta4/doc/ssl/SSL_CTX_set_options.pod
--- openssl-1.0.0-beta4/doc/ssl/SSL_CTX_set_options.pod.scsv	2007-08-24 00:49:13.000000000 +0200
+++ openssl-1.0.0-beta4/doc/ssl/SSL_CTX_set_options.pod	2010-01-07 23:37:39.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<options> to B<ctx>.
 Options already set before are not cleared!
 
 SSL_set_options() adds the options set via bitmask in B<options> to B<ssl>.
 Options already set before are not cleared!
 
+SSL_CTX_clear_options() clears the options set via bitmask in B<options>
+to B<ctx>.
+
+SSL_clear_options() clears the options set via bitmask in B<options> to B<ssl>.
+
 SSL_CTX_get_options() returns the options set for B<ctx>.
 
 SSL_get_options() returns the options set for B<ssl>.
 
+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<or>
-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,7 +214,7 @@ 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_NO_TICKET
 
@@ -209,15 +224,63 @@ of RFC4507bis tickets for stateless sess
 If this option is set this functionality is disabled and tickets will
 not be used by clients or servers.
 
+=item SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
+
+See the B<SECURE RENEGOTIATION> section for a discussion of the purpose of
+this option
+
 =back
 
+=head1 SECURE RENEGOTIATION
+
+OpenSSL 0.9.8m and later always attempts to use secure renegotiation as
+described in draft-ietf-tls-renegotiation (FIXME: replace by RFC). This
+counters a prefix attack described in the draft and elsewhere (FIXME: need full
+reference).
+
+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<patched>. A server not supporting secure
+renegotiation is referred to as I<unpatched>.
+
+If an unpatched client attempts to connect to a patched OpenSSL server then
+the attempt will succeed but renegotiation is not permitted. As required
+by the standard a B<no_renegotiation> alert is sent back to the client if
+the TLS v1.0 protocol is used. If SSLv3.0 is used then renegotiation results
+in a fatal B<handshake_failed> alert.
+
+If a patched OpenSSL client attempts to connect to an unpatched server
+then the connection will fail because it is not possible to determine
+whether an attack is taking place.
+
+If the option B<SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION> is set then the
+above restrictions are relaxed. Renegotiation is permissible and initial
+connections to unpatched servers will succeed.
+
+This option should be used with caution because it leaves both clients and
+servers vulnerable. However unpatched servers and clients are likely to be
+around for some time and refusing to connect to unpatched servers or denying
+renegotion altogether may be unacceptable. So applications may be forced to
+tolerate unsafe renegotiation for the immediate future.
+
+The function SSL_get_secure_renegotiation_support() indicates whether the peer
+supports secure renegotiation. 
+
+The deprecated SSLv2 protocol does not support secure renegotiation at all.
+
 =head1 RETURN VALUES
 
 SSL_CTX_set_options() and SSL_set_options() return the new options bitmask
 after adding B<options>.
 
+SSL_CTX_clear_options() and SSL_clear_options() return the new options bitmask
+after clearing B<options>.
+
 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<ssl(3)|ssl(3)>, L<SSL_new(3)|SSL_new(3)>, L<SSL_clear(3)|SSL_clear(3)>,
@@ -240,4 +303,10 @@ 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<SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION> was first added in OpenSSL
+0.9.8m.
+
 =cut
diff -up openssl-1.0.0-beta4/ssl/d1_clnt.c.scsv openssl-1.0.0-beta4/ssl/d1_clnt.c
--- openssl-1.0.0-beta4/ssl/d1_clnt.c.scsv	2010-01-07 23:37:39.000000000 +0100
+++ openssl-1.0.0-beta4/ssl/d1_clnt.c	2010-01-07 23:37:39.000000000 +0100
@@ -698,7 +698,7 @@ int dtls1_client_hello(SSL *s)
 #ifndef OPENSSL_NO_TLSEXT
 		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);
+			SSLerr(SSL_F_DTLS1_CLIENT_HELLO,ERR_R_INTERNAL_ERROR);
 			goto err;
 			}
 #endif		
diff -up openssl-1.0.0-beta4/ssl/d1_srvr.c.scsv openssl-1.0.0-beta4/ssl/d1_srvr.c
--- openssl-1.0.0-beta4/ssl/d1_srvr.c.scsv	2010-01-07 23:37:39.000000000 +0100
+++ openssl-1.0.0-beta4/ssl/d1_srvr.c	2010-01-07 23:37:39.000000000 +0100
@@ -814,7 +814,7 @@ int dtls1_send_server_hello(SSL *s)
 #ifndef OPENSSL_NO_TLSEXT
 		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);
+			SSLerr(SSL_F_DTLS1_SEND_SERVER_HELLO,ERR_R_INTERNAL_ERROR);
 			return -1;
 			}
 #endif
diff -up openssl-1.0.0-beta4/ssl/ssl_err.c.scsv openssl-1.0.0-beta4/ssl/ssl_err.c
--- openssl-1.0.0-beta4/ssl/ssl_err.c.scsv	2010-01-07 23:37:39.000000000 +0100
+++ openssl-1.0.0-beta4/ssl/ssl_err.c	2010-01-07 23:37:39.000000000 +0100
@@ -414,6 +414,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_REQUIRED_DIGEST)    ,"digest requred for handshake isn't computed"},
 {ERR_REASON(SSL_R_NO_SHARED_CIPHER)      ,"no shared cipher"},
 {ERR_REASON(SSL_R_NO_VERIFY_CALLBACK)    ,"no verify callback"},
@@ -453,6 +454,7 @@ static ERR_STRING_DATA SSL_str_reasons[]
 {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_SERVERHELLO_TLSEXT)    ,"serverhello tlsext"},
 {ERR_REASON(SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED),"session id context uninitialized"},
 {ERR_REASON(SSL_R_SHORT_READ)            ,"short read"},
diff -up openssl-1.0.0-beta4/ssl/ssl.h.scsv openssl-1.0.0-beta4/ssl/ssl.h
--- openssl-1.0.0-beta4/ssl/ssl.h.scsv	2010-01-07 23:37:39.000000000 +0100
+++ openssl-1.0.0-beta4/ssl/ssl.h	2010-01-07 23:37:39.000000000 +0100
@@ -511,6 +511,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
@@ -518,7 +520,6 @@ 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)
@@ -544,6 +545,8 @@ typedef struct ssl_session_st
 #define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION	0x00010000L
 /* Don't use compression even if supported */
 #define SSL_OP_NO_COMPRESSION				0x00020000L
+/* 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 */
@@ -599,17 +602,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) \
@@ -617,6 +628,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));
@@ -1389,6 +1402,10 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
 #define DTLS_CTRL_HANDLE_TIMEOUT	74
 #define DTLS_CTRL_LISTEN			75
 
+#define SSL_CTRL_GET_RI_SUPPORT			76
+#define SSL_CTRL_CLEAR_OPTIONS			77
+#define SSL_CTRL_CLEAR_MODE			78
+
 #define DTLSv1_get_timeout(ssl, arg) \
 	SSL_ctrl(ssl,DTLS_CTRL_GET_TIMEOUT,0, (void *)arg)
 #define DTLSv1_handle_timeout(ssl) \
@@ -2119,6 +2136,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				 339
 #define SSL_R_NO_REQUIRED_DIGEST			 324
 #define SSL_R_NO_SHARED_CIPHER				 193
 #define SSL_R_NO_VERIFY_CALLBACK			 194
@@ -2158,6 +2176,7 @@ void ERR_load_SSL_strings(void);
 #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		 345
 #define SSL_R_SERVERHELLO_TLSEXT			 275
 #define SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED		 277
 #define SSL_R_SHORT_READ				 219
diff -up openssl-1.0.0-beta4/ssl/ssl_lib.c.scsv openssl-1.0.0-beta4/ssl/ssl_lib.c
--- openssl-1.0.0-beta4/ssl/ssl_lib.c.scsv	2010-01-07 23:37:39.000000000 +0100
+++ openssl-1.0.0-beta4/ssl/ssl_lib.c	2010-01-07 23:38:08.000000000 +0100
@@ -1041,8 +1041,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:
@@ -1062,6 +1066,10 @@ long SSL_ctrl(SSL *s,int cmd,long larg,v
 			return 0;
 		s->max_send_fragment = larg;
 		return 1;
+	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));
 		}
@@ -1148,8 +1156,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);
 	case SSL_CTRL_SET_MAX_SEND_FRAGMENT:
 		if (larg < 512 || larg > SSL3_RT_MAX_PLAIN_LENGTH)
 			return 0;
@@ -1357,6 +1369,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, 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);
 	}
 
@@ -1366,6 +1394,8 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_ciphe
 	const 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)
@@ -1383,6 +1413,26 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_ciphe
 
 	for (i=0; i<num; i+=n)
 		{
+		/* Check for SCSV */
+		if (s->s3 && (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)
@@ -1642,6 +1692,10 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *m
 	}
 #endif
 #endif
+	/* 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:
diff -up openssl-1.0.0-beta4/ssl/ssl3.h.scsv openssl-1.0.0-beta4/ssl/ssl3.h
--- openssl-1.0.0-beta4/ssl/ssl3.h.scsv	2010-01-07 23:37:38.000000000 +0100
+++ openssl-1.0.0-beta4/ssl/ssl3.h	2010-01-07 23:37:39.000000000 +0100
@@ -128,6 +128,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
diff -up openssl-1.0.0-beta4/ssl/s3_clnt.c.scsv openssl-1.0.0-beta4/ssl/s3_clnt.c
--- openssl-1.0.0-beta4/ssl/s3_clnt.c.scsv	2010-01-07 23:37:39.000000000 +0100
+++ openssl-1.0.0-beta4/ssl/s3_clnt.c	2010-01-07 23:37:39.000000000 +0100
@@ -916,7 +916,7 @@ int ssl3_get_server_hello(SSL *s)
 
 #ifndef OPENSSL_NO_TLSEXT
 	/* TLS extensions*/
-	if (s->version > SSL3_VERSION)
+	if (s->version >= SSL3_VERSION)
 		{
 		if (!ssl_parse_serverhello_tlsext(s,&p,d,n, &al))
 			{
diff -up openssl-1.0.0-beta4/ssl/s3_pkt.c.scsv openssl-1.0.0-beta4/ssl/s3_pkt.c
--- openssl-1.0.0-beta4/ssl/s3_pkt.c.scsv	2009-07-14 17:28:44.000000000 +0200
+++ openssl-1.0.0-beta4/ssl/s3_pkt.c	2010-01-07 23:37:39.000000000 +0100
@@ -1120,7 +1120,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];
@@ -1150,6 +1168,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-1.0.0-beta4/ssl/s3_srvr.c.scsv openssl-1.0.0-beta4/ssl/s3_srvr.c
--- openssl-1.0.0-beta4/ssl/s3_srvr.c.scsv	2010-01-07 23:37:39.000000000 +0100
+++ openssl-1.0.0-beta4/ssl/s3_srvr.c	2010-01-07 23:37:39.000000000 +0100
@@ -1015,7 +1015,7 @@ int ssl3_get_client_hello(SSL *s)
 
 #ifndef OPENSSL_NO_TLSEXT
 	/* TLS extensions*/
-	if (s->version > SSL3_VERSION)
+	if (s->version >= SSL3_VERSION)
 		{
 		if (!ssl_parse_clienthello_tlsext(s,&p,d,n, &al))
 			{
diff -up openssl-1.0.0-beta4/ssl/t1_lib.c.scsv openssl-1.0.0-beta4/ssl/t1_lib.c
--- openssl-1.0.0-beta4/ssl/t1_lib.c.scsv	2010-01-07 23:37:39.000000000 +0100
+++ openssl-1.0.0-beta4/ssl/t1_lib.c	2010-01-07 23:38:08.000000000 +0100
@@ -275,8 +275,9 @@ unsigned char *ssl_add_clienthello_tlsex
 	int extdatalen=0;
 	unsigned char *ret = p;
 
-	/* don't add extensions for SSLv3 */
-	if (s->client_version == SSL3_VERSION)
+	/* 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;
@@ -315,8 +316,9 @@ unsigned char *ssl_add_clienthello_tlsex
 		ret+=size_str;
 		}
 
-        /* Add the renegotiation option: TODOEKR switch */
-        {
+        /* Add RI if renegotiating */
+        if (s->new_session)
+          {
           int el;
           
           if(!ssl_add_clienthello_renegotiate_ext(s, 0, &el, 0))
@@ -504,8 +506,8 @@ unsigned char *ssl_add_serverhello_tlsex
 	int extdatalen=0;
 	unsigned char *ret = p;
 
-	/* don't add extensions for SSLv3 */
-	if (s->version == SSL3_VERSION)
+	/* don't add extensions for SSLv3, unless doing secure renegotiation */
+	if (s->version == SSL3_VERSION && !s->s3->send_connection_binding)
 		return p;
 	
 	ret+=2;
@@ -633,24 +635,13 @@ int ssl_parse_clienthello_tlsext(SSL *s,
 
 	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? */
-			SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
-			return 0;
-			}
-		return 1;
-		}
+		goto ri_check;
 	n2s(data,len);
 
 	if (data > (d+n-len)) 
-		return 1;
+		goto ri_check;
 
 	while (data <= (d+n-4))
 		{
@@ -658,7 +649,7 @@ int ssl_parse_clienthello_tlsext(SSL *s,
 		n2s(data,size);
 
 		if (data+size > (d+n))
-	   		return 1;
+	   		goto ri_check;
 #if 0
 		fprintf(stderr,"Received extension type %d size %d\n",type,size);
 #endif
@@ -971,17 +962,22 @@ int ssl_parse_clienthello_tlsext(SSL *s,
 		/* session ticket processed earlier */
 		data+=size;
 		}
-  
- 	if (s->new_session && !renegotiate_seen
- 		&& !(s->ctx->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
- 		{
-		SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
- 		*al = SSL_AD_ILLEGAL_PARAMETER; /* is this the right alert? */
- 		return 0;
- 		}
- 
 				
 	*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;
 	}
 
@@ -995,21 +991,7 @@ int ssl_parse_serverhello_tlsext(SSL *s,
 	int renegotiate_seen = 0;
 
 	if (data >= (d+n-2))
-		{
-#if 0
-		/* 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? */
-			SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
-			return 0;
-			}
-#endif
-		return 1;
-		}
+		goto ri_check;
 
 	n2s(data,len);
 
@@ -1019,7 +1001,7 @@ int ssl_parse_serverhello_tlsext(SSL *s,
 		n2s(data,size);
 
 		if (data+size > (d+n))
-	   		return 1;
+	   		goto ri_check;
 
 		if (s->tlsext_debug_cb)
 			s->tlsext_debug_cb(s, 1, type, data, size,
@@ -1143,16 +1125,6 @@ int ssl_parse_serverhello_tlsext(SSL *s,
 		return 0;
 		}
 
-#if 0
-	if (!renegotiate_seen
-		&& !(s->ctx->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
-		{
-		*al = SSL_AD_ILLEGAL_PARAMETER; /* is this the right alert? */
-		SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
-		return 0;
-		}
-#endif
-
 	if (!s->hit && tlsext_servername == 1)
 		{
  		if (s->tlsext_hostname)
@@ -1175,6 +1147,26 @@ int ssl_parse_serverhello_tlsext(SSL *s,
 		}
 
 	*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->new_session || !(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-1.0.0-beta4/ssl/t1_reneg.c.scsv openssl-1.0.0-beta4/ssl/t1_reneg.c
--- openssl-1.0.0-beta4/ssl/t1_reneg.c.scsv	2009-11-09 19:45:42.000000000 +0100
+++ openssl-1.0.0-beta4/ssl/t1_reneg.c	2010-01-07 23:37:39.000000000 +0100
@@ -130,10 +130,15 @@ int ssl_add_clienthello_renegotiate_ext(
 
         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;
     }
 
@@ -166,7 +171,7 @@ int ssl_parse_clienthello_renegotiate_ex
     if(ilen != s->s3->previous_client_finished_len)
         {
         SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_MISMATCH);
-        *al=SSL_AD_ILLEGAL_PARAMETER;
+        *al=SSL_AD_HANDSHAKE_FAILURE;
         return 0;
         }
     
@@ -174,9 +179,13 @@ int ssl_parse_clienthello_renegotiate_ex
 	      s->s3->previous_client_finished_len))
         {
         SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_MISMATCH);
-        *al=SSL_AD_ILLEGAL_PARAMETER;
+        *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;
 
@@ -206,6 +215,10 @@ int ssl_add_serverhello_renegotiate_ext(
 
         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
@@ -249,7 +262,7 @@ int ssl_parse_serverhello_renegotiate_ex
     if(ilen != expected_len)
         {
         SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_MISMATCH);
-        *al=SSL_AD_ILLEGAL_PARAMETER;
+        *al=SSL_AD_HANDSHAKE_FAILURE;
         return 0;
         }
 
@@ -257,7 +270,7 @@ int ssl_parse_serverhello_renegotiate_ex
 	      s->s3->previous_client_finished_len))
         {
         SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_MISMATCH);
-        *al=SSL_AD_ILLEGAL_PARAMETER;
+        *al=SSL_AD_HANDSHAKE_FAILURE;
         return 0;
         }
     d += s->s3->previous_client_finished_len;
@@ -269,6 +282,11 @@ int ssl_parse_serverhello_renegotiate_ex
         *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;
     }