From 2d268628ba9a8fef7648af4498cadaba9e963153 Mon Sep 17 00:00:00 2001
From: Noriko Hosoi <nhosoi@redhat.com>
Date: Thu, 14 Apr 2016 12:56:19 -0700
Subject: [PATCH] Ticket #47536 - Allow usage of OpenLDAP libraries that don't
 use NSS for crypto

Design Doc: http://www.port389.org/docs/389ds/design/allow-usage-of-openldap-lib-w-openssl.html

This patch also addresses the issue described in
    Ticket #48756 - if startTLS is enabled, perl utilities fail to start.
The ticket #48756 is closed as dup of Ticket #47536.

Note: Instead of checking with "OpenSSL" for the openldap client library,
      this patch checks with "Not MozNSS" for non-Fedora/RHEL platform support.
---
 ldap/admin/src/scripts/DSUtil.pm.in                |  13 +
 ldap/schema/01core389.ldif                         |   7 +-
 .../servers/plugins/replication/repl5_connection.c |   8 +-
 .../plugins/replication/windows_connection.c       |   8 +-
 ldap/servers/slapd/ldaputil.c                      | 120 ++-
 ldap/servers/slapd/libglobs.c                      |  26 +
 ldap/servers/slapd/proto-slap.h                    |   2 +
 ldap/servers/slapd/slap.h                          |   4 +-
 ldap/servers/slapd/slapi-plugin.h                  |  23 +-
 ldap/servers/slapd/slapi-private.h                 |   3 +
 ldap/servers/slapd/ssl.c                           | 919 ++++++++++++++++++---
 ldap/servers/slapd/util.c                          | 123 +--
 12 files changed, 1054 insertions(+), 202 deletions(-)

--- a/ldap/admin/src/scripts/DSUtil.pm.in
+++ b/ldap/admin/src/scripts/DSUtil.pm.in
@@ -1245,6 +1245,19 @@ sub get_info {
         $info{ldapiURL} = "ldapi://" . $value;
     }
 
+    while($entry = readOneEntry $ldif){
+        if($entry->getDN() eq "cn=encryption,cn=config"){
+            $foundcfg = "yes";
+            last;
+        }
+    }
+    if($foundcfg eq "yes"){
+        $info{cacertfile} = $entry->getValues("CACertExtractFile");
+        if ($info{cacertfile}) {
+            $ENV{LDAPTLS_CACERT}=$info{cacertfile};
+        }
+    }
+
     close (DSE);
     return %info;
 }
--- a/ldap/schema/01core389.ldif
+++ b/ldap/schema/01core389.ldif
@@ -103,6 +103,9 @@ attributeTypes: ( allowWeakCipher-oid NA
 attributeTypes: ( nsSSLToken-oid NAME 'nsSSLToken' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
 attributeTypes: ( nsSSLPersonalitySSL-oid NAME 'nsSSLPersonalitySSL' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
 attributeTypes: ( nsSSLActivation-oid NAME 'nsSSLActivation' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( CACertExtractFile-oid NAME 'CACertExtractFile' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( ServerKeyExtractFile-oid NAME 'ServerKeyExtractFile' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( ServerCertExtractFile-oid NAME 'ServerCertExtractFile' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
 attributeTypes: ( 2.16.840.1.113730.3.1.2091 NAME 'nsslapd-suffix' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape' )
 attributeTypes: ( 2.16.840.1.113730.3.1.2092 NAME 'nsslapd-ldapiautodnsuffix' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape' )
 attributeTypes: ( 2.16.840.1.113730.3.1.2095 NAME 'connection' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
@@ -293,8 +296,8 @@ objectClasses: ( 2.16.840.1.113730.3.2.1
 objectClasses: ( 2.16.840.1.113730.3.2.39 NAME 'nsslapdConfig' DESC 'Netscape defined objectclass' SUP top MAY ( cn ) X-ORIGIN 'Netscape Directory Server' )
 objectClasses: ( 2.16.840.1.113730.3.2.317 NAME 'nsSaslMapping' DESC 'Netscape defined objectclass' SUP top MUST ( cn $ nsSaslMapRegexString $ nsSaslMapBaseDNTemplate $ nsSaslMapFilterTemplate ) MAY ( nsSaslMapPriority ) X-ORIGIN 'Netscape Directory Server' )
 objectClasses: ( 2.16.840.1.113730.3.2.43 NAME 'nsSNMP' DESC 'Netscape defined objectclass' SUP top MUST ( cn $ nsSNMPEnabled ) MAY ( nsSNMPOrganization $ nsSNMPLocation $ nsSNMPContact $ nsSNMPDescription $ nsSNMPName $ nsSNMPMasterHost $ nsSNMPMasterPort ) X-ORIGIN 'Netscape Directory Server' )
-objectClasses: ( nsEncryptionConfig-oid NAME 'nsEncryptionConfig' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsCertfile $ nsKeyfile $ nsSSL2 $ nsSSL3 $ nsTLS1 $ sslVersionMin $ sslVersionMax $ nsSSLSessionTimeout $ nsSSL3SessionTimeout $ nsSSLClientAuth $ nsSSL2Ciphers $ nsSSL3Ciphers $ nsSSLSupportedCiphers $ allowWeakCipher) X-ORIGIN 'Netscape' )
-objectClasses: ( nsEncryptionModule-oid NAME 'nsEncryptionModule' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsSSLToken $ nsSSLPersonalityssl $ nsSSLActivation ) X-ORIGIN 'Netscape' )
+objectClasses: ( nsEncryptionConfig-oid NAME 'nsEncryptionConfig' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsCertfile $ nsKeyfile $ nsSSL2 $ nsSSL3 $ nsTLS1 $ sslVersionMin $ sslVersionMax $ nsSSLSessionTimeout $ nsSSL3SessionTimeout $ nsSSLClientAuth $ nsSSL2Ciphers $ nsSSL3Ciphers $ nsSSLSupportedCiphers $ allowWeakCipher $ CACertExtractFile ) X-ORIGIN 'Netscape' )
+objectClasses: ( nsEncryptionModule-oid NAME 'nsEncryptionModule' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsSSLToken $ nsSSLPersonalityssl $ nsSSLActivation $ ServerKeyExtractFile $ ServerCertExtractFile ) X-ORIGIN 'Netscape' )
 objectClasses: ( 2.16.840.1.113730.3.2.327 NAME 'rootDNPluginConfig' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( rootdn-open-time $ rootdn-close-time $ rootdn-days-allowed $ rootdn-allow-host $ rootdn-deny-host $ rootdn-allow-ip $ rootdn-deny-ip ) X-ORIGIN 'Netscape' )
 objectClasses: ( 2.16.840.1.113730.3.2.328 NAME 'nsSchemaPolicy' DESC 'Netscape defined objectclass' SUP top  MAY ( cn $ schemaUpdateObjectclassAccept $ schemaUpdateObjectclassReject $ schemaUpdateAttributeAccept $ schemaUpdateAttributeReject) X-ORIGIN 'Netscape Directory Server' )
 
--- a/ldap/servers/plugins/replication/repl5_connection.c
+++ b/ldap/servers/plugins/replication/repl5_connection.c
@@ -1234,9 +1234,9 @@ conn_connect(Repl_Connection *conn)
 	 * initialisation should be done before ever trying to open any connection at all.
 	 */
 	if (conn->transport_flags == TRANSPORT_FLAG_TLS) {
-		secure = 2;
+		secure = SLAPI_LDAP_INIT_FLAG_startTLS;
 	} else if (conn->transport_flags == TRANSPORT_FLAG_SSL) {
-		secure = 1;
+		secure = SLAPI_LDAP_INIT_FLAG_SSL;
 	}
 
 	if (secure > 0) {
@@ -1261,7 +1261,7 @@ conn_connect(Repl_Connection *conn)
 			"%s: Trying %s%s slapi_ldap_init_ext\n",
 			agmt_get_long_name(conn->agmt),
 			secure ? "secure" : "non-secure",
-			(secure == 2) ? " startTLS" : "");
+			(secure == SLAPI_LDAP_INIT_FLAG_startTLS) ? " startTLS" : "");
 		/* shared = 1 because we will read results from a second thread */
 		if (conn->ld) {
 			/* Since we call slapi_ldap_init, we must call slapi_ldap_unbind */
@@ -1279,7 +1279,7 @@ conn_connect(Repl_Connection *conn)
 				"%s: Failed to establish %s%sconnection to the consumer\n",
 				agmt_get_long_name(conn->agmt),
 				secure ? "secure " : "",
-				(secure == 2) ? "startTLS " : "");
+				(secure == SLAPI_LDAP_INIT_FLAG_startTLS) ? "startTLS " : "");
 			goto done;
 		}
 		
--- a/ldap/servers/plugins/replication/windows_connection.c
+++ b/ldap/servers/plugins/replication/windows_connection.c
@@ -1313,9 +1313,9 @@ windows_conn_connect(Repl_Connection *co
 	 * initialisation should be done before ever trying to open any connection at all.
 	 */
 	if (conn->transport_flags == TRANSPORT_FLAG_TLS) {
-        secure = 2;
+        secure = SLAPI_LDAP_INIT_FLAG_startTLS;
     } else if (conn->transport_flags == TRANSPORT_FLAG_SSL) {
-        secure = 1;
+        secure = SLAPI_LDAP_INIT_FLAG_SSL;
     }
  
 	if (secure > 0) {
@@ -1340,7 +1340,7 @@ windows_conn_connect(Repl_Connection *co
 			"%s: Trying %s%s slapi_ldap_init_ext\n",
 			agmt_get_long_name(conn->agmt),
 			secure ? "secure" : "non-secure",
-			(secure == 2) ? " startTLS" : "");
+			(secure == SLAPI_LDAP_INIT_FLAG_startTLS) ? " startTLS" : "");
 		
 		conn->ld = slapi_ldap_init_ext(NULL, conn->hostname, conn->port, secure, 0, NULL);
 		if (NULL == conn->ld)
@@ -1353,7 +1353,7 @@ windows_conn_connect(Repl_Connection *co
 				"%s: Failed to establish %s%sconnection to the consumer\n",
 				agmt_get_long_name(conn->agmt),
 				secure ? "secure " : "",
-				(secure == 2) ? "startTLS " : "");
+				(secure == SLAPI_LDAP_INIT_FLAG_startTLS) ? "startTLS " : "");
 			goto done;
 		}
 		
--- a/ldap/servers/slapd/ldaputil.c
+++ b/ldap/servers/slapd/ldaputil.c
@@ -560,6 +560,7 @@ setup_ol_tls_conn(LDAP *ld, int clientau
     int optval = 0;
     int ssl_strength = 0;
     int rc = 0;
+    const char *cacert = NULL;
 
     if (config_get_ssl_check_hostname()) {
 	ssl_strength = LDAP_OPT_X_TLS_HARD;
@@ -572,7 +573,29 @@ setup_ol_tls_conn(LDAP *ld, int clientau
 	slapi_log_error(SLAPI_LOG_FATAL, "setup_ol_tls_conn",
 			"failed: unable to set REQUIRE_CERT option to %d\n", ssl_strength);
     }
-    /* tell it where our cert db is */
+    if (slapi_client_uses_non_nss(ld)) {
+        cacert = slapi_get_cacertfile();
+        if (cacert) {
+            /* CA Cert PEM file exists.  Set the path to openldap option. */
+            rc = ldap_set_option(ld, LDAP_OPT_X_TLS_CACERTFILE, cacert);
+            if (rc) {
+                slapi_log_error(SLAPI_LOG_FATAL, "setup_ol_tls_conn",
+                                "Could not set CA cert path [%s]: %d:%s\n",
+                                cacert, rc, ldap_err2string(rc));
+            }
+        }
+        if (!slapi_client_uses_openssl(ld)) {
+            const int crlcheck = LDAP_OPT_X_TLS_CRL_ALL;
+            /* Sets the CRL evaluation strategy. */
+            rc = ldap_set_option(ld, LDAP_OPT_X_TLS_CRLCHECK, &crlcheck);
+            if (rc) {
+                slapi_log_error(SLAPI_LOG_FATAL, "setup_ol_tls_conn",
+                                "Could not set CRLCHECK [%d]: %d:%s\n",
+                                crlcheck, rc, ldap_err2string(rc));
+            }
+        }
+    }
+    /* tell it where our cert db/file is */
     if ((rc = ldap_set_option(ld, LDAP_OPT_X_TLS_CACERTDIR, certdir))) {
 	slapi_log_error(SLAPI_LOG_FATAL, "setup_ol_tls_conn",
 			"failed: unable to set CACERTDIR option to %s\n", certdir);
@@ -616,8 +639,8 @@ setup_ol_tls_conn(LDAP *ld, int clientau
   on the secure setting (389 for ldap, 636 for ldaps, 389 for starttls)
   secure takes 1 of 3 values - 0 means regular ldap, 1 means ldaps, 2
   means regular ldap with starttls.
-  filename is the ldapi file name - if this is given, and no other options
-  are given, ldapi is assumed.
+  ldapi_socket is the ldapi file name 
+     if this is given, and no other options are given, ldapi is assumed.
  */
 /* util_sasl_path: the string argument for putenv.
    It must be a global or a static */
@@ -627,12 +650,12 @@ LDAP *
 slapi_ldap_init_ext(
     const char *ldapurl, /* full ldap url */
     const char *hostname, /* can also use this to override
-			     host in url */
+                             host in url */
     int port, /* can also use this to override port in url */
     int secure, /* 0 for ldap, 1 for ldaps, 2 for starttls -
-		   override proto in url */
+                   override proto in url */
     int shared, /* if true, LDAP* will be shared among multiple threads */
-    const char *filename /* for ldapi */
+    const char *ldapi_socket /* for ldapi */
 )
 {
     LDAPURLDesc	*ludp = NULL;
@@ -686,16 +709,16 @@ slapi_ldap_init_ext(
     /* use secure setting from url if none given */
     if (!secure && ludp) {
         if (secureurl) {
-            secure = 1;
+            secure = SLAPI_LDAP_INIT_FLAG_SSL;
         } else if (0/* starttls option - not supported yet in LDAP URLs */) {
-            secure = 2;
+            secure = SLAPI_LDAP_INIT_FLAG_startTLS;
         }
     }
 
     /* ldap_url_parse doesn't yet handle ldapi */
     /*
-      if (!filename && ludp && ludp->lud_file) {
-      filename = ludp->lud_file;
+      if (!ldapi_socket && ludp && ludp->lud_file) {
+      ldapi_socket = ludp->lud_file;
       }
     */
 
@@ -743,10 +766,11 @@ slapi_ldap_init_ext(
     } else {
         char *makeurl = NULL;
 
-        if (filename) {
-            makeurl = slapi_ch_smprintf("ldapi://%s/", filename);
+        if (ldapi_socket) {
+            makeurl = slapi_ch_smprintf("ldapi://%s/", ldapi_socket);
         } else { /* host port */
-            makeurl = convert_to_openldap_uri(hostname, port, (secure == 1 ? "ldaps" : "ldap"));
+            makeurl = convert_to_openldap_uri(hostname, port,
+                                              (secure == SLAPI_LDAP_INIT_FLAG_SSL ? "ldaps" : "ldap"));
         }
         if (PR_SUCCESS != PR_CallOnce(&ol_init_callOnce, internal_ol_init_init)) {
             slapi_log_error(SLAPI_LOG_FATAL, "slapi_ldap_init_ext",
@@ -777,15 +801,15 @@ slapi_ldap_init_ext(
          * hostname (such as localhost.localdomain).
          */
         if((rc = ldap_set_option(ld, LDAP_OPT_X_SASL_NOCANON, LDAP_OPT_ON))){
-        	slapi_log_error(SLAPI_LOG_FATAL, "slapi_ldap_init_ext",
+            slapi_log_error(SLAPI_LOG_FATAL, "slapi_ldap_init_ext",
                 "Could not set ldap option LDAP_OPT_X_SASL_NOCANON for (%s), error %d (%s)\n",
                 ldapurl, rc, ldap_err2string(rc) );
         }
     }
 #else /* !USE_OPENLDAP */
-    if (filename) {
+    if (ldapi_socket) {
         /* ldapi in mozldap client is not yet supported */
-    } else if (secure == 1) {
+    } else if (secure == SLAPI_LDAP_INIT_FLAG_SSL) {
         ld = ldapssl_init(hostname, port, secure);
     } else { /* regular ldap and/or starttls */
         /*
@@ -809,7 +833,7 @@ slapi_ldap_init_ext(
         }
     }
 
-    if ((ld != NULL) && !filename) {
+    if (ld && !ldapi_socket) {
         /*
          * Set the outbound LDAP I/O timeout based on the server config.
          */
@@ -857,7 +881,7 @@ slapi_ldap_init_ext(
              * LDAP* if it has already gone through ldapssl_init -
              * so, use NULL if using starttls
              */
-            if (secure == 1) {
+            if (secure == SLAPI_LDAP_INIT_FLAG_SSL) {
                 myld = ld;
             }
 
@@ -881,7 +905,7 @@ slapi_ldap_init_ext(
                     SLAPI_COMPONENT_NAME_NSPR " error %d - %s)\n",
                     prerr, slapd_pr_strerror(prerr));
             }
-            if (secure == 1) {
+            if (secure == SLAPI_LDAP_INIT_FLAG_SSL) {
                 /* tell bind code we are using SSL */
                 ldap_set_option(ld, LDAP_OPT_SSL, LDAP_OPT_ON);
             }
@@ -889,7 +913,7 @@ slapi_ldap_init_ext(
         }
     }
 
-    if (ld && (secure == 2)) {
+    if (ld && (secure == SLAPI_LDAP_INIT_FLAG_startTLS)) {
         /*
          * We don't have a way to stash context data with the LDAP*, so we
          * stash the information in the client controls (currently unused).
@@ -919,8 +943,8 @@ slapi_ldap_init_ext(
     slapi_log_error(SLAPI_LOG_SHELL, "slapi_ldap_init_ext",
             "Success: set up conn to [%s:%d]%s\n",
             hostname, port,
-            (secure == 2) ? " using startTLS" :
-            ((secure == 1) ? " using SSL" : ""));
+            (secure == SLAPI_LDAP_INIT_FLAG_startTLS) ? " using startTLS" :
+            ((secure == SLAPI_LDAP_INIT_FLAG_SSL) ? " using SSL" : ""));
 done:
     ldap_free_urldesc(ludp);
 
@@ -974,7 +998,7 @@ ldaputil_get_saslpath()
 LDAP *
 slapi_ldap_init( char *ldaphost, int ldapport, int secure, int shared )
 {
-    return slapi_ldap_init_ext(NULL, ldaphost, ldapport, secure, shared, NULL);
+    return slapi_ldap_init_ext(NULL, ldaphost, ldapport, secure, shared, NULL/*, NULL*/);
 }
 
 /*
@@ -1011,7 +1035,7 @@ slapi_ldap_bind(
     ldap_get_option(ld, LDAP_OPT_CLIENT_CONTROLS, &clientctrls);
     if (clientctrls && clientctrls[0] &&
         slapi_control_present(clientctrls, START_TLS_OID, NULL, NULL)) {
-        secure = 2;
+        secure = SLAPI_LDAP_INIT_FLAG_startTLS;
     } else {
 #if defined(USE_OPENLDAP)
 	/* openldap doesn't have a SSL/TLS yes/no flag - so grab the
@@ -1020,7 +1044,7 @@ slapi_ldap_bind(
 
 	ldap_get_option(ld, LDAP_OPT_URI, &ldapurl);
 	if (ldapurl && !PL_strncasecmp(ldapurl, "ldaps", 5)) {
-	    secure = 1;
+	    secure = SLAPI_LDAP_INIT_FLAG_SSL;
 	}
 	slapi_ch_free_string(&ldapurl);
 #else /* !USE_OPENLDAP */
@@ -1058,7 +1082,7 @@ slapi_ldap_bind(
         bvcreds.bv_len = creds ? strlen(creds) : 0;
     }
 
-    if (secure == 2) { /* send start tls */
+    if (secure == SLAPI_LDAP_INIT_FLAG_startTLS) { /* send start tls */
 	rc = ldap_start_tls_s(ld, NULL /* serverctrls?? */, NULL);
 	if (LDAP_SUCCESS != rc) {
 	    slapi_log_error(SLAPI_LOG_FATAL, "slapi_ldap_bind",
@@ -2367,3 +2391,47 @@ slapi_berval_get_msg_len(struct berval *
 
     return len;
 }
+
+int
+slapi_client_uses_non_nss(LDAP *ld)
+{
+    static int not_nss = 0;
+#if defined(USE_OPENLDAP)
+    static int initialized = 0;
+    char *package_name = NULL;
+    int rc;
+
+    if (initialized) {
+        return not_nss;
+    }
+    rc = ldap_get_option(ld, LDAP_OPT_X_TLS_PACKAGE, &package_name);
+    if (!rc && PL_strcasecmp(package_name, "MozNSS")) {
+        not_nss = 1;
+        slapi_ch_free_string(&package_name);
+    }
+    initialized = 1;
+#endif
+    return not_nss;
+}
+
+int
+slapi_client_uses_openssl(LDAP *ld)
+{
+    static int is_openssl = 0;
+#if defined(USE_OPENLDAP)
+    static int initialized = 0;
+    char *package_name = NULL;
+    int rc;
+
+    if (initialized) {
+        return is_openssl;
+    }
+    rc = ldap_get_option(ld, LDAP_OPT_X_TLS_PACKAGE, &package_name);
+    if (!rc && PL_strcasecmp(package_name, "OpenSSL")) {
+        is_openssl = 1;
+        slapi_ch_free_string(&package_name);
+    }
+    initialized = 1;
+#endif
+    return is_openssl;
+}
--- a/ldap/servers/slapd/libglobs.c
+++ b/ldap/servers/slapd/libglobs.c
@@ -244,6 +244,7 @@ slapi_int_t init_malloc_mmap_threshold;
 #ifdef MEMPOOL_EXPERIMENTAL
 slapi_onoff_t init_mempool_switch;
 #endif
+slapi_onoff_t init_extract_pem;
 
 #define DEFAULT_SSLCLIENTAPTH "off"
 #define DEFAULT_ALLOW_ANON_ACCESS "on"
@@ -1094,6 +1095,10 @@ static struct config_get_and_set {
 		NULL, 0,
 		(void**)&global_slapdFrontendConfig.maxsimplepaged_per_conn,
 		CONFIG_INT, (ConfigGetFunc)config_get_maxsimplepaged_per_conn, DEFAULT_MAXSIMPLEPAGED_PER_CONN_STR},
+	{CONFIG_EXTRACT_PEM, config_set_extract_pem,
+               NULL, 0,
+               (void**)&global_slapdFrontendConfig.extract_pem,
+               CONFIG_ON_OFF, (ConfigGetFunc)config_get_extract_pem, &init_extract_pem},
 #ifdef ENABLE_NUNC_STANS
 	{CONFIG_ENABLE_NUNC_STANS, config_set_enable_nunc_stans,
 		NULL, 0,
@@ -1568,6 +1573,7 @@ FrontendConfig_init () {
     }
   }
 #endif /* MEMPOOL_EXPERIMENTAL */
+  init_extract_pem = cfg->extract_pem = LDAP_OFF;
 
   init_config_get_and_set();
 }
@@ -7834,6 +7840,26 @@ config_get_maxsimplepaged_per_conn()
   return retVal; 
 }
 
+int
+config_set_extract_pem(const char *attrname, char *value, char *errorbuf, int apply)
+{
+    slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+    int retVal = LDAP_SUCCESS;
+
+    retVal = config_set_onoff(attrname, value, &(slapdFrontendConfig->extract_pem), errorbuf, apply);
+    return retVal;
+}
+
+int
+config_get_extract_pem()
+{
+  slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+  int retVal;
+
+  retVal = slapdFrontendConfig->extract_pem;
+  return retVal; 
+}
+
 #if defined(LINUX)
 int
 config_set_malloc_mxfast(const char *attrname, char *value, char *errorbuf, int apply)
--- a/ldap/servers/slapd/proto-slap.h
+++ b/ldap/servers/slapd/proto-slap.h
@@ -565,6 +565,7 @@ int config_get_cn_uses_dn_syntax_in_dns(
 int config_get_enable_nunc_stans(void);
 int config_set_enable_nunc_stans(const char *attrname, char *value, char *errorbuf, int apply);
 #endif
+int config_set_extract_pem(const char *attrname, char *value, char *errorbuf, int apply);
 
 PLHashNumber hashNocaseString(const void *key);
 PRIntn hashNocaseCompare(const void *v1, const void *v2);
@@ -578,6 +579,7 @@ int config_get_malloc_mmap_threshold();
 #endif
 
 int config_get_maxsimplepaged_per_conn();
+int config_get_extract_pem();
 
 int is_abspath(const char *);
 char* rel2abspath( char * );
--- a/ldap/servers/slapd/slap.h
+++ b/ldap/servers/slapd/slap.h
@@ -2093,6 +2093,8 @@ typedef struct _slapdEntryPoints {
 
 #define CONFIG_MAXSIMPLEPAGED_PER_CONN_ATTRIBUTE "nsslapd-maxsimplepaged-per-conn"
 
+#define CONFIG_EXTRACT_PEM "nsslapd-extract-pemfiles"
+
 /* getenv alternative */
 #define CONFIG_MALLOC_MXFAST "nsslapd-malloc-mxfast"
 #define CONFIG_MALLOC_TRIM_THRESHOLD "nsslapd-malloc-trim-threshold"
@@ -2362,6 +2364,7 @@ typedef struct _slapdFrontendConfig {
   int malloc_trim_threshold;    /* mallopt M_TRIM_THRESHOLD */
   int malloc_mmap_threshold;    /* mallopt M_MMAP_THRESHOLD */
 #endif
+  slapi_onoff_t extract_pem;     /* If "on", export key/cert as pem files */
 } slapdFrontendConfig_t;
 
 /* possible values for slapdFrontendConfig_t.schemareplace */
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -6151,12 +6151,14 @@ int slapi_rwlock_get_size();
 /*
  * thread-safe LDAP connections
  */
+#define SLAPI_LDAP_INIT_FLAG_SSL      1  /* SSL */
+#define SLAPI_LDAP_INIT_FLAG_startTLS 2  /* startTLS */
 /**
  * Initializes an LDAP connection, and returns a handle to the connection.
  *
  * \param ldaphost Hostname or IP address - NOTE: for TLS or GSSAPI, should be the FQDN
  * \param ldapport LDAP server port number (default 389)
- * \param secure \c 0 - LDAP \c 1 - LDAPS \c 2 - startTLS
+ * \param secure \c 0 - LDAP \c SLAPI_LDAP_INIT_FLAG_SSL - LDAPS \c SLAPI_LDAP_INIT_FLAG_startTLS - startTLS
  * \param shared \c 0 - single thread access \c 1 - LDAP* will be shared among multiple threads
  * \return A pointer to an LDAP* handle
  *
@@ -6175,6 +6177,7 @@ LDAP *slapi_ldap_init( char *ldaphost, i
  * \see slapi_ldap_init_ext()
  */
 void slapi_ldap_unbind( LDAP *ld );
+
 /**
  * Initializes an LDAP connection, and returns a handle to the connection.
  *
@@ -6182,9 +6185,9 @@ void slapi_ldap_unbind( LDAP *ld );
  *                ldapi://path - if \c NULL, #hostname, #port, and #secure must be provided
  * \param hostname Hostname or IP address - NOTE: for TLS or GSSAPI, should be the FQDN
  * \param port LDAP server port number (default 389)
- * \param secure \c 0 - LDAP \c 1 - LDAPS \c 2 - startTLS
+ * \param secure \c 0 - LDAP \c SLAPI_LDAP_INIT_FLAG_SSL - LDAPS \c SLAPI_LDAP_INIT_FLAG_startTLS - startTLS
  * \param shared \c 0 - single thread access \c 1 - LDAP* will be shared among multiple threads
- * \param filename - currently not supported
+ * \param ldapi_socket - ldapi socket path
  * \return A pointer to an LDAP* handle
  *
  * \note Use #slapi_ldap_unbind() to close and free the handle
@@ -6200,7 +6203,7 @@ LDAP *slapi_ldap_init_ext(
     int secure, /* 0 for ldap, 1 for ldaps, 2 for starttls -
                    override proto in url */
     int shared, /* if true, LDAP* will be shared among multiple threads */
-    const char *filename /* for ldapi */
+    const char *ldap_socket /* ldapi socket path */
 );
 /**
  * The LDAP bind request - this function handles all of the different types of mechanisms
@@ -6237,6 +6240,18 @@ int slapi_ldap_bind(
 );
 
 /**
+ * Return the full path of PEM format CA Cert
+ * 
+ * \return the full path of PEM format CA Cert
+ */
+const char * slapi_get_cacertfile();
+
+/**
+ * Set the full path of PEM format CA Cert
+ */
+void slapi_set_cacertfile(char *certfile);
+
+/**
  * Create either a v1 Proxy Auth Control or a v2 Proxied Auth Control
  *
  * \param ld the LDAP connection handle
--- a/ldap/servers/slapd/slapi-private.h
+++ b/ldap/servers/slapd/slapi-private.h
@@ -1160,6 +1160,7 @@ char* slapd_get_tmp_dir( void );
 #include <stdio.h> /* GGOODREPL - For BUFSIZ, below, gak */
 const char* escape_string (const char* str, char buf[BUFSIZ]);
 const char* escape_string_with_punctuation(const char* str, char buf[BUFSIZ]);
+const char* escape_string_for_filename(const char* str);
 void strcpy_unescape_value( char *d, const char *s );
 
 char *slapi_berval_get_string_copy(const struct berval *bval);
@@ -1304,6 +1305,8 @@ void add_internal_modifiersname(Slapi_PB
 
 /* ldaputil.c */
 char *ldaputil_get_saslpath();
+int slapi_client_uses_non_nss(LDAP *ld);
+int slapi_client_uses_openssl(LDAP *ld);
 
 /* ssl.c */
 /* 
--- a/ldap/servers/slapd/ssl.c
+++ b/ldap/servers/slapd/ssl.c
@@ -231,6 +231,19 @@ PRBool enableSSL3 = PR_FALSE;
  */
 PRBool enableTLS1 = PR_TRUE;
 
+/*
+ * OpenLDAP client library with OpenSSL (ticket 47536)
+ */
+#define PEMEXT ".pem"
+/* CA cert pem file */
+static char *CACertPemFile = NULL;
+
+/* helper functions for openldap update. */
+static int slapd_extract_cert(Slapi_Entry *entry, int isCA);
+static int slapd_extract_key(Slapi_Entry *entry, char *token, PK11SlotInfo *slot);
+static void entrySetValue(Slapi_DN *sdn, char *type, char *value);
+static char *gen_pem_path(char *filename);
+
 static void
 slapd_SSL_report(int degree, char *fmt, va_list args)
 {
@@ -277,7 +290,7 @@ getSupportedCiphers()
 			SSL_GetCipherSuiteInfo((PRUint16)_conf_ciphers[i].num,&info,sizeof(info));
 			/* only support FIPS approved ciphers in FIPS mode */
 			if (!isFIPS || info.isFIPS) {
-				cipher_names[idx++] = PR_smprintf("%s%s%s%s%s%s%d",
+				cipher_names[idx++] = slapi_ch_smprintf("%s%s%s%s%s%s%d",
 						_conf_ciphers[i].name,sep,
 						info.symCipherName,sep,
 						info.macAlgorithmName,sep,
@@ -315,7 +328,7 @@ getEnabledCiphers()
             SSL_CipherPrefGetDefault(_conf_ciphers[x].num, &enabled);
             if (enabled) {
                 SSL_GetCipherSuiteInfo((PRUint16)_conf_ciphers[x].num,&info,sizeof(info));
-                enabled_cipher_names[idx++] = PR_smprintf("%s%s%s%s%s%s%d",
+                enabled_cipher_names[idx++] = slapi_ch_smprintf("%s%s%s%s%s%s%d",
                         _conf_ciphers[x].name,sep,
                         info.symCipherName,sep,
                         info.macAlgorithmName,sep,
@@ -496,7 +509,7 @@ charray2str(char **ary, const char *deli
         if (str) {
             str = PR_sprintf_append(str, "%s%s", delim, *ary++);
         } else {
-            str = PR_smprintf("%s", *ary++);
+            str = slapi_ch_smprintf("%s", *ary++);
         }
     }
 
@@ -678,7 +691,7 @@ _conf_setciphers(char *ciphers, int flag
     slapi_ch_free((void **)&unsuplist); /* strings inside are static */
 
     if (!enabledOne) {
-        char *nocipher = PR_smprintf("No active cipher suite is available.");
+        char *nocipher = slapi_ch_smprintf("No active cipher suite is available.");
         return nocipher;
     }
     _conf_dumpciphers();
@@ -777,6 +790,31 @@ freeChildren( char **list ) {
 	}
 }
 
+static void
+entrySetValue(Slapi_DN *sdn, char *type, char *value)
+{
+    Slapi_PBlock mypb;
+    LDAPMod attr;
+    LDAPMod *mods[2];
+    char *values[2];
+
+    values[0] = value;
+    values[1] = NULL;
+
+    /* modify the attribute */
+    attr.mod_type = type;
+    attr.mod_op = LDAP_MOD_REPLACE;
+    attr.mod_values = values;
+
+    mods[0] = &attr;
+    mods[1] = NULL;
+
+    pblock_init(&mypb);
+    slapi_modify_internal_set_pb_ext(&mypb, sdn, mods, NULL, NULL, (void *)plugin_get_default_component_id(), 0);
+    slapi_modify_internal_pb(&mypb);
+    pblock_done(&mypb);
+}
+
 /* Logs a warning and returns 1 if cert file doesn't exist. You
  * can skip the warning log message by setting no_log to 1.*/
 static int 
@@ -784,8 +822,8 @@ warn_if_no_cert_file(const char *dir, in
 {
     int ret = 0;
     char *filename = slapi_ch_smprintf("%s/cert8.db", dir);
-	PRStatus status = PR_Access(filename, PR_ACCESS_READ_OK);
-	if (PR_SUCCESS != status) {
+    PRStatus status = PR_Access(filename, PR_ACCESS_READ_OK);
+    if (PR_SUCCESS != status) {
         slapi_ch_free_string(&filename);
         filename = slapi_ch_smprintf("%s/cert7.db", dir);
         status = PR_Access(filename, PR_ACCESS_READ_OK);
@@ -1067,7 +1105,7 @@ slapd_nss_init(int init_ssl, int config_
 	slapd_pk11_configurePKCS11(NULL, NULL, tokPBE, ptokPBE, NULL, NULL, NULL, NULL, 0, 0 );
 	secStatus = NSS_Initialize(certdir, NULL, NULL, "secmod.db", nssFlags);
 
-	dongle_file_name = PR_smprintf("%s/pin.txt", certdir);
+	dongle_file_name = slapi_ch_smprintf("%s/pin.txt", certdir);
 
 	if (secStatus != SECSuccess) {
 		errorCode = PR_GetError();
@@ -1190,10 +1228,16 @@ slapd_ssl_init()
         freeConfigEntry( &entry );
         return -1;
     }
+    if (config_get_extract_pem()) {
+        /* extract cert file and convert it to a pem file. */
+        slapd_extract_cert(entry, PR_TRUE);
+    }
+
     if ((family_list = getChildren(configDN))) {
         char **family;
         char *token;
         char *activation;
+        int isinternal = 0;
 
         for (family = family_list; *family; family++) {
 
@@ -1221,6 +1265,7 @@ slapd_ssl_init()
                 if (!PL_strcasecmp(token, "internal") ||
                     !PL_strcasecmp(token, "internal (software)")) {
                     slot = slapd_pk11_getInternalKeySlot();
+                    isinternal = 1;
                 } else {
                     slot = slapd_pk11_findSlotByName(token);
                 }
@@ -1234,8 +1279,6 @@ slapd_ssl_init()
                 return -1;
             }
 
-            slapi_ch_free((void **) &token);
-
             if (!slot) {
                 errorCode = PR_GetError();
                 slapd_SSL_warn("Security Initialization: Unable to find slot ("
@@ -1243,18 +1286,26 @@ slapd_ssl_init()
                        errorCode, slapd_pr_strerror(errorCode));
                 freeChildren(family_list);
                 freeConfigEntry( &entry );
+                slapi_ch_free((void **) &token);
                 return -1;
             }
             /* authenticate */
             if (slapd_pk11_authenticate(slot, PR_TRUE, NULL) != SECSuccess) {
                 errorCode = PR_GetError();
-                slapd_SSL_warn("Security Initialization: Unable to authenticate ("
-                       SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
-                       errorCode, slapd_pr_strerror(errorCode));
+                slapi_log_error(SLAPI_LOG_FATAL, "slapd_ssl_init", 
+                                "Unable to authenticate (" SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
+                                errorCode, slapd_pr_strerror(errorCode));
                 freeChildren(family_list);
                 freeConfigEntry( &entry );
+                slapi_ch_free((void **) &token);
                 return -1;
             }
+            if (config_get_extract_pem()) {
+                /* Get Server{Key,Cert}ExtractFile from cn=Cipher,cn=encryption entry if any. */
+                slapd_extract_cert(entry, PR_FALSE);
+                slapd_extract_key(entry, isinternal?internalTokenName:token, slot);
+            }
+            slapi_ch_free((void **) &token);
         }
         freeChildren( family_list );
         freeConfigEntry( &entry );
@@ -1570,9 +1621,9 @@ slapd_ssl_init2(PRFileDesc **fd, int sta
         if(slapd_pk11_isFIPS()) {
             if(slapd_pk11_authenticate(slot, PR_TRUE, NULL) != SECSuccess) {
                errorCode = PR_GetError();
-               slapd_SSL_warn("Security Initialization: Unable to authenticate ("
-                  SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
-                  errorCode, slapd_pr_strerror(errorCode));
+               slapi_log_error(SLAPI_LOG_FATAL, "slapd_ssl_init2", 
+                                "Unable to authenticate (" SLAPI_COMPONENT_NAME_NSPR " error %d - %s)\n",
+                                errorCode, slapd_pr_strerror(errorCode));
                return -1;
             }
             fipsMode = PR_TRUE;
@@ -2004,111 +2055,117 @@ slapd_SSL_client_auth (LDAP* ld)
     char *token = NULL;
     SVRCOREStdPinObj *StdPinObj;
     SVRCOREError err = SVRCORE_Success;
+    char *finalpersonality = NULL;
+    char *CertExtractFile = NULL;
+    char *KeyExtractFile = NULL;
 
-    if((family_list = getChildren(configDN))) {
+    if ((family_list = getChildren(configDN))) {
         char **family;
-        char *personality = NULL;
         char *activation = NULL;
         char *cipher = NULL;
+        char *personality = NULL;
 
         for (family = family_list; *family; family++) {
             getConfigEntry( *family, &entry );
             if ( entry == NULL ) {
-                    continue;
+                continue;
             }
 
             activation = slapi_entry_attr_get_charptr( entry, "nssslactivation" );
-            if((!activation) || (!PL_strcasecmp(activation, "off"))) {
-                    /* this family was turned off, goto next */
-					slapi_ch_free((void **) &activation);
-					freeConfigEntry( &entry );
-                    continue;
+            if ((!activation) || (!PL_strcasecmp(activation, "off"))) {
+                /* this family was turned off, goto next */
+                slapi_ch_free((void **) &activation);
+                freeConfigEntry( &entry );
+                continue;
             }
-
-	    slapi_ch_free((void **) &activation);
+            slapi_ch_free((void **) &activation);
 
             personality = slapi_entry_attr_get_charptr( entry, "nssslpersonalityssl" );
             cipher = slapi_entry_attr_get_charptr( entry, "cn" );
-	    if ( cipher && !PL_strcasecmp(cipher, "RSA" )) {
-			char *ssltoken;
+            if ( cipher && !PL_strcasecmp(cipher, "RSA" )) {
+                char *ssltoken;
 
-			/* If there already is a token name, use it */
-			if (token) {
-				slapi_ch_free((void **) &personality);
-				slapi_ch_free((void **) &cipher);
-				freeConfigEntry( &entry );
-				continue;
-			}
+                /* If there already is a token name, use it */
+                if (token) {
+                    slapi_ch_free_string(&personality);
+                    slapi_ch_free_string(&cipher);
+                    freeConfigEntry( &entry );
+                    continue;
+                }
 
-			ssltoken = slapi_entry_attr_get_charptr( entry, "nsssltoken" );
- 			if( ssltoken && personality ) {
-			  if( !PL_strcasecmp(ssltoken, "internal") ||
-			      !PL_strcasecmp(ssltoken, "internal (software)") ) {
-
-						/* Translate config internal name to more
-			 			 * readable form.  Certificate name is just
-			 			 * the personality for internal tokens.
-			 			 */
-						token = slapi_ch_strdup(internalTokenName);
+                ssltoken = slapi_entry_attr_get_charptr( entry, "nsssltoken" );
+                if( ssltoken && personality ) {
+                    if (!PL_strcasecmp(ssltoken, "internal") ||
+                        !PL_strcasecmp(ssltoken, "internal (software)")) {
+
+                        /* Translate config internal name to more
+                          * readable form.  Certificate name is just
+                          * the personality for internal tokens.
+                          */
+                        token = slapi_ch_strdup(internalTokenName);
 #if defined(USE_OPENLDAP)
-						/* openldap needs tokenname:certnick */
-						PR_snprintf(cert_name, sizeof(cert_name), "%s:%s", token, personality);
+                        /* openldap needs tokenname:certnick */
+                        PR_snprintf(cert_name, sizeof(cert_name), "%s:%s", token, personality);
 #else
-						PL_strncpyz(cert_name, personality, sizeof(cert_name));
+                        PL_strncpyz(cert_name, personality, sizeof(cert_name));
 #endif
-						slapi_ch_free((void **) &ssltoken);
-			  } else {
-						/* external PKCS #11 token - attach token name */
-						/*ssltoken was already dupped and we don't need it anymore*/
-						token = ssltoken;
-						PR_snprintf(cert_name, sizeof(cert_name), "%s:%s", token, personality);
-			  }
- 			} else {
-			  errorCode = PR_GetError(); 
-			  slapd_SSL_warn("Security Initialization: Failed to get cipher "
-					 "family information.  Missing nsssltoken or"
-					 "nssslpersonalityssl in %s ("
-					 SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
-					 *family, errorCode, slapd_pr_strerror(errorCode));
-	  		  slapi_ch_free((void **) &ssltoken);
-			  slapi_ch_free((void **) &personality);
-			  slapi_ch_free((void **) &cipher);
-			  freeConfigEntry( &entry );
-			  continue;
-			}
-	    } else { /* external PKCS #11 cipher */
-			char *ssltoken;
+                        slapi_ch_free_string(&ssltoken);
+                    } else {
+                        /* external PKCS #11 token - attach token name */
+                        token = ssltoken; /*ssltoken was already dupped */
+                        PR_snprintf(cert_name, sizeof(cert_name), "%s:%s", token, personality);
+                    }
+                } else {
+                    errorCode = PR_GetError(); 
+                    slapd_SSL_warn("Security Initialization: Failed to get cipher "
+                        "family information.  Missing nsssltoken or"
+                        "nssslpersonalityssl in %s ("
+                        SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
+                        *family, errorCode, slapd_pr_strerror(errorCode));
+                    slapi_ch_free_string(&ssltoken);
+                    slapi_ch_free_string(&personality);
+                    slapi_ch_free_string(&cipher);
+                    freeConfigEntry( &entry );
+                    continue;
+                }
+            } else { /* external PKCS #11 cipher */
+                char *ssltoken;
 
-			ssltoken = slapi_entry_attr_get_charptr( entry, "nsssltoken" );
-			if( token && personality ) {
+                ssltoken = slapi_entry_attr_get_charptr( entry, "nsssltoken" );
+                if( ssltoken && personality ) {
 
-				/* free the old token and remember the new one */
-				if (token) slapi_ch_free((void **)&token);
-				token = ssltoken; /*ssltoken was already dupped and we don't need it anymore*/
-
-				/* external PKCS #11 token - attach token name */
-				PR_snprintf(cert_name, sizeof(cert_name), "%s:%s", token, personality);
-			} else {
-			  errorCode = PR_GetError();
-			  slapd_SSL_warn("Security Initialization: Failed to get cipher "
-					 "family information.  Missing nsssltoken or"
-					 "nssslpersonalityssl in %s ("
-					 SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
-					 *family, errorCode, slapd_pr_strerror(errorCode));
-	        	  slapi_ch_free((void **) &ssltoken);
-	    		  slapi_ch_free((void **) &personality);
-			  slapi_ch_free((void **) &cipher);
-			  freeConfigEntry( &entry );
-			  continue;
-			}
+                    /* free the old token and remember the new one */
+                    if (token) slapi_ch_free_string(&token);
+                    token = ssltoken; /*ssltoken was already dupped */
 
-	    }
-	    slapi_ch_free((void **) &personality);
-	    slapi_ch_free((void **) &cipher);
-		freeConfigEntry( &entry );
+                    /* external PKCS #11 token - attach token name */
+                    PR_snprintf(cert_name, sizeof(cert_name), "%s:%s", token, personality);
+                } else {
+                    errorCode = PR_GetError();
+                    slapd_SSL_warn("Security Initialization: Failed to get cipher "
+                       "family information.  Missing nsssltoken or"
+                       "nssslpersonalityssl in %s ("
+                       SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
+                     *  family, errorCode, slapd_pr_strerror(errorCode));
+                    slapi_ch_free_string(&ssltoken);
+                    slapi_ch_free_string(&personality);
+                    slapi_ch_free_string(&cipher);
+                    freeConfigEntry( &entry );
+                    continue;
+                }
+            }
+            slapi_ch_free_string(&finalpersonality);
+            finalpersonality = personality;
+            slapi_ch_free_string(&cipher);
+            /* Get ServerCert/KeyExtractFile from given entry if any. */
+            slapi_ch_free_string(&CertExtractFile);
+            CertExtractFile = slapi_entry_attr_get_charptr(entry, "ServerCertExtractFile");
+            slapi_ch_free_string(&KeyExtractFile);
+            KeyExtractFile = slapi_entry_attr_get_charptr(entry, "ServerKeyExtractFile");
+            freeConfigEntry( &entry );
         } /* end of for */
 
-		freeChildren( family_list );
+        freeChildren( family_list );
     }
 
     /* Free config data */
@@ -2123,15 +2180,69 @@ slapd_SSL_client_auth (LDAP* ld)
                 errorCode, slapd_pr_strerror(errorCode));
         } else {
 #if defined(USE_OPENLDAP)
-            rc = ldap_set_option(ld, LDAP_OPT_X_TLS_KEYFILE, SERVER_KEY_NAME);
-            if (rc) {
-                slapd_SSL_warn("SSL client authentication cannot be used "
-                    "unable to set the key to use to %s", SERVER_KEY_NAME);
-            }
-            rc = ldap_set_option(ld, LDAP_OPT_X_TLS_CERTFILE, cert_name);
-            if (rc) {
-                slapd_SSL_warn("SSL client authentication cannot be used "
-                    "unable to set the cert to use to %s", cert_name);
+            if (slapi_client_uses_non_nss(ld)) {
+                char *certdir = config_get_certdir();
+                char *keyfile = NULL;
+                char *certfile = NULL;
+                if (KeyExtractFile) {
+                    if ('/' == *KeyExtractFile) {
+                        keyfile = KeyExtractFile;
+                    } else {
+                        keyfile = slapi_ch_smprintf("%s/%s", certdir, KeyExtractFile);
+                        slapi_ch_free_string(&KeyExtractFile);
+                    }
+                } else {
+                    keyfile = slapi_ch_smprintf("%s/%s-Key%s", certdir, finalpersonality, PEMEXT);
+                }
+                if (CertExtractFile) {
+                    if ('/' == *CertExtractFile) {
+                        certfile = CertExtractFile;
+                    } else {
+                        certfile = slapi_ch_smprintf("%s/%s", certdir, CertExtractFile);
+                        slapi_ch_free_string(&CertExtractFile);
+                    }
+                } else {
+                    certfile = slapi_ch_smprintf("%s/%s%s", certdir, finalpersonality, PEMEXT);
+                }
+                slapi_ch_free_string(&certdir);
+                if (PR_SUCCESS != PR_Access(keyfile, PR_ACCESS_EXISTS)) {
+                    slapi_ch_free_string(&keyfile);
+                    slapd_SSL_warn("SSL key file (%s) for client authentication does not exist. "
+                                   "Using %s", keyfile, SERVER_KEY_NAME);
+                    keyfile = slapi_ch_strdup(SERVER_KEY_NAME);
+                }
+                rc = ldap_set_option(ld, LDAP_OPT_X_TLS_KEYFILE, keyfile);
+                if (rc) {
+                    slapd_SSL_warn("SSL client authentication cannot be used "
+                        "unable to set the key to use to %s", keyfile);
+                }
+                slapi_ch_free_string(&keyfile);
+                rc = PR_Access(certfile, PR_ACCESS_EXISTS);
+                if (rc) {
+                    slapi_ch_free_string(&certfile);
+                    slapd_SSL_warn("SSL cert file (%s) for client authentication does not exist. "
+                                   "Using %s", certfile, cert_name);
+                    certfile = cert_name;
+                }
+                rc = ldap_set_option(ld, LDAP_OPT_X_TLS_CERTFILE, certfile);
+                if (rc) {
+                    slapd_SSL_warn("SSL client authentication cannot be used "
+                        "unable to set the cert to use to %s", certfile);
+                }
+                if (certfile != cert_name) {
+                    slapi_ch_free_string(&certfile);
+                }
+            } else {
+                rc = ldap_set_option(ld, LDAP_OPT_X_TLS_KEYFILE, SERVER_KEY_NAME);
+                if (rc) {
+                    slapd_SSL_warn("SSL client authentication cannot be used "
+                        "unable to set the key to use to %s", SERVER_KEY_NAME);
+                }
+                rc = ldap_set_option(ld, LDAP_OPT_X_TLS_CERTFILE, cert_name);
+                if (rc) {
+                    slapd_SSL_warn("SSL client authentication cannot be used "
+                        "unable to set the cert to use to %s", cert_name);
+                }
             }
             /*
              * not sure what else needs to be done for client auth - don't
@@ -2162,6 +2273,7 @@ slapd_SSL_client_auth (LDAP* ld)
 
     slapi_ch_free_string(&token);
     slapi_ch_free_string(&pw);
+    slapi_ch_free_string(&finalpersonality);
 
     LDAPDebug (LDAP_DEBUG_TRACE, "slapd_SSL_client_auth() %i\n", rc, 0, 0);
     return rc;
@@ -2262,9 +2374,10 @@ slapd_get_unlocked_key_for_cert(CERTCert
 					slotname, tokenname, certsubject);
 			break;
 		} else {
-			slapi_log_error(SLAPI_LOG_TRACE, "slapd_get_unlocked_key_for_cert",
-					"Skipping locked slot [%s] token [%s] for certificate [%s]\n",
-					slotname, tokenname, certsubject);
+			PRErrorCode errcode = PR_GetError();
+			slapi_log_error(SLAPI_LOG_FATAL, "slapd_get_unlocked_key_for_cert",
+					"Skipping locked slot [%s] token [%s] for certificate [%s] (%d - %s)\n",
+					slotname, tokenname, certsubject, errcode, slapd_pr_strerror(errcode));
 		}
 	}
 
@@ -2288,3 +2401,591 @@ slapd_get_unlocked_key_for_cert(CERTCert
 	return key;
 }
 
+/*
+ * Functions to extract key and cert from the NSS cert db.
+ */
+#include <libgen.h>
+#include <seccomon.h>
+#include <secmodt.h>
+#include <certt.h>
+#include <base64.h>
+#define DONOTEDIT "This file is auto-generated by 389-ds-base.\nDo not edit directly.\n"
+#define NS_CERT_HEADER "-----BEGIN CERTIFICATE-----"
+#define NS_CERT_TRAILER "-----END CERTIFICATE-----"
+#define KEY_HEADER  "-----BEGIN PRIVATE KEY-----"
+#define KEY_TRAILER "-----END PRIVATE KEY-----"
+#define ENCRYPTED_KEY_HEADER  "-----BEGIN ENCRYPTED PRIVATE KEY-----"
+#define ENCRYPTED_KEY_TRAILER "-----END ENCRYPTED PRIVATE KEY-----"
+
+typedef struct {
+    enum {
+    PW_NONE = 0,
+    PW_FROMFILE = 1,
+    PW_PLAINTEXT = 2,
+    PW_EXTERNAL = 3
+    } source;
+    char *data;
+} secuPWData;
+
+static SECStatus
+listCerts(CERTCertDBHandle *handle, CERTCertificate *cert, PK11SlotInfo *slot,
+          PRFileDesc *outfile, void *pwarg)
+{
+    SECItem data;
+    SECStatus rv = SECFailure;
+    CERTCertList *certs;
+    CERTCertListNode *node;
+    CERTCertificate *the_cert = NULL;
+    char *name = NULL;
+
+    if (!cert) {
+        slapi_log_error(SLAPI_LOG_FATAL, "listCerts", "No cert given\n");
+        return rv;
+    }
+    name = cert->nickname;
+
+    if (!name) {
+        slapi_log_error(SLAPI_LOG_FATAL, "listCerts", "No cert nickname\n");
+        return rv;
+    }
+    the_cert = CERT_FindCertByNicknameOrEmailAddr(handle, name);
+    if (!the_cert) {
+        slapi_log_error(SLAPI_LOG_FATAL, "listCerts", "Could not find cert: %s\n", name);
+        return SECFailure;
+    }
+
+    PR_fprintf(outfile, "%s\n", DONOTEDIT);
+    /* Here, we have one cert with the desired nickname or email 
+     * address.  Now, we will attempt to get a list of ALL certs 
+     * with the same subject name as the cert we have.  That list 
+     * should contain, at a minimum, the one cert we have already found.
+     * If the list of certs is empty (NULL), the libraries have failed.
+     */
+    certs = CERT_CreateSubjectCertList(NULL, handle, &the_cert->derSubject,
+                                       PR_Now(), PR_FALSE);
+    CERT_DestroyCertificate(the_cert);
+    if (!certs) {
+        slapi_log_error(SLAPI_LOG_FATAL, "listCerts", "problem printing certificates");
+        return SECFailure;
+    }
+    for (node = CERT_LIST_HEAD(certs); !CERT_LIST_END(node,certs); node = CERT_LIST_NEXT(node)) {
+        the_cert = node->cert;
+        PR_fprintf(outfile, "Issuer: %s\n", the_cert->issuerName);
+        PR_fprintf(outfile, "Subject: %s\n", the_cert->subjectName);
+        /* now get the subjectList that matches this cert */
+        data.data = the_cert->derCert.data;
+        data.len = the_cert->derCert.len;
+        PR_fprintf(outfile, "\n%s\n%s\n%s\n", NS_CERT_HEADER, 
+                   BTOA_DataToAscii(data.data, data.len), NS_CERT_TRAILER);
+        rv = SECSuccess;
+    }
+    if (certs) {
+        CERT_DestroyCertList(certs);
+    }
+    if (rv) {
+        slapi_log_error(SLAPI_LOG_FATAL, "listCerts", "problem printing certificate nicknames");
+        return SECFailure;
+    }
+
+    return rv;
+}
+
+static char *
+gen_pem_path(char *filename)
+{
+    char *pem = NULL;
+    char *pempath = NULL;
+    char *dname = NULL;
+    char *bname = NULL;
+    char *certdir = config_get_certdir();
+
+    if (!filename) {
+        goto bail;
+    }
+    pem = PL_strstr(filename, PEMEXT);
+    if (pem) {
+        *pem = '\0';
+    }
+    bname = basename(filename);
+    dname = dirname(filename);
+    if (!PL_strcmp(dname, ".")) {
+        /* just a file name */
+        pempath = slapi_ch_smprintf("%s/%s%s", certdir, bname, PEMEXT);
+    } else if (*dname == '/') {
+        /* full path */
+        pempath = slapi_ch_smprintf("%s/%s%s", dname, bname, PEMEXT);
+    } else {
+        /* relative path */
+        pempath = slapi_ch_smprintf("%s/%s/%s%s", certdir, dname, bname, PEMEXT);
+    }
+bail:
+    return pempath;
+}
+
+static int
+slapd_extract_cert(Slapi_Entry *entry, int isCA)
+{
+    CERTCertDBHandle *certHandle;
+    char *certdir = config_get_certdir();
+    CERTCertListNode *node;
+    CERTCertList *list = PK11_ListCerts(PK11CertListAll, NULL);
+    PRFileDesc *outFile = NULL;
+    SECStatus rv = SECFailure;
+    char *CertExtractFile = NULL;
+    char *certfile = NULL;
+    char *personality = NULL;
+
+    if (!entry) {
+        slapi_log_error(SLAPI_LOG_FATAL, "slapd_extract_cert",
+                        "No entry is given for %s Cert.\n", isCA?"CA":"Server");
+        goto bail;
+    }
+
+    /* Get CertExtractFile from given entry if any. */
+    if (isCA) {
+        CertExtractFile = slapi_entry_attr_get_charptr(entry, "CACertExtractFile");
+    } else {
+        CertExtractFile = slapi_entry_attr_get_charptr(entry, "ServerCertExtractFile");
+        personality = slapi_entry_attr_get_charptr(entry, "nsSSLPersonalitySSL" );
+    }
+    certfile = gen_pem_path(CertExtractFile);
+    if (isCA) {
+        slapi_ch_free_string(&CACertPemFile);
+        CACertPemFile = certfile;
+    }
+
+    certHandle = CERT_GetDefaultCertDB();
+    for (node = CERT_LIST_HEAD(list); !CERT_LIST_END(node, list);
+         node = CERT_LIST_NEXT(node)) {
+        CERTCertificate *cert = node->cert;
+        CERTCertTrust trust;
+          switch (isCA) {
+          case PR_TRUE:
+            if ((CERT_GetCertTrust(cert, &trust) == SECSuccess) &&
+                (trust.sslFlags & (CERTDB_VALID_CA|CERTDB_TRUSTED_CA|CERTDB_TRUSTED_CLIENT_CA))) {
+                /* default token "internal" */
+                PK11SlotInfo *slot = slapd_pk11_getInternalKeySlot();
+                slapi_log_error(SLAPI_LOG_FATAL, "slapd_extract_cert", "CA CERT NAME: %s\n", cert->nickname);
+                if (!certfile) {
+                    certfile = slapi_ch_smprintf("%s/%s%s", certdir, escape_string_for_filename(cert->nickname), PEMEXT);
+                    entrySetValue(slapi_entry_get_sdn(entry), "CACertExtractFile", certfile);
+                    slapi_set_cacertfile(certfile);
+                }
+                if (!outFile) {
+                    outFile = PR_Open(certfile, PR_CREATE_FILE | PR_RDWR | PR_TRUNCATE, 00660);
+                }
+                if (!outFile) {
+                    slapi_log_error(SLAPI_LOG_FATAL, "slapd_extract_cert",
+                                    "Unable to open \"%s\" for writing (%d, %d).\n",
+                                    certfile, PR_GetError(), PR_GetOSError());
+                    goto bail;
+                }
+                rv = listCerts(certHandle, cert, slot, outFile, NULL);
+                if (rv) {
+                    slapi_log_error(SLAPI_LOG_FATAL, "slapd_extract_cert", "listCerts failed\n");
+                    break;
+                }
+            }
+            break;
+        default:
+            if (!PL_strcmp(cert->nickname, personality)) {
+                PK11SlotInfo *slot = slapd_pk11_getInternalKeySlot();
+                slapi_log_error(SLAPI_LOG_FATAL, "slapd_extract_cert", "SERVER CERT NAME: %s\n", cert->nickname);
+                if (!certfile) {
+                    certfile = slapi_ch_smprintf("%s/%s%s", certdir, escape_string_for_filename(cert->nickname), PEMEXT);
+                }
+                if (!outFile) {
+                    outFile = PR_Open(certfile, PR_CREATE_FILE | PR_RDWR | PR_TRUNCATE, 00660);
+                }
+                if (!outFile) {
+                    slapi_log_error(SLAPI_LOG_FATAL, "slapd_extract_cert",
+                                    "Unable to open \"%s\" for writing (%d, %d).\n",
+                                    certfile, PR_GetError(), PR_GetOSError());
+                    goto bail;
+                }
+                rv = listCerts(certHandle, cert, slot, outFile, NULL);
+                if (rv) {
+                    slapi_log_error(SLAPI_LOG_FATAL, "slapd_extract_cert", "listCerts failed\n");
+                }
+                PR_Close(outFile);
+                outFile = NULL;
+                break; /* One cert per one pem file. */
+            }
+            break;
+        }
+    }
+    rv = SECSuccess;
+bail:
+    CERT_DestroyCertList(list);
+    slapi_ch_free_string(&CertExtractFile);
+    if (CACertPemFile != certfile) {
+        slapi_ch_free_string(&certfile);
+    }
+    slapi_ch_free_string(&personality);
+    if (outFile) {
+        PR_Close(outFile);
+    }
+    return rv;
+}
+
+/*
+ * Borrowed from keyutil.c (crypto-util)
+ *
+ * Extract the public and private keys and the subject
+ * distinguished from the cert with the given nickname
+ * in the given slot.
+ *
+ * @param nickname the certificate nickname
+ * @param slot the slot where keys it was loaded
+ * @param pwdat module authentication password
+ * @param privkey private key out
+ * @param pubkey public key out
+ * @param subject subject out
+ */
+static SECStatus 
+extractRSAKeysAndSubject(
+    const char *nickname,
+    PK11SlotInfo *slot,
+    secuPWData *pwdata,
+    SECKEYPrivateKey **privkey,
+    SECKEYPublicKey **pubkey,
+    CERTName **subject)
+{
+    PRErrorCode rv = SECFailure;
+    CERTCertificate *cert = PK11_FindCertFromNickname((char *)nickname, NULL);
+    if (!cert) {
+        rv = PR_GetError();
+        slapi_log_error(SLAPI_LOG_FATAL, "extractRSAKeysAndSubject",
+                        "Failed extract cert with %s, (%d-%s, %d).\n",
+                        nickname, rv, slapd_pr_strerror(rv), PR_GetOSError());
+        goto bail;
+    }
+
+    *pubkey = CERT_ExtractPublicKey(cert);
+    if (!*pubkey) {
+        rv = PR_GetError();
+        slapi_log_error(SLAPI_LOG_FATAL, "extractRSAKeysAndSubject",
+                        "Could not get public key from cert for %s, (%d-%s, %d)\n",
+                        nickname, rv, slapd_pr_strerror(rv), PR_GetOSError());
+        goto bail;
+    }
+
+    *privkey = PK11_FindKeyByDERCert(slot, cert, pwdata);
+    if (!*privkey) {
+        rv = PR_GetError();
+        slapi_log_error(SLAPI_LOG_FATAL, "extractRSAKeysAndSubject",
+                        "Unable to find the key with PK11_FindKeyByDERCert for %s, (%d-%s, %d)\n",
+                        nickname, rv, slapd_pr_strerror(rv), PR_GetOSError());
+        *privkey= PK11_FindKeyByAnyCert(cert, &pwdata);
+        if (!*privkey) {
+            rv = PR_GetError();
+            slapi_log_error(SLAPI_LOG_FATAL, "extractRSAKeysAndSubject",
+                            "Unable to find the key with PK11_FindKeyByAnyCert for %s, (%d-%s, %d)\n",
+                            nickname, rv, slapd_pr_strerror(rv), PR_GetOSError());
+            goto bail;
+        }
+    }
+
+    PR_ASSERT(((*privkey)->keyType) == rsaKey);
+    *subject = CERT_AsciiToName(cert->subjectName);
+
+    if (!*subject) {
+        slapi_log_error(SLAPI_LOG_FATAL, "extractRSAKeysAndSubject",
+                        "Improperly formatted name: \"%s\"\n",
+                        cert->subjectName);
+        goto bail;
+    }
+    rv = SECSuccess;
+bail:
+    if (cert)
+        CERT_DestroyCertificate(cert);
+    return rv;
+}
+
+/*
+ * Decrypt the private key
+ */
+SECStatus DecryptKey(
+    SECKEYEncryptedPrivateKeyInfo *epki,
+    SECOidTag algTag,
+    SECItem *pwitem,
+    secuPWData *pwdata,
+    SECItem *derPKI)
+{
+    SECItem  *cryptoParam = NULL;
+    PK11SymKey *symKey = NULL;
+    PK11Context *ctx = NULL;
+    SECStatus rv = SECFailure;
+
+    if (!pwitem) {
+        return rv;
+    }
+
+    do {
+        SECAlgorithmID algid = epki->algorithm;
+        CK_MECHANISM_TYPE cryptoMechType;
+        CK_ATTRIBUTE_TYPE operation = CKA_DECRYPT;
+        PK11SlotInfo *slot = NULL;
+
+        cryptoMechType = PK11_GetPBECryptoMechanism(&algid, &cryptoParam, pwitem);
+        if (cryptoMechType == CKM_INVALID_MECHANISM)  {
+            break;
+        }
+
+        slot = PK11_GetBestSlot(cryptoMechType, NULL);
+        if (!slot) {
+            break;
+        }
+
+        symKey = PK11_PBEKeyGen(slot, &algid, pwitem, PR_FALSE, pwdata);
+        if (symKey == NULL) {
+            break;
+        }
+
+        ctx = PK11_CreateContextBySymKey(cryptoMechType, operation, symKey, cryptoParam);
+        if (ctx == NULL) {
+             break;
+        }
+
+        rv = PK11_CipherOp(ctx,
+                derPKI->data,                  /* out     */
+                (int *)(&derPKI->len),         /* out len */
+                (int)epki->encryptedData.len,  /* max out */
+                epki->encryptedData.data,      /* in      */
+                (int)epki->encryptedData.len); /* in len  */
+
+        PR_ASSERT(derPKI->len == epki->encryptedData.len);
+        PR_ASSERT(rv == SECSuccess);
+        rv = PK11_Finalize(ctx);
+        PR_ASSERT(rv == SECSuccess);
+
+    } while (0);
+
+    /* cleanup */
+    if (symKey) {
+        PK11_FreeSymKey(symKey);
+    }
+    if (cryptoParam) {
+        SECITEM_ZfreeItem(cryptoParam, PR_TRUE);
+        cryptoParam = NULL;
+    }
+    if (ctx) {
+        PK11_DestroyContext(ctx, PR_TRUE);
+    }
+
+    return rv;
+
+}
+
+/* #define ENCRYPTEDKEY 1 */
+#define RAND_PASS_LEN 32
+static int
+slapd_extract_key(Slapi_Entry *entry, char *token, PK11SlotInfo *slot)
+{
+    char *KeyExtractFile = NULL;
+    char *personality = NULL;
+    char *keyfile = NULL;
+    unsigned char randomPassword[RAND_PASS_LEN] = {0};
+    SECStatus rv = SECFailure;
+    SECItem pwitem = { 0, NULL, 0 };
+    SECItem clearKeyDER = { 0, NULL, 0 };
+    PRFileDesc *outFile = NULL;
+    SECKEYEncryptedPrivateKeyInfo *epki = NULL;
+    SECKEYPrivateKey *privkey = NULL;
+    SECKEYPublicKey *pubkey = NULL;
+    secuPWData pwdata = { PW_NONE, 0 };
+    CERTName *subject = NULL;
+    PLArenaPool *arenaForPKI = NULL;
+    char *b64 = NULL;
+    PRUint32 total = 0;
+    PRUint32 numBytes = 0;
+    char *certdir = config_get_certdir();
+#if defined(ENCRYPTEDKEY)
+    char *keyEncPwd = NULL;
+    SVRCOREError err = SVRCORE_Success;
+    PRArenaPool *arenaForEPKI = NULL;
+    SVRCOREStdPinObj *StdPinObj;
+    SECItem *encryptedKeyDER = NULL;
+#endif
+
+    if (!entry) {
+        slapi_log_error(SLAPI_LOG_FATAL, "slapd_extract_key",
+                        "No entry is given for Server Key.\n");
+        goto bail;
+    }
+#if defined(ENCRYPTEDKEY)
+    if (!token) {
+        slapi_log_error(SLAPI_LOG_FATAL, "slapd_extract_key",
+                        "No token is given.\n");
+        goto bail;
+    }
+    StdPinObj = (SVRCOREStdPinObj *)SVRCORE_GetRegisteredPinObj();
+    if (!StdPinObj) {
+        slapi_log_error(SLAPI_LOG_FATAL, "slapd_extract_key",
+                        "No entry is given for Server Key.\n");
+        goto bail;
+    }
+    err =  SVRCORE_StdPinGetPin(&keyEncPwd, StdPinObj, token);
+    if (err || !keyEncPwd) {
+        slapi_log_error(SLAPI_LOG_FATAL, "slapd_extract_key",
+                        "Failed to extract pw with token %s.\n", token);
+        goto bail;
+    }
+    pwitem.data = (unsigned char *)keyEncPwd;
+    pwitem.len = (unsigned int)strlen(keyEncPwd);
+    pwitem.type = siBuffer;
+#else
+    /* Caller wants clear keys. Make up a dummy
+     * password to get NSS to export an encrypted
+     * key which we will decrypt.
+     */
+    rv = PK11_GenerateRandom(randomPassword, sizeof((const char *)randomPassword) - 1);
+    if (rv != SECSuccess) {
+        slapi_log_error(SLAPI_LOG_FATAL, "slapd_extract_key", "Failed to generate random.\n");
+        goto bail;
+    }
+    pwitem.data = randomPassword;
+    pwitem.len = strlen((const char *)randomPassword);
+    pwitem.type = siBuffer;
+#endif
+
+    /* Get ServerKeyExtractFile from given entry if any. */
+    KeyExtractFile = slapi_entry_attr_get_charptr(entry, "ServerKeyExtractFile");
+    personality = slapi_entry_attr_get_charptr(entry, "nsSSLPersonalitySSL" );
+    if (!personality) {
+        slapi_log_error(SLAPI_LOG_FATAL, "slapd_extract_key",
+                        "nsSSLPersonalitySSL value not found.\n");
+        goto bail;
+    }
+    keyfile = gen_pem_path(KeyExtractFile);
+    if (!keyfile) {
+        keyfile = slapi_ch_smprintf("%s/%s-Key%s", certdir, escape_string_for_filename(personality), PEMEXT);
+    }
+    outFile = PR_Open(keyfile, PR_CREATE_FILE | PR_RDWR | PR_TRUNCATE, 00660);
+    if (!outFile) {
+        slapi_log_error(SLAPI_LOG_FATAL, "slapd_extract_key",
+                        "Unable to open \"%s\" for writing (%d, %d).\n",
+                        keyfile, PR_GetError(), PR_GetOSError());
+        goto bail;
+    }
+    rv = extractRSAKeysAndSubject(personality, slot, &pwdata, &privkey, &pubkey, &subject);
+    if (rv != SECSuccess) {
+#if defined(ENCRYPTEDKEY)
+        slapi_log_error(SLAPI_LOG_FATAL, "slapd_extract_key",
+                        "Failed to extract keys for \"%s\".\n", token);
+#else
+        slapi_log_error(SLAPI_LOG_FATAL, "slapd_extract_key", "Failed to extract keys for %s.\n", personality);
+#endif
+        goto bail;
+    }
+
+    /* 
+     * Borrowed the code from KeyOut in keyutil.c (crypto-util).
+     * Is it ok to hardcode the algorithm SEC_OID_DES_EDE3_CBC???
+     */
+    epki = PK11_ExportEncryptedPrivKeyInfo(NULL, SEC_OID_DES_EDE3_CBC, &pwitem, privkey, 1000, &pwdata);
+    if (!epki) {
+        slapi_log_error(SLAPI_LOG_FATAL, "slapd_extract_key",
+                        "Unable to export encrypted private key (%d, %d).\n",
+                        PR_GetError(), PR_GetOSError());
+        goto bail;
+    }
+#if defined(ENCRYPTEDKEY)
+    arenaForEPKI = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    /* NULL dest to let it allocate memory for us */
+    encryptedKeyDER = SEC_ASN1EncodeItem(arenaForEPKI, NULL, epki, SECKEY_EncryptedPrivateKeyInfoTemplate);
+    if (!encryptedKeyDER) {
+        slapi_log_error(SLAPI_LOG_FATAL, "slapd_extract_key",
+                        "SEC_ASN1EncodeItem failed. (%d, %d).\n", PR_GetError(), PR_GetOSError());
+        goto bail;
+    }
+#else
+    /* Make a decrypted key the one to write out. */
+    arenaForPKI = PORT_NewArena(2048);
+    if (!arenaForPKI) {
+        slapi_log_error(SLAPI_LOG_FATAL, "slapd_extract_key",
+                        "PORT_NewArena failed. (%d, %d).\n", PR_GetError(), PR_GetOSError());
+        goto bail;
+    }
+    clearKeyDER.data = PORT_ArenaAlloc(arenaForPKI, epki->encryptedData.len);
+    clearKeyDER.len = epki->encryptedData.len;
+    clearKeyDER.type = siBuffer;
+
+    rv = DecryptKey(epki, SEC_OID_DES_EDE3_CBC, &pwitem, &pwdata, &clearKeyDER);
+    if (rv != SECSuccess) {
+        slapi_log_error(SLAPI_LOG_FATAL, "slapd_extract_key",
+                        "DekryptKey failed. (%d, %d).\n", PR_GetError(), PR_GetOSError());
+        goto bail;
+    }
+#endif
+
+    /* we could be exporting a clear or encrypted key */
+#if defined(ENCRYPTEDKEY)
+    b64 = BTOA_ConvertItemToAscii(encryptedKeyDER);
+#else
+    b64 = BTOA_ConvertItemToAscii(&clearKeyDER);
+#endif
+    if (!b64) {
+        slapi_log_error(SLAPI_LOG_FATAL, "slapd_extract_key",
+                        "Failed to conver to the ASCII (%d, %d).\n",
+                        PR_GetError(), PR_GetOSError());
+        goto bail;
+    }
+
+    total = PL_strlen(b64);
+    PR_fprintf(outFile, "%s\n", DONOTEDIT);
+#if defined(ENCRYPTEDKEY)
+    PR_fprintf(outFile, "%s\n", ENCRYPTED_KEY_HEADER);
+#else
+    PR_fprintf(outFile, "%s\n", KEY_HEADER);
+#endif
+    numBytes = PR_Write(outFile, b64, total);
+    if (numBytes != total) {
+        slapi_log_error(SLAPI_LOG_FATAL, "slapd_extract_key",
+                        "Failed to write to the file (%d, %d).\n",
+                        PR_GetError(), PR_GetOSError());
+        goto bail;
+    }
+#if defined(ENCRYPTEDKEY)
+    PR_fprintf(outFile, "\n%s\n", ENCRYPTED_KEY_TRAILER);
+#else
+    PR_fprintf(outFile, "\n%s\n", KEY_TRAILER);
+#endif
+    rv = SECSuccess;
+bail:
+    slapi_ch_free_string(&certdir);
+    slapi_ch_free_string(&KeyExtractFile);
+    slapi_ch_free_string(&keyfile);
+    if (outFile) {
+        PR_Close(outFile);
+    }
+#if defined(ENCRYPTEDKEY)
+    if (arenaForEPKI) {
+        PORT_FreeArena(arenaForEPKI, PR_FALSE);
+    }
+    if (pwitem.data) {
+        memset(pwitem.data, 0, pwitem.len);
+        PORT_Free(pwitem.data);
+    }
+    memset(&pwitem, 0, sizeof(SECItem));
+#else
+    if (arenaForPKI) {
+        PORT_FreeArena(arenaForPKI, PR_FALSE);
+    }
+    memset(randomPassword, 0, strlen((const char *)randomPassword));
+#endif
+    return rv;
+}
+
+const char *
+slapi_get_cacertfile()
+{
+    return CACertPemFile;
+}
+
+void
+slapi_set_cacertfile(char *certfile)
+{
+    slapi_ch_free_string(&CACertPemFile);
+    CACertPemFile = certfile;
+}
--- a/ldap/servers/slapd/util.c
+++ b/ldap/servers/slapd/util.c
@@ -39,6 +39,15 @@
 #define FILTER_BUF 128 /* initial buffer size for attr value */
 #define BUF_INCR 16    /* the amount to increase the FILTER_BUF once it fills up */
 
+static int special_filename(unsigned char c)
+{
+    if ((c < 45) || (c == '/') || ((c > 57) && (c < 65)) ||
+        ((c > 90) && (c < 95)) || (c == 96) ||(c > 122) ) {
+       return UTIL_ESCAPE_HEX;
+    } 
+    return UTIL_ESCAPE_NONE;
+}
+
 static int special_np(unsigned char c)
 {
     if (c == '\\') {
@@ -99,12 +108,16 @@ special_attr_char(unsigned char c)
             c == '"');
 }
 
+/* No '\\' */
+#define DOESCAPE_FLAGS_HEX_NOESC 0x1
+
 static const char*
 do_escape_string (
     const char* str, 
     int len,                    /* -1 means str is nul-terminated */
     char buf[BUFSIZ],
-    int (*special)(unsigned char)
+    int (*special)(unsigned char),
+    int flags
 )
 {
     const char* s;
@@ -121,54 +134,56 @@ do_escape_string (
 
     last = str + len - 1;
     for (s = str; s <= last; ++s) {
-	if ( (esc = (*special)((unsigned char)*s))) {
-	    const char* first = str;
-	    char* bufNext = buf;
-	    int bufSpace = BUFSIZ - 4;
-	    while (1) {
-		if (bufSpace < (s - first)) s = first + bufSpace - 1;
-		if (s > first) {
-		    memcpy (bufNext, first, s - first);
-		    bufNext  += (s - first);
-		    bufSpace -= (s - first);
-		}
-		if (s > last) {
-		    break;
-		}
-		do {
-		    if (esc == UTIL_ESCAPE_BACKSLASH) {
-			/* *s is '\\' */
-			/* If *(s+1) and *(s+2) are both hex digits,
-			 * the char is already escaped. */
-			if (isxdigit(*(s+1)) && isxdigit(*(s+2))) {
-			    memcpy(bufNext, s, 3);
-			    bufNext += 3;
-			    bufSpace -= 3;
-			    s += 2;
-			} else {
-			    *bufNext++ = *s; --bufSpace;
-			}
-		    } else {    /* UTIL_ESCAPE_HEX */
-			*bufNext++ = '\\'; --bufSpace;
-			if (bufSpace < 3) {
-			    memcpy(bufNext, "..", 2);
-			    bufNext += 2;
-			    goto bail;
-			}
-			PR_snprintf(bufNext, 3, "%02x", *(unsigned char*)s);
-			bufNext += 2; bufSpace -= 2;
-		    }
-	        } while (++s <= last && 
+        if ( (esc = (*special)((unsigned char)*s))) {
+            const char* first = str;
+            char* bufNext = buf;
+            int bufSpace = BUFSIZ - 4;
+            while (1) {
+                if (bufSpace < (s - first)) s = first + bufSpace - 1;
+                if (s > first) {
+                    memcpy (bufNext, first, s - first);
+                    bufNext  += (s - first);
+                    bufSpace -= (s - first);
+                }
+                if (s > last) {
+                    break;
+                }
+                do {
+                    if (esc == UTIL_ESCAPE_BACKSLASH) {
+                        /* *s is '\\' */
+                        /* If *(s+1) and *(s+2) are both hex digits,
+                         * the char is already escaped. */
+                        if (isxdigit(*(s+1)) && isxdigit(*(s+2))) {
+                            memcpy(bufNext, s, 3);
+                            bufNext += 3;
+                            bufSpace -= 3;
+                            s += 2;
+                        } else {
+                            *bufNext++ = *s; --bufSpace;
+                        }
+                    } else {    /* UTIL_ESCAPE_HEX */
+                        if (!(flags & DOESCAPE_FLAGS_HEX_NOESC)) {
+                            *bufNext++ = '\\'; --bufSpace;
+                        }
+                        if (bufSpace < 3) {
+                            memcpy(bufNext, "..", 2);
+                            bufNext += 2;
+                            goto bail;
+                        }
+                        PR_snprintf(bufNext, 3, "%02x", *(unsigned char*)s);
+                        bufNext += 2; bufSpace -= 2;
+                    }
+                } while (++s <= last && 
                          (esc = (*special)((unsigned char)*s)));
-		if (s > last) break;
-		first = s;
-		while ( (esc = (*special)((unsigned char)*s)) == UTIL_ESCAPE_NONE && s <= last) ++s;
-	    }
-	  bail:
-	    *bufNext = '\0';
-	    return buf;
-	}
-    }
+                if (s > last) break;
+                first = s;
+                while ( (esc = (*special)((unsigned char)*s)) == UTIL_ESCAPE_NONE && s <= last) ++s;
+            }
+bail:
+            *bufNext = '\0';
+            return buf;
+        }
+    } /* for */
     return str;
 }
 
@@ -185,13 +200,20 @@ do_escape_string (
 const char*
 escape_string (const char* str, char buf[BUFSIZ])
 {
-  return do_escape_string(str,-1,buf,special_np);
+  return do_escape_string(str,-1,buf,special_np, 0);
 }
 
 const char*
 escape_string_with_punctuation(const char* str, char buf[BUFSIZ])
 {
-  return do_escape_string(str,-1,buf,special_np_and_punct);
+  return do_escape_string(str,-1,buf,special_np_and_punct, 0);
+}
+
+const char*
+escape_string_for_filename(const char *str)
+{
+  char buf[BUFSIZ];
+  return do_escape_string(str,-1,buf,special_filename, DOESCAPE_FLAGS_HEX_NOESC);
 }
 
 #define ESCAPE_FILTER 1
