I need to be able to reconfigure the server certificate without stopping
and starting Apache. Working on the theory that the only reason this is
currently not possible is due to the potential need for user intervention
to read the key's pass phrase, I have written the attached patch against
mod_ssl-2.4.6-1.3.9.
The patch defines a new function (ssl_reread_pphrase_Handle()), which is
a direct copy of ssl_pphrase_Handle() with the user dialog stuff taken out.
The new function is called from ssl_init_Module() when mc->nInitCount>2.
It seems to work OK here, so I was hoping that my starting assumption
could be verified (ie that I haven't missed something vital that stops my
patch from working properly).
- Dick
diff -ur mod_ssl-2.4.6-1.3.9-orig/pkg.sslmod/mod_ssl.h
mod_ssl-2.4.6-1.3.9/pkg.sslmod/mod_ssl.h
--- mod_ssl-2.4.6-1.3.9-orig/pkg.sslmod/mod_ssl.h Fri Oct 1 12:28:49 1999
+++ mod_ssl-2.4.6-1.3.9/pkg.sslmod/mod_ssl.h Thu Oct 28 11:33:55 1999
@@ -686,6 +686,7 @@
/* Pass Phrase Support */
void ssl_pphrase_Handle(server_rec *, pool *);
int ssl_pphrase_Handle_CB(char *, int, int);
+void ssl_reread_pphrase_Handle(server_rec *, pool *);
/* Diffie-Hellman Parameter Support */
DH *ssl_dh_GetTmpParam(int);
diff -ur mod_ssl-2.4.6-1.3.9-orig/pkg.sslmod/ssl_engine_init.c
mod_ssl-2.4.6-1.3.9/pkg.sslmod/ssl_engine_init.c
--- mod_ssl-2.4.6-1.3.9-orig/pkg.sslmod/ssl_engine_init.c Tue Aug 3 10:47:45
1999
+++ mod_ssl-2.4.6-1.3.9/pkg.sslmod/ssl_engine_init.c Thu Oct 28 11:47:02 1999
@@ -240,6 +240,13 @@
}
/*
+ * Apache has been restarted
+ */
+ if(mc->nInitCount > 2) {
+ ssl_reread_pphrase_Handle(s, p);
+ }
+
+ /*
* Warn the user that he should use the session cache.
* But we can operate without it, of course.
*/
diff -ur mod_ssl-2.4.6-1.3.9-orig/pkg.sslmod/ssl_engine_pphrase.c
mod_ssl-2.4.6-1.3.9/pkg.sslmod/ssl_engine_pphrase.c
--- mod_ssl-2.4.6-1.3.9-orig/pkg.sslmod/ssl_engine_pphrase.c Tue Oct 19 11:33:10
1999
+++ mod_ssl-2.4.6-1.3.9/pkg.sslmod/ssl_engine_pphrase.c Thu Oct 28 11:46:54 1999
@@ -531,3 +531,229 @@
return (len);
}
+/*
+ * This is a straight copy of ssl_pphrase_Handle(), except that the pphrase
+ * user dialog handling (including the key caching) has been removed, and the
+ * mc->tPublicCert and mc->tPrivateKey tables are cleared beforehand.
+ */
+void ssl_reread_pphrase_Handle(server_rec *s, pool *p)
+{
+ SSLModConfigRec *mc = myModConfig();
+ SSLSrvConfigRec *sc;
+ server_rec *pServ;
+ char *cpVHostID;
+ char szPath[MAX_STRING_LEN];
+ EVP_PKEY *pPrivateKey;
+ ssl_asn1_t *asn1;
+ unsigned char *ucp;
+ X509 *pX509Cert;
+ FILE *fp;
+ BOOL bReadable;
+ ssl_ds_array *aPassPhrase;
+ int nPassPhraseCur;
+ char *cpPassPhraseCur;
+ int nPassPhraseRetry;
+ int nPassPhraseDialog;
+ int nPassPhraseDialogCur;
+ BOOL bPassPhraseDialogOnce;
+ int i, j;
+ ssl_algo_t algoCert, algoKey, at;
+ char *an;
+ char *cp;
+
+ /*
+ * Free the previous certificate tables
+ */
+ ssl_ds_table_wipeout(mc->tPublicCert);
+ ssl_ds_table_wipeout(mc->tPrivateKey);
+
+ /*
+ * Walk through all configured servers
+ */
+ for (pServ = s; pServ != NULL; pServ = pServ->next) {
+ sc = mySrvConfig(pServ);
+
+ if (!sc->bEnabled)
+ continue;
+
+ cpVHostID = ssl_util_vhostid(p, pServ);
+ ssl_log(pServ, SSL_LOG_INFO,
+ "Init: Reloading certificate & private key of SSL-aware server %s",
+ cpVHostID);
+
+ /*
+ * Read in server certificate(s): This is the easy part
+ * because this file isn't encrypted in any way.
+ */
+ if (sc->szPublicCertFile[0] == NULL) {
+ ssl_log(pServ, SSL_LOG_ERROR,
+ "Init: Server %s should be SSL-aware but has no certificate
+configured "
+ "[Hint: SSLCertifcateFile]", cpVHostID);
+ ssl_die();
+ }
+ algoCert = SSL_ALGO_UNKNOWN;
+ algoKey = SSL_ALGO_UNKNOWN;
+ for (i = 0, j = 0; i < SSL_AIDX_MAX && sc->szPublicCertFile[i] != NULL; i++) {
+
+ ap_cpystrn(szPath, sc->szPublicCertFile[i], sizeof(szPath));
+ if ((fp = ap_pfopen(p, szPath, "r")) == NULL) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO,
+ "Init: Can't open server certificate file %s", szPath);
+ ssl_die();
+ }
+ if ((pX509Cert = SSL_read_X509(fp, NULL, NULL)) == NULL) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "Init: Unable to read server certificate from file %s",
+szPath);
+ ssl_die();
+ }
+ ap_pfclose(p, fp);
+
+ /*
+ * 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) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "Init: Multiple %s server certificates not allowed", an);
+ ssl_die();
+ }
+ algoCert |= at;
+
+ /*
+ * Insert the certificate into global module configuration to get it
+ * read when the per-server configuration structures are set up.
+ */
+ cp = ap_psprintf(mc->pPool, "%s:%s", cpVHostID, an);
+ asn1 = (ssl_asn1_t *)ssl_ds_table_push(mc->tPublicCert, cp);
+ asn1->nData = i2d_X509(pX509Cert, NULL);
+ asn1->cpData = ap_palloc(mc->pPool, asn1->nData);
+ ucp = asn1->cpData; i2d_X509(pX509Cert, &ucp); /* 2nd arg increments */
+
+ /*
+ * Free the X509 structure
+ */
+ X509_free(pX509Cert);
+
+ /*
+ * Read in the private key: This is the non-trivial part, because the
+ * key is typically encrypted. A pass phrase dialog cannot be used
+ * to request it from the user because Apache has long since
+ * detached from the terminal, so it has to be gathered
+ * from a dialog program.
+ */
+ if (sc->szPrivateKeyFile[j] != NULL)
+ ap_cpystrn(szPath, sc->szPrivateKeyFile[j++], sizeof(szPath));
+
+ /*
+ * Try to read the private key file with the help of
+ * the callback function which serves the pass
+ * phrases to OpenSSL
+ */
+ myCtxVarSet(mc, 1, pServ);
+ myCtxVarSet(mc, 2, p);
+ myCtxVarSet(mc, 3, aPassPhrase);
+ myCtxVarSet(mc, 4, &nPassPhraseCur);
+ myCtxVarSet(mc, 5, &cpPassPhraseCur);
+ myCtxVarSet(mc, 6, cpVHostID);
+ myCtxVarSet(mc, 7, an);
+ myCtxVarSet(mc, 8, &nPassPhraseDialog);
+ myCtxVarSet(mc, 9, &nPassPhraseDialogCur);
+ myCtxVarSet(mc, 10, &bPassPhraseDialogOnce);
+
+ nPassPhraseCur = 0;
+ nPassPhraseRetry = 0;
+ nPassPhraseDialogCur = 0;
+ bPassPhraseDialogOnce = TRUE;
+
+ 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 ((fp = ap_pfopen(p, szPath, "r")) == NULL) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO,
+ "Init: Can't open server private key file %s", szPath);
+ ssl_die();
+ }
+ cpPassPhraseCur = NULL;
+ bReadable = ((pPrivateKey = SSL_read_PrivateKey(fp, NULL,
+ ssl_pphrase_Handle_CB)) != NULL ? TRUE : FALSE);
+ ap_pfclose(p, fp);
+
+ /*
+ * when the private key file now was readable,
+ * it's fine and we go out of the loop
+ */
+ if (bReadable)
+ break;
+
+ /*
+ * We cant find the pass phrase :-(
+ */
+ ssl_log(pServ, SSL_LOG_ERROR|SSL_ADD_SSLERR, "Init: Private key not
+found during reconfigure");
+ ssl_die();
+ }
+
+ if (pPrivateKey == NULL) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "Init: Unable to read server private key from file %s",
+szPath);
+ ssl_die();
+ }
+
+ /*
+ * 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) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "Init: Multiple %s server private keys not allowed", an);
+ ssl_die();
+ }
+ algoKey |= at;
+
+ /*
+ * Log the type of reading
+ */
+ if (nPassPhraseDialogCur == 0)
+ ssl_log(pServ, SSL_LOG_TRACE,
+ "Init: (%s) unencrypted %s private key - pass phrase not
+required",
+ cpVHostID, an);
+ else {
+ if (cpPassPhraseCur != NULL)
+ ssl_log(pServ, SSL_LOG_TRACE,
+ "Init: (%s) encrypted %s private key - pass phrase
+requested",
+ cpVHostID, an);
+ else
+ ssl_log(pServ, SSL_LOG_TRACE,
+ "Init: (%s) encrypted %s private key - pass phrase
+reused",
+ cpVHostID, an);
+ }
+
+ /*
+ * 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!)
+ */
+ cp = ap_psprintf(mc->pPool, "%s:%s", cpVHostID, an);
+ asn1 = (ssl_asn1_t *)ssl_ds_table_push(mc->tPrivateKey, cp);
+ asn1->nData = i2d_PrivateKey(pPrivateKey, NULL);
+ asn1->cpData = ap_palloc(mc->pPool, asn1->nData);
+ ucp = asn1->cpData; i2d_PrivateKey(pPrivateKey, &ucp); /* 2nd arg
+increments */
+
+ /*
+ * Free the private key structure
+ */
+ EVP_PKEY_free(pPrivateKey);
+ }
+ }
+
+ return;
+}
______________________________________________________________________
Apache Interface to OpenSSL (mod_ssl) www.modssl.org
User Support Mailing List [EMAIL PROTECTED]
Automated List Manager [EMAIL PROTECTED]