]> granicus.if.org Git - apache/commitdiff
Remove the hardcoded algorithm-type dependency for the SSLCertificateFile
authorKaspar Brand <kbrand@apache.org>
Sat, 28 Dec 2013 13:24:17 +0000 (13:24 +0000)
committerKaspar Brand <kbrand@apache.org>
Sat, 28 Dec 2013 13:24:17 +0000 (13:24 +0000)
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
docs/log-message-tags/next-number
docs/manual/mod/mod_ssl.xml
modules/ssl/ssl_engine_config.c
modules/ssl/ssl_engine_init.c
modules/ssl/ssl_engine_pphrase.c
modules/ssl/ssl_private.h
modules/ssl/ssl_util.c
modules/ssl/ssl_util_ssl.c
modules/ssl/ssl_util_ssl.h

diff --git a/CHANGES b/CHANGES
index 1487c68b87c044b69f07e11d00fc3508d2f62365..d4c50f918c4c61c2fcc627e16eb5e75739b2696a 100644 (file)
--- 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
index 12fda76f5d0c5d4781a3e87b1aa4cf5df4479ce1..d0f1b35877e99f828223c41ff14de2e8e217d52b 100644 (file)
@@ -1 +1 @@
-2559
+2585
index 6e03af12d387c5bf0ac6f49996634cf3d1211d6c..c7f91576599712f2f9947ac3d7084c691ad54f4a 100644 (file)
@@ -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
index 4f9db0b36238dd78aa1edd0680891600eff1829c..ea5c622b1cdfed50026f752c0b1920aedbdb5e8d 100644 (file)
@@ -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 *));
                 }
             }
 
index 377fb67b520f12141245bf7760a013bef07683fa..ddfdfb5c131e6b7aa6c243233e3cae19e1aeb268 100644 (file)
@@ -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;
 }
-
index 4583a99367591026c7b52f700869de9c38e52a2f..4d06c4fe034c3fff3701172ac300cfee2f0427c6 100644 (file)
@@ -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);
 }
-
index 39df19099730d4babcc6639e3b2709cf59950225..5f1fb23d2e82c1f711f622e5693bcaf26a747c58 100644 (file)
@@ -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 *);
index 5f8039c20649463acd0b5726d090d6fc17469853..c21971dd77fedd00f8b640fba924d4fdf45dce63 100644 (file)
@@ -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
index d2e3be366d5c9c5a51d388aa9876e4677840313d..0bf377682c0c6d02f94fa19ba515255334029b5d 100644 (file)
@@ -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;
index 80a7b98ede377e6a49dd709e91a13e640d60f03c..6f6873b487b660b011128a699d4a10c861355429 100644 (file)
@@ -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);