1
0
mirror of https://github.com/apache/httpd.git synced 2025-08-08 15:02:10 +03:00

Remove the hardcoded algorithm-type dependency for the SSLCertificateFile

and SSLCertificateKeyFile directives, and deprecate SSLCertificateChainFile

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

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

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

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

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

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

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


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1553824 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Kaspar Brand
2013-12-28 13:24:17 +00:00
parent f4d9c8df8c
commit 1e80b68ec1
10 changed files with 577 additions and 894 deletions

View File

@@ -1,6 +1,11 @@
-*- coding: utf-8 -*- -*- coding: utf-8 -*-
Changes with Apache 2.5.0 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: *) mod_proxy: Remove <Proxy ~ wildcard-url> syntax which:
- is equivalent to <ProxyMatch wildcard-url> - is equivalent to <ProxyMatch wildcard-url>
- has never been documented - has never been documented

View File

@@ -1 +1 @@
2559 2585

View File

@@ -801,25 +801,44 @@ SSLCipherSuite RSA:!EXP:!NULL:+HIGH:+MEDIUM:-LOW
<directivesynopsis> <directivesynopsis>
<name>SSLCertificateFile</name> <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> <syntax>SSLCertificateFile <em>file-path</em></syntax>
<contextlist><context>server config</context> <contextlist><context>server config</context>
<context>virtual host</context></contextlist> <context>virtual host</context></contextlist>
<usage> <usage>
<p> <p>
This directive points to the file with the PEM-encoded certificate, This directive points to a file with certificate data in PEM format.
optionally also the corresponding private key, and - beginning with At a minimum, the file must include an end-entity (leaf) certificate.
version 2.5.0-dev as of 2013-09-29 - DH parameters and/or an EC curve name Beginning with version 2.5.0-dev as of 2013-12-28, it may also
for ephemeral keys (as generated by <code>openssl dhparam</code> include intermediate CA certificates, sorted from leaf to root,
and <code>openssl ecparam</code>, respectively). If the private key and obsoletes <directive module="mod_ssl">SSLCertificateChainFile</directive>.
is encrypted, the pass phrase dialog is forced at startup time.
</p> </p>
<p> <p>
This directive can be used up to three times (referencing different filenames) Additional optional elements are DH parameters and/or an EC curve name
when both an RSA, a DSA, and an ECC based server certificate is used in for ephemeral keys, as generated by <code>openssl dhparam</code> and
parallel. Note that DH and ECDH parameters are only read from the first <code>openssl ecparam</code>, respectively (supported in version 2.5.0-dev
<directive>SSLCertificateFile</directive> directive.</p> 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>
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> <note>
<title>DH parameter interoperability with primes > 1024 bit</title> <title>DH parameter interoperability with primes > 1024 bit</title>
@@ -845,25 +864,26 @@ SSLCertificateFile /usr/local/apache2/conf/ssl.crt/server.crt
<directivesynopsis> <directivesynopsis>
<name>SSLCertificateKeyFile</name> <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> <syntax>SSLCertificateKeyFile <em>file-path</em></syntax>
<contextlist><context>server config</context> <contextlist><context>server config</context>
<context>virtual host</context></contextlist> <context>virtual host</context></contextlist>
<usage> <usage>
<p> <p>
This directive points to the PEM-encoded Private Key file for the 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 server (the private key may also be combined with the certificate in the
<directive>SSLCertificateFile</directive>, use this additional directive to <directive module="mod_ssl">SSLCertificateFile</directive>, but this practice
point to the file with the stand-alone Private Key. When is discouraged). If the contained private key is encrypted, the pass phrase
<directive>SSLCertificateFile</directive> is used and the file dialog is forced at startup time.</p>
contains both the Certificate and the Private Key this directive need
not be used. But we strongly discourage this practice. Instead we <p>
recommend you to separate the Certificate and the Private Key. If the The directive can be used multiple times (referencing different filenames)
contained Private Key is encrypted, the Pass Phrase dialog is forced to support multiple algorithms for server authentication. For each
at startup time. This directive can be used up to three times <directive module="mod_ssl">SSLCertificateKeyFile</directive>
(referencing different filenames) when both a RSA, a DSA, and an ECC based directive, there must be a matching <directive>SSLCertificateFile</directive>
private key is used in parallel.</p> directive.</p>
<example><title>Example</title> <example><title>Example</title>
<highlight language="config"> <highlight language="config">
SSLCertificateKeyFile /usr/local/apache2/conf/ssl.key/server.key 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> <context>virtual host</context></contextlist>
<usage> <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> <p>
This directive sets the optional <em>all-in-one</em> file where you can This directive sets the optional <em>all-in-one</em> file where you can
assemble the certificates of Certification Authorities (CA) which form the assemble the certificates of Certification Authorities (CA) which form the

View File

@@ -66,7 +66,6 @@ SSLModConfigRec *ssl_config_global_create(server_rec *s)
sizeof(ssl_randseed_t)); sizeof(ssl_randseed_t));
mc->tVHostKeys = apr_hash_make(pool); mc->tVHostKeys = apr_hash_make(pool);
mc->tPrivateKey = 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) #if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT)
mc->szCryptoDevice = NULL; mc->szCryptoDevice = NULL;
#endif #endif
@@ -190,7 +189,8 @@ static void modssl_ctx_init_server(SSLSrvConfigRec *sc,
mctx->pks = apr_pcalloc(p, sizeof(*mctx->pks)); 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 #ifdef HAVE_TLS_SESSION_TICKETS
mctx->ticket_key = apr_pcalloc(p, sizeof(*mctx->ticket_key)); 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 *add,
modssl_ctx_t *mrg) modssl_ctx_t *mrg)
{ {
int i;
modssl_ctx_cfg_merge(p, base, add, mrg); modssl_ctx_cfg_merge(p, base, add, mrg);
for (i = 0; i < SSL_AIDX_MAX; i++) { cfgMergeArray(pks->cert_files);
cfgMergeString(pks->cert_files[i]); cfgMergeArray(pks->key_files);
cfgMergeString(pks->key_files[i]);
}
cfgMergeString(pks->ca_name_path); cfgMergeString(pks->ca_name_path);
cfgMergeString(pks->ca_name_file); 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, const char *ssl_cmd_SSLCertificateFile(cmd_parms *cmd,
void *dcfg, void *dcfg,
const char *arg) const char *arg)
{ {
SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
const char *err; 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; return err;
} }
*(const char **)apr_array_push(sc->server->pks->cert_files) =
apr_pstrdup(cmd->pool, arg);
return NULL; return NULL;
} }
@@ -815,12 +775,16 @@ const char *ssl_cmd_SSLCertificateKeyFile(cmd_parms *cmd,
void *dcfg, void *dcfg,
const char *arg) const char *arg)
{ {
SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
const char *err; 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; return err;
} }
*(const char **)apr_array_push(sc->server->pks->key_files) =
apr_pstrdup(cmd->pool, arg);
return NULL; return NULL;
} }
@@ -831,6 +795,12 @@ const char *ssl_cmd_SSLCertificateChainFile(cmd_parms *cmd,
SSLSrvConfigRec *sc = mySrvConfig(cmd->server); SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
const char *err; 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))) { if ((err = ssl_cmd_check_file(cmd, &arg))) {
return err; 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; modssl_pk_server_t *const pks = sc->server->pks;
int i; int i;
for (i = 0; (i < SSL_AIDX_MAX) && pks->cert_files[i]; i++) { for (i = 0; (i < pks->cert_files->nelts) &&
apr_file_printf(out, " %s\n", pks->cert_files[i]); 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 *));
} }
} }

View File

@@ -67,6 +67,7 @@ apr_status_t ssl_init_Module(apr_pool_t *p, apr_pool_t *plog,
SSLSrvConfigRec *sc; SSLSrvConfigRec *sc;
server_rec *s; server_rec *s;
apr_status_t rv; apr_status_t rv;
apr_array_header_t *pphrases;
if (SSLeay() < SSL_LIBRARY_VERSION) { if (SSLeay() < SSL_LIBRARY_VERSION) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, base_server, APLOGNO(01882) 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 #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 * initialize the mutex handling
*/ */
@@ -218,6 +209,8 @@ apr_status_t ssl_init_Module(apr_pool_t *p, apr_pool_t *plog,
return rv; return rv;
} }
pphrases = apr_array_make(ptemp, 2, sizeof(char *));
/* /*
* initialize servers * 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 * 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; 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 * Configuration consistency checks
*/ */
@@ -299,40 +300,6 @@ apr_status_t ssl_init_Engine(server_rec *s, apr_pool_t *p)
} }
#endif #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 #ifdef HAVE_TLSEXT
static apr_status_t ssl_init_ctx_tls_extensions(server_rec *s, static apr_status_t ssl_init_ctx_tls_extensions(server_rec *s,
apr_pool_t *p, apr_pool_t *p,
@@ -783,8 +750,9 @@ static apr_status_t ssl_init_ctx_cert_chain(server_rec *s,
return APR_SUCCESS; return APR_SUCCESS;
} }
for (i = 0; (i < SSL_AIDX_MAX) && mctx->pks->cert_files[i]; i++) { for (i = 0; (i < mctx->pks->cert_files->nelts) &&
if (strEQ(mctx->pks->cert_files[i], chain)) { 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; skip_first = TRUE;
break; break;
} }
@@ -850,104 +818,10 @@ static apr_status_t ssl_init_ctx(server_rec *s,
return APR_SUCCESS; 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, static void ssl_check_public_cert(server_rec *s,
apr_pool_t *ptemp, apr_pool_t *ptemp,
X509 *cert, X509 *cert,
int type) const char *key_id)
{ {
int is_ca, pathlen; int is_ca, pathlen;
@@ -963,132 +837,215 @@ static void ssl_check_public_cert(server_rec *s,
if (is_ca) { if (is_ca) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(01906) ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(01906)
"%s server certificate is a CA certificate " "%s server certificate is a CA certificate "
"(BasicConstraints: CA == TRUE !?)", "(BasicConstraints: CA == TRUE !?)", key_id);
ssl_asn1_keystr(type));
} }
if (pathlen > 0) { if (pathlen > 0) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(01907) ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(01907)
"%s server certificate is not a leaf certificate " "%s server certificate is not a leaf certificate "
"(BasicConstraints: pathlen == %d > 0 !?)", "(BasicConstraints: pathlen == %d > 0 !?)",
ssl_asn1_keystr(type), pathlen); key_id, pathlen);
} }
} }
if (SSL_X509_match_name(ptemp, cert, (const char *)s->server_hostname, if (SSL_X509_match_name(ptemp, cert, (const char *)s->server_hostname,
TRUE, s) == FALSE) { TRUE, s) == FALSE) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(01909) ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(01909)
"%s certificate configured for %s does NOT include " "%s server certificate does NOT include an ID "
"an ID which matches the server name", "which matches the server name", key_id);
ssl_asn1_keystr(type), (mySrvConfig(s))->vhost_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, static apr_status_t ssl_init_server_certs(server_rec *s,
apr_pool_t *p, apr_pool_t *p,
apr_pool_t *ptemp, 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 #ifdef HAVE_ECC
const char *ecc_id;
EC_GROUP *ecparams; EC_GROUP *ecparams;
int nid; int nid;
EC_KEY *eckey; EC_KEY *eckey;
#endif #endif
const char *vhost_id = mctx->sc->vhost_id; #ifndef HAVE_SSL_CONF_CMD
int i; SSL *ssl;
apr_status_t have_rsa, have_dsa;
DH *dhparams;
#ifdef HAVE_ECC
apr_status_t have_ecc;
#endif #endif
rsa_id = ssl_asn1_table_keyfmt(ptemp, vhost_id, SSL_AIDX_RSA); /* no OpenSSL default prompts for any of the SSL_CTX_use_* calls, please */
dsa_id = ssl_asn1_table_keyfmt(ptemp, vhost_id, SSL_AIDX_DSA); SSL_CTX_set_default_passwd_cb(mctx->ssl_ctx, ssl_no_passwd_prompt_cb);
#ifdef HAVE_ECC
ecc_id = ssl_asn1_table_keyfmt(ptemp, vhost_id, SSL_AIDX_ECC);
#endif
have_rsa = ssl_server_import_cert(s, mctx, rsa_id, SSL_AIDX_RSA); /* Iterate over the SSLCertificateFile array */
if (have_rsa != APR_SUCCESS && have_rsa != APR_NOTFOUND) { for (i = 0; (i < mctx->pks->cert_files->nelts) &&
return have_rsa; (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;
} }
have_dsa = ssl_server_import_cert(s, mctx, dsa_id, SSL_AIDX_DSA); } else {
if (have_dsa != APR_SUCCESS && have_dsa != APR_NOTFOUND) { if ((SSL_CTX_use_certificate_chain_file(mctx->ssl_ctx,
return have_dsa; 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;
} }
#ifdef HAVE_ECC
have_ecc = ssl_server_import_cert(s, mctx, ecc_id, SSL_AIDX_ECC); #if defined(SSL_CTX_set1_chain)
if (have_ecc != APR_SUCCESS && have_ecc != APR_NOTFOUND) { /*
return have_ecc; * 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
}
/* 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_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;
}
/* warn about potential cert issues */
ssl_check_public_cert(s, ptemp, cert, key_id);
#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 #endif
if ((have_rsa != APR_SUCCESS) && (have_dsa != APR_SUCCESS) #ifndef HAVE_SSL_CONF_CMD
#ifdef HAVE_ECC SSL_free(ssl);
&& (have_ecc != APR_SUCCESS)
#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);
}
for (i = 0; i < SSL_AIDX_MAX; i++) {
ssl_check_public_cert(s, ptemp, mctx->pks->certs[i], i);
}
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;
}
#endif #endif
if ((have_rsa != APR_SUCCESS) && (have_dsa != APR_SUCCESS) ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(02568)
#ifdef HAVE_ECC "Certificate and private key %s configured from %s and %s",
&& (have_ecc != APR_SUCCESS) key_id, certfile, keyfile);
#endif
) {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01911)
"Oops, no " KEYTYPES " server private key found?!");
return ssl_die(s);
} }
/* /*
* Try to read DH parameters from the (first) SSLCertificateFile * Try to read DH parameters from the (first) SSLCertificateFile
*/ */
if ((mctx->pks->cert_files[0] != NULL) && if ((certfile = APR_ARRAY_IDX(mctx->pks->cert_files, 0, const char *)) &&
(dhparams = ssl_dh_GetParamFromFile(mctx->pks->cert_files[0]))) { (dhparams = ssl_dh_GetParamFromFile(certfile))) {
SSL_CTX_set_tmp_dh(mctx->ssl_ctx, dhparams); SSL_CTX_set_tmp_dh(mctx->ssl_ctx, dhparams);
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02540) ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02540)
"Custom DH parameters (%d bits) for %s loaded from %s", "Custom DH parameters (%d bits) for %s loaded from %s",
BN_num_bits(dhparams->p), vhost_id, BN_num_bits(dhparams->p), vhost_id, certfile);
mctx->pks->cert_files[0]);
} }
#ifdef HAVE_ECC #ifdef HAVE_ECC
/* /*
* Similarly, try to read the ECDH curve name from SSLCertificateFile... * Similarly, try to read the ECDH curve name from SSLCertificateFile...
*/ */
if ((mctx->pks->cert_files[0] != NULL) && if ((certfile != NULL) &&
(ecparams = ssl_ec_GetParamFromFile(mctx->pks->cert_files[0])) && (ecparams = ssl_ec_GetParamFromFile(certfile)) &&
(nid = EC_GROUP_get_curve_name(ecparams)) && (nid = EC_GROUP_get_curve_name(ecparams)) &&
(eckey = EC_KEY_new_by_curve_name(nid))) { (eckey = EC_KEY_new_by_curve_name(nid))) {
SSL_CTX_set_tmp_ecdh(mctx->ssl_ctx, eckey); SSL_CTX_set_tmp_ecdh(mctx->ssl_ctx, eckey);
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02541) ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02541)
"ECDH curve %s for %s specified in %s", "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) * ...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, static apr_status_t ssl_init_server_ctx(server_rec *s,
apr_pool_t *p, apr_pool_t *p,
apr_pool_t *ptemp, apr_pool_t *ptemp,
SSLSrvConfigRec *sc) SSLSrvConfigRec *sc,
apr_array_header_t *pphrases)
{ {
apr_status_t rv; apr_status_t rv;
#ifdef HAVE_SSL_CONF_CMD #ifdef HAVE_SSL_CONF_CMD
@@ -1334,15 +1292,22 @@ static apr_status_t ssl_init_server_ctx(server_rec *s,
int i; int i;
#endif #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) { if ((rv = ssl_init_ctx(s, p, ptemp, sc->server)) != APR_SUCCESS) {
return rv; 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; return rv;
} }
@@ -1360,6 +1325,54 @@ static apr_status_t ssl_init_server_ctx(server_rec *s,
"\"SSLOpenSSLConfCmd %s %s\" applied to %s", "\"SSLOpenSSLConfCmd %s %s\" applied to %s",
param->name, param->value, sc->vhost_id); 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) { if (SSL_CONF_CTX_finish(cctx) == 0) {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02547) 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); SSL_CONF_CTX_free(cctx);
#endif #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 #ifdef HAVE_TLS_SESSION_TICKETS
if ((rv = ssl_init_ticket_key(s, p, ptemp, sc->server)) != APR_SUCCESS) { if ((rv = ssl_init_ticket_key(s, p, ptemp, sc->server)) != APR_SUCCESS) {
return rv; 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_status_t ssl_init_ConfigureServer(server_rec *s,
apr_pool_t *p, apr_pool_t *p,
apr_pool_t *ptemp, apr_pool_t *ptemp,
SSLSrvConfigRec *sc) SSLSrvConfigRec *sc,
apr_array_header_t *pphrases)
{ {
apr_status_t rv; 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)) { if ((sc->enabled == SSL_ENABLED_TRUE) || (sc->enabled == SSL_ENABLED_OPTIONAL)) {
ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(01914) ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(01914)
"Configuring server %s for SSL protocol", sc->vhost_id); "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; 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) apr_status_t ssl_init_ModuleKill(void *data)
{ {
SSLSrvConfigRec *sc; 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_proxy(sc->proxy);
ssl_init_ctx_cleanup_server(sc->server); ssl_init_ctx_cleanup(sc->server);
} }
return APR_SUCCESS; return APR_SUCCESS;
} }

View File

@@ -36,17 +36,19 @@ typedef struct {
apr_array_header_t *aPassPhrase; apr_array_header_t *aPassPhrase;
int nPassPhraseCur; int nPassPhraseCur;
char *cpPassPhraseCur; char *cpPassPhraseCur;
char *an;
int nPassPhraseDialog; int nPassPhraseDialog;
int nPassPhraseDialogCur; int nPassPhraseDialogCur;
BOOL bPassPhraseDialogOnce; BOOL bPassPhraseDialogOnce;
const char *key_id;
const char *pkey_file;
} pphrase_cb_arg_t; } pphrase_cb_arg_t;
/* /*
* Return true if the named file exists and is readable * 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_status_t stat;
apr_finfo_t sbuf; 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, * since apr_array_push() will apr_alloc arr->nalloc * 2 elts,
* leaving the original arr->elts to waste. * leaving the original arr->elts to waste.
*/ */
static char *asn1_table_vhost_key(SSLModConfigRec *mc, apr_pool_t *p, static const char *asn1_table_vhost_key(SSLModConfigRec *mc, apr_pool_t *p,
const char *id, char *an) const char *id, int i)
{ {
/* 'p' pool used here is cleared on restarts (or sooner) */ /* '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, void *keyptr = apr_hash_get(mc->tVHostKeys, key,
APR_HASH_KEY_STRING); APR_HASH_KEY_STRING);
@@ -126,186 +128,44 @@ static char *pphrase_array_get(apr_array_header_t *arr, int idx)
return ((char **)arr->elts)[idx]; return ((char **)arr->elts)[idx];
} }
static void pphrase_array_clear(apr_array_header_t *arr) apr_status_t ssl_load_encrypted_pkey(server_rec *s, apr_pool_t *p, int idx,
{ apr_array_header_t **pphrases)
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)
{ {
SSLModConfigRec *mc = myModConfig(s); SSLModConfigRec *mc = myModConfig(s);
SSLSrvConfigRec *sc; SSLSrvConfigRec *sc = mySrvConfig(s);
server_rec *pServ; const char *key_id = asn1_table_vhost_key(mc, p, sc->vhost_id, idx);
char szPath[MAX_STRING_LEN]; EVP_PKEY *pPrivateKey = NULL;
EVP_PKEY *pPrivateKey;
ssl_asn1_t *asn1; ssl_asn1_t *asn1;
unsigned char *ucp; unsigned char *ucp;
long int length; long int length;
X509 *pX509Cert;
BOOL bReadable; BOOL bReadable;
int nPassPhrase = 0; int nPassPhrase = (*pphrases)->nelts;
int nPassPhraseRetry; int nPassPhraseRetry = 0;
int i, j;
ssl_algo_t algoCert, algoKey, at;
char *an;
apr_time_t pkey_mtime = 0; apr_time_t pkey_mtime = 0;
apr_status_t rv; apr_status_t rv;
pphrase_cb_arg_t *ppcb_arg = apr_pcalloc(p, sizeof(*ppcb_arg)); pphrase_cb_arg_t ppcb_arg = {
ppcb_arg->p = p; s,
/* p,
* Start with a fresh pass phrase array *pphrases,
*/ 0,
ppcb_arg->aPassPhrase = apr_array_make(p, 2, sizeof(char *)); NULL,
0,
0,
TRUE,
key_id,
APR_ARRAY_IDX(sc->server->pks->key_files, idx, const char *)
};
/* if (!ppcb_arg.pkey_file) {
* Walk through all configured servers ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02573)
*/ "Init: No private key specified for %s", key_id);
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;
}
ap_log_error(APLOG_MARK, APLOG_INFO, 0, pServ, APLOGNO(02200)
"Loading certificate & private key of SSL-aware server '%s'",
sc->vhost_id);
/*
* Read in server certificate(s): This is the easy part
* because this file isn't encrypted in any way.
*/
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); return ssl_die(s);
} }
if ((pX509Cert = SSL_read_X509(szPath, NULL, NULL)) == NULL) { else if ((rv = exists_and_readable(ppcb_arg.pkey_file, p,
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;
/* 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);
/*
* 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);
/*
* 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 ) { &pkey_mtime)) != APR_SUCCESS ) {
ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(02243) ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(02574)
"Init: Can't open server private key file " "Init: Can't open server private key file %s",
"%s",szPath); ppcb_arg.pkey_file);
return ssl_die(s); return ssl_die(s);
} }
@@ -330,29 +190,34 @@ apr_status_t ssl_pphrase_Handle(server_rec *s, apr_pool_t *p)
* are used to give a better idea as to what failed. * are used to give a better idea as to what failed.
*/ */
if (pkey_mtime) { if (pkey_mtime) {
ssl_asn1_t *asn1 = ssl_asn1_t *asn1 = ssl_asn1_table_get(mc->tPrivateKey, key_id);
ssl_asn1_table_get(mc->tPrivateKey, key_id);
if (asn1 && (asn1->source_mtime == pkey_mtime)) { if (asn1 && (asn1->source_mtime == pkey_mtime)) {
ap_log_error(APLOG_MARK, APLOG_INFO, ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(02575)
0, pServ, APLOGNO(02244) "Reusing existing private key from %s on restart",
"%s reusing existing " ppcb_arg.pkey_file);
"%s private key on restart", return APR_SUCCESS;
sc->vhost_id, ssl_asn1_keystr(i));
using_cache = 1;
break;
} }
} }
ppcb_arg->cpPassPhraseCur = NULL; ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(02576)
"Attempting to load encrypted (?) private key %s", key_id);
for (;;) {
/*
* Try to read the private key file with the help of
* the callback function which serves the pass
* phrases to OpenSSL
*/
ppcb_arg.cpPassPhraseCur = NULL;
/* Ensure that the error stack is empty; some SSL /* Ensure that the error stack is empty; some SSL
* functions will fail spuriously if the error stack * functions will fail spuriously if the error stack
* is not empty. */ * is not empty. */
ERR_clear_error(); ERR_clear_error();
bReadable = ((pPrivateKey = SSL_read_PrivateKey(szPath, NULL, bReadable = ((pPrivateKey = SSL_read_PrivateKey(ppcb_arg.pkey_file,
ssl_pphrase_Handle_CB, ppcb_arg)) != NULL ? NULL, ssl_pphrase_Handle_CB, &ppcb_arg)) != NULL ?
TRUE : FALSE); TRUE : FALSE);
/* /*
@@ -366,8 +231,8 @@ apr_status_t ssl_pphrase_Handle(server_rec *s, apr_pool_t *p)
* when we have more remembered pass phrases * when we have more remembered pass phrases
* try to reuse these first. * try to reuse these first.
*/ */
if (ppcb_arg->nPassPhraseCur < nPassPhrase) { if (ppcb_arg.nPassPhraseCur < nPassPhrase) {
ppcb_arg->nPassPhraseCur++; ppcb_arg.nPassPhraseCur++;
continue; continue;
} }
@@ -385,7 +250,7 @@ apr_status_t ssl_pphrase_Handle(server_rec *s, apr_pool_t *p)
#else #else
if (sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE if (sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE
#endif #endif
&& ppcb_arg->cpPassPhraseCur != NULL && ppcb_arg.cpPassPhraseCur != NULL
&& nPassPhraseRetry < BUILTIN_DIALOG_RETRIES ) { && nPassPhraseRetry < BUILTIN_DIALOG_RETRIES ) {
apr_file_printf(writetty, "Apache:mod_ssl:Error: Pass phrase incorrect " apr_file_printf(writetty, "Apache:mod_ssl:Error: Pass phrase incorrect "
"(%d more retr%s permitted).\n", "(%d more retr%s permitted).\n",
@@ -399,10 +264,10 @@ apr_status_t ssl_pphrase_Handle(server_rec *s, apr_pool_t *p)
} }
#ifdef WIN32 #ifdef WIN32
if (sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN) { if (sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN) {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02245) ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02577)
"Init: SSLPassPhraseDialog builtin is not " "Init: SSLPassPhraseDialog builtin is not "
"supported on Win32 (key file " "supported on Win32 (key file "
"%s)", szPath); "%s)", ppcb_arg.pkey_file);
return ssl_die(s); return ssl_die(s);
} }
#endif /* WIN32 */ #endif /* WIN32 */
@@ -410,21 +275,21 @@ apr_status_t ssl_pphrase_Handle(server_rec *s, apr_pool_t *p)
/* /*
* Ok, anything else now means a fatal error. * Ok, anything else now means a fatal error.
*/ */
if (ppcb_arg->cpPassPhraseCur == NULL) { if (ppcb_arg.cpPassPhraseCur == NULL) {
if (ppcb_arg->nPassPhraseDialogCur && pkey_mtime && if (ppcb_arg.nPassPhraseDialogCur && pkey_mtime &&
!isatty(fileno(stdout))) /* XXX: apr_isatty() */ !isatty(fileno(stdout))) /* XXX: apr_isatty() */
{ {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_log_error(APLOG_MARK, APLOG_ERR, 0,
pServ, APLOGNO(02246) s, APLOGNO(02578)
"Init: Unable to read pass phrase " "Init: Unable to read pass phrase "
"[Hint: key introduced or changed " "[Hint: key introduced or changed "
"before restart?]"); "before restart?]");
ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, pServ); ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s);
} }
else { else {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_log_error(APLOG_MARK, APLOG_ERR, 0,
pServ, APLOGNO(02203) "Init: Private key not found"); s, APLOGNO(02579) "Init: Private key not found");
ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, pServ); ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s);
} }
if (writetty) { if (writetty) {
apr_file_printf(writetty, "Apache:mod_ssl:Error: Private key not found.\n"); apr_file_printf(writetty, "Apache:mod_ssl:Error: Private key not found.\n");
@@ -432,78 +297,56 @@ apr_status_t ssl_pphrase_Handle(server_rec *s, apr_pool_t *p)
} }
} }
else { else {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, pServ, APLOGNO(02204) ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02580)
"Init: Pass phrase incorrect for key of %s", "Init: Pass phrase incorrect for key %s",
sc->vhost_id); key_id);
ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, pServ); ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
if (writetty) { if (writetty) {
apr_file_printf(writetty, "Apache:mod_ssl:Error: Pass phrase incorrect.\n"); apr_file_printf(writetty, "Apache:mod_ssl:Error: Pass phrase incorrect.\n");
apr_file_printf(writetty, "**Stopped\n"); apr_file_printf(writetty, "**Stopped\n");
} }
} }
return ssl_die(pServ); return ssl_die(s);
} }
/* 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) { if (pPrivateKey == NULL) {
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02247) ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02581)
"Init: Unable to read server private key from " "Init: Unable to read server private key from file %s",
"file %s [Hint: Perhaps it is in a separate file? " ppcb_arg.pkey_file);
" See SSLCertificateKeyFile]", szPath);
ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
return ssl_die(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 * Log the type of reading
*/ */
if (ppcb_arg->nPassPhraseDialogCur == 0) { if (ppcb_arg.nPassPhraseDialogCur == 0) {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, pServ, APLOGNO(02249) ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02582)
"unencrypted %s private key - pass phrase not " "unencrypted %s private key - pass phrase not "
"required", an); "required", key_id);
} }
else { else {
if (ppcb_arg->cpPassPhraseCur != NULL) { if (ppcb_arg.cpPassPhraseCur != NULL) {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
pServ, APLOGNO(02250) s, APLOGNO(02583)
"encrypted %s private key - pass phrase " "encrypted %s private key - pass phrase "
"requested", an); "requested", key_id);
} }
else { else {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
pServ, APLOGNO(02251) s, APLOGNO(02584)
"encrypted %s private key - pass phrase" "encrypted %s private key - pass phrase"
" reused", an); " reused", key_id);
} }
} }
/* /*
* Ok, when we have one more pass phrase store it * Ok, when we have one more pass phrase store it
*/ */
if (ppcb_arg->cpPassPhraseCur != NULL) { if (ppcb_arg.cpPassPhraseCur != NULL) {
*(const char **)apr_array_push(ppcb_arg->aPassPhrase) = *(const char **)apr_array_push(ppcb_arg.aPassPhrase) =
ppcb_arg->cpPassPhraseCur; ppcb_arg.cpPassPhraseCur;
nPassPhrase++; nPassPhrase++;
} }
@@ -517,7 +360,7 @@ apr_status_t ssl_pphrase_Handle(server_rec *s, apr_pool_t *p)
ucp = ssl_asn1_table_set(mc->tPrivateKey, key_id, length); ucp = ssl_asn1_table_set(mc->tPrivateKey, key_id, length);
(void)i2d_PrivateKey(pPrivateKey, &ucp); /* 2nd arg increments */ (void)i2d_PrivateKey(pPrivateKey, &ucp); /* 2nd arg increments */
if (ppcb_arg->nPassPhraseDialogCur != 0) { if (ppcb_arg.nPassPhraseDialogCur != 0) {
/* remember mtime of encrypted keys */ /* remember mtime of encrypted keys */
asn1 = ssl_asn1_table_get(mc->tPrivateKey, key_id); asn1 = ssl_asn1_table_get(mc->tPrivateKey, key_id);
asn1->source_mtime = pkey_mtime; asn1->source_mtime = pkey_mtime;
@@ -527,29 +370,18 @@ apr_status_t ssl_pphrase_Handle(server_rec *s, apr_pool_t *p)
* Free the private key structure * Free the private key structure
*/ */
EVP_PKEY_free(pPrivateKey); EVP_PKEY_free(pPrivateKey);
}
}
/* /*
* Let the user know when we're successful. * Let the user know when we're successful.
*/ */
if (ppcb_arg->nPassPhraseDialog > 0) { if ((ppcb_arg.nPassPhraseDialog > 0) &&
(ppcb_arg.cpPassPhraseCur != NULL)) {
if (writetty) { if (writetty) {
apr_file_printf(writetty, "\n" apr_file_printf(writetty, "\n"
"OK: Pass Phrase Dialog successful.\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 /* Close the pipes if they were opened
*/ */
if (readtty) { if (readtty) {
@@ -662,7 +494,8 @@ int ssl_pphrase_Handle_CB(char *buf, int bufsize, int verify, void *srv)
APLOGNO(01966) APLOGNO(01966)
"Init: Failed to create pass phrase pipe '%s'", "Init: Failed to create pass phrase pipe '%s'",
sc->server->pphrase_dialog_path); 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); memset(buf, 0, (unsigned int)bufsize);
return (-1); 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 */ else { /* sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN */
#ifdef WIN32 #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); memset(buf, 0, (unsigned int)bufsize);
return (-1); return (-1);
#else #else
@@ -705,8 +538,8 @@ int ssl_pphrase_Handle_CB(char *buf, int bufsize, int verify, void *srv)
if (ppcb_arg->bPassPhraseDialogOnce) { if (ppcb_arg->bPassPhraseDialogOnce) {
ppcb_arg->bPassPhraseDialogOnce = FALSE; ppcb_arg->bPassPhraseDialogOnce = FALSE;
apr_file_printf(writetty, "\n"); apr_file_printf(writetty, "\n");
apr_file_printf(writetty, "Server %s (%s)\n", sc->vhost_id, apr_file_printf(writetty, "Private key %s (%s)\n",
ppcb_arg->an); 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) { else if (sc->server->pphrase_dialog_type == SSL_PPTYPE_FILTER) {
const char *cmd = sc->server->pphrase_dialog_path; 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; char *result;
ap_log_error(APLOG_MARK, APLOG_INFO, 0, ppcb_arg->s, APLOGNO(01969) 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); "program (%s)", cmd);
argv[0] = cmd; argv[0] = cmd;
argv[1] = sc->vhost_id; argv[1] = ppcb_arg->key_id;
argv[2] = ppcb_arg->an; argv[2] = NULL;
argv[3] = NULL;
result = ssl_util_readfilter(ppcb_arg->s, ppcb_arg->p, cmd, argv); result = ssl_util_readfilter(ppcb_arg->s, ppcb_arg->p, cmd, argv);
apr_cpystrn(buf, result, bufsize); apr_cpystrn(buf, result, bufsize);
@@ -768,4 +600,3 @@ int ssl_pphrase_Handle_CB(char *buf, int bufsize, int verify, void *srv)
*/ */
return (len); return (len);
} }

View File

@@ -263,31 +263,6 @@ ap_set_module_config(c->conn_config, &ssl_module, val)
#define DEFAULT_OCSP_TIMEOUT 10 #define DEFAULT_OCSP_TIMEOUT 10
#endif #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 * Define the SSL options
*/ */
@@ -510,13 +485,10 @@ typedef struct {
apr_array_header_t *aRandSeed; apr_array_header_t *aRandSeed;
apr_hash_t *tVHostKeys; apr_hash_t *tVHostKeys;
/* Two hash tables of pointers to ssl_asn1_t structures. The /* A hash table of pointers to ssl_asn1_t structures. The structures
* structures are used to store certificates and private keys * are used to store private keys in raw DER format (serialized OpenSSL
* respectively, in raw DER format (serialized OpenSSL X509 and * PrivateKey structures). The table is indexed by (vhost-id,
* PrivateKey structures). The tables are indexed by (vhost-id, * index), for example the string "vhost.example.com:443:0". */
* 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; apr_hash_t *tPrivateKey;
#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT) #if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT)
@@ -531,20 +503,11 @@ typedef struct {
} SSLModConfigRec; } SSLModConfigRec;
/** Structure representing configured filenames for certs and keys for /** Structure representing configured filenames for certs and keys for
* a given vhost, and the corresponding in-memory structures once the * a given vhost */
* files are parsed. */
typedef struct { typedef struct {
/* Lists of configured certs and keys for this server; from index /* Lists of configured certs and keys for this server */
* 0 up to SSL_AIDX_MAX-1 or the first NULL pointer. Note that apr_array_header_t *cert_files;
* these arrays are NOT indexed by algorithm type, they are simply apr_array_header_t *key_files;
* 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];
/** Certificates which specify the set of CA names which should be /** Certificates which specify the set of CA names which should be
* sent in the CertificateRequest message: */ * sent in the CertificateRequest message: */
@@ -782,7 +745,8 @@ const char *ssl_cmd_SSLFIPS(cmd_parms *cmd, void *dcfg, int flag);
/** module initialization */ /** module initialization */
apr_status_t ssl_init_Module(apr_pool_t *, apr_pool_t *, apr_pool_t *, server_rec *); 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_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 *); apr_status_t ssl_init_CheckServers(server_rec *, apr_pool_t *);
STACK_OF(X509_NAME) STACK_OF(X509_NAME)
*ssl_init_FindCAList(server_rec *, apr_pool_t *, const char *, const char *); *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 *, char *ssl_util_readfilter(server_rec *, apr_pool_t *, const char *,
const char * const *); const char * const *);
BOOL ssl_util_path_check(ssl_pathcheck_t, const char *, apr_pool_t *); 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 *); void ssl_util_thread_setup(apr_pool_t *);
int ssl_init_ssl_connection(conn_rec *c, request_rec *r); int ssl_init_ssl_connection(conn_rec *c, request_rec *r);
/** Pass Phrase Support */ /** 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 */ /** Diffie-Hellman Parameter Support */
DH *ssl_dh_GetParamFromFile(const char *); 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, void ssl_asn1_table_unset(apr_hash_t *table,
const char *key); 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 */ /** Mutex Support */
int ssl_mutex_init(server_rec *, apr_pool_t *); int ssl_mutex_init(server_rec *, apr_pool_t *);
int ssl_mutex_reinit(server_rec *, apr_pool_t *); int ssl_mutex_reinit(server_rec *, apr_pool_t *);

View File

@@ -135,61 +135,8 @@ BOOL ssl_util_path_check(ssl_pathcheck_t pcm, const char *path, apr_pool_t *p)
return TRUE; 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. * which are stored in the user data table of s->process->pool.
* to prevent "leaking" of this data, we use malloc/free * to prevent "leaking" of this data, we use malloc/free
* rather than apr_palloc and these wrappers to help make sure * 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); 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 #if APR_HAS_THREADS
/* /*
* To ensure thread-safetyness in OpenSSL - work in progress * To ensure thread-safetyness in OpenSSL - work in progress

View 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) EVP_PKEY *SSL_read_PrivateKey(const char* filename, EVP_PKEY **key, pem_password_cb *cb, void *s)
{
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 *rc; EVP_PKEY *rc;
BIO *bioS; BIO *bioS;

View File

@@ -60,8 +60,7 @@
void SSL_init_app_data2_idx(void); void SSL_init_app_data2_idx(void);
void *SSL_get_app_data2(SSL *); void *SSL_get_app_data2(SSL *);
void SSL_set_app_data2(SSL *, void *); void SSL_set_app_data2(SSL *, void *);
X509 *SSL_read_X509(char *, X509 **, pem_password_cb *); EVP_PKEY *SSL_read_PrivateKey(const char *, EVP_PKEY **, pem_password_cb *, void *);
EVP_PKEY *SSL_read_PrivateKey(char *, EVP_PKEY **, pem_password_cb *, void *);
int SSL_smart_shutdown(SSL *ssl); int SSL_smart_shutdown(SSL *ssl);
BOOL SSL_X509_getBC(X509 *, int *, int *); BOOL SSL_X509_getBC(X509 *, int *, int *);
char *SSL_X509_NAME_ENTRY_to_string(apr_pool_t *p, X509_NAME_ENTRY *xsne); char *SSL_X509_NAME_ENTRY_to_string(apr_pool_t *p, X509_NAME_ENTRY *xsne);