summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGES11
-rw-r--r--include/ap_mmn.h3
-rw-r--r--include/http_protocol.h85
-rw-r--r--modules/md/mod_md.c2
-rw-r--r--modules/ssl/ssl_engine_init.c15
-rw-r--r--modules/ssl/ssl_engine_kernel.c35
-rw-r--r--modules/ssl/ssl_private.h3
-rw-r--r--server/protocol.c36
8 files changed, 177 insertions, 13 deletions
diff --git a/CHANGES b/CHANGES
index 5c61df237d..b444557f8a 100644
--- a/CHANGES
+++ b/CHANGES
@@ -23,6 +23,17 @@ Changes with Apache 2.5.1
server/connection/request.
- Hooks for 'ssl_conn_is_ssl' and 'ssl_var_lookup' where modules
providing SSL can install their own value supplying functions.
+ - ap_ssl_add_cert_files() to enable other modules like mod_md to provide
+ certificate and keys for an SSL module like mod_ssl.
+ - ap_ssl_add_fallback_cert_files() to enable other modules like mod_md to
+ provide a fallback certificate in case no 'proper' certificate is
+ available for an SSL module like mod_ssl.
+ - ap_ssl_answer_challenge() to enable other modules like mod_md to
+ provide a certificate as used in the RFC 8555 'tls-alpn-01' challenge
+ for the ACME protocol for an SSL module like mod_ssl.
+ - Hooks for 'ssl_add_cert_files', 'ssl_add_fallback_cert_files' and
+ 'ssl_answer_challenge' where modules like mod_md can provide providers
+ to the above mentioned functions.
[Stefan Eissing]
*) mod_http2: new option 'H2OutputBuffering on/off' which controls the
diff --git a/include/ap_mmn.h b/include/ap_mmn.h
index f6a6d2597a..1106c2f37e 100644
--- a/include/ap_mmn.h
+++ b/include/ap_mmn.h
@@ -665,6 +665,7 @@
* 20200705.4 (2.5.1-dev) Add ap_get_status_line_ex()
* 20201214.0 (2.5.1-dev) Axe struct core_net_rec
* 20201214.1 (2.5.1-dev) Add ap_ssl_conn_is_ssl()/ap_ssl_var_lookup() and hooks
+ * 20201214.2 (2.5.1-dev) Add ap_ssl_add_cert_files, ap_ssl_add_fallback_cert_files
*/
#define MODULE_MAGIC_COOKIE 0x41503235UL /* "AP25" */
@@ -672,7 +673,7 @@
#ifndef MODULE_MAGIC_NUMBER_MAJOR
#define MODULE_MAGIC_NUMBER_MAJOR 20201214
#endif
-#define MODULE_MAGIC_NUMBER_MINOR 1 /* 0...n */
+#define MODULE_MAGIC_NUMBER_MINOR 2 /* 0...n */
/**
* Determine if the server's current MODULE_MAGIC_NUMBER is at least a
diff --git a/include/http_protocol.h b/include/http_protocol.h
index 5c57a85181..c4f064a7c8 100644
--- a/include/http_protocol.h
+++ b/include/http_protocol.h
@@ -1108,6 +1108,91 @@ AP_DECLARE(const char *) ap_ssl_var_lookup(apr_pool_t *p, server_rec *s,
conn_rec *c, request_rec *r,
const char *name);
+/**
+ * Register to provide certificate/key files for servers. Certificate files are
+ * exepcted to contain the certificate chain, beginning with the server's certificate,
+ * excluding the trust anchor, in PEM format.
+ * They must be accompanied by a private key file, also in PEM format.
+ *
+ * @param s the server certificates are collected for
+ * @param p the pool to use for allocations
+ * @param cert_file and array of const char* with the path to the certificate chain
+ * @param key_file and array of const char* with the path to the private key file
+ * @return OK if files were added, DECLINED if not, or other for error.
+ */
+
+AP_DECLARE_HOOK(int, ssl_add_cert_files, (server_rec *s, apr_pool_t *p,
+ apr_array_header_t *cert_files,
+ apr_array_header_t *key_files))
+
+/**
+ * Collect certificate/key files from all providers registered. This includes
+ * providers registered at the global 'ssl_add_cert_files', as well as those
+ * installed in the OPTIONAL 'ssl_add_cert_files' hook as may be provided by
+ * ssl modules.
+ *
+ * @param s the server certificates are collected for
+ * @param p the pool to use for allocations
+ * @param cert_file and array of const char* with the path to the certificate chain
+ * @param key_file and array of const char* with the path to the private key file
+ */
+AP_DECLARE(apr_status_t) ap_ssl_add_cert_files(server_rec *s, apr_pool_t *p,
+ apr_array_header_t *cert_files,
+ apr_array_header_t *key_files);
+
+
+/**
+ * Register to provide 'fallback' certificates in case no 'real' certificates
+ * have been configured/added by other providers. Modules using these certificates
+ * are encouraged to answer requests to this server with a 503 response code.
+ *
+ * @param s the server certificates are collected for
+ * @param p the pool to use for allocations
+ * @param cert_file and array of const char* with the path to the certificate chain
+ * @param key_file and array of const char* with the path to the private key file
+ * @return OK if files were added, DECLINED if not, or other for error.
+ */
+AP_DECLARE_HOOK(int, ssl_add_fallback_cert_files, (server_rec *s, apr_pool_t *p,
+ apr_array_header_t *cert_files,
+ apr_array_header_t *key_files))
+
+/**
+ * Collect 'fallback' certificate/key files from all registered providers, either
+ * in the global 'ssl_add_fallback_cert_files' hook or the optional one of similar
+ * name as provided by mod_ssl and sorts.
+ * Certificates obtained this way are commonly self signed, temporary crutches.
+ * To be used to the time it takes to retrieve a 'read', trusted certificate.
+ * A module using fallbacks is encouraged to answer all requests with a 503.
+ *
+ * @param s the server certificates are collected for
+ * @param p the pool to use for allocations
+ * @param cert_file and array of const char* with the path to the certificate chain
+ * @param key_file and array of const char* with the path to the private key file
+ */
+AP_DECLARE(apr_status_t) ap_ssl_add_fallback_cert_files(server_rec *s, apr_pool_t *p,
+ apr_array_header_t *cert_files,
+ apr_array_header_t *key_files);
+
+
+/**
+ * On TLS connections that do not relate to a configured virtual host,
+ * allow modules to provide a certificate and key to
+ * be used on the connection.
+ */
+AP_DECLARE_HOOK(int, ssl_answer_challenge, (conn_rec *c, const char *server_name,
+ const char **pcert_file, const char **pkey_file))
+
+/**
+ * Returns != 0 iff the connection is a challenge to the server, for example
+ * as defined in RFC 8555 for the 'tls-alpn-01' domain verification, and needs
+ * a specific certificate as answer in the handshake.
+ * ALPN protocol negotiation via the hooks 'protocol_propose' and 'protocol_switch'
+ * need to have run before this call is made.
+ */
+AP_DECLARE(int) ap_ssl_answer_challenge(conn_rec *c, const char *server_name,
+ const char **pcert_file, const char **pkey_file);
+
+
#ifdef __cplusplus
}
#endif
diff --git a/modules/md/mod_md.c b/modules/md/mod_md.c
index 55413f5b67..dac239527f 100644
--- a/modules/md/mod_md.c
+++ b/modules/md/mod_md.c
@@ -1237,7 +1237,7 @@ static int md_answer_challenge(conn_rec *c, const char *servername,
X509 **pcert, EVP_PKEY **pkey)
{
if (md_is_challenge(c, servername, pcert, pkey)) {
- return APR_SUCCESS;
+ return OK;
}
return DECLINED;
}
diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c
index bec4d7b255..3dbdda6544 100644
--- a/modules/ssl/ssl_engine_init.c
+++ b/modules/ssl/ssl_engine_init.c
@@ -198,13 +198,18 @@ static void ssl_add_version_components(apr_pool_t *ptemp, apr_pool_t *pconf,
*/
int ssl_is_challenge(conn_rec *c, const char *servername,
- X509 **pcert, EVP_PKEY **pkey)
+ X509 **pcert, EVP_PKEY **pkey,
+ const char **pcert_file, const char **pkey_file)
{
- if (APR_SUCCESS == ssl_run_answer_challenge(c, servername, pcert, pkey)) {
- return 1;
- }
*pcert = NULL;
*pkey = NULL;
+ *pcert_file = *pkey_file = NULL;
+ if (ap_ssl_answer_challenge(c, servername, pcert_file, pkey_file)) {
+ return 1;
+ }
+ else if (OK == ssl_run_answer_challenge(c, servername, pcert, pkey)) {
+ return 1;
+ }
return 0;
}
@@ -1973,10 +1978,12 @@ static apr_status_t ssl_init_server_ctx(server_rec *s,
/* Allow others to provide certificate files */
pks = sc->server->pks;
n = pks->cert_files->nelts;
+ ap_ssl_add_cert_files(s, p, pks->cert_files, pks->key_files);
ssl_run_add_cert_files(s, p, pks->cert_files, pks->key_files);
if (apr_is_empty_array(pks->cert_files)) {
/* does someone propose a certiciate to fall back on here? */
+ ap_ssl_add_fallback_cert_files(s, p, pks->cert_files, pks->key_files);
ssl_run_add_fallback_cert_files(s, p, pks->cert_files, pks->key_files);
if (n < pks->cert_files->nelts) {
pks->service_unavailable = 1;
diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c
index 0b22c2de28..9306ec07a2 100644
--- a/modules/ssl/ssl_engine_kernel.c
+++ b/modules/ssl/ssl_engine_kernel.c
@@ -2316,11 +2316,29 @@ void ssl_callback_Info(const SSL *ssl, int where, int rc)
#ifdef HAVE_TLSEXT
static apr_status_t set_challenge_creds(conn_rec *c, const char *servername,
- SSL *ssl, X509 *cert, EVP_PKEY *key)
+ SSL *ssl, X509 *cert, EVP_PKEY *key,
+ const char *cert_file, const char *key_file)
{
SSLConnRec *sslcon = myConnConfig(c);
sslcon->service_unavailable = 1;
+ if (cert_file) {
+ if (SSL_use_certificate_chain_file(ssl, cert_file) < 1) {
+ ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c, APLOGNO()
+ "Failed to configure challenge certificate %s",
+ servername);
+ return APR_EGENERAL;
+ }
+ if (key_file == NULL) key_file = cert_file;
+ if (SSL_use_PrivateKey_file(ssl, key_file, SSL_FILETYPE_PEM) < 1) {
+ ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c, APLOGNO()
+ "Failed to configure challenge private key %s",
+ servername);
+ return APR_EGENERAL;
+ }
+ goto check;
+ }
+
if ((SSL_use_certificate(ssl, cert) < 1)) {
ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c, APLOGNO(10086)
"Failed to configure challenge certificate %s",
@@ -2336,6 +2354,7 @@ static apr_status_t set_challenge_creds(conn_rec *c, const char *servername,
return APR_EGENERAL;
}
+check:
if (SSL_check_private_key(ssl) < 1) {
ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c, APLOGNO(10088)
"Challenge certificate and private key %s "
@@ -2353,6 +2372,7 @@ static apr_status_t init_vhost(conn_rec *c, SSL *ssl, const char *servername)
{
X509 *cert;
EVP_PKEY *key;
+ const char *cert_file, *key_file;
if (c) {
SSLConnRec *sslcon = myConnConfig(c);
@@ -2376,11 +2396,12 @@ static apr_status_t init_vhost(conn_rec *c, SSL *ssl, const char *servername)
sslcon->vhost_found = +1;
return APR_SUCCESS;
}
- else if (ssl_is_challenge(c, servername, &cert, &key)) {
+ else if (ssl_is_challenge(c, servername, &cert, &key, &cert_file, &key_file)) {
/* With ACMEv1 we can have challenge connections to a unknown domains
* that need to be answered with a special certificate and will
* otherwise not answer any requests. */
- if (set_challenge_creds(c, servername, ssl, cert, key) != APR_SUCCESS) {
+ if (set_challenge_creds(c, servername, ssl, cert, key,
+ cert_file, key_file) != APR_SUCCESS) {
return APR_EGENERAL;
}
SSL_set_verify(ssl, SSL_VERIFY_NONE, ssl_callback_SSLVerify);
@@ -2771,9 +2792,11 @@ int ssl_callback_alpn_select(SSL *ssl,
const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
X509 *cert;
EVP_PKEY *key;
-
- if (ssl_is_challenge(c, servername, &cert, &key)) {
- if (set_challenge_creds(c, servername, ssl, cert, key) != APR_SUCCESS) {
+ const char *cert_file, *key_file;
+
+ if (ssl_is_challenge(c, servername, &cert, &key, &cert_file, &key_file)) {
+ if (set_challenge_creds(c, servername, ssl, cert, key,
+ cert_file, key_file) != APR_SUCCESS) {
return SSL_TLSEXT_ERR_ALERT_FATAL;
}
SSL_set_verify(ssl, SSL_VERIFY_NONE, ssl_callback_SSLVerify);
diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h
index 1fd6b7bb72..417105d387 100644
--- a/modules/ssl/ssl_private.h
+++ b/modules/ssl/ssl_private.h
@@ -1169,7 +1169,8 @@ extern int ssl_running_on_valgrind;
#endif
int ssl_is_challenge(conn_rec *c, const char *servername,
- X509 **pcert, EVP_PKEY **pkey);
+ X509 **pcert, EVP_PKEY **pkey,
+ const char **pcert_file, const char **pkey_file);
/* Set the renegotation state for connection. */
void modssl_set_reneg_state(SSLConnRec *sslconn, modssl_reneg_state state);
diff --git a/server/protocol.c b/server/protocol.c
index afd76aa07c..4ce2b6172a 100644
--- a/server/protocol.c
+++ b/server/protocol.c
@@ -72,6 +72,9 @@ APR_HOOK_STRUCT(
APR_HOOK_LINK(protocol_get)
APR_HOOK_LINK(ssl_conn_is_ssl)
APR_HOOK_LINK(ssl_var_lookup)
+ APR_HOOK_LINK(ssl_add_cert_files)
+ APR_HOOK_LINK(ssl_add_fallback_cert_files)
+ APR_HOOK_LINK(ssl_answer_challenge)
)
AP_DECLARE_DATA ap_filter_rec_t *ap_old_write_func = NULL;
@@ -2697,6 +2700,27 @@ AP_DECLARE(void) ap_setup_ssl_optional_fns(apr_pool_t *pool)
APR_REGISTER_OPTIONAL_FN(ssl_var_lookup);
}
+AP_DECLARE(apr_status_t) ap_ssl_add_cert_files(server_rec *s, apr_pool_t *p,
+ apr_array_header_t *cert_files,
+ apr_array_header_t *key_files)
+{
+ int rv = ap_run_ssl_add_cert_files(s, p, cert_files, key_files);
+ return (rv == OK || rv == DECLINED)? APR_SUCCESS : APR_EGENERAL;
+}
+
+AP_DECLARE(apr_status_t) ap_ssl_add_fallback_cert_files(server_rec *s, apr_pool_t *p,
+ apr_array_header_t *cert_files,
+ apr_array_header_t *key_files)
+{
+ int rv = ap_run_ssl_add_fallback_cert_files(s, p, cert_files, key_files);
+ return (rv == OK || rv == DECLINED)? APR_SUCCESS : APR_EGENERAL;
+}
+
+AP_DECLARE(int) ap_ssl_answer_challenge(conn_rec *c, const char *server_name,
+ const char **pcert_file, const char **pkey_file)
+{
+ return (ap_run_ssl_answer_challenge(c, server_name, pcert_file, pkey_file) == OK);
+}
AP_IMPLEMENT_HOOK_VOID(pre_read_request,
(request_rec *r, conn_rec *c),
@@ -2728,3 +2752,15 @@ AP_IMPLEMENT_HOOK_RUN_FIRST(int, ssl_conn_is_ssl,
AP_IMPLEMENT_HOOK_RUN_FIRST(const char *,ssl_var_lookup,
(apr_pool_t *p, server_rec *s, conn_rec *c, request_rec *r, const char *name),
(p, s, c, r, name), NULL)
+AP_IMPLEMENT_HOOK_RUN_ALL(int, ssl_add_cert_files,
+ (server_rec *s, apr_pool_t *p,
+ apr_array_header_t *cert_files, apr_array_header_t *key_files),
+ (s, p, cert_files, key_files), OK, DECLINED)
+AP_IMPLEMENT_HOOK_RUN_ALL(int, ssl_add_fallback_cert_files,
+ (server_rec *s, apr_pool_t *p,
+ apr_array_header_t *cert_files, apr_array_header_t *key_files),
+ (s, p, cert_files, key_files), OK, DECLINED)
+AP_IMPLEMENT_HOOK_RUN_FIRST(int, ssl_answer_challenge,
+ (conn_rec *c, const char *server_name, const char **pcert_file, const char **pkey_file),
+ (c, server_name, pcert_file, pkey_file), DECLINED)
+