Blame SOURCES/openldap-openssl-ITS7595-Add-EC-support-1.patch

adf540
ITS#7595 Add Elliptic Curve support for OpenSSL
adf540
adf540
Cherry-picked upstream e631ce808ed56119e61321463d06db7999ba5a08
adf540
Author:    Howard Chu <hyc@openldap.org>
adf540
Date:      Sat Sep 7 09:47:19 2013 -0700
adf540
adf540
diff --git a/doc/man/man5/slapd-config.5 b/doc/man/man5/slapd-config.5
adf540
index 49a3959ae..9cd0a4dd1 100644
adf540
--- a/doc/man/man5/slapd-config.5
adf540
+++ b/doc/man/man5/slapd-config.5
adf540
@@ -918,6 +918,13 @@ from the default, otherwise no certificate exchanges or verification will
adf540
 be done. When using GnuTLS or Mozilla NSS these parameters are always generated randomly
adf540
 so this directive is ignored.
adf540
 .TP
adf540
+.B olcTLSECName: <name>
adf540
+Specify the name of a curve to use for Elliptic curve Diffie-Hellman
adf540
+ephemeral key exchange.  This is required to enable ECDHE algorithms in
adf540
+OpenSSL.  This option is not used with GnuTLS; the curves may be
adf540
+chosen in the GnuTLS ciphersuite specification. This option is also
adf540
+ignored for Mozilla NSS.
adf540
+.TP
adf540
 .B olcTLSProtocolMin: <major>[.<minor>]
adf540
 Specifies minimum SSL/TLS protocol version that will be negotiated.
adf540
 If the server doesn't support at least that version,
adf540
diff --git a/doc/man/man5/slapd.conf.5 b/doc/man/man5/slapd.conf.5
adf540
index e2344547e..4eb238162 100644
adf540
--- a/doc/man/man5/slapd.conf.5
adf540
+++ b/doc/man/man5/slapd.conf.5
adf540
@@ -1149,6 +1149,13 @@ from the default, otherwise no certificate exchanges or verification will
adf540
 be done. When using GnuTLS these parameters are always generated randomly so
adf540
 this directive is ignored.  This directive is ignored when using Mozilla NSS.
adf540
 .TP
adf540
+.B TLSECName <name>
adf540
+Specify the name of a curve to use for Elliptic curve Diffie-Hellman
adf540
+ephemeral key exchange.  This is required to enable ECDHE algorithms in
adf540
+OpenSSL.  This option is not used with GnuTLS; the curves may be
adf540
+chosen in the GnuTLS ciphersuite specification. This option is also
adf540
+ignored for Mozilla NSS.
adf540
+.TP
adf540
 .B TLSProtocolMin <major>[.<minor>]
adf540
 Specifies minimum SSL/TLS protocol version that will be negotiated.
adf540
 If the server doesn't support at least that version,
adf540
diff --git a/include/ldap.h b/include/ldap.h
adf540
index d4d10fa79..9922c9fa8 100644
adf540
--- a/include/ldap.h
adf540
+++ b/include/ldap.h
adf540
@@ -158,6 +158,7 @@ LDAP_BEGIN_DECL
adf540
 #define LDAP_OPT_X_TLS_NEWCTX		0x600f
adf540
 #define LDAP_OPT_X_TLS_CRLFILE		0x6010	/* GNUtls only */
adf540
 #define LDAP_OPT_X_TLS_PACKAGE		0x6011
adf540
+#define LDAP_OPT_X_TLS_ECNAME		0x6012
adf540
 #define LDAP_OPT_X_TLS_MOZNSS_COMPATIBILITY  0x6050
adf540
 
adf540
 #define LDAP_OPT_X_TLS_MOZNSS_COMPATIBILITY_DISABLED	0
adf540
diff --git a/libraries/libldap/ldap-int.h b/libraries/libldap/ldap-int.h
adf540
index 1a26b3cb0..5fff785d8 100644
adf540
--- a/libraries/libldap/ldap-int.h
adf540
+++ b/libraries/libldap/ldap-int.h
adf540
@@ -165,6 +165,7 @@ struct ldaptls {
adf540
 	char		*lt_ciphersuite;
adf540
 	char		*lt_crlfile;
adf540
 	char		*lt_randfile;	/* OpenSSL only */
adf540
+	char		*lt_ecname;		/* OpenSSL only */
adf540
 	int		lt_protocol_min;
adf540
 };
adf540
 #endif
adf540
@@ -250,6 +251,7 @@ struct ldapoptions {
adf540
 #define ldo_tls_certfile	ldo_tls_info.lt_certfile
adf540
 #define ldo_tls_keyfile	ldo_tls_info.lt_keyfile
adf540
 #define ldo_tls_dhfile	ldo_tls_info.lt_dhfile
adf540
+#define ldo_tls_ecname	ldo_tls_info.lt_ecname
adf540
 #define ldo_tls_cacertfile	ldo_tls_info.lt_cacertfile
adf540
 #define ldo_tls_cacertdir	ldo_tls_info.lt_cacertdir
adf540
 #define ldo_tls_ciphersuite	ldo_tls_info.lt_ciphersuite
adf540
diff --git a/libraries/libldap/tls2.c b/libraries/libldap/tls2.c
adf540
index a616133da..f39546450 100644
adf540
--- a/libraries/libldap/tls2.c
adf540
+++ b/libraries/libldap/tls2.c
adf540
@@ -121,6 +121,10 @@ ldap_int_tls_destroy( struct ldapoptions *lo )
adf540
 		LDAP_FREE( lo->ldo_tls_dhfile );
adf540
 		lo->ldo_tls_dhfile = NULL;
adf540
 	}
adf540
+	if ( lo->ldo_tls_ecname ) {
adf540
+		LDAP_FREE( lo->ldo_tls_ecname );
adf540
+		lo->ldo_tls_ecname = NULL;
adf540
+	}
adf540
 	if ( lo->ldo_tls_cacertfile ) {
adf540
 		LDAP_FREE( lo->ldo_tls_cacertfile );
adf540
 		lo->ldo_tls_cacertfile = NULL;
adf540
@@ -257,6 +261,10 @@ ldap_int_tls_init_ctx( struct ldapoptions *lo, int is_server )
adf540
 		lts.lt_dhfile = LDAP_STRDUP( lts.lt_dhfile );
adf540
 		__atoe( lts.lt_dhfile );
adf540
 	}
adf540
+	if ( lts.lt_ecname ) {
adf540
+		lts.lt_ecname = LDAP_STRDUP( lts.lt_ecname );
adf540
+		__atoe( lts.lt_ecname );
adf540
+	}
adf540
 #endif
adf540
 	lo->ldo_tls_ctx = ti->ti_ctx_new( lo );
adf540
 	if ( lo->ldo_tls_ctx == NULL ) {
adf540
@@ -282,6 +290,7 @@ error_exit:
adf540
 	LDAP_FREE( lts.lt_crlfile );
adf540
 	LDAP_FREE( lts.lt_cacertdir );
adf540
 	LDAP_FREE( lts.lt_dhfile );
adf540
+	LDAP_FREE( lts.lt_ecname );
adf540
 #endif
adf540
 	return rc;
adf540
 }
adf540
@@ -674,6 +683,10 @@ ldap_pvt_tls_get_option( LDAP *ld, int option, void *arg )
adf540
 		*(char **)arg = lo->ldo_tls_dhfile ?
adf540
 			LDAP_STRDUP( lo->ldo_tls_dhfile ) : NULL;
adf540
 		break;
adf540
+	case LDAP_OPT_X_TLS_ECNAME:
adf540
+		*(char **)arg = lo->ldo_tls_ecname ?
adf540
+			LDAP_STRDUP( lo->ldo_tls_ecname ) : NULL;
adf540
+		break;
adf540
 	case LDAP_OPT_X_TLS_CRLFILE:	/* GnuTLS only */
adf540
 		*(char **)arg = lo->ldo_tls_crlfile ?
adf540
 			LDAP_STRDUP( lo->ldo_tls_crlfile ) : NULL;
adf540
@@ -796,6 +809,10 @@ ldap_pvt_tls_set_option( LDAP *ld, int option, void *arg )
adf540
 		if ( lo->ldo_tls_dhfile ) LDAP_FREE( lo->ldo_tls_dhfile );
adf540
 		lo->ldo_tls_dhfile = (arg && *(char *)arg) ? LDAP_STRDUP( (char *) arg ) : NULL;
adf540
 		return 0;
adf540
+	case LDAP_OPT_X_TLS_ECNAME:
adf540
+		if ( lo->ldo_tls_ecname ) LDAP_FREE( lo->ldo_tls_ecname );
adf540
+		lo->ldo_tls_ecname = arg ? LDAP_STRDUP( (char *) arg ) : NULL;
adf540
+		return 0;
adf540
 	case LDAP_OPT_X_TLS_CRLFILE:	/* GnuTLS only */
adf540
 		if ( lo->ldo_tls_crlfile ) LDAP_FREE( lo->ldo_tls_crlfile );
adf540
 		lo->ldo_tls_crlfile = (arg && *(char *)arg) ? LDAP_STRDUP( (char *) arg ) : NULL;
adf540
diff --git a/libraries/libldap/tls_o.c b/libraries/libldap/tls_o.c
adf540
index a2d9cd31f..1a81bc625 100644
adf540
--- a/libraries/libldap/tls_o.c
adf540
+++ b/libraries/libldap/tls_o.c
adf540
@@ -296,10 +296,9 @@ tlso_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server )
adf540
 		return -1;
adf540
 	}
adf540
 
adf540
-	if ( lo->ldo_tls_dhfile ) {
adf540
-		DH *dh = NULL;
adf540
+	if ( is_server && lo->ldo_tls_dhfile ) {
adf540
+		DH *dh;
adf540
 		BIO *bio;
adf540
-		SSL_CTX_set_options( ctx, SSL_OP_SINGLE_DH_USE );
adf540
 
adf540
 		if (( bio=BIO_new_file( lt->lt_dhfile,"r" )) == NULL ) {
adf540
 			Debug( LDAP_DEBUG_ANY,
adf540
@@ -318,7 +317,35 @@ tlso_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server )
adf540
 		}
adf540
 		BIO_free( bio );
adf540
 		SSL_CTX_set_tmp_dh( ctx, dh );
adf540
+		SSL_CTX_set_options( ctx, SSL_OP_SINGLE_DH_USE );
adf540
+		DH_free( dh );
adf540
+	}
adf540
+
adf540
+#ifdef SSL_OP_SINGLE_ECDH_USE
adf540
+	if ( is_server && lo->ldo_tls_ecname ) {
adf540
+		EC_KEY *ecdh;
adf540
+
adf540
+		int nid = OBJ_sn2nid( lt->lt_ecname );
adf540
+		if ( nid == NID_undef ) {
adf540
+			Debug( LDAP_DEBUG_ANY,
adf540
+				"TLS: could not use EC name `%s'.\n",
adf540
+				lo->ldo_tls_ecname,0,0);
adf540
+			tlso_report_error();
adf540
+			return -1;
adf540
+		}
adf540
+		ecdh = EC_KEY_new_by_curve_name( nid );
adf540
+		if ( ecdh == NULL ) {
adf540
+			Debug( LDAP_DEBUG_ANY,
adf540
+				"TLS: could not generate key for EC name `%s'.\n",
adf540
+				lo->ldo_tls_ecname,0,0);
adf540
+			tlso_report_error();
adf540
+			return -1;
adf540
+		}
adf540
+		SSL_CTX_set_tmp_ecdh( ctx, ecdh );
adf540
+		SSL_CTX_set_options( ctx, SSL_OP_SINGLE_ECDH_USE );
adf540
+		EC_KEY_free( ecdh );
adf540
 	}
adf540
+#endif
adf540
 
adf540
 	if ( tlso_opt_trace ) {
adf540
 		SSL_CTX_set_info_callback( ctx, tlso_info_cb );
adf540
diff --git a/servers/slapd/bconfig.c b/servers/slapd/bconfig.c
adf540
index 8ade0c3f2..5a3c67a72 100644
adf540
--- a/servers/slapd/bconfig.c
adf540
+++ b/servers/slapd/bconfig.c
adf540
@@ -194,6 +194,7 @@ enum {
adf540
 	CFG_ACL_ADD,
adf540
 	CFG_SYNC_SUBENTRY,
adf540
 	CFG_LTHREADS,
adf540
+	CFG_TLS_ECNAME,
adf540
 
adf540
 	CFG_LAST
adf540
 };
adf540
@@ -738,6 +739,14 @@ static ConfigTable config_back_cf_table[] = {
adf540
 #endif
adf540
 		"( OLcfgGlAt:77 NAME 'olcTLSDHParamFile' "
adf540
 			"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
adf540
+	{ "TLSECName", NULL, 2, 2, 0,
adf540
+#ifdef HAVE_TLS
adf540
+		CFG_TLS_ECNAME|ARG_STRING|ARG_MAGIC, &config_tls_option,
adf540
+#else
adf540
+		ARG_IGNORED, NULL,
adf540
+#endif
adf540
+		"( OLcfgGlAt:96 NAME 'olcTLSECName' "
adf540
+			"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
adf540
 	{ "TLSProtocolMin",	NULL, 2, 2, 0,
adf540
 #ifdef HAVE_TLS
adf540
 		CFG_TLS_PROTOCOL_MIN|ARG_STRING|ARG_MAGIC, &config_tls_config,
adf540
@@ -819,7 +828,7 @@ static ConfigOCs cf_ocs[] = {
adf540
 		 "olcThreads $ olcTimeLimit $ olcTLSCACertificateFile $ "
adf540
 		 "olcTLSCACertificatePath $ olcTLSCertificateFile $ "
adf540
 		 "olcTLSCertificateKeyFile $ olcTLSCipherSuite $ olcTLSCRLCheck $ "
adf540
-		 "olcTLSRandFile $ olcTLSVerifyClient $ olcTLSDHParamFile $ "
adf540
+		 "olcTLSRandFile $ olcTLSVerifyClient $ olcTLSDHParamFile $ olcTLSECName $ "
adf540
 		 "olcTLSCRLFile $ olcTLSProtocolMin $ olcToolThreads $ olcWriteTimeout $ "
adf540
 		 "olcObjectIdentifier $ olcAttributeTypes $ olcObjectClasses $ "
adf540
 		 "olcDitContentRules $ olcLdapSyntaxes ) )", Cft_Global },
adf540
@@ -3824,6 +3833,7 @@ config_tls_option(ConfigArgs *c) {
adf540
 	case CFG_TLS_CA_PATH:	flag = LDAP_OPT_X_TLS_CACERTDIR;	break;
adf540
 	case CFG_TLS_CA_FILE:	flag = LDAP_OPT_X_TLS_CACERTFILE;	break;
adf540
 	case CFG_TLS_DH_FILE:	flag = LDAP_OPT_X_TLS_DHFILE;	break;
adf540
+	case CFG_TLS_ECNAME:	flag = LDAP_OPT_X_TLS_ECNAME;	break;
adf540
 #ifdef HAVE_GNUTLS
adf540
 	case CFG_TLS_CRL_FILE:	flag = LDAP_OPT_X_TLS_CRLFILE;	break;
adf540
 #endif