From b1b4356c4d92835ba9b03b90824f69334342d4a8 Mon Sep 17 00:00:00 2001
From: Firstyear <william@blackhats.net.au>
Date: Fri, 18 Oct 2024 11:29:19 +1000
Subject: [PATCH] Issue 6349 - RFE - Use previously extracted key path (#6363)

Bug Description: slapd_SSL_client_auth uses the values of
KeyExtractFile and CertExtractFile from the configuration
entry, and each time it's called attempts to determine if
this is an absolute or relative path. If the path is
relative, it prepends a /tmp location based on if the
running system /tmp is a private namespace or not. This
causes a replication client that uses TLS certificate
authentication to repeatedly emit warnings that the
key extraction occurred to non-private tmp in a
container.

Fix Description: During key extraction, we extract
keys and files using the "last token" from nss as the
item that we extract. Because of this, we know that there
can only be a single extracted key and cert, allowing
us to extract these and store the full abs path of
the extracted files rather than deriving them during
each client iteration.

fixes: https://github.com/389ds/389-ds-base/issues/6349

Author: William Brown <william@blackhats.net.au>

Review by: @tbordaz @progier389 @droideck (Thanks!)
---
 ldap/servers/slapd/main.c       |    1 
 ldap/servers/slapd/proto-slap.h |    1 
 ldap/servers/slapd/ssl.c        |   61 +++++++++++++++++-----------------------
 3 files changed, 28 insertions(+), 35 deletions(-)

--- a/ldap/servers/slapd/main.c
+++ b/ldap/servers/slapd/main.c
@@ -1153,6 +1153,7 @@ cleanup:
     compute_terminate();
     SSL_ShutdownServerSessionIDCache();
     SSL_ClearSessionCache();
+    slapd_ssl_destroy();
     ndn_cache_destroy();
     NSS_Shutdown();
     PR_Cleanup();
--- a/ldap/servers/slapd/proto-slap.h
+++ b/ldap/servers/slapd/proto-slap.h
@@ -1154,6 +1154,7 @@ void do_search(Slapi_PBlock *pb);
 char *check_private_certdir(void);
 int slapd_nss_init(int init_ssl, int config_available);
 int slapd_ssl_init(void);
+void slapd_ssl_destroy(void);
 int slapd_ssl_init2(PRFileDesc **fd, int startTLS);
 int slapd_security_library_is_initialized(void);
 int slapd_ssl_listener_is_initialized(void);
--- a/ldap/servers/slapd/ssl.c
+++ b/ldap/servers/slapd/ssl.c
@@ -75,6 +75,10 @@ static int stimeout;
 static char *ciphers = NULL;
 static char *configDN = "cn=encryption,cn=config";
 
+/* The paths of extracted key and certs if any. */
+static char *key_extract_file = NULL;
+static char *cert_extract_file = NULL;
+
 
 /* Copied from libadmin/libadmin.h public/nsapi.h */
 #define SERVER_KEY_NAME "Server-Key"
@@ -1341,6 +1345,13 @@ slapd_ssl_init()
     return 0;
 }
 
+void
+slapd_ssl_destroy(void)
+{
+    slapi_ch_free_string(&key_extract_file);
+    slapi_ch_free_string(&cert_extract_file);
+}
+
 /*
  * val:   sslVersionMin/Max value set in cn=encryption,cn=config (INPUT)
  * rval:  Corresponding value to set SSLVersionRange (OUTPUT)
@@ -2063,8 +2074,6 @@ slapd_SSL_client_auth(LDAP *ld)
     SVRCOREStdPinObj *StdPinObj;
     SVRCOREError err = SVRCORE_Success;
     char *finalpersonality = NULL;
-    char *CertExtractFile = NULL;
-    char *KeyExtractFile = NULL;
 
     if ((family_list = getChildren(configDN))) {
         char **family;
@@ -2169,11 +2178,6 @@ slapd_SSL_client_auth(LDAP *ld)
             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 */
 
@@ -2191,37 +2195,12 @@ slapd_SSL_client_auth(LDAP *ld)
                            "(no password). (" SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
                            errorCode, slapd_pr_strerror(errorCode));
         } else {
-            if (slapi_client_uses_non_nss(ld)  && config_get_extract_pem()) {
-                char *certdir;
-                char *keyfile = NULL;
-                char *certfile = NULL;
+            if (slapi_client_uses_non_nss(ld)  && key_extract_file && cert_extract_file) {
+                char *keyfile = slapi_ch_strdup(key_extract_file);
+                char *certfile = slapi_ch_strdup(cert_extract_file);
                 /* If a private tmp namespace exists
                  * it is the place where PEM files will be extracted
                  */
-                if ((certdir = check_private_certdir()) == NULL) {
-                    certdir = config_get_certdir();
-                }
-                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. "
@@ -2254,6 +2233,10 @@ slapd_SSL_client_auth(LDAP *ld)
                     slapi_ch_free_string(&certfile);
                 }
             } else {
+                if (config_get_extract_pem() && (key_extract_file == NULL || cert_extract_file == NULL)) {
+                    slapd_SSL_warn("SSL key or certificate file were not extracted during initialisation.");
+                }
+
                 rc = ldap_set_option(ld, LDAP_OPT_X_TLS_KEYFILE, SERVER_KEY_NAME);
                 if (rc) {
                     slapd_SSL_warn("SSL client authentication cannot be used "
@@ -2659,6 +2642,10 @@ slapd_extract_cert(Slapi_Entry *entry, i
         }
     }
     rv = SECSuccess;
+
+    slapi_ch_free_string(&cert_extract_file);
+    cert_extract_file = slapi_ch_strdup(certfile);
+
 bail:
     CERT_DestroyCertList(list);
     slapi_ch_free_string(&CertExtractFile);
@@ -3012,6 +2999,10 @@ slapd_extract_key(Slapi_Entry *entry, ch
     PR_fprintf(outFile, "\n%s\n", KEY_TRAILER);
 #endif
     rv = SECSuccess;
+
+    slapi_ch_free_string(&key_extract_file);
+    key_extract_file = slapi_ch_strdup(keyfile);
+
 bail:
     slapi_ch_free_string(&certdir);
     slapi_ch_free_string(&KeyExtractFile);
