From 1e80b68ec14bba0caaa0ee61124b12ae0f483a68 Mon Sep 17 00:00:00 2001
From: Kaspar Brand <kbrand@apache.org>
Date: Sat, 28 Dec 2013 13:24:17 +0000
Subject: [PATCH] Remove the hardcoded algorithm-type dependency for the
 SSLCertificateFile and SSLCertificateKeyFile directives, and deprecate
 SSLCertificateChainFile

Splitting the patch into smaller pieces turned out to be infeasible,
unfortunately, due to the heavily intertwined code in ssl_engine_config.c,
ssl_engine_init.c and ssl_engine_pphrase.c, which all depends on the
modssl_pk_server_t data structure. For better comprehensibility,
a detailed listing of the changes follows:

ssl_private.h
- drop the X509 certs and EVP_PKEY keys arrays from modssl_pk_server_t
- use apr_array_header_t for cert_files and key_files
- drop tPublicCert from SSLModConfigRec
- drop the ssl_algo_t struct and the SSL_ALGO_* and SSL_AIDX_* constants

ssl_engine_config.c
- change to apr_array_header_t for SSLCertificate[Key]File
- drop ssl_cmd_check_aidx_max, i.e. allow an arbitrary number of certs
  and keys (in theory; currently OpenSSL does not support more than
  one cert/key per algorithm type)
- add deprecation warning for SSLCertificateChainFile

ssl_engine_init.c
- configure server certs/keys in ssl_init_server_certs (no longer via
  ssl_pphrase_Handle in ssl_init_Module)
- in ssl_init_server_certs, read in certificates and keys with standard
  OpenSSL API functions (SSL_CTX_use_*_file), and only fall back to
  ssl_load_encrypted_pkey when encountering an encrypted private key
- drop ssl_server_import_cert, ssl_server_import_key, ssl_init_server_check,
  and ssl_init_ctx_cleanup_server
- move the "problematic re-initialization" check to ssl_init_server_ctx

ssl_engine_pphrase.c
- use servername:port:index as the key identifier, instead of the
  previously used servername:port:algorithm
- ssl_pphrase_Handle overhaul: remove all cert/public-key handling,
  make it only load a single (encrypted) private key, and rename
  to ssl_load_encrypted_pkey
- in the passphrase prompt message, show the private key file name
  instead of the vhost id and the algorithm name
- do no longer supply the algorithm name as an argument to "exec"-type
  passphrase prompting programs

ssl_util.c
- drop ssl_util_algotypeof, ssl_util_algotypestr, ssl_asn1_keystr,
  and ssl_asn1_table_keyfmt

ssl_util_ssl.{c,h}
- drop SSL_read_X509
- constify the filename arg for SSL_read_PrivateKey


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1553824 13f79535-47bb-0310-9956-ffa450edef68
---
 CHANGES                           |   5 +
 docs/log-message-tags/next-number |   2 +-
 docs/manual/mod/mod_ssl.xml       |  76 ++--
 modules/ssl/ssl_engine_config.c   |  78 ++--
 modules/ssl/ssl_engine_init.c     | 481 +++++++++++------------
 modules/ssl/ssl_engine_pphrase.c  | 615 +++++++++++-------------------
 modules/ssl/ssl_private.h         |  67 +---
 modules/ssl/ssl_util.c            |  79 +---
 modules/ssl/ssl_util_ssl.c        |  45 +--
 modules/ssl/ssl_util_ssl.h        |   3 +-
 10 files changed, 567 insertions(+), 884 deletions(-)

diff --git a/CHANGES b/CHANGES
index 1487c68b87..d4c50f918c 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,11 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache 2.5.0
 
+  *) mod_ssl: Remove the hardcoded algorithm-type dependency for the
+     SSLCertificateFile and SSLCertificateKeyFile directives, to enable
+     future algorithm agility, and deprecate the SSLCertificateChainFile
+     directive (obsoleted by SSLCertificateFile). [Kaspar Brand]
+
   *) mod_proxy: Remove <Proxy ~ wildcard-url> syntax which:
       - is equivalent to <ProxyMatch wildcard-url>
       - has never been documented
diff --git a/docs/log-message-tags/next-number b/docs/log-message-tags/next-number
index 12fda76f5d..d0f1b35877 100644
--- a/docs/log-message-tags/next-number
+++ b/docs/log-message-tags/next-number
@@ -1 +1 @@
-2559
+2585
diff --git a/docs/manual/mod/mod_ssl.xml b/docs/manual/mod/mod_ssl.xml
index 6e03af12d3..c7f9157659 100644
--- a/docs/manual/mod/mod_ssl.xml
+++ b/docs/manual/mod/mod_ssl.xml
@@ -801,25 +801,44 @@ SSLCipherSuite RSA:!EXP:!NULL:+HIGH:+MEDIUM:-LOW
 
 <directivesynopsis>
 <name>SSLCertificateFile</name>
-<description>Server PEM-encoded X.509 Certificate file</description>
+<description>Server PEM-encoded X.509 certificate data file</description>
 <syntax>SSLCertificateFile <em>file-path</em></syntax>
 <contextlist><context>server config</context>
 <context>virtual host</context></contextlist>
 
 <usage>
 <p>
-This directive points to the file with the PEM-encoded certificate,
-optionally also the corresponding private key, and - beginning with
-version 2.5.0-dev as of 2013-09-29 - DH parameters and/or an EC curve name
-for ephemeral keys (as generated by <code>openssl dhparam</code>
-and <code>openssl ecparam</code>, respectively). If the private key
-is encrypted, the pass phrase dialog is forced at startup time.
+This directive points to a file with certificate data in PEM format.
+At a minimum, the file must include an end-entity (leaf) certificate.
+Beginning with version 2.5.0-dev as of 2013-12-28, it may also
+include intermediate CA certificates, sorted from leaf to root,
+and obsoletes <directive module="mod_ssl">SSLCertificateChainFile</directive>.
 </p>
+
+<p>
+Additional optional elements are DH parameters and/or an EC curve name
+for ephemeral keys, as generated by <code>openssl dhparam</code> and
+<code>openssl ecparam</code>, respectively (supported in version 2.5.0-dev
+as of 2013-09-29), and finally, the end-entity certificate's private key.
+If the private key is encrypted, the pass phrase dialog is forced
+at startup time.</p>
+
+<p>
+This directive can be used multiple times (referencing different filenames)
+to support multiple algorithms for server authentication - typically
+RSA, DSA, and ECC. The number of supported algorithms depends on the
+OpenSSL version being used for mod_ssl: with version 1.0.0 or later,
+<code>openssl list-public-key-algorithms</code> will output a list
+of supported algorithms.</p>
+
 <p>
-This directive can be used up to three times (referencing different filenames)
-when both an RSA, a DSA, and an ECC based server certificate is used in
-parallel. Note that DH and ECDH parameters are only read from the first
-<directive>SSLCertificateFile</directive> directive.</p>
+When running with OpenSSL 1.0.2 or later, this directive allows
+to configure the intermediate CA chain on a per-certificate basis,
+which removes a limitation of the (now obsolete)
+<directive module="mod_ssl">SSLCertificateChainFile</directive> directive.
+DH and ECDH parameters, however, are only read from the first
+<directive>SSLCertificateFile</directive> directive, as they
+are applied independently of the authentication algorithm type.</p>
 
 <note>
 <title>DH parameter interoperability with primes > 1024 bit</title>
@@ -845,25 +864,26 @@ SSLCertificateFile /usr/local/apache2/conf/ssl.crt/server.crt
 
 <directivesynopsis>
 <name>SSLCertificateKeyFile</name>
-<description>Server PEM-encoded Private Key file</description>
+<description>Server PEM-encoded private key file</description>
 <syntax>SSLCertificateKeyFile <em>file-path</em></syntax>
 <contextlist><context>server config</context>
 <context>virtual host</context></contextlist>
 
 <usage>
 <p>
-This directive points to the PEM-encoded Private Key file for the
-server. If the Private Key is not combined with the Certificate in the
-<directive>SSLCertificateFile</directive>, use this additional directive to
-point to the file with the stand-alone Private Key. When
-<directive>SSLCertificateFile</directive> is used and the file
-contains both the Certificate and the Private Key this directive need
-not be used. But we strongly discourage this practice.  Instead we
-recommend you to separate the Certificate and the Private Key. If the
-contained Private Key is encrypted, the Pass Phrase dialog is forced
-at startup time. This directive can be used up to three times
-(referencing different filenames) when both a RSA, a DSA, and an ECC based
-private key is used in parallel.</p>
+This directive points to the PEM-encoded private key file for the
+server (the private key may also be combined with the certificate in the
+<directive module="mod_ssl">SSLCertificateFile</directive>, but this practice
+is discouraged). If the contained private key is encrypted, the pass phrase
+dialog is forced at startup time.</p>
+
+<p>
+The directive can be used multiple times (referencing different filenames)
+to support multiple algorithms for server authentication. For each
+<directive module="mod_ssl">SSLCertificateKeyFile</directive>
+directive, there must be a matching <directive>SSLCertificateFile</directive>
+directive.</p>
+
 <example><title>Example</title>
 <highlight language="config">
 SSLCertificateKeyFile /usr/local/apache2/conf/ssl.key/server.key
@@ -880,6 +900,14 @@ SSLCertificateKeyFile /usr/local/apache2/conf/ssl.key/server.key
 <context>virtual host</context></contextlist>
 
 <usage>
+<note><title>SSLCertificateChainFile is deprecated</title>
+<p><code>SSLCertificateChainFile</code> became obsolete with version
+2.5.0-dev as of 2013-12-28, when
+<directive module="mod_ssl">SSLCertificateFile</directive>
+was extended to also load intermediate CA certificates from the server
+certificate file.</p>
+</note>
+
 <p>
 This directive sets the optional <em>all-in-one</em> file where you can
 assemble the certificates of Certification Authorities (CA) which form the
diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c
index 4f9db0b362..ea5c622b1c 100644
--- a/modules/ssl/ssl_engine_config.c
+++ b/modules/ssl/ssl_engine_config.c
@@ -66,7 +66,6 @@ SSLModConfigRec *ssl_config_global_create(server_rec *s)
                                                 sizeof(ssl_randseed_t));
     mc->tVHostKeys             = apr_hash_make(pool);
     mc->tPrivateKey            = apr_hash_make(pool);
-    mc->tPublicCert            = apr_hash_make(pool);
 #if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT)
     mc->szCryptoDevice         = NULL;
 #endif
@@ -190,7 +189,8 @@ static void modssl_ctx_init_server(SSLSrvConfigRec *sc,
 
     mctx->pks = apr_pcalloc(p, sizeof(*mctx->pks));
 
-    /* mctx->pks->... certs/keys are set during module init */
+    mctx->pks->cert_files = apr_array_make(p, 3, sizeof(char *));
+    mctx->pks->key_files  = apr_array_make(p, 3, sizeof(char *));
 
 #ifdef HAVE_TLS_SESSION_TICKETS
     mctx->ticket_key = apr_pcalloc(p, sizeof(*mctx->ticket_key));
@@ -314,14 +314,10 @@ static void modssl_ctx_cfg_merge_server(apr_pool_t *p,
                                         modssl_ctx_t *add,
                                         modssl_ctx_t *mrg)
 {
-    int i;
-
     modssl_ctx_cfg_merge(p, base, add, mrg);
 
-    for (i = 0; i < SSL_AIDX_MAX; i++) {
-        cfgMergeString(pks->cert_files[i]);
-        cfgMergeString(pks->key_files[i]);
-    }
+    cfgMergeArray(pks->cert_files);
+    cfgMergeArray(pks->key_files);
 
     cfgMergeString(pks->ca_name_path);
     cfgMergeString(pks->ca_name_file);
@@ -758,56 +754,20 @@ static const char *ssl_cmd_check_dir(cmd_parms *parms,
 
 }
 
-#define SSL_AIDX_CERTS 1
-#define SSL_AIDX_KEYS  2
-
-static const char *ssl_cmd_check_aidx_max(cmd_parms *parms,
-                                          const char *arg,
-                                          int idx)
-{
-    SSLSrvConfigRec *sc = mySrvConfig(parms->server);
-    const char *err, *desc=NULL, **files=NULL;
-    int i;
-
-    if ((err = ssl_cmd_check_file(parms, &arg))) {
-        return err;
-    }
-
-    switch (idx) {
-      case SSL_AIDX_CERTS:
-        desc = "certificates";
-        files = sc->server->pks->cert_files;
-        break;
-      case SSL_AIDX_KEYS:
-        desc = "private keys";
-        files = sc->server->pks->key_files;
-        break;
-    }
-
-    for (i = 0; i < SSL_AIDX_MAX; i++) {
-        if (!files[i]) {
-            files[i] = arg;
-            return NULL;
-        }
-    }
-
-    return apr_psprintf(parms->pool,
-                        "%s: only up to %d "
-                        "different %s per virtual host allowed",
-                         parms->cmd->name, SSL_AIDX_MAX, desc);
-}
-
 const char *ssl_cmd_SSLCertificateFile(cmd_parms *cmd,
                                        void *dcfg,
                                        const char *arg)
 {
-
+    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
     const char *err;
 
-    if ((err = ssl_cmd_check_aidx_max(cmd, arg, SSL_AIDX_CERTS))) {
+    if ((err = ssl_cmd_check_file(cmd, &arg))) {
         return err;
     }
 
+    *(const char **)apr_array_push(sc->server->pks->cert_files) =
+        apr_pstrdup(cmd->pool, arg);
+    
     return NULL;
 }
 
@@ -815,12 +775,16 @@ const char *ssl_cmd_SSLCertificateKeyFile(cmd_parms *cmd,
                                           void *dcfg,
                                           const char *arg)
 {
+    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
     const char *err;
 
-    if ((err = ssl_cmd_check_aidx_max(cmd, arg, SSL_AIDX_KEYS))) {
+    if ((err = ssl_cmd_check_file(cmd, &arg))) {
         return err;
     }
 
+    *(const char **)apr_array_push(sc->server->pks->key_files) =
+        apr_pstrdup(cmd->pool, arg);
+
     return NULL;
 }
 
@@ -831,6 +795,12 @@ const char *ssl_cmd_SSLCertificateChainFile(cmd_parms *cmd,
     SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
     const char *err;
 
+    ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_STARTUP, 0, cmd->server,
+                 APLOGNO(02559)
+                 "The SSLCertificateChainFile directive (%s:%d) is deprecated, "
+                 "SSLCertificateFile should be used instead",
+                 cmd->directive->filename, cmd->directive->line_num);
+
     if ((err = ssl_cmd_check_file(cmd, &arg))) {
         return err;
     }
@@ -1927,8 +1897,12 @@ void ssl_hook_ConfigTest(apr_pool_t *pconf, server_rec *s)
                 modssl_pk_server_t *const pks = sc->server->pks;
                 int i;
 
-                for (i = 0; (i < SSL_AIDX_MAX) && pks->cert_files[i]; i++) {
-                    apr_file_printf(out, "  %s\n", pks->cert_files[i]);
+                for (i = 0; (i < pks->cert_files->nelts) &&
+                            APR_ARRAY_IDX(pks->cert_files, i, const char *);
+                     i++) {
+                    apr_file_printf(out, "  %s\n",
+                                    APR_ARRAY_IDX(pks->cert_files,
+                                                  i, const char *));
                 }
             }
 
diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c
index 377fb67b52..ddfdfb5c13 100644
--- a/modules/ssl/ssl_engine_init.c
+++ b/modules/ssl/ssl_engine_init.c
@@ -67,6 +67,7 @@ apr_status_t ssl_init_Module(apr_pool_t *p, apr_pool_t *plog,
     SSLSrvConfigRec *sc;
     server_rec *s;
     apr_status_t rv;
+    apr_array_header_t *pphrases;
 
     if (SSLeay() < SSL_LIBRARY_VERSION) {
         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, base_server, APLOGNO(01882)
@@ -191,16 +192,6 @@ apr_status_t ssl_init_Module(apr_pool_t *p, apr_pool_t *plog,
     }
 #endif
 
-    /*
-     * read server private keys/public certs into memory.
-     * decrypting any encrypted keys via configured SSLPassPhraseDialogs
-     * anything that needs to live longer than ptemp needs to also survive
-     * restarts, in which case they'll live inside s->process->pool.
-     */
-    if ((rv = ssl_pphrase_Handle(base_server, ptemp)) != APR_SUCCESS) {
-        return rv;
-    }
-
     /*
      * initialize the mutex handling
      */
@@ -218,6 +209,8 @@ apr_status_t ssl_init_Module(apr_pool_t *p, apr_pool_t *plog,
         return rv;
     }
 
+    pphrases = apr_array_make(ptemp, 2, sizeof(char *));
+
     /*
      *  initialize servers
      */
@@ -235,11 +228,19 @@ apr_status_t ssl_init_Module(apr_pool_t *p, apr_pool_t *plog,
         /*
          * Read the server certificate and key
          */
-        if ((rv = ssl_init_ConfigureServer(s, p, ptemp, sc)) != APR_SUCCESS) {
+        if ((rv = ssl_init_ConfigureServer(s, p, ptemp, sc, pphrases))
+            != APR_SUCCESS) {
             return rv;
         }
     }
 
+    if (pphrases->nelts > 0) {
+        memset(pphrases->elts, 0, pphrases->elt_size * pphrases->nelts);
+        pphrases->nelts = 0;
+        ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(02560)
+                     "Init: Wiped out the queried pass phrases from memory");
+    }
+
     /*
      * Configuration consistency checks
      */
@@ -299,40 +300,6 @@ apr_status_t ssl_init_Engine(server_rec *s, apr_pool_t *p)
 }
 #endif
 
-static apr_status_t ssl_init_server_check(server_rec *s,
-                                          apr_pool_t *p,
-                                          apr_pool_t *ptemp,
-                                          modssl_ctx_t *mctx)
-{
-    /*
-     * check for important parameters and the
-     * possibility that the user forgot to set them.
-     */
-    if (!mctx->pks->cert_files[0]) {
-        ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01891)
-                "No SSL Certificate set [hint: SSLCertificateFile]");
-        return ssl_die(s);
-    }
-
-    /*
-     *  Check for problematic re-initializations
-     */
-    if (mctx->pks->certs[SSL_AIDX_RSA] ||
-        mctx->pks->certs[SSL_AIDX_DSA]
-#ifdef HAVE_ECC
-      || mctx->pks->certs[SSL_AIDX_ECC]
-#endif
-        )
-    {
-        ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01892)
-                "Illegal attempt to re-initialise SSL for server "
-                "(SSLEngine On should go in the VirtualHost, not in global scope.)");
-        return ssl_die(s);
-    }
-
-    return APR_SUCCESS;
-}
-
 #ifdef HAVE_TLSEXT
 static apr_status_t ssl_init_ctx_tls_extensions(server_rec *s,
                                                 apr_pool_t *p,
@@ -783,8 +750,9 @@ static apr_status_t ssl_init_ctx_cert_chain(server_rec *s,
         return APR_SUCCESS;
     }
 
-    for (i = 0; (i < SSL_AIDX_MAX) && mctx->pks->cert_files[i]; i++) {
-        if (strEQ(mctx->pks->cert_files[i], chain)) {
+    for (i = 0; (i < mctx->pks->cert_files->nelts) &&
+         APR_ARRAY_IDX(mctx->pks->cert_files, i, const char *); i++) {
+        if (strEQ(APR_ARRAY_IDX(mctx->pks->cert_files, i, const char *), chain)) {
             skip_first = TRUE;
             break;
         }
@@ -850,104 +818,10 @@ static apr_status_t ssl_init_ctx(server_rec *s,
     return APR_SUCCESS;
 }
 
-static apr_status_t ssl_server_import_cert(server_rec *s,
-                                           modssl_ctx_t *mctx,
-                                           const char *id,
-                                           int idx)
-{
-    SSLModConfigRec *mc = myModConfig(s);
-    ssl_asn1_t *asn1;
-    const unsigned char *ptr;
-    const char *type = ssl_asn1_keystr(idx);
-    X509 *cert;
-
-    if (!(asn1 = ssl_asn1_table_get(mc->tPublicCert, id))) {
-        return APR_NOTFOUND;
-    }
-
-    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02232)
-                 "Configuring %s server certificate", type);
-
-    ptr = asn1->cpData;
-    if (!(cert = d2i_X509(NULL, &ptr, asn1->nData))) {
-        ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02233)
-                "Unable to import %s server certificate", type);
-        ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
-        return ssl_die(s);
-    }
-
-    if (SSL_CTX_use_certificate(mctx->ssl_ctx, cert) <= 0) {
-        ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02234)
-                "Unable to configure %s server certificate", type);
-        ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
-        return ssl_die(s);
-    }
-
-#ifdef HAVE_OCSP_STAPLING
-    if ((mctx->pkp == FALSE) && (mctx->stapling_enabled == TRUE)) {
-        if (!ssl_stapling_init_cert(s, mctx, cert)) {
-            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02235)
-                         "Unable to configure server certificate for stapling");
-        }
-    }
-#endif
-
-    mctx->pks->certs[idx] = cert;
-
-    return APR_SUCCESS;
-}
-
-static apr_status_t ssl_server_import_key(server_rec *s,
-                                          modssl_ctx_t *mctx,
-                                          const char *id,
-                                          int idx)
-{
-    SSLModConfigRec *mc = myModConfig(s);
-    ssl_asn1_t *asn1;
-    const unsigned char *ptr;
-    const char *type = ssl_asn1_keystr(idx);
-    int pkey_type;
-    EVP_PKEY *pkey;
-
-#ifdef HAVE_ECC
-    if (idx == SSL_AIDX_ECC)
-      pkey_type = EVP_PKEY_EC;
-    else
-#endif
-    pkey_type = (idx == SSL_AIDX_RSA) ? EVP_PKEY_RSA : EVP_PKEY_DSA;
-
-    if (!(asn1 = ssl_asn1_table_get(mc->tPrivateKey, id))) {
-        return APR_NOTFOUND;
-    }
-
-    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02236)
-                 "Configuring %s server private key", type);
-
-    ptr = asn1->cpData;
-    if (!(pkey = d2i_PrivateKey(pkey_type, NULL, &ptr, asn1->nData)))
-    {
-        ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02237)
-                "Unable to import %s server private key", type);
-        ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
-        return ssl_die(s);
-    }
-
-    if (SSL_CTX_use_PrivateKey(mctx->ssl_ctx, pkey) <= 0) {
-        ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02238)
-                "Unable to configure %s server private key", type);
-        ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
-        return ssl_die(s);
-    }
-
-    mctx->pks->keys[idx] = pkey;
-
-    return APR_SUCCESS;
-}
-
 static void ssl_check_public_cert(server_rec *s,
                                   apr_pool_t *ptemp,
                                   X509 *cert,
-                                  int type)
+                                  const char *key_id)
 {
     int is_ca, pathlen;
 
@@ -963,132 +837,215 @@ static void ssl_check_public_cert(server_rec *s,
         if (is_ca) {
             ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(01906)
                          "%s server certificate is a CA certificate "
-                         "(BasicConstraints: CA == TRUE !?)",
-                         ssl_asn1_keystr(type));
+                         "(BasicConstraints: CA == TRUE !?)", key_id);
         }
 
         if (pathlen > 0) {
             ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(01907)
                          "%s server certificate is not a leaf certificate "
                          "(BasicConstraints: pathlen == %d > 0 !?)",
-                         ssl_asn1_keystr(type), pathlen);
+                         key_id, pathlen);
         }
     }
 
     if (SSL_X509_match_name(ptemp, cert, (const char *)s->server_hostname,
                             TRUE, s) == FALSE) {
         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(01909)
-                     "%s certificate configured for %s does NOT include "
-                     "an ID which matches the server name",
-                     ssl_asn1_keystr(type), (mySrvConfig(s))->vhost_id);
+                     "%s server certificate does NOT include an ID "
+                     "which matches the server name", key_id);
     }
 }
 
+/* prevent OpenSSL from showing its "Enter PEM pass phrase:" prompt */
+static int ssl_no_passwd_prompt_cb(char *buf, int size, int rwflag,
+                                   void *userdata) {
+   return 0;
+}
+
 static apr_status_t ssl_init_server_certs(server_rec *s,
                                           apr_pool_t *p,
                                           apr_pool_t *ptemp,
-                                          modssl_ctx_t *mctx)
+                                          modssl_ctx_t *mctx,
+                                          apr_array_header_t *pphrases)
 {
-    const char *rsa_id, *dsa_id;
+    SSLModConfigRec *mc = myModConfig(s);
+    const char *vhost_id = mctx->sc->vhost_id, *key_id, *certfile, *keyfile;
+    int i;
+    X509 *cert;
+    DH *dhparams;
 #ifdef HAVE_ECC
-    const char *ecc_id;
     EC_GROUP *ecparams;
     int nid;
     EC_KEY *eckey;
 #endif
-    const char *vhost_id = mctx->sc->vhost_id;
-    int i;
-    apr_status_t have_rsa, have_dsa;
-    DH *dhparams;
-#ifdef HAVE_ECC
-    apr_status_t have_ecc;
+#ifndef HAVE_SSL_CONF_CMD
+    SSL *ssl;
 #endif
 
-    rsa_id = ssl_asn1_table_keyfmt(ptemp, vhost_id, SSL_AIDX_RSA);
-    dsa_id = ssl_asn1_table_keyfmt(ptemp, vhost_id, SSL_AIDX_DSA);
-#ifdef HAVE_ECC
-    ecc_id = ssl_asn1_table_keyfmt(ptemp, vhost_id, SSL_AIDX_ECC);
-#endif
+    /* no OpenSSL default prompts for any of the SSL_CTX_use_* calls, please */
+    SSL_CTX_set_default_passwd_cb(mctx->ssl_ctx, ssl_no_passwd_prompt_cb);
+
+    /* Iterate over the SSLCertificateFile array */
+    for (i = 0; (i < mctx->pks->cert_files->nelts) &&
+                (certfile = APR_ARRAY_IDX(mctx->pks->cert_files, i,
+                                          const char *));
+         i++) {
+        key_id = apr_psprintf(ptemp, "%s:%d", vhost_id, i);
+
+        /* first the certificate (public key) */
+        if (mctx->cert_chain) {
+            if ((SSL_CTX_use_certificate_file(mctx->ssl_ctx, certfile,
+                                              SSL_FILETYPE_PEM) < 1)) {
+                ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02561)
+                             "Failed to configure certificate %s, check %s",
+                             key_id, certfile);
+                ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
+                return APR_EGENERAL;
+            }
+        } else {
+            if ((SSL_CTX_use_certificate_chain_file(mctx->ssl_ctx,
+                                                    certfile) < 1)) {
+                ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02562)
+                             "Failed to configure certificate %s (with chain),"
+                             " check %s", key_id, certfile);
+                ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
+                return APR_EGENERAL;
+            }
 
-    have_rsa = ssl_server_import_cert(s, mctx, rsa_id, SSL_AIDX_RSA);
-    if (have_rsa != APR_SUCCESS && have_rsa != APR_NOTFOUND) {
-        return have_rsa;
-    }
-    have_dsa = ssl_server_import_cert(s, mctx, dsa_id, SSL_AIDX_DSA);
-    if (have_dsa != APR_SUCCESS && have_dsa != APR_NOTFOUND) {
-        return have_dsa;
-    }
-#ifdef HAVE_ECC
-    have_ecc = ssl_server_import_cert(s, mctx, ecc_id, SSL_AIDX_ECC);
-    if (have_ecc != APR_SUCCESS && have_ecc != APR_NOTFOUND) {
-        return have_ecc;
-    }
+#if defined(SSL_CTX_set1_chain)
+            /*
+             * OpenSSL 1.0.2 and later supports certificate-specific
+             * chains with intermediate CA certificates.
+             * SSL_CTX_use_certificate_chain_file currently (Dec 2013)
+             * loads them to ctx->extra_certs, however, which possibly
+             * overwrites a previously configured chain.
+             * If more than one SSLCertificateFile is configured for
+             * this server_rec, we manually "convert" the chain
+             * to a per-certificate setting.
+             */
+            if (mctx->pks->cert_files->nelts > 1) {
+                STACK_OF(X509) *extra_certs;
+                if ((SSL_CTX_get_extra_chain_certs(mctx->ssl_ctx,
+                                                   &extra_certs) > 0) &&
+                    (sk_X509_num(extra_certs) > 0) &&
+                    (SSL_CTX_set1_chain(mctx->ssl_ctx, extra_certs) > 0)) {
+                        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                                     APLOGNO(02563)
+                                     "Per-certificate chain for %s configured "
+                                     "(%d certificate[s])",
+                                     key_id, sk_X509_num(extra_certs));
+                        /* clear the "global" chain for this SSL_CTX */
+                        SSL_CTX_clear_extra_chain_certs(mctx->ssl_ctx);
+                }
+            }
 #endif
+        }
 
-    if ((have_rsa != APR_SUCCESS) && (have_dsa != APR_SUCCESS)
-#ifdef HAVE_ECC
-        && (have_ecc != APR_SUCCESS)
+        /* and second, the private key */
+        keyfile = APR_ARRAY_IDX(mctx->pks->key_files, i, const char *);
+        if (keyfile == NULL)
+            keyfile = certfile;
+
+        ERR_clear_error();
+
+        if ((SSL_CTX_use_PrivateKey_file(mctx->ssl_ctx, keyfile,
+                                         SSL_FILETYPE_PEM) < 1) &&
+            (ERR_GET_FUNC(ERR_peek_last_error())
+                != X509_F_X509_CHECK_PRIVATE_KEY)) {
+            ssl_asn1_t *asn1;
+            EVP_PKEY *pkey;
+            const unsigned char *ptr;
+
+            /* perhaps it's an encrypted private key, so try again */
+            ssl_load_encrypted_pkey(s, ptemp, i, &pphrases);
+
+            if (!(asn1 = ssl_asn1_table_get(mc->tPrivateKey, key_id)) ||
+                !(ptr = asn1->cpData) ||
+                !(pkey = d2i_AutoPrivateKey(NULL, &ptr, asn1->nData)) ||
+                (SSL_CTX_use_PrivateKey(mctx->ssl_ctx, pkey) < 1)) {
+                ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02564)
+                             "Failed to configure encrypted (?) private key %s,"
+                             " check %s", key_id, keyfile);
+                ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
+                return APR_EGENERAL;
+            }
+        }
+
+        if (SSL_CTX_check_private_key(mctx->ssl_ctx) < 1) {
+            ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02565)
+                         "Certificate and private key %s from %s and %s "
+                         "do not match", key_id, certfile, keyfile);
+            return APR_EGENERAL;
+        }
+
+#ifdef HAVE_SSL_CONF_CMD
+        /* 
+         * workaround for those OpenSSL versions where SSL_CTX_get0_certificate
+         * is not yet available: create an SSL struct which we dispose of
+         * as soon as we no longer need access to the cert. (Strictly speaking,
+         * SSL_CTX_get0_certificate does not depend on the SSL_CONF stuff,
+         * but there's no reliable way to check for its existence, so we
+         * assume that if SSL_CONF is available, it's OpenSSL 1.0.2 or later,
+         * and SSL_CTX_get0_certificate is implemented.)
+         */
+        if (!(cert = SSL_CTX_get0_certificate(mctx->ssl_ctx))) {
+#else
+        if (!(ssl = SSL_new(mctx->ssl_ctx)) ||
+            !(cert = SSL_get_certificate(ssl))) {
 #endif
-) {
-        ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01910)
-                "Oops, no " KEYTYPES " server certificate found "
-                "for '%s:%d'?!", s->server_hostname, s->port);
-        return ssl_die(s);
-    }
+            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02566)
+                         "Unable to retrieve certificate %s", key_id);
+#ifndef HAVE_SSL_CONF_CMD
+            if (ssl)
+                SSL_free(ssl);
+#endif
+            return APR_EGENERAL;
+        }
 
-    for (i = 0; i < SSL_AIDX_MAX; i++) {
-        ssl_check_public_cert(s, ptemp, mctx->pks->certs[i], i);
-    }
+        /* warn about potential cert issues */
+        ssl_check_public_cert(s, ptemp, cert, key_id);
 
-    have_rsa = ssl_server_import_key(s, mctx, rsa_id, SSL_AIDX_RSA);
-    if (have_rsa != APR_SUCCESS && have_rsa != APR_NOTFOUND) {
-        return have_rsa;
-    }
-    have_dsa = ssl_server_import_key(s, mctx, dsa_id, SSL_AIDX_DSA);
-    if (have_dsa != APR_SUCCESS && have_dsa != APR_NOTFOUND) {
-        return have_dsa;
-    }
-#ifdef HAVE_ECC
-    have_ecc = ssl_server_import_key(s, mctx, ecc_id, SSL_AIDX_ECC);
-    if (have_ecc != APR_SUCCESS && have_ecc != APR_NOTFOUND) {
-        return have_ecc;
-    }
+#ifdef HAVE_OCSP_STAPLING
+        if ((mctx->stapling_enabled == TRUE) &&
+            !ssl_stapling_init_cert(s, mctx, cert)) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02567)
+                         "Unable to configure certificate %s for stapling",
+                         key_id);
+        }
 #endif
 
-    if ((have_rsa != APR_SUCCESS) && (have_dsa != APR_SUCCESS)
-#ifdef HAVE_ECC
-        && (have_ecc != APR_SUCCESS)
+#ifndef HAVE_SSL_CONF_CMD
+        SSL_free(ssl);
 #endif
-          ) {
-        ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01911)
-                "Oops, no " KEYTYPES " server private key found?!");
-        return ssl_die(s);
+
+        ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(02568)
+                     "Certificate and private key %s configured from %s and %s",
+                     key_id, certfile, keyfile);
     }
 
     /*
      * Try to read DH parameters from the (first) SSLCertificateFile
      */
-    if ((mctx->pks->cert_files[0] != NULL) &&
-        (dhparams = ssl_dh_GetParamFromFile(mctx->pks->cert_files[0]))) {
+    if ((certfile = APR_ARRAY_IDX(mctx->pks->cert_files, 0, const char *)) &&
+        (dhparams = ssl_dh_GetParamFromFile(certfile))) {
         SSL_CTX_set_tmp_dh(mctx->ssl_ctx, dhparams);
         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02540)
                      "Custom DH parameters (%d bits) for %s loaded from %s",
-                     BN_num_bits(dhparams->p), vhost_id,
-                     mctx->pks->cert_files[0]);
+                     BN_num_bits(dhparams->p), vhost_id, certfile);
     }
 
 #ifdef HAVE_ECC
     /*
      * Similarly, try to read the ECDH curve name from SSLCertificateFile...
      */
-    if ((mctx->pks->cert_files[0] != NULL) &&
-        (ecparams = ssl_ec_GetParamFromFile(mctx->pks->cert_files[0])) &&
+    if ((certfile != NULL) && 
+        (ecparams = ssl_ec_GetParamFromFile(certfile)) &&
         (nid = EC_GROUP_get_curve_name(ecparams)) &&
         (eckey = EC_KEY_new_by_curve_name(nid))) {
         SSL_CTX_set_tmp_ecdh(mctx->ssl_ctx, eckey);
         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02541)
                      "ECDH curve %s for %s specified in %s",
-                     OBJ_nid2sn(nid), vhost_id, mctx->pks->cert_files[0]);
+                     OBJ_nid2sn(nid), vhost_id, certfile);
     }
     /*
      * ...otherwise, configure NIST P-256 (required to enable ECDHE)
@@ -1325,7 +1282,8 @@ static apr_status_t ssl_init_proxy_ctx(server_rec *s,
 static apr_status_t ssl_init_server_ctx(server_rec *s,
                                         apr_pool_t *p,
                                         apr_pool_t *ptemp,
-                                        SSLSrvConfigRec *sc)
+                                        SSLSrvConfigRec *sc,
+                                        apr_array_header_t *pphrases)
 {
     apr_status_t rv;
 #ifdef HAVE_SSL_CONF_CMD
@@ -1334,15 +1292,22 @@ static apr_status_t ssl_init_server_ctx(server_rec *s,
     int i;
 #endif
 
-    if ((rv = ssl_init_server_check(s, p, ptemp, sc->server)) != APR_SUCCESS) {
-        return rv;
+    /*
+     *  Check for problematic re-initializations
+     */
+    if (sc->server->ssl_ctx) {
+        ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02569)
+                     "Illegal attempt to re-initialise SSL for server "
+                     "(SSLEngine On should go in the VirtualHost, not in global scope.)");
+        return APR_EGENERAL;
     }
 
     if ((rv = ssl_init_ctx(s, p, ptemp, sc->server)) != APR_SUCCESS) {
         return rv;
     }
 
-    if ((rv = ssl_init_server_certs(s, p, ptemp, sc->server)) != APR_SUCCESS) {
+    if ((rv = ssl_init_server_certs(s, p, ptemp, sc->server, pphrases))
+        != APR_SUCCESS) {
         return rv;
     }
 
@@ -1360,6 +1325,54 @@ static apr_status_t ssl_init_server_ctx(server_rec *s,
                          "\"SSLOpenSSLConfCmd %s %s\" applied to %s",
                          param->name, param->value, sc->vhost_id);
         }
+        if (!strcasecmp(param->name, "Certificate")) {
+            /*
+             * Special case: a certificate has been loaded via
+             * SSLOpenSSLConfCmd. Two potential tweaks are needed
+             * (similar to what is done in ssl_init_server_certs,
+             * see the comments there for the rationale):
+             * a) "fixing up" the per-certificate chain
+             * b) configure OCSP stapling for the cert
+             */
+#if defined(SSL_CTX_set1_chain)
+            STACK_OF(X509) *extra_certs;
+            if ((SSL_CTX_get_extra_chain_certs(sc->server->ssl_ctx,
+                                               &extra_certs) > 0) &&
+                (sk_X509_num(extra_certs) > 0) &&
+                (SSL_CTX_set1_chain(sc->server->ssl_ctx, extra_certs) > 0)) {
+                    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02570)
+                                 "Per-certificate chain for certificate "
+                                 "loaded from %s for %s configured "
+                                 "(%d certificate[s])",
+                                 param->value, sc->vhost_id,
+                                 sk_X509_num(extra_certs));
+                    /* clear the "global" chain for this SSL_CTX */
+                    SSL_CTX_clear_extra_chain_certs(sc->server->ssl_ctx);
+            }
+#endif
+#ifdef HAVE_OCSP_STAPLING
+            if (sc->server->stapling_enabled == TRUE) {
+                X509 *cert;
+#ifndef HAVE_SSL_CONF_CMD
+                SSL *ssl;
+                if (!(ssl = SSL_new(sc->server->ssl_ctx)) ||
+                    !(cert = SSL_get_certificate(ssl)) ||
+#else
+                if (!(cert = SSL_CTX_get0_certificate(sc->server->ssl_ctx)) ||
+#endif
+                    !ssl_stapling_init_cert(s, sc->server, cert)) {
+                    ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02571)
+                                 "Unable to configure certificate loaded "
+                                 "from %s for %s for stapling",
+                                 param->value, sc->vhost_id);
+                }
+#ifndef HAVE_SSL_CONF_CMD
+                if (ssl)
+                    SSL_free(ssl);
+#endif
+            }
+#endif
+        }
     }
     if (SSL_CONF_CTX_finish(cctx) == 0) {
             ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02547)
@@ -1371,6 +1384,14 @@ static apr_status_t ssl_init_server_ctx(server_rec *s,
     SSL_CONF_CTX_free(cctx);
 #endif
 
+    if (SSL_CTX_check_private_key(sc->server->ssl_ctx) != 1) {
+        ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02572)
+                     "Failed to configure at least one certificate and key "
+                     "for %s", sc->vhost_id);
+        ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
+        return ssl_die(s);
+    }
+
 #ifdef HAVE_TLS_SESSION_TICKETS
     if ((rv = ssl_init_ticket_key(s, p, ptemp, sc->server)) != APR_SUCCESS) {
         return rv;
@@ -1386,7 +1407,8 @@ static apr_status_t ssl_init_server_ctx(server_rec *s,
 apr_status_t ssl_init_ConfigureServer(server_rec *s,
                                       apr_pool_t *p,
                                       apr_pool_t *ptemp,
-                                      SSLSrvConfigRec *sc)
+                                      SSLSrvConfigRec *sc,
+                                      apr_array_header_t *pphrases)
 {
     apr_status_t rv;
 
@@ -1395,7 +1417,8 @@ apr_status_t ssl_init_ConfigureServer(server_rec *s,
     if ((sc->enabled == SSL_ENABLED_TRUE) || (sc->enabled == SSL_ENABLED_OPTIONAL)) {
         ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(01914)
                      "Configuring server %s for SSL protocol", sc->vhost_id);
-        if ((rv = ssl_init_server_ctx(s, p, ptemp, sc)) != APR_SUCCESS) {
+        if ((rv = ssl_init_server_ctx(s, p, ptemp, sc, pphrases))
+            != APR_SUCCESS) {
             return rv;
         }
     }
@@ -1672,21 +1695,6 @@ static void ssl_init_ctx_cleanup_proxy(modssl_ctx_t *mctx)
     }
 }
 
-static void ssl_init_ctx_cleanup_server(modssl_ctx_t *mctx)
-{
-    int i;
-
-    ssl_init_ctx_cleanup(mctx);
-
-    for (i=0; i < SSL_AIDX_MAX; i++) {
-        MODSSL_CFG_ITEM_FREE(X509_free,
-                             mctx->pks->certs[i]);
-
-        MODSSL_CFG_ITEM_FREE(EVP_PKEY_free,
-                             mctx->pks->keys[i]);
-    }
-}
-
 apr_status_t ssl_init_ModuleKill(void *data)
 {
     SSLSrvConfigRec *sc;
@@ -1707,9 +1715,8 @@ apr_status_t ssl_init_ModuleKill(void *data)
 
         ssl_init_ctx_cleanup_proxy(sc->proxy);
 
-        ssl_init_ctx_cleanup_server(sc->server);
+        ssl_init_ctx_cleanup(sc->server);
     }
 
     return APR_SUCCESS;
 }
-
diff --git a/modules/ssl/ssl_engine_pphrase.c b/modules/ssl/ssl_engine_pphrase.c
index 4583a99367..4d06c4fe03 100644
--- a/modules/ssl/ssl_engine_pphrase.c
+++ b/modules/ssl/ssl_engine_pphrase.c
@@ -36,17 +36,19 @@ typedef struct {
     apr_array_header_t *aPassPhrase;
     int                 nPassPhraseCur;
     char               *cpPassPhraseCur;
-    char               *an;
     int                 nPassPhraseDialog;
     int                 nPassPhraseDialogCur;
     BOOL                bPassPhraseDialogOnce;
+    const char         *key_id;
+    const char         *pkey_file;
 } pphrase_cb_arg_t;
 
 /*
  * Return true if the named file exists and is readable
  */
 
-static apr_status_t exists_and_readable(char *fname, apr_pool_t *pool, apr_time_t *mtime)
+static apr_status_t exists_and_readable(const char *fname, apr_pool_t *pool,
+                                        apr_time_t *mtime)
 {
     apr_status_t stat;
     apr_finfo_t sbuf;
@@ -85,11 +87,11 @@ static apr_status_t exists_and_readable(char *fname, apr_pool_t *pool, apr_time_
  * since apr_array_push() will apr_alloc arr->nalloc * 2 elts,
  * leaving the original arr->elts to waste.
  */
-static char *asn1_table_vhost_key(SSLModConfigRec *mc, apr_pool_t *p,
-                                  const char *id, char *an)
+static const char *asn1_table_vhost_key(SSLModConfigRec *mc, apr_pool_t *p,
+                                  const char *id, int i)
 {
     /* 'p' pool used here is cleared on restarts (or sooner) */
-    char *key = apr_psprintf(p, "%s:%s", id, an);
+    char *key = apr_psprintf(p, "%s:%d", id, i);
     void *keyptr = apr_hash_get(mc->tVHostKeys, key,
                                 APR_HASH_KEY_STRING);
 
@@ -126,430 +128,260 @@ static char *pphrase_array_get(apr_array_header_t *arr, int idx)
     return ((char **)arr->elts)[idx];
 }
 
-static void pphrase_array_clear(apr_array_header_t *arr)
-{
-    if (arr->nelts > 0) {
-        memset(arr->elts, 0, arr->elt_size * arr->nelts);
-    }
-    arr->nelts = 0;
-}
-
-/* Abandon all hope, ye who read this code.  Don't believe the name:
- * "passphrase handling" is really a peripheral (if complex) concern;
- * the core purpose of this function to load into memory all
- * configured certs and key from files.  The private key handling in
- * here should be split out into a separate function for improved
- * readability.
- */
-apr_status_t ssl_pphrase_Handle(server_rec *s, apr_pool_t *p)
+apr_status_t ssl_load_encrypted_pkey(server_rec *s, apr_pool_t *p, int idx,
+                                     apr_array_header_t **pphrases)
 {
     SSLModConfigRec *mc = myModConfig(s);
-    SSLSrvConfigRec *sc;
-    server_rec *pServ;
-    char szPath[MAX_STRING_LEN];
-    EVP_PKEY *pPrivateKey;
+    SSLSrvConfigRec *sc = mySrvConfig(s);
+    const char *key_id = asn1_table_vhost_key(mc, p, sc->vhost_id, idx);
+    EVP_PKEY *pPrivateKey = NULL;
     ssl_asn1_t *asn1;
     unsigned char *ucp;
     long int length;
-    X509 *pX509Cert;
     BOOL bReadable;
-    int nPassPhrase = 0;
-    int nPassPhraseRetry;
-    int i, j;
-    ssl_algo_t algoCert, algoKey, at;
-    char *an;
+    int nPassPhrase = (*pphrases)->nelts;
+    int nPassPhraseRetry = 0;
     apr_time_t pkey_mtime = 0;
     apr_status_t rv;
-    pphrase_cb_arg_t *ppcb_arg = apr_pcalloc(p, sizeof(*ppcb_arg));
-    ppcb_arg->p = p;
-    /*
-     * Start with a fresh pass phrase array
-     */
-    ppcb_arg->aPassPhrase = apr_array_make(p, 2, sizeof(char *));
+    pphrase_cb_arg_t ppcb_arg = {
+        s,
+        p,
+        *pphrases,
+        0,
+        NULL,
+        0,
+        0,
+        TRUE,
+        key_id,
+        APR_ARRAY_IDX(sc->server->pks->key_files, idx, const char *)
+    };
+
+    if (!ppcb_arg.pkey_file) {
+         ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02573)
+                      "Init: No private key specified for %s", key_id);
+         return ssl_die(s);
+    }
+    else if ((rv = exists_and_readable(ppcb_arg.pkey_file, p,
+                                       &pkey_mtime)) != APR_SUCCESS ) {
+         ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(02574)
+                      "Init: Can't open server private key file %s",
+                      ppcb_arg.pkey_file);
+         return ssl_die(s);
+    }
 
     /*
-     * Walk through all configured servers
+     * if the private key is encrypted and SSLPassPhraseDialog
+     * is configured to "builtin" it isn't possible to prompt for
+     * a password after httpd has detached from the tty.
+     * in this case if we already have a private key and the
+     * file name/mtime hasn't changed, then reuse the existing key.
+     * we also reuse existing private keys that were encrypted for
+     * exec: and pipe: dialogs to minimize chances to snoop the
+     * password.  that and pipe: dialogs might prompt the user
+     * for password, which on win32 for example could happen 4
+     * times at startup.  twice for each child and twice within
+     * each since apache "restarts itself" on startup.
+     * of course this will not work for the builtin dialog if
+     * the server was started without LoadModule ssl_module
+     * configured, then restarted with it configured.
+     * but we fall through with a chance of success if the key
+     * is not encrypted or can be handled via exec or pipe dialog.
+     * and in the case of fallthrough, pkey_mtime and isatty()
+     * are used to give a better idea as to what failed.
      */
-    for (pServ = s; pServ != NULL; pServ = pServ->next) {
-        sc = mySrvConfig(pServ);
-        if (!sc->enabled) {
-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, pServ, APLOGNO(02199)
-                         "SSL not enabled on vhost %s, skipping SSL setup",
-                         sc->vhost_id);
-            continue;
+    if (pkey_mtime) {
+        ssl_asn1_t *asn1 = ssl_asn1_table_get(mc->tPrivateKey, key_id);
+        if (asn1 && (asn1->source_mtime == pkey_mtime)) {
+            ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(02575)
+                         "Reusing existing private key from %s on restart",
+                         ppcb_arg.pkey_file);
+            return APR_SUCCESS;
         }
+    }
 
-        ap_log_error(APLOG_MARK, APLOG_INFO, 0, pServ, APLOGNO(02200)
-                     "Loading certificate & private key of SSL-aware server '%s'",
-                     sc->vhost_id);
+    ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(02576)
+                 "Attempting to load encrypted (?) private key %s", key_id);
 
+    for (;;) {
         /*
-         * Read in server certificate(s): This is the easy part
-         * because this file isn't encrypted in any way.
+         * Try to read the private key file with the help of
+         * the callback function which serves the pass
+         * phrases to OpenSSL
          */
-        if (sc->server->pks->cert_files[0] == NULL) {
-            ap_log_error(APLOG_MARK, APLOG_EMERG, 0, pServ, APLOGNO(02240)
-                         "Server should be SSL-aware but has no certificate "
-                         "configured [Hint: SSLCertificateFile] (%s:%d)",
-                         pServ->defn_name, pServ->defn_line_number);
-            return ssl_die(pServ);
-        }
 
-        /* Bitmasks for all key algorithms configured for this server;
-         * initialize to zero. */
-        algoCert = SSL_ALGO_UNKNOWN;
-        algoKey  = SSL_ALGO_UNKNOWN;
-
-        /* Iterate through configured certificate files for this
-         * server. */
-        for (i = 0, j = 0; i < SSL_AIDX_MAX
-                 && (sc->server->pks->cert_files[i] != NULL); i++) {
-            const char *key_id;
-            int using_cache = 0;
-
-            apr_cpystrn(szPath, sc->server->pks->cert_files[i], sizeof(szPath));
-            if ((rv = exists_and_readable(szPath, p, NULL)) != APR_SUCCESS) {
-                ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(02201)
-                             "Init: Can't open server certificate file %s",
-                             szPath);
-                return ssl_die(s);
-            }
-            if ((pX509Cert = SSL_read_X509(szPath, NULL, NULL)) == NULL) {
-                ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02241)
-                             "Init: Unable to read server certificate from"
-                             " file %s", szPath);
-                ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
-                return ssl_die(s);
-            }
-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02202)
-                         "Init: Read server certificate from '%s'", szPath);
-
-            /*
-             * check algorithm type of certificate and make
-             * sure only one certificate per type is used.
-             */
-            at = ssl_util_algotypeof(pX509Cert, NULL);
-            an = ssl_util_algotypestr(at);
-            if (algoCert & at) {
-                ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02242)
-                             "Init: Multiple %s server certificates not "
-                             "allowed", an);
-                ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
-                return ssl_die(s);
-            }
-            algoCert |= at;
+        ppcb_arg.cpPassPhraseCur = NULL;
 
-            /* Determine the hash key used for this (vhost, algo-type)
-             * pair used to index both the mc->tPrivateKey and
-             * mc->tPublicCert tables: */
-            key_id = asn1_table_vhost_key(mc, p, sc->vhost_id, an);
+        /* Ensure that the error stack is empty; some SSL
+         * functions will fail spuriously if the error stack
+         * is not empty. */
+        ERR_clear_error();
 
-            /*
-             * Insert the certificate into global module configuration to let it
-             * survive the processing between the 1st Apache API init round (where
-             * we operate here) and the 2nd Apache init round (where the
-             * certificate is actually used to configure mod_ssl's per-server
-             * configuration structures).
-             */
-            length = i2d_X509(pX509Cert, NULL);
-            ucp = ssl_asn1_table_set(mc->tPublicCert, key_id, length);
-            (void)i2d_X509(pX509Cert, &ucp); /* 2nd arg increments */
-
-            /*
-             * Free the X509 structure
-             */
-            X509_free(pX509Cert);
+        bReadable = ((pPrivateKey = SSL_read_PrivateKey(ppcb_arg.pkey_file,
+                     NULL, ssl_pphrase_Handle_CB, &ppcb_arg)) != NULL ?
+                     TRUE : FALSE);
 
-            /*
-             * Read in the private key: This is the non-trivial part, because the
-             * key is typically encrypted, so a pass phrase dialog has to be used
-             * to request it from the user (or it has to be alternatively gathered
-             * from a dialog program). The important point here is that ISPs
-             * usually have hundrets of virtual servers configured and a lot of
-             * them use SSL, so really we have to minimize the pass phrase
-             * dialogs.
-             *
-             * The idea is this: When N virtual hosts are configured and all of
-             * them use encrypted private keys with different pass phrases, we
-             * have no chance and have to pop up N pass phrase dialogs. But
-             * usually the admin is clever enough and uses the same pass phrase
-             * for more private key files (typically he even uses one single pass
-             * phrase for all). When this is the case we can minimize the dialogs
-             * by trying to re-use already known/entered pass phrases.
-             */
-            if (sc->server->pks->key_files[j] != NULL)
-                apr_cpystrn(szPath, sc->server->pks->key_files[j++], sizeof(szPath));
-
-            /*
-             * Try to read the private key file with the help of
-             * the callback function which serves the pass
-             * phrases to OpenSSL
-             */
-            ppcb_arg->s                     = pServ;
-            ppcb_arg->nPassPhraseCur        = 0;
-            ppcb_arg->an                    = an;
-            ppcb_arg->nPassPhraseDialogCur  = 0;
-            ppcb_arg->bPassPhraseDialogOnce = TRUE;
-
-            nPassPhraseRetry = 0;
-
-            pPrivateKey = NULL;
-
-            for (;;) {
-                /*
-                 * Try to read the private key file with the help of
-                 * the callback function which serves the pass
-                 * phrases to OpenSSL
-                 */
-                if ((rv = exists_and_readable(szPath, p,
-                                              &pkey_mtime)) != APR_SUCCESS ) {
-                     ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(02243)
-                                  "Init: Can't open server private key file "
-                                  "%s",szPath);
-                     return ssl_die(s);
-                }
-
-                /*
-                 * if the private key is encrypted and SSLPassPhraseDialog
-                 * is configured to "builtin" it isn't possible to prompt for
-                 * a password after httpd has detached from the tty.
-                 * in this case if we already have a private key and the
-                 * file name/mtime hasn't changed, then reuse the existing key.
-                 * we also reuse existing private keys that were encrypted for
-                 * exec: and pipe: dialogs to minimize chances to snoop the
-                 * password.  that and pipe: dialogs might prompt the user
-                 * for password, which on win32 for example could happen 4
-                 * times at startup.  twice for each child and twice within
-                 * each since apache "restarts itself" on startup.
-                 * of course this will not work for the builtin dialog if
-                 * the server was started without LoadModule ssl_module
-                 * configured, then restarted with it configured.
-                 * but we fall through with a chance of success if the key
-                 * is not encrypted or can be handled via exec or pipe dialog.
-                 * and in the case of fallthrough, pkey_mtime and isatty()
-                 * are used to give a better idea as to what failed.
-                 */
-                if (pkey_mtime) {
-                    ssl_asn1_t *asn1 =
-                        ssl_asn1_table_get(mc->tPrivateKey, key_id);
-
-                    if (asn1 && (asn1->source_mtime == pkey_mtime)) {
-                        ap_log_error(APLOG_MARK, APLOG_INFO,
-                                     0, pServ, APLOGNO(02244)
-                                     "%s reusing existing "
-                                     "%s private key on restart",
-                                     sc->vhost_id, ssl_asn1_keystr(i));
-                        using_cache = 1;
-                        break;
-                    }
-                }
+        /*
+         * when the private key file now was readable,
+         * it's fine and we go out of the loop
+         */
+        if (bReadable)
+           break;
 
-                ppcb_arg->cpPassPhraseCur = NULL;
-
-                /* Ensure that the error stack is empty; some SSL
-                 * functions will fail spuriously if the error stack
-                 * is not empty. */
-                ERR_clear_error();
-
-                bReadable = ((pPrivateKey = SSL_read_PrivateKey(szPath, NULL,
-                            ssl_pphrase_Handle_CB, ppcb_arg)) != NULL ?
-                            TRUE : FALSE);
-
-                /*
-                 * when the private key file now was readable,
-                 * it's fine and we go out of the loop
-                 */
-                if (bReadable)
-                   break;
-
-                /*
-                 * when we have more remembered pass phrases
-                 * try to reuse these first.
-                 */
-                if (ppcb_arg->nPassPhraseCur < nPassPhrase) {
-                    ppcb_arg->nPassPhraseCur++;
-                    continue;
-                }
+        /*
+         * when we have more remembered pass phrases
+         * try to reuse these first.
+         */
+        if (ppcb_arg.nPassPhraseCur < nPassPhrase) {
+            ppcb_arg.nPassPhraseCur++;
+            continue;
+        }
 
-                /*
-                 * else it's not readable and we have no more
-                 * remembered pass phrases. Then this has to mean
-                 * that the callback function popped up the dialog
-                 * but a wrong pass phrase was entered.  We give the
-                 * user (but not the dialog program) a few more
-                 * chances...
-                 */
+        /*
+         * else it's not readable and we have no more
+         * remembered pass phrases. Then this has to mean
+         * that the callback function popped up the dialog
+         * but a wrong pass phrase was entered.  We give the
+         * user (but not the dialog program) a few more
+         * chances...
+         */
 #ifndef WIN32
-                if ((sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN
-                       || sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE)
+        if ((sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN
+             || sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE)
 #else
-                if (sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE
+        if (sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE
 #endif
-                    && ppcb_arg->cpPassPhraseCur != NULL
-                    && nPassPhraseRetry < BUILTIN_DIALOG_RETRIES ) {
-                    apr_file_printf(writetty, "Apache:mod_ssl:Error: Pass phrase incorrect "
-                            "(%d more retr%s permitted).\n",
-                            (BUILTIN_DIALOG_RETRIES-nPassPhraseRetry),
-                            (BUILTIN_DIALOG_RETRIES-nPassPhraseRetry) == 1 ? "y" : "ies");
-                    nPassPhraseRetry++;
-                    if (nPassPhraseRetry > BUILTIN_DIALOG_BACKOFF)
-                        apr_sleep((nPassPhraseRetry-BUILTIN_DIALOG_BACKOFF)
-                                    * 5 * APR_USEC_PER_SEC);
-                    continue;
-                }
+            && ppcb_arg.cpPassPhraseCur != NULL
+            && nPassPhraseRetry < BUILTIN_DIALOG_RETRIES ) {
+            apr_file_printf(writetty, "Apache:mod_ssl:Error: Pass phrase incorrect "
+                    "(%d more retr%s permitted).\n",
+                    (BUILTIN_DIALOG_RETRIES-nPassPhraseRetry),
+                    (BUILTIN_DIALOG_RETRIES-nPassPhraseRetry) == 1 ? "y" : "ies");
+            nPassPhraseRetry++;
+            if (nPassPhraseRetry > BUILTIN_DIALOG_BACKOFF)
+                apr_sleep((nPassPhraseRetry-BUILTIN_DIALOG_BACKOFF)
+                            * 5 * APR_USEC_PER_SEC);
+            continue;
+        }
 #ifdef WIN32
-                if (sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN) {
-                    ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02245)
-                                 "Init: SSLPassPhraseDialog builtin is not "
-                                 "supported on Win32 (key file "
-                                 "%s)", szPath);
-                    return ssl_die(s);
-                }
+        if (sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN) {
+            ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02577)
+                         "Init: SSLPassPhraseDialog builtin is not "
+                         "supported on Win32 (key file "
+                         "%s)", ppcb_arg.pkey_file);
+            return ssl_die(s);
+        }
 #endif /* WIN32 */
 
-                /*
-                 * Ok, anything else now means a fatal error.
-                 */
-                if (ppcb_arg->cpPassPhraseCur == NULL) {
-                    if (ppcb_arg->nPassPhraseDialogCur && pkey_mtime &&
-                        !isatty(fileno(stdout))) /* XXX: apr_isatty() */
-                    {
-                        ap_log_error(APLOG_MARK, APLOG_ERR, 0,
-                                     pServ, APLOGNO(02246)
-                                     "Init: Unable to read pass phrase "
-                                     "[Hint: key introduced or changed "
-                                     "before restart?]");
-                        ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, pServ);
-                    }
-                    else {
-                        ap_log_error(APLOG_MARK, APLOG_ERR, 0,
-                                     pServ, APLOGNO(02203) "Init: Private key not found");
-                        ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, pServ);
-                    }
-                    if (writetty) {
-                        apr_file_printf(writetty, "Apache:mod_ssl:Error: Private key not found.\n");
-                        apr_file_printf(writetty, "**Stopped\n");
-                    }
-                }
-                else {
-                    ap_log_error(APLOG_MARK, APLOG_EMERG, 0, pServ, APLOGNO(02204)
-                                 "Init: Pass phrase incorrect for key of %s",
-                                 sc->vhost_id);
-                    ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, pServ);
-
-                    if (writetty) {
-                        apr_file_printf(writetty, "Apache:mod_ssl:Error: Pass phrase incorrect.\n");
-                        apr_file_printf(writetty, "**Stopped\n");
-                    }
-                }
-                return ssl_die(pServ);
-            }
-
-            /* If a cached private key was found, nothing more to do
-             * here; loop through to the next configured cert for this
-             * vhost. */
-            if (using_cache)
-                continue;
-
-            if (pPrivateKey == NULL) {
-                ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02247)
-                            "Init: Unable to read server private key from "
-                            "file %s [Hint: Perhaps it is in a separate file? "
-                            "  See SSLCertificateKeyFile]", szPath);
-                ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
-                return ssl_die(s);
-            }
-
-            /*
-             * check algorithm type of private key and make
-             * sure only one private key per type is used.
-             */
-            at = ssl_util_algotypeof(NULL, pPrivateKey);
-            an = ssl_util_algotypestr(at);
-            if (algoKey & at) {
-                ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02248)
-                             "Init: Multiple %s server private keys not "
-                             "allowed", an);
-                ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
-                return ssl_die(s);
-            }
-            algoKey |= at;
-
-            /*
-             * Log the type of reading
-             */
-            if (ppcb_arg->nPassPhraseDialogCur == 0) {
-                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, pServ, APLOGNO(02249)
-                             "unencrypted %s private key - pass phrase not "
-                             "required", an);
+        /*
+         * Ok, anything else now means a fatal error.
+         */
+        if (ppcb_arg.cpPassPhraseCur == NULL) {
+            if (ppcb_arg.nPassPhraseDialogCur && pkey_mtime &&
+                !isatty(fileno(stdout))) /* XXX: apr_isatty() */
+            {
+                ap_log_error(APLOG_MARK, APLOG_ERR, 0,
+                             s, APLOGNO(02578)
+                             "Init: Unable to read pass phrase "
+                             "[Hint: key introduced or changed "
+                             "before restart?]");
+                ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s);
             }
             else {
-                if (ppcb_arg->cpPassPhraseCur != NULL) {
-                    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
-                                 pServ, APLOGNO(02250)
-                                 "encrypted %s private key - pass phrase "
-                                 "requested", an);
-                }
-                else {
-                    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
-                                 pServ, APLOGNO(02251)
-                                 "encrypted %s private key - pass phrase"
-                                 " reused", an);
-                }
+                ap_log_error(APLOG_MARK, APLOG_ERR, 0,
+                             s, APLOGNO(02579) "Init: Private key not found");
+                ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s);
             }
-
-            /*
-             * Ok, when we have one more pass phrase store it
-             */
-            if (ppcb_arg->cpPassPhraseCur != NULL) {
-                *(const char **)apr_array_push(ppcb_arg->aPassPhrase) =
-                    ppcb_arg->cpPassPhraseCur;
-                nPassPhrase++;
+            if (writetty) {
+                apr_file_printf(writetty, "Apache:mod_ssl:Error: Private key not found.\n");
+                apr_file_printf(writetty, "**Stopped\n");
             }
-
-            /*
-             * Insert private key into the global module configuration
-             * (we convert it to a stand-alone DER byte sequence
-             * because the SSL library uses static variables inside a
-             * RSA structure which do not survive DSO reloads!)
-             */
-            length = i2d_PrivateKey(pPrivateKey, NULL);
-            ucp = ssl_asn1_table_set(mc->tPrivateKey, key_id, length);
-            (void)i2d_PrivateKey(pPrivateKey, &ucp); /* 2nd arg increments */
-
-            if (ppcb_arg->nPassPhraseDialogCur != 0) {
-                /* remember mtime of encrypted keys */
-                asn1 = ssl_asn1_table_get(mc->tPrivateKey, key_id);
-                asn1->source_mtime = pkey_mtime;
+        }
+        else {
+            ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02580)
+                         "Init: Pass phrase incorrect for key %s",
+                         key_id);
+            ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
+
+            if (writetty) {
+                apr_file_printf(writetty, "Apache:mod_ssl:Error: Pass phrase incorrect.\n");
+                apr_file_printf(writetty, "**Stopped\n");
             }
+        }
+        return ssl_die(s);
+    }
 
-            /*
-             * Free the private key structure
-             */
-            EVP_PKEY_free(pPrivateKey);
+    if (pPrivateKey == NULL) {
+        ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02581)
+                     "Init: Unable to read server private key from file %s",
+                     ppcb_arg.pkey_file);
+        ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
+        return ssl_die(s);
+    }
+
+    /*
+     * Log the type of reading
+     */
+    if (ppcb_arg.nPassPhraseDialogCur == 0) {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02582)
+                     "unencrypted %s private key - pass phrase not "
+                     "required", key_id);
+    }
+    else {
+        if (ppcb_arg.cpPassPhraseCur != NULL) {
+            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
+                         s, APLOGNO(02583)
+                         "encrypted %s private key - pass phrase "
+                         "requested", key_id);
         }
+        else {
+            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
+                         s, APLOGNO(02584)
+                         "encrypted %s private key - pass phrase"
+                         " reused", key_id);
+        }
+    }
+
+    /*
+     * Ok, when we have one more pass phrase store it
+     */
+    if (ppcb_arg.cpPassPhraseCur != NULL) {
+        *(const char **)apr_array_push(ppcb_arg.aPassPhrase) =
+            ppcb_arg.cpPassPhraseCur;
+        nPassPhrase++;
     }
 
+    /*
+     * Insert private key into the global module configuration
+     * (we convert it to a stand-alone DER byte sequence
+     * because the SSL library uses static variables inside a
+     * RSA structure which do not survive DSO reloads!)
+     */
+    length = i2d_PrivateKey(pPrivateKey, NULL);
+    ucp = ssl_asn1_table_set(mc->tPrivateKey, key_id, length);
+    (void)i2d_PrivateKey(pPrivateKey, &ucp); /* 2nd arg increments */
+
+    if (ppcb_arg.nPassPhraseDialogCur != 0) {
+        /* remember mtime of encrypted keys */
+        asn1 = ssl_asn1_table_get(mc->tPrivateKey, key_id);
+        asn1->source_mtime = pkey_mtime;
+    }
+
+    /*
+     * Free the private key structure
+     */
+    EVP_PKEY_free(pPrivateKey);
+
     /*
      * Let the user know when we're successful.
      */
-    if (ppcb_arg->nPassPhraseDialog > 0) {
+    if ((ppcb_arg.nPassPhraseDialog > 0) &&
+        (ppcb_arg.cpPassPhraseCur != NULL)) {
         if (writetty) {
             apr_file_printf(writetty, "\n"
                             "OK: Pass Phrase Dialog successful.\n");
         }
     }
 
-    /*
-     * Wipe out the used memory from the
-     * pass phrase array and then deallocate it
-     */
-    if (ppcb_arg->aPassPhrase->nelts) {
-        pphrase_array_clear(ppcb_arg->aPassPhrase);
-        ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(02205)
-                     "Init: Wiped out the queried pass phrases from memory");
-    }
-
     /* Close the pipes if they were opened
      */
     if (readtty) {
@@ -662,7 +494,8 @@ int ssl_pphrase_Handle_CB(char *buf, int bufsize, int verify, void *srv)
                                  APLOGNO(01966)
                                  "Init: Failed to create pass phrase pipe '%s'",
                                  sc->server->pphrase_dialog_path);
-                    PEMerr(PEM_F_PEM_DEF_CALLBACK,PEM_R_PROBLEMS_GETTING_PASSWORD);
+                    PEMerr(PEM_F_PEM_DEF_CALLBACK,
+                           PEM_R_PROBLEMS_GETTING_PASSWORD);
                     memset(buf, 0, (unsigned int)bufsize);
                     return (-1);
                 }
@@ -672,7 +505,7 @@ int ssl_pphrase_Handle_CB(char *buf, int bufsize, int verify, void *srv)
         }
         else { /* sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN */
 #ifdef WIN32
-            PEMerr(PEM_F_PEM_DEF_CALLBACK,PEM_R_PROBLEMS_GETTING_PASSWORD);
+            PEMerr(PEM_F_PEM_DEF_CALLBACK, PEM_R_PROBLEMS_GETTING_PASSWORD);
             memset(buf, 0, (unsigned int)bufsize);
             return (-1);
 #else
@@ -705,8 +538,8 @@ int ssl_pphrase_Handle_CB(char *buf, int bufsize, int verify, void *srv)
         if (ppcb_arg->bPassPhraseDialogOnce) {
             ppcb_arg->bPassPhraseDialogOnce = FALSE;
             apr_file_printf(writetty, "\n");
-            apr_file_printf(writetty, "Server %s (%s)\n", sc->vhost_id,
-                            ppcb_arg->an);
+            apr_file_printf(writetty, "Private key %s (%s)\n",
+                            ppcb_arg->key_id, ppcb_arg->pkey_file);
         }
 
         /*
@@ -741,7 +574,7 @@ int ssl_pphrase_Handle_CB(char *buf, int bufsize, int verify, void *srv)
      */
     else if (sc->server->pphrase_dialog_type == SSL_PPTYPE_FILTER) {
         const char *cmd = sc->server->pphrase_dialog_path;
-        const char **argv = apr_palloc(ppcb_arg->p, sizeof(char *) * 4);
+        const char **argv = apr_palloc(ppcb_arg->p, sizeof(char *) * 3);
         char *result;
 
         ap_log_error(APLOG_MARK, APLOG_INFO, 0, ppcb_arg->s, APLOGNO(01969)
@@ -749,9 +582,8 @@ int ssl_pphrase_Handle_CB(char *buf, int bufsize, int verify, void *srv)
                      "program (%s)", cmd);
 
         argv[0] = cmd;
-        argv[1] = sc->vhost_id;
-        argv[2] = ppcb_arg->an;
-        argv[3] = NULL;
+        argv[1] = ppcb_arg->key_id;
+        argv[2] = NULL;
 
         result = ssl_util_readfilter(ppcb_arg->s, ppcb_arg->p, cmd, argv);
         apr_cpystrn(buf, result, bufsize);
@@ -768,4 +600,3 @@ int ssl_pphrase_Handle_CB(char *buf, int bufsize, int verify, void *srv)
      */
     return (len);
 }
-
diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h
index 39df190997..5f1fb23d2e 100644
--- a/modules/ssl/ssl_private.h
+++ b/modules/ssl/ssl_private.h
@@ -263,31 +263,6 @@ ap_set_module_config(c->conn_config, &ssl_module, val)
 #define DEFAULT_OCSP_TIMEOUT 10
 #endif
 
-/**
- * Define the certificate algorithm types
- */
-
-typedef int ssl_algo_t;
-
-#define SSL_ALGO_UNKNOWN (0)
-#define SSL_ALGO_RSA     (1<<0)
-#define SSL_ALGO_DSA     (1<<1)
-#ifdef HAVE_ECC
-#define SSL_ALGO_ECC     (1<<2)
-#define SSL_ALGO_ALL     (SSL_ALGO_RSA|SSL_ALGO_DSA|SSL_ALGO_ECC)
-#else
-#define SSL_ALGO_ALL     (SSL_ALGO_RSA|SSL_ALGO_DSA)
-#endif
-
-#define SSL_AIDX_RSA     (0)
-#define SSL_AIDX_DSA     (1)
-#ifdef HAVE_ECC
-#define SSL_AIDX_ECC     (2)
-#define SSL_AIDX_MAX     (3)
-#else
-#define SSL_AIDX_MAX     (2)
-#endif
-
 /**
  * Define the SSL options
  */
@@ -510,13 +485,10 @@ typedef struct {
     apr_array_header_t   *aRandSeed;
     apr_hash_t     *tVHostKeys;
 
-    /* Two hash tables of pointers to ssl_asn1_t structures.  The
-     * structures are used to store certificates and private keys
-     * respectively, in raw DER format (serialized OpenSSL X509 and
-     * PrivateKey structures).  The tables are indexed by (vhost-id,
-     * algorithm type) using the function ssl_asn1_table_keyfmt(); for
-     * example the string "vhost.example.com:443:RSA". */
-    apr_hash_t     *tPublicCert;
+    /* A hash table of pointers to ssl_asn1_t structures.  The structures
+     * are used to store private keys in raw DER format (serialized OpenSSL
+     * PrivateKey structures).  The table is indexed by (vhost-id,
+     * index), for example the string "vhost.example.com:443:0". */
     apr_hash_t     *tPrivateKey;
 
 #if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT)
@@ -531,20 +503,11 @@ typedef struct {
 } SSLModConfigRec;
 
 /** Structure representing configured filenames for certs and keys for
- * a given vhost, and the corresponding in-memory structures once the
- * files are parsed.  */
+ * a given vhost */
 typedef struct {
-    /* Lists of configured certs and keys for this server; from index
-     * 0 up to SSL_AIDX_MAX-1 or the first NULL pointer.  Note that
-     * these arrays are NOT indexed by algorithm type, they are simply
-     * unordered lists. */
-    const char  *cert_files[SSL_AIDX_MAX];
-    const char  *key_files[SSL_AIDX_MAX];
-    /* Loaded certs and keys; these arrays ARE indexed by the
-     * algorithm type, i.e.  keys[SSL_AIDX_RSA] maps to the RSA
-     * private key. */
-    X509        *certs[SSL_AIDX_MAX];
-    EVP_PKEY    *keys[SSL_AIDX_MAX];
+    /* Lists of configured certs and keys for this server */
+    apr_array_header_t *cert_files;
+    apr_array_header_t *key_files;
 
     /** Certificates which specify the set of CA names which should be
      * sent in the CertificateRequest message: */
@@ -782,7 +745,8 @@ const char *ssl_cmd_SSLFIPS(cmd_parms *cmd, void *dcfg, int flag);
 /**  module initialization  */
 apr_status_t ssl_init_Module(apr_pool_t *, apr_pool_t *, apr_pool_t *, server_rec *);
 apr_status_t ssl_init_Engine(server_rec *, apr_pool_t *);
-apr_status_t ssl_init_ConfigureServer(server_rec *, apr_pool_t *, apr_pool_t *, SSLSrvConfigRec *);
+apr_status_t ssl_init_ConfigureServer(server_rec *, apr_pool_t *, apr_pool_t *, SSLSrvConfigRec *,
+                                      apr_array_header_t *);
 apr_status_t ssl_init_CheckServers(server_rec *, apr_pool_t *);
 STACK_OF(X509_NAME)
             *ssl_init_FindCAList(server_rec *, apr_pool_t *, const char *, const char *);
@@ -870,13 +834,12 @@ void         ssl_util_ppclose(server_rec *, apr_pool_t *, apr_file_t *);
 char        *ssl_util_readfilter(server_rec *, apr_pool_t *, const char *,
                                  const char * const *);
 BOOL         ssl_util_path_check(ssl_pathcheck_t, const char *, apr_pool_t *);
-ssl_algo_t   ssl_util_algotypeof(X509 *, EVP_PKEY *);
-char        *ssl_util_algotypestr(ssl_algo_t);
 void         ssl_util_thread_setup(apr_pool_t *);
 int          ssl_init_ssl_connection(conn_rec *c, request_rec *r);
 
 /**  Pass Phrase Support  */
-apr_status_t ssl_pphrase_Handle(server_rec *, apr_pool_t *);
+apr_status_t ssl_load_encrypted_pkey(server_rec *, apr_pool_t *, int,
+                                     apr_array_header_t **);
 
 /**  Diffie-Hellman Parameter Support  */
 DH           *ssl_dh_GetParamFromFile(const char *);
@@ -894,12 +857,6 @@ ssl_asn1_t *ssl_asn1_table_get(apr_hash_t *table,
 void ssl_asn1_table_unset(apr_hash_t *table,
                           const char *key);
 
-const char *ssl_asn1_keystr(int keytype);
-
-const char *ssl_asn1_table_keyfmt(apr_pool_t *p,
-                                  const char *id,
-                                  int keytype);
-
 /**  Mutex Support  */
 int          ssl_mutex_init(server_rec *, apr_pool_t *);
 int          ssl_mutex_reinit(server_rec *, apr_pool_t *);
diff --git a/modules/ssl/ssl_util.c b/modules/ssl/ssl_util.c
index 5f8039c206..c21971dd77 100644
--- a/modules/ssl/ssl_util.c
+++ b/modules/ssl/ssl_util.c
@@ -135,61 +135,8 @@ BOOL ssl_util_path_check(ssl_pathcheck_t pcm, const char *path, apr_pool_t *p)
     return TRUE;
 }
 
-ssl_algo_t ssl_util_algotypeof(X509 *pCert, EVP_PKEY *pKey)
-{
-    ssl_algo_t t;
-    EVP_PKEY *pFreeKey = NULL;
-
-    t = SSL_ALGO_UNKNOWN;
-    if (pCert != NULL)
-        pFreeKey = pKey = X509_get_pubkey(pCert);
-    if (pKey != NULL) {
-        switch (EVP_PKEY_type(pKey->type)) {
-            case EVP_PKEY_RSA:
-                t = SSL_ALGO_RSA;
-                break;
-            case EVP_PKEY_DSA:
-                t = SSL_ALGO_DSA;
-                break;
-#ifdef HAVE_ECC
-            case EVP_PKEY_EC:
-                t = SSL_ALGO_ECC;
-                break;
-#endif
-            default:
-                break;
-        }
-    }
-    if (pFreeKey != NULL)
-        EVP_PKEY_free(pFreeKey);
-    return t;
-}
-
-char *ssl_util_algotypestr(ssl_algo_t t)
-{
-    char *cp;
-
-    cp = "UNKNOWN";
-    switch (t) {
-        case SSL_ALGO_RSA:
-            cp = "RSA";
-            break;
-        case SSL_ALGO_DSA:
-            cp = "DSA";
-            break;
-#ifdef HAVE_ECC
-        case SSL_ALGO_ECC:
-            cp = "ECC";
-            break;
-#endif
-        default:
-            break;
-    }
-    return cp;
-}
-
 /*
- * certain key and cert data needs to survive restarts,
+ * certain key data needs to survive restarts,
  * which are stored in the user data table of s->process->pool.
  * to prevent "leaking" of this data, we use malloc/free
  * rather than apr_palloc and these wrappers to help make sure
@@ -253,30 +200,6 @@ void ssl_asn1_table_unset(apr_hash_t *table,
     apr_hash_set(table, key, klen, NULL);
 }
 
-#ifdef HAVE_ECC
-static const char *ssl_asn1_key_types[] = {"RSA", "DSA", "ECC"};
-#else
-static const char *ssl_asn1_key_types[] = {"RSA", "DSA"};
-#endif
-
-const char *ssl_asn1_keystr(int keytype)
-{
-    if (keytype >= SSL_AIDX_MAX) {
-        return NULL;
-    }
-
-    return ssl_asn1_key_types[keytype];
-}
-
-const char *ssl_asn1_table_keyfmt(apr_pool_t *p,
-                                  const char *id,
-                                  int keytype)
-{
-    const char *keystr = ssl_asn1_keystr(keytype);
-
-    return apr_pstrcat(p, id, ":", keystr, NULL);
-}
-
 #if APR_HAS_THREADS
 /*
  * To ensure thread-safetyness in OpenSSL - work in progress
diff --git a/modules/ssl/ssl_util_ssl.c b/modules/ssl/ssl_util_ssl.c
index d2e3be366d..0bf377682c 100644
--- a/modules/ssl/ssl_util_ssl.c
+++ b/modules/ssl/ssl_util_ssl.c
@@ -70,52 +70,11 @@ void SSL_set_app_data2(SSL *ssl, void *arg)
 
 /*  _________________________________________________________________
 **
-**  High-Level Certificate / Private Key Loading
+**  High-Level Private Key Loading
 **  _________________________________________________________________
 */
 
-X509 *SSL_read_X509(char* filename, X509 **x509, pem_password_cb *cb)
-{
-    X509 *rc;
-    BIO *bioS;
-    BIO *bioF;
-
-    /* 1. try PEM (= DER+Base64+headers) */
-    if ((bioS=BIO_new_file(filename, "r")) == NULL)
-        return NULL;
-    rc = PEM_read_bio_X509 (bioS, x509, cb, NULL);
-    BIO_free(bioS);
-
-    if (rc == NULL) {
-        /* 2. try DER+Base64 */
-        if ((bioS=BIO_new_file(filename, "r")) == NULL)
-            return NULL;
-
-        if ((bioF = BIO_new(BIO_f_base64())) == NULL) {
-            BIO_free(bioS);
-            return NULL;
-        }
-        bioS = BIO_push(bioF, bioS);
-        rc = d2i_X509_bio(bioS, NULL);
-        BIO_free_all(bioS);
-
-        if (rc == NULL) {
-            /* 3. try plain DER */
-            if ((bioS=BIO_new_file(filename, "r")) == NULL)
-                return NULL;
-            rc = d2i_X509_bio(bioS, NULL);
-            BIO_free(bioS);
-        }
-    }
-    if (rc != NULL && x509 != NULL) {
-        if (*x509 != NULL)
-            X509_free(*x509);
-        *x509 = rc;
-    }
-    return rc;
-}
-
-EVP_PKEY *SSL_read_PrivateKey(char* filename, EVP_PKEY **key, pem_password_cb *cb, void *s)
+EVP_PKEY *SSL_read_PrivateKey(const char* filename, EVP_PKEY **key, pem_password_cb *cb, void *s)
 {
     EVP_PKEY *rc;
     BIO *bioS;
diff --git a/modules/ssl/ssl_util_ssl.h b/modules/ssl/ssl_util_ssl.h
index 80a7b98ede..6f6873b487 100644
--- a/modules/ssl/ssl_util_ssl.h
+++ b/modules/ssl/ssl_util_ssl.h
@@ -60,8 +60,7 @@
 void        SSL_init_app_data2_idx(void);
 void       *SSL_get_app_data2(SSL *);
 void        SSL_set_app_data2(SSL *, void *);
-X509       *SSL_read_X509(char *, X509 **, pem_password_cb *);
-EVP_PKEY   *SSL_read_PrivateKey(char *, EVP_PKEY **, pem_password_cb *, void *);
+EVP_PKEY   *SSL_read_PrivateKey(const char *, EVP_PKEY **, pem_password_cb *, void *);
 int         SSL_smart_shutdown(SSL *ssl);
 BOOL        SSL_X509_getBC(X509 *, int *, int *);
 char       *SSL_X509_NAME_ENTRY_to_string(apr_pool_t *p, X509_NAME_ENTRY *xsne);
-- 
2.40.0