
https://bugzilla.redhat.com/show_bug.cgi?id=649648

http://svn.apache.org/viewvc?view=revision&revision=1069765
http://svn.apache.org/viewvc?view=revision&revision=1069772

--- httpd-2.2.3/modules/ssl/ssl_engine_pphrase.c.ssldupkeys
+++ httpd-2.2.3/modules/ssl/ssl_engine_pphrase.c
@@ -132,6 +132,13 @@ static void pphrase_array_clear(apr_arra
     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.  The myCtxVarGet abomination can be thrown away with
+ * SSLC support, vastly simplifying the code. */
 void ssl_pphrase_Handle(server_rec *s, apr_pool_t *p)
 {
     SSLModConfigRec *mc = myModConfig(s);
@@ -157,7 +164,6 @@ void ssl_pphrase_Handle(server_rec *s, a
     int i, j;
     ssl_algo_t algoCert, algoKey, at;
     char *an;
-    char *cp;
     apr_time_t pkey_mtime = 0;
     int isterm = 1;
     apr_status_t rv;
@@ -179,7 +185,8 @@ void ssl_pphrase_Handle(server_rec *s, a
 
         cpVHostID = ssl_util_vhostid(p, pServ);
         ap_log_error(APLOG_MARK, APLOG_INFO, 0, pServ,
-                     "Loading certificate & private key of SSL-aware server");
+                     "Loading certificate & private key of SSL-aware server '%s'",
+                     cpVHostID);
 
         /*
          * Read in server certificate(s): This is the easy part
@@ -191,9 +198,17 @@ void ssl_pphrase_Handle(server_rec *s, a
                          "configured [Hint: SSLCertificateFile]");
             ssl_die();
         }
+
+        /* 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) {
@@ -224,6 +239,11 @@ void ssl_pphrase_Handle(server_rec *s, a
             }
             algoCert |= at;
 
+            /* 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, cpVHostID, an);
+
             /*
              * Insert the certificate into global module configuration to let it
              * survive the processing between the 1st Apache API init round (where
@@ -231,9 +251,8 @@ void ssl_pphrase_Handle(server_rec *s, a
              * certificate is actually used to configure mod_ssl's per-server
              * configuration structures).
              */
-            cp = asn1_table_vhost_key(mc, p, cpVHostID, an);
             length = i2d_X509(pX509Cert, NULL);
-            ucp = ssl_asn1_table_set(mc->tPublicCert, cp, length);
+            ucp = ssl_asn1_table_set(mc->tPublicCert, key_id, length);
             (void)i2d_X509(pX509Cert, &ucp); /* 2nd arg increments */
 
             /*
@@ -319,22 +338,17 @@ void ssl_pphrase_Handle(server_rec *s, a
                  * are used to give a better idea as to what failed.
                  */
                 if (pkey_mtime) {
-                    int i;
-
-                    for (i=0; i < SSL_AIDX_MAX; i++) {
-                        const char *key_id =
-                            ssl_asn1_table_keyfmt(p, cpVHostID, i);
-                        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,
-                                         "%s reusing existing "
-                                         "%s private key on restart",
-                                         cpVHostID, ssl_asn1_keystr(i));
-                            return;
-                        }
+                    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,
+                                     "%s reusing existing "
+                                     "%s private key on restart",
+                                     cpVHostID, ssl_asn1_keystr(i));
+                        using_cache = 1;
+                        break;
                     }
                 }
 
@@ -438,6 +452,12 @@ void ssl_pphrase_Handle(server_rec *s, a
                 ssl_die();
             }
 
+            /* 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_ERR, 0, s,
                             "Init: Unable to read server private key from "
@@ -500,14 +520,13 @@ void ssl_pphrase_Handle(server_rec *s, a
              * because the SSL library uses static variables inside a
              * RSA structure which do not survive DSO reloads!)
              */
-            cp = asn1_table_vhost_key(mc, p, cpVHostID, an);
             length = i2d_PrivateKey(pPrivateKey, NULL);
-            ucp = ssl_asn1_table_set(mc->tPrivateKey, cp, length);
+            ucp = ssl_asn1_table_set(mc->tPrivateKey, key_id, length);
             (void)i2d_PrivateKey(pPrivateKey, &ucp); /* 2nd arg increments */
 
             if (nPassPhraseDialogCur != 0) {
                 /* remember mtime of encrypted keys */
-                asn1 = ssl_asn1_table_get(mc->tPrivateKey, cp);
+                asn1 = ssl_asn1_table_get(mc->tPrivateKey, key_id);
                 asn1->source_mtime = pkey_mtime;
             }
 
--- httpd-2.2.3/modules/ssl/ssl_private.h.sslvhost
+++ httpd-2.2.3/modules/ssl/ssl_private.h
@@ -384,8 +384,16 @@ typedef struct {
     apr_array_header_t   *aRandSeed;
     apr_hash_t     *tVHostKeys;
     void           *pTmpKeys[SSL_TMP_KEY_MAX];
+
+    /* 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;
     apr_hash_t     *tPrivateKey;
+
 #if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT)
     const char     *szCryptoDevice;
 #endif
