ITS#7595 Add Elliptic Curve support for OpenSSL Cherry-picked upstream e631ce808ed56119e61321463d06db7999ba5a08 Author: Howard Chu Date: Sat Sep 7 09:47:19 2013 -0700 diff --git a/doc/man/man5/slapd-config.5 b/doc/man/man5/slapd-config.5 index 9c72e8296..2311c3096 100644 --- a/doc/man/man5/slapd-config.5 +++ b/doc/man/man5/slapd-config.5 @@ -922,6 +922,13 @@ are not used. When using Mozilla NSS these parameters are always generated randomly so this directive is ignored. .TP +.B olcTLSECName: +Specify the name of a curve to use for Elliptic curve Diffie-Hellman +ephemeral key exchange. This is required to enable ECDHE algorithms in +OpenSSL. This option is not used with GnuTLS; the curves may be +chosen in the GnuTLS ciphersuite specification. This option is also +ignored for Mozilla NSS. +.TP .B olcTLSProtocolMin: [.] Specifies minimum SSL/TLS protocol version that will be negotiated. If the server doesn't support at least that version, diff --git a/doc/man/man5/slapd.conf.5 b/doc/man/man5/slapd.conf.5 index f504adcf9..ef03e0ad8 100644 --- a/doc/man/man5/slapd.conf.5 +++ b/doc/man/man5/slapd.conf.5 @@ -1153,6 +1153,13 @@ are not used. When using Mozilla NSS these parameters are always generated randomly so this directive is ignored. .TP +.B TLSECName +Specify the name of a curve to use for Elliptic curve Diffie-Hellman +ephemeral key exchange. This is required to enable ECDHE algorithms in +OpenSSL. This option is not used with GnuTLS; the curves may be +chosen in the GnuTLS ciphersuite specification. This option is also +ignored for Mozilla NSS. +.TP .B TLSProtocolMin [.] Specifies minimum SSL/TLS protocol version that will be negotiated. If the server doesn't support at least that version, diff --git a/include/ldap.h b/include/ldap.h index c245651c2..0964a193e 100644 --- a/include/ldap.h +++ b/include/ldap.h @@ -158,6 +158,7 @@ LDAP_BEGIN_DECL #define LDAP_OPT_X_TLS_NEWCTX 0x600f #define LDAP_OPT_X_TLS_CRLFILE 0x6010 /* GNUtls only */ #define LDAP_OPT_X_TLS_PACKAGE 0x6011 +#define LDAP_OPT_X_TLS_ECNAME 0x6012 #define LDAP_OPT_X_TLS_NEVER 0 #define LDAP_OPT_X_TLS_HARD 1 diff --git a/libraries/libldap/ldap-int.h b/libraries/libldap/ldap-int.h index 66e04ae80..db7193f4f 100644 --- a/libraries/libldap/ldap-int.h +++ b/libraries/libldap/ldap-int.h @@ -165,6 +165,7 @@ struct ldaptls { char *lt_ciphersuite; char *lt_crlfile; char *lt_randfile; /* OpenSSL only */ + char *lt_ecname; /* OpenSSL only */ int lt_protocol_min; }; #endif @@ -250,6 +251,7 @@ struct ldapoptions { #define ldo_tls_certfile ldo_tls_info.lt_certfile #define ldo_tls_keyfile ldo_tls_info.lt_keyfile #define ldo_tls_dhfile ldo_tls_info.lt_dhfile +#define ldo_tls_ecname ldo_tls_info.lt_ecname #define ldo_tls_cacertfile ldo_tls_info.lt_cacertfile #define ldo_tls_cacertdir ldo_tls_info.lt_cacertdir #define ldo_tls_ciphersuite ldo_tls_info.lt_ciphersuite diff --git a/libraries/libldap/tls2.c b/libraries/libldap/tls2.c index d25c190ea..0451b01af 100644 --- a/libraries/libldap/tls2.c +++ b/libraries/libldap/tls2.c @@ -118,6 +118,10 @@ ldap_int_tls_destroy( struct ldapoptions *lo ) LDAP_FREE( lo->ldo_tls_dhfile ); lo->ldo_tls_dhfile = NULL; } + if ( lo->ldo_tls_ecname ) { + LDAP_FREE( lo->ldo_tls_ecname ); + lo->ldo_tls_ecname = NULL; + } if ( lo->ldo_tls_cacertfile ) { LDAP_FREE( lo->ldo_tls_cacertfile ); lo->ldo_tls_cacertfile = NULL; @@ -232,6 +236,10 @@ ldap_int_tls_init_ctx( struct ldapoptions *lo, int is_server ) lts.lt_dhfile = LDAP_STRDUP( lts.lt_dhfile ); __atoe( lts.lt_dhfile ); } + if ( lts.lt_ecname ) { + lts.lt_ecname = LDAP_STRDUP( lts.lt_ecname ); + __atoe( lts.lt_ecname ); + } #endif lo->ldo_tls_ctx = ti->ti_ctx_new( lo ); if ( lo->ldo_tls_ctx == NULL ) { @@ -257,6 +265,7 @@ error_exit: LDAP_FREE( lts.lt_crlfile ); LDAP_FREE( lts.lt_cacertdir ); LDAP_FREE( lts.lt_dhfile ); + LDAP_FREE( lts.lt_ecname ); #endif return rc; } @@ -646,6 +655,10 @@ ldap_pvt_tls_get_option( LDAP *ld, int option, void *arg ) *(char **)arg = lo->ldo_tls_dhfile ? LDAP_STRDUP( lo->ldo_tls_dhfile ) : NULL; break; + case LDAP_OPT_X_TLS_ECNAME: + *(char **)arg = lo->ldo_tls_ecname ? + LDAP_STRDUP( lo->ldo_tls_ecname ) : NULL; + break; case LDAP_OPT_X_TLS_CRLFILE: /* GnuTLS only */ *(char **)arg = lo->ldo_tls_crlfile ? LDAP_STRDUP( lo->ldo_tls_crlfile ) : NULL; @@ -765,6 +778,10 @@ ldap_pvt_tls_set_option( LDAP *ld, int option, void *arg ) if ( lo->ldo_tls_dhfile ) LDAP_FREE( lo->ldo_tls_dhfile ); lo->ldo_tls_dhfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL; return 0; + case LDAP_OPT_X_TLS_ECNAME: + if ( lo->ldo_tls_ecname ) LDAP_FREE( lo->ldo_tls_ecname ); + lo->ldo_tls_ecname = arg ? LDAP_STRDUP( (char *) arg ) : NULL; + return 0; case LDAP_OPT_X_TLS_CRLFILE: /* GnuTLS only */ if ( lo->ldo_tls_crlfile ) LDAP_FREE( lo->ldo_tls_crlfile ); lo->ldo_tls_crlfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL; diff --git a/libraries/libldap/tls_o.c b/libraries/libldap/tls_o.c index f24060b7e..1370923af 100644 --- a/libraries/libldap/tls_o.c +++ b/libraries/libldap/tls_o.c @@ -373,10 +373,9 @@ tlso_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) return -1; } - if ( lo->ldo_tls_dhfile ) { - DH *dh = NULL; + if ( is_server && lo->ldo_tls_dhfile ) { + DH *dh; BIO *bio; - SSL_CTX_set_options( ctx, SSL_OP_SINGLE_DH_USE ); if (( bio=BIO_new_file( lt->lt_dhfile,"r" )) == NULL ) { Debug( LDAP_DEBUG_ANY, @@ -395,7 +394,35 @@ tlso_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) } BIO_free( bio ); SSL_CTX_set_tmp_dh( ctx, dh ); + SSL_CTX_set_options( ctx, SSL_OP_SINGLE_DH_USE ); + DH_free( dh ); + } + +#ifdef SSL_OP_SINGLE_ECDH_USE + if ( is_server && lo->ldo_tls_ecname ) { + EC_KEY *ecdh; + + int nid = OBJ_sn2nid( lt->lt_ecname ); + if ( nid == NID_undef ) { + Debug( LDAP_DEBUG_ANY, + "TLS: could not use EC name `%s'.\n", + lo->ldo_tls_ecname,0,0); + tlso_report_error(); + return -1; + } + ecdh = EC_KEY_new_by_curve_name( nid ); + if ( ecdh == NULL ) { + Debug( LDAP_DEBUG_ANY, + "TLS: could not generate key for EC name `%s'.\n", + lo->ldo_tls_ecname,0,0); + tlso_report_error(); + return -1; + } + SSL_CTX_set_tmp_ecdh( ctx, ecdh ); + SSL_CTX_set_options( ctx, SSL_OP_SINGLE_ECDH_USE ); + EC_KEY_free( ecdh ); } +#endif if ( tlso_opt_trace ) { SSL_CTX_set_info_callback( ctx, tlso_info_cb ); diff --git a/servers/slapd/bconfig.c b/servers/slapd/bconfig.c index 250f14100..8b1e4e582 100644 --- a/servers/slapd/bconfig.c +++ b/servers/slapd/bconfig.c @@ -194,6 +194,7 @@ enum { CFG_ACL_ADD, CFG_SYNC_SUBENTRY, CFG_LTHREADS, + CFG_TLS_ECNAME, CFG_LAST }; @@ -738,6 +739,14 @@ static ConfigTable config_back_cf_table[] = { #endif "( OLcfgGlAt:77 NAME 'olcTLSDHParamFile' " "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, + { "TLSECName", NULL, 2, 2, 0, +#ifdef HAVE_TLS + CFG_TLS_ECNAME|ARG_STRING|ARG_MAGIC, &config_tls_option, +#else + ARG_IGNORED, NULL, +#endif + "( OLcfgGlAt:96 NAME 'olcTLSECName' " + "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, { "TLSProtocolMin", NULL, 2, 2, 0, #ifdef HAVE_TLS CFG_TLS_PROTOCOL_MIN|ARG_STRING|ARG_MAGIC, &config_tls_config, @@ -819,7 +828,7 @@ static ConfigOCs cf_ocs[] = { "olcThreads $ olcTimeLimit $ olcTLSCACertificateFile $ " "olcTLSCACertificatePath $ olcTLSCertificateFile $ " "olcTLSCertificateKeyFile $ olcTLSCipherSuite $ olcTLSCRLCheck $ " - "olcTLSRandFile $ olcTLSVerifyClient $ olcTLSDHParamFile $ " + "olcTLSRandFile $ olcTLSVerifyClient $ olcTLSDHParamFile $ olcTLSECName $ " "olcTLSCRLFile $ olcTLSProtocolMin $ olcToolThreads $ olcWriteTimeout $ " "olcObjectIdentifier $ olcAttributeTypes $ olcObjectClasses $ " "olcDitContentRules $ olcLdapSyntaxes ) )", Cft_Global }, @@ -3824,6 +3833,7 @@ config_tls_option(ConfigArgs *c) { case CFG_TLS_CA_PATH: flag = LDAP_OPT_X_TLS_CACERTDIR; break; case CFG_TLS_CA_FILE: flag = LDAP_OPT_X_TLS_CACERTFILE; break; case CFG_TLS_DH_FILE: flag = LDAP_OPT_X_TLS_DHFILE; break; + case CFG_TLS_ECNAME: flag = LDAP_OPT_X_TLS_ECNAME; break; #ifdef HAVE_GNUTLS case CFG_TLS_CRL_FILE: flag = LDAP_OPT_X_TLS_CRLFILE; break; #endif