]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
Adding more ap_ssl_* functions and hooks to the core server.
authorStefan Eissing <icing@apache.org>
Tue, 2 Mar 2021 14:21:18 +0000 (14:21 +0000)
committerStefan Eissing <icing@apache.org>
Tue, 2 Mar 2021 14:21:18 +0000 (14:21 +0000)
     - 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.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1887085 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
include/ap_mmn.h
include/http_protocol.h
modules/md/mod_md.c
modules/ssl/ssl_engine_init.c
modules/ssl/ssl_engine_kernel.c
modules/ssl/ssl_private.h
server/protocol.c

diff --git a/CHANGES b/CHANGES
index 5c61df237d12a8b2a0c9158061b61bac440b81cc..b444557f8ab51403688140f0d1572976b5108d67 100644 (file)
--- 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 
index f6a6d2597ab0a741d9eecb6d466452ee0b54b561..1106c2f37ea229bfa29f4cce5ff4c126c6b4fc04 100644 (file)
  * 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" */
 #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
index 5c57a851814855dd2974618d5c3e5294823c10fa..c4f064a7c87f38e5c5a916bce13f0f70edf09180 100644 (file)
@@ -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
index 55413f5b67c4db42743a6e4419e30692da0ef048..dac239527f75e5606991eecc1ca2d109deaa5db3 100644 (file)
@@ -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;
 }
index bec4d7b2550bf5adf59a6a4d8510db2cd189234d..3dbdda65448585583ae66c0fbaf96a5b9bbe29c4 100644 (file)
@@ -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;
index 0b22c2de28831a1bb5d9a9ea68831ceed144543c..9306ec07a2b4acdffde2df2c07c838eaafb57858 100644 (file)
@@ -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);
index 1fd6b7bb7217c71b6ad0be7f9eb98fbe720d7180..417105d3874a01fedd23075e5851514de163997e 100644 (file)
@@ -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);
index afd76aa07c1d81091294df04fb3a9f8fe7dc5ccf..4ce2b6172a058b223aee9036ec4a0e53a60489f2 100644 (file)
@@ -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)
+