]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
mod_md: New directive: MDHttpProxyCACertificateFile
authorRainer Jung <rjung@apache.org>
Tue, 16 Jun 2026 19:28:00 +0000 (19:28 +0000)
committerRainer Jung <rjung@apache.org>
Tue, 16 Jun 2026 19:28:00 +0000 (19:28 +0000)
Sets the CA certificates to use for connections to the HTTPS proxy that has
been configured with MDHttpProxy.

Merge from icing/md:
https://github.com/icing/mod_md/commit/b7c956391aa116129e24a0191eec74616ff6b1a0

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

14 files changed:
docs/manual/mod/mod_md.xml
modules/md/md.h
modules/md/md_acme.c
modules/md/md_acme.h
modules/md/md_acme_drive.c
modules/md/md_core.c
modules/md/md_curl.c
modules/md/md_http.c
modules/md/md_http.h
modules/md/md_reg.c
modules/md/md_reg.h
modules/md/mod_md.c
modules/md/mod_md_config.c
modules/md/mod_md_config.h

index 3ed739d0e81e1f8c4e7b182863248d9d777c02b1..f4aedc8592691fa0afd5a426a9eb102152b3a6bd 100644 (file)
@@ -124,7 +124,7 @@ Protocols h2 http/1.1 acme-tls/1
         </highlight>
         <p>
             And the `tls-alpn-01` challenge type is available.
-       </p>
+        </p>
         </note>
 
         <note><title>Wildcard Certificates</title>
@@ -540,12 +540,41 @@ MDCertificateAuthority https://acme-staging-v02.api.letsencrypt.org/directory
         </contextlist>
         <compatibility>Since version 2.4.69, a proxy can be configured separately for each MDomain.</compatibility>
         <usage>
-            <p>Use the given http forward proxy URL to connect to the <directive module="mod_md">MDCertificateAuthority</directive>.
+            <p>
+                Use the given http forward proxy URL to connect to the <directive module="mod_md">MDCertificateAuthority</directive>.
                 Define this if your webserver can only reach the internet with a forward proxy.
             </p>
         </usage>
     </directivesynopsis>
 
+    <directivesynopsis>
+        <name>MDHttpProxyCACertificateFile</name>
+        <description>Sets the root (CA) certificates to use for TLS connections to the http-proxy.</description>
+        <syntax>MDHttpProxyCACertificateFile <var>path-to-pem-file</var></syntax>
+        <default>MDHttpProxyCACertificateFile none</default>
+        <contextlist>
+            <context>server config</context>
+        </contextlist>
+        <compatibility>Available in version 2.4.69 and later</compatibility>
+        <usage>
+            <p>
+                This is used for connections to the HTTPS forward proxy (<directive module="mod_md">MDHttpProxy</directive>).
+                It is needed if the certificate of the HTTPS proxy cannot be verified using the general CA root store.
+                This is sometimes the case in test setups or enterprise environments.
+            </p>
+            <p>
+                The certificate of the ACME server is verified with the root certificates set by
+                <directive module="mod_md">MDCACertificateFile</directive>, so you might need to use both settings.
+            </p>
+            <p>
+                Use "none" as path to disable explicitly.
+            </p>
+            <p>
+                This can be configured separately for each <directive module="mod_md">MDomain</directive>.
+            </p>
+        </usage>
+    </directivesynopsis>
+
     <directivesynopsis>
         <name>MDMember</name>
         <description>Additional hostname for the managed domain.</description>
@@ -1623,6 +1652,7 @@ MDMessageCmd /etc/apache/md-message
         <contextlist>
             <context>server config</context>
         </contextlist>
+        <compatibility>Since version 2.4.69, this can be configured separately for each MDomain.</compatibility>
         <usage>
             <p>
                 This is mainly used in test setups where the module needs to
index 415a9dde726a6795df51efe42e1e5d3dc96fb753..da6bdefc9be1a630731d6ea03be259d018921c47 100644 (file)
@@ -103,6 +103,8 @@ struct md_t {
     const char *proxy_url;          /* Proxy URL, override global command */
     const char *ca_certs;           /* root certificates to use for connections,
                                        override global command */
+    const char *proxy_ca_certs;     /* root certificates to use for proxy connections,
+                                       override global command */
     const struct md_srv_conf_t *sc; /* server config where it was defined or NULL */
     const char *defn_name;          /* config file this MD was defined */
     unsigned defn_line_number;      /* line number of definition */
@@ -188,6 +190,7 @@ struct md_t {
 #define MD_KEY_PROFILE          "profile"
 #define MD_KEY_PROFILE_MANDATORY "profile-mandatory"
 #define MD_KEY_PROTO            "proto"
+#define MD_KEY_PROXY_CA_CERTS   "proxy-ca-certs"
 #define MD_KEY_PROXY_URL        "proxy-url"
 #define MD_KEY_READY            "ready"
 #define MD_KEY_REGISTRATION     "registration"
index 2225ca96ee70b7d8938979b24573603040179722..3b102e65e527a973611a40a516221dc182180e72 100644 (file)
@@ -624,7 +624,8 @@ apr_status_t md_acme_POST_new_account(md_acme_t *acme,
 /* ACME setup */
 
 apr_status_t md_acme_create(md_acme_t **pacme, apr_pool_t *p, const char *url,
-                            const char *proxy_url, const char *ca_file)
+                            const char *proxy_url, const char *ca_file,
+                            const char *proxy_ca_file)
 {
     md_acme_t *acme;
     const char *err = NULL;
@@ -650,6 +651,7 @@ apr_status_t md_acme_create(md_acme_t **pacme, apr_pool_t *p, const char *url,
     acme->proxy_url = apr_pstrdup(p, proxy_url);
     acme->max_retries = 9;
     acme->ca_file = ca_file;
+    acme->proxy_ca_file = proxy_ca_file;
 
     if (APR_SUCCESS != (rv = apr_uri_parse(p, url, &uri_parsed))) {
         md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "parsing ACME uri: %s", url);
@@ -802,6 +804,7 @@ apr_status_t md_acme_setup(md_acme_t *acme, md_result_t *result)
     md_http_set_connect_timeout_default(acme->http, apr_time_from_sec(30));
     md_http_set_stalling_default(acme->http, 10, apr_time_from_sec(30));
     md_http_set_ca_file(acme->http, acme->ca_file);
+    md_http_set_proxy_ca_file(acme->http, acme->proxy_ca_file);
     
     md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, acme->p, "get directory from %s", acme->url);
     
index 6f9c9aa0193df3c568731953bd0114d70fbdd6d5..76c27a88dd0ebbb3e75df36ad3ca9a9819850d58 100644 (file)
@@ -98,6 +98,7 @@ struct md_acme_t {
     const char *user_agent;
     const char *proxy_url;
     const char *ca_file;
+    const char *proxy_ca_file;
     
     const char *acct_id;            /* local storage id account was loaded from or NULL */
     struct md_acme_acct_t *acct;    /* account at ACME server to use for requests */
@@ -152,9 +153,11 @@ apr_status_t md_acme_init(apr_pool_t *pool, const char *base_version, int init_s
  * @param url     url of the server, optional if known at path
  * @param proxy_url optional url of a HTTP(S) proxy to use
  * @param ca_file optional CA trust anchor file to use
+ * @param proxy_ca_file optional CA trust anchor file to use for the HTTP proxy
  */
 apr_status_t md_acme_create(md_acme_t **pacme, apr_pool_t *p, const char *url,
-                            const char *proxy_url, const char *ca_file);
+                            const char *proxy_url, const char *ca_file,
+                            const char *proxy_ca_file);
 
 /**
  * Contact the ACME server and retrieve its directory information.
index 76e59bfe3d13d2cb01372e1acd2eb24b7c69aeb4..bef07e52d910c75b4ac5ca2c66c91bcfe6fa3051 100644 (file)
@@ -772,7 +772,8 @@ static apr_status_t acme_renew(md_proto_driver_t *d, md_result_t *result)
                               d->md->name, ca_effective);
     if (APR_SUCCESS != (rv = md_acme_create(&ad->acme, d->p, ca_effective,
                                             ad->md->proxy_url ? ad->md->proxy_url : d->proxy_url,
-                                            ad->md->ca_certs ? ad->md->ca_certs : d->ca_certs))) {
+                                            ad->md->ca_certs ? ad->md->ca_certs : d->ca_certs,
+                                            ad->md->proxy_ca_certs ? ad->md->proxy_ca_certs : d->proxy_ca_certs))) {
         md_result_printf(result, rv, "setup ACME communications");
         md_result_log(result, MD_LOG_ERR);
         goto out;
@@ -1035,7 +1036,8 @@ static apr_status_t acme_preload(md_proto_driver_t *d, md_store_group_t load_gro
         
         if (APR_SUCCESS != (rv = md_acme_create(&acme, d->p, md->ca_effective,
                                                 d->md->proxy_url ? d->md->proxy_url : d->proxy_url,
-                                                d->md->ca_certs ? d->md->ca_certs : d->ca_certs))) {
+                                                d->md->ca_certs ? d->md->ca_certs : d->ca_certs,
+                                                d->md->proxy_ca_certs ? d->md->proxy_ca_certs : d->proxy_ca_certs))) {
             md_result_set(result, rv, "error setting up acme");
             goto leave;
         }
@@ -1145,7 +1147,8 @@ static apr_status_t acme_get_ari(md_proto_driver_t *d,
 
     if (APR_SUCCESS != (rv = md_acme_create(&ad->acme, d->p, ca_effective,
                                             d->md->proxy_url ? d->md->proxy_url : d->proxy_url,
-                                            d->md->ca_certs ? d->md->ca_certs : d->ca_certs))) {
+                                            d->md->ca_certs ? d->md->ca_certs : d->ca_certs,
+                                            d->md->proxy_ca_certs ? d->md->proxy_ca_certs : d->proxy_ca_certs))) {
         md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, d->p,
                       "create ACME communications");
         goto out;
index ac3336671e0a9cc6c70cee6d5c5b2cd2c9f9c171..704212365e943d8d4f842af570ddd482081a1855 100644 (file)
@@ -260,6 +260,7 @@ md_t *md_clone(apr_pool_t *p, const md_t *src)
         if (src->dns01_cmd) md->dns01_cmd = apr_pstrdup(p, src->dns01_cmd);
         if (src->proxy_url) md->proxy_url = apr_pstrdup(p, src->proxy_url);
         if (src->ca_certs) md->ca_certs = apr_pstrdup(p, src->ca_certs);
+        if (src->proxy_ca_certs) md->proxy_ca_certs = apr_pstrdup(p, src->proxy_ca_certs);
         if (src->cert_files) md->cert_files = md_array_str_clone(p, src->cert_files);
         if (src->pkey_files) md->pkey_files = md_array_str_clone(p, src->pkey_files);
     }    
@@ -319,6 +320,7 @@ md_json_t *md_to_json(const md_t *md, apr_pool_t *p)
         if (md->dns01_cmd) md_json_sets(md->dns01_cmd, json, MD_KEY_CMD_DNS01, NULL);
         if (md->proxy_url) md_json_sets(md->proxy_url, json, MD_KEY_PROXY_URL, NULL);
         if (md->ca_certs) md_json_sets(md->ca_certs, json, MD_KEY_CA_CERTS, NULL);
+        if (md->proxy_ca_certs) md_json_sets(md->proxy_ca_certs, json, MD_KEY_PROXY_CA_CERTS, NULL);
         if (md->ca_eab_kid && strcmp("none", md->ca_eab_kid)) {
             md_json_sets(md->ca_eab_kid, json, MD_KEY_EAB, MD_KEY_KID, NULL);
             if (md->ca_eab_hmac) md_json_sets(md->ca_eab_hmac, json, MD_KEY_EAB, MD_KEY_HMAC, NULL);
@@ -390,6 +392,7 @@ md_t *md_from_json(md_json_t *json, apr_pool_t *p)
         md->dns01_cmd = md_json_dups(p, json, MD_KEY_CMD_DNS01, NULL);
         md->proxy_url = md_json_dups(p, json, MD_KEY_PROXY_URL, NULL);
         md->ca_certs = md_json_dups(p, json, MD_KEY_CA_CERTS, NULL);
+        md->proxy_ca_certs = md_json_dups(p, json, MD_KEY_PROXY_CA_CERTS, NULL);
         if (md_json_has_key(json, MD_KEY_EAB, NULL)) {
             md->ca_eab_kid = md_json_dups(p, json, MD_KEY_EAB, MD_KEY_KID, NULL);
             md->ca_eab_hmac = md_json_dups(p, json, MD_KEY_EAB, MD_KEY_HMAC, NULL);
index 2484faf51a1f1c5048c108c8b3e284c3d7d61fb9..ee1c3cabd23183932154a006a50da2f115132e19 100644 (file)
@@ -248,6 +248,7 @@ static apr_status_t internals_setup(md_http_request_t *req)
     CURL *curl;
     apr_status_t rv = APR_SUCCESS;
     long ssl_options = 0;
+    long proxy_ssl_options = 0;
 
     curl = md_http_get_impl_data(req->http);
     if (!curl) {
@@ -315,6 +316,16 @@ static apr_status_t internals_setup(md_http_request_t *req)
         ssl_options |= CURLSSLOPT_NO_REVOKE;
 #endif
     }
+    if (req->proxy_ca_file) {
+        curl_easy_setopt(curl, CURLOPT_PROXY_CAINFO, req->proxy_ca_file);
+        /* for a custom CA, allow certificates checking to ignore the
+         * Schannel error CRYPT_E_NO_REVOCATION_CHECK (could be a missing OCSP
+         * responder URL in the certs???). See issue #361 */
+#ifdef CURLSSLOPT_NO_REVOKE
+        proxy_ssl_options |= CURLSSLOPT_NO_REVOKE;
+#endif
+    }
+
     if (req->unix_socket_path) {
         curl_easy_setopt(curl, CURLOPT_UNIX_SOCKET_PATH, req->unix_socket_path);
     }
@@ -356,6 +367,9 @@ static apr_status_t internals_setup(md_http_request_t *req)
     if (ssl_options)
         curl_easy_setopt(curl, CURLOPT_SSL_OPTIONS, ssl_options);
 
+    if (proxy_ssl_options)
+        curl_easy_setopt(curl, CURLOPT_PROXY_SSL_OPTIONS, proxy_ssl_options);
+
 leave:
     req->internals = (APR_SUCCESS == rv)? internals : NULL;
     return rv;
index 11f10a6b1bbee9c3a1f8b336907bacbb0697eeaa..4884dcaa66275f96642b091b215163eb813ba23b 100644 (file)
@@ -36,6 +36,7 @@ struct md_http_t {
     const char *unix_socket_path;
     md_http_timeouts_t timeout;
     const char *ca_file;
+    const char *proxy_ca_file;
 };
 
 static md_http_impl_t *cur_impl;
@@ -107,6 +108,9 @@ apr_status_t md_http_clone(md_http_t **phttp,
         if (source_http->ca_file) {
             (*phttp)->ca_file = apr_pstrdup(p, source_http->ca_file);
         }
+        if (source_http->proxy_ca_file) {
+            (*phttp)->proxy_ca_file = apr_pstrdup(p, source_http->proxy_ca_file);
+        }
     }
     return rv;
 }
@@ -163,6 +167,11 @@ void md_http_set_ca_file(md_http_t *http, const char *ca_file)
     http->ca_file = ca_file;
 }
 
+void md_http_set_proxy_ca_file(md_http_t *http, const char *ca_file)
+{
+    http->proxy_ca_file = ca_file;
+}
+
 void md_http_set_unix_socket_path(md_http_t *http, const char *path)
 {
     http->unix_socket_path = path;
@@ -235,6 +244,7 @@ static apr_status_t req_create(md_http_request_t **preq, md_http_t *http,
     req->proxy_url = http->proxy_url;
     req->timeout = http->timeout;
     req->ca_file = http->ca_file;
+    req->proxy_ca_file = http->proxy_ca_file;
     req->unix_socket_path = http->unix_socket_path;
     *preq = req;
     return rv;
index 2f250f6d769e3a195aebb1d9937640ea1efd5695..a777c1498341c0eceea3d552ef36d11a58deeeae 100644 (file)
@@ -65,6 +65,7 @@ struct md_http_request_t {
     const char *user_agent;
     const char *proxy_url;
     const char *ca_file;
+    const char *proxy_ca_file;
     const char *unix_socket_path;
     apr_table_t *headers;
     struct apr_bucket_brigade *body;
@@ -119,12 +120,19 @@ void md_http_set_stalling_default(md_http_t *http, long bytes_per_sec, apr_time_
 void md_http_set_stalling(md_http_request_t *req, long bytes_per_sec, apr_time_t timeout);
 
 /**
- * Set a CA file (in PERM format) to use for root certificates when
+ * Set a CA file (in PEM format) to use for root certificates when
  * verifying SSL connections. If not set (or set to NULL), the systems
  * certificate store will be used.
  */
 void md_http_set_ca_file(md_http_t *http, const char *ca_file);
 
+/**
+ * Set a CA file (in PEM format) to use for root certificates when
+ * verifying SSL connections to the HTTP proxy. If not set (or set to NULL),
+ * the systems certificate store will be used.
+ */
+void md_http_set_proxy_ca_file(md_http_t *http, const char *ca_file);
+
 /**
  * Set the path of a unix domain socket for use instead of TCP
  * in a connection. Disable by providing NULL as path.
index 5dd0dddf9083f0b938b1b0956ca088a20c415639..c461fc2b614e0a9d9ba8ac81577ac3246be63af7 100644 (file)
@@ -48,6 +48,7 @@ struct md_reg_t {
     int can_https;
     const char *proxy_url;
     const char *ca_certs;
+    const char *proxy_ca_certs;
     int domains_frozen;
     md_timeslice_t *renew_window;
     md_timeslice_t *warn_window;
@@ -97,8 +98,9 @@ static apr_status_t load_props(md_reg_t *reg, apr_pool_t *p)
 
 apr_status_t md_reg_create(md_reg_t **preg, apr_pool_t *p, struct md_store_t *store,
                            const char *proxy_url, const char *ca_certs,
-                           apr_time_t min_delay, int retry_failover,
-                           int use_store_locks, apr_time_t lock_wait_timeout)
+                           const char *proxy_ca_certs, apr_time_t min_delay,
+                           int retry_failover, int use_store_locks,
+                           apr_time_t lock_wait_timeout)
 {
     md_reg_t *reg;
     apr_status_t rv;
@@ -113,6 +115,8 @@ apr_status_t md_reg_create(md_reg_t **preg, apr_pool_t *p, struct md_store_t *st
     reg->proxy_url = apr_pstrdup(p, proxy_url);
     reg->ca_certs = (ca_certs && apr_cstr_casecmp("none", ca_certs))?
                     apr_pstrdup(p, ca_certs) : NULL;
+    reg->proxy_ca_certs = (proxy_ca_certs && apr_cstr_casecmp("none", proxy_ca_certs))?
+                    apr_pstrdup(p, proxy_ca_certs) : NULL;
     reg->min_delay = min_delay;
     reg->retry_failover = retry_failover;
     reg->use_store_locks = use_store_locks;
@@ -1110,6 +1114,7 @@ static apr_status_t run_init(void *baton, apr_pool_t *p, ...)
     driver->store = md_reg_store_get(reg);
     driver->proxy_url = reg->proxy_url;
     driver->ca_certs = reg->ca_certs;
+    driver->proxy_ca_certs = reg->proxy_ca_certs;
     driver->md = md;
     driver->can_http = reg->can_http;
     driver->can_https = reg->can_https;
index 0299272c2eeba9bd55a88c5a93d4f61933126a77..452b58ec3d310e6dae308c5b897b623f10ee2652 100644 (file)
@@ -40,13 +40,15 @@ typedef struct md_reg_t md_reg_t;
  * @param store the store to base on
  * @param proxy_url optional URL of a proxy to use for requests
  * @param ca_certs optional CA trust anchor file to use
+ * @param proxy_ca_certs optional CA trust anchor file to use for the HTTP proxy
  * @param min_delay minimum delay between renewal attempts for a domain
  * @param retry_failover number of failed renewals attempt to fail over to alternate ACME ca
  */
 apr_status_t md_reg_create(md_reg_t **preg, apr_pool_t *pm, md_store_t *store,
                            const char *proxy_url, const char *ca_certs,
-                           apr_time_t min_delay, int retry_failover,
-                           int use_store_locks, apr_time_t lock_wait_timeout);
+                           const char *proxy_ca_certs, apr_time_t min_delay,
+                           int retry_failover, int use_store_locks,
+                           apr_time_t lock_wait_timeout);
 
 md_store_t *md_reg_store_get(md_reg_t *reg);
 
@@ -225,6 +227,7 @@ struct md_proto_driver_t {
     md_store_t *store;
     const char *proxy_url;
     const char *ca_certs;
+    const char *proxy_ca_certs;
     const md_t *md;
 
     int can_http;
index f8107f44b0716ac7fc3868931e2083bae2cb4614..03862c22985a1845ce46c14437c4c8f0622cd70e 100644 (file)
@@ -857,6 +857,7 @@ static apr_status_t md_post_config_before_ssl(apr_pool_t *p, apr_pool_t *plog,
     md_store_t *store;
     const char *proxy_url;
     const char *ca_certs;
+    const char *proxy_ca_certs;
 
     apr_pool_userdata_get(&data, mod_md_init_key, s->process->pool);
     if (data == NULL) {
@@ -897,8 +898,9 @@ static apr_status_t md_post_config_before_ssl(apr_pool_t *p, apr_pool_t *plog,
 
     proxy_url = apr_table_get(mc->env, MD_KEY_PROXY_URL);
     ca_certs = apr_table_get(mc->env, MD_KEY_CA_CERTS);
+    proxy_ca_certs = apr_table_get(mc->env, MD_KEY_PROXY_CA_CERTS);
 
-    rv = md_reg_create(&mc->reg, p, store, proxy_url, ca_certs,
+    rv = md_reg_create(&mc->reg, p, store, proxy_url, ca_certs, proxy_ca_certs,
                        mc->min_delay, mc->retry_failover,
                        mc->use_store_locks, mc->lock_wait_timeout);
     if (APR_SUCCESS != rv) {
index 7f109781cc8d240c6a97f51d30133a661f3a831f..a691b1d016fe4af3afb822e528d02df8d4a67361 100644 (file)
@@ -127,6 +127,7 @@ static md_srv_conf_t defconf = {
     NULL,                      /* dns01_cmd */
     NULL,                      /* proxy URL */
     NULL,                      /* CA cert file to use */
+    NULL,                      /* CA cert file to use for proxy */
     NULL,                      /* currently defined md */
     NULL,                      /* assigned md, post config */
     0,                         /* is_ssl, set during mod_ssl post_config */
@@ -187,6 +188,7 @@ static void srv_conf_props_clear(md_srv_conf_t *sc)
     sc->dns01_cmd = NULL;
     sc->proxy_url = NULL;
     sc->ca_certs = NULL;
+    sc->proxy_ca_certs = NULL;
 }
 
 static void srv_conf_props_copy(md_srv_conf_t *to, const md_srv_conf_t *from)
@@ -213,6 +215,7 @@ static void srv_conf_props_copy(md_srv_conf_t *to, const md_srv_conf_t *from)
     to->dns01_cmd = from->dns01_cmd;
     to->proxy_url = from->proxy_url;
     to->ca_certs = from->ca_certs;
+    to->proxy_ca_certs = from->proxy_ca_certs;
 }
 
 static void srv_conf_props_apply(md_t *md, const md_srv_conf_t *from, apr_pool_t *p)
@@ -242,6 +245,7 @@ static void srv_conf_props_apply(md_t *md, const md_srv_conf_t *from, apr_pool_t
     if (from->dns01_cmd) md->dns01_cmd = from->dns01_cmd;
     if (from->proxy_url) md->proxy_url = from->proxy_url;
     if (from->ca_certs) md->ca_certs = from->ca_certs;
+    if (from->proxy_ca_certs) md->proxy_ca_certs = from->proxy_ca_certs;
 }
 
 void *md_config_create_svr(apr_pool_t *pool, server_rec *s)
@@ -293,6 +297,7 @@ static void *md_config_merge(apr_pool_t *pool, void *basev, void *addv)
     nsc->dns01_cmd = (add->dns01_cmd)? add->dns01_cmd : base->dns01_cmd;
     nsc->proxy_url = (add->proxy_url)? add->proxy_url : base->proxy_url;
     nsc->ca_certs = (add->ca_certs)? add->ca_certs : base->ca_certs;
+    nsc->proxy_ca_certs = (add->proxy_ca_certs)? add->proxy_ca_certs : base->proxy_ca_certs;
     nsc->current = NULL;
     
     return nsc;
@@ -1273,6 +1278,25 @@ static const char *md_config_set_ca_certs(cmd_parms *cmd, void *arg, const char
     return NULL;
 }
 
+static const char *md_config_set_proxy_ca_certs(cmd_parms *cmd, void *arg, const char *value)
+{
+    md_srv_conf_t *sc = md_config_get(cmd->server);
+    const char *err;
+
+    if ((err = md_conf_check_location(cmd, MD_LOC_ALL))) {
+        return err;
+    }
+
+    if (inside_md_section(cmd)) {
+        sc->proxy_ca_certs = value;
+    } else {
+        apr_table_set(sc->mc->env, MD_KEY_PROXY_CA_CERTS, value);
+    }
+
+    (void)arg;
+    return NULL;
+}
+
 static const char *md_config_set_eab(cmd_parms *cmd, void *dc,
                                      const char *keyid, const char *hmac)
 {
@@ -1411,6 +1435,8 @@ const command_rec md_cmds[] = {
                   "How long to delay activation of new certificates"),
     AP_INIT_TAKE1("MDCACertificateFile", md_config_set_ca_certs, NULL, RSRC_CONF,
                   "Set the CA file to use for connections"),
+    AP_INIT_TAKE1("MDHttpProxyCACertificateFile", md_config_set_proxy_ca_certs, NULL, RSRC_CONF,
+                  "Set the CA file to use for connections to the HTTP(S) proxy"),
     AP_INIT_TAKE12("MDExternalAccountBinding", md_config_set_eab, NULL, RSRC_CONF,
                   "Set the external account binding keyid and hmac values to use at CA"),
     AP_INIT_TAKE1("MDRetryDelay", md_config_set_min_delay, NULL, RSRC_CONF,
index 8e685f08dbf909c6bf48c3e2bfa30a579d487151..3bff6c4c7d3042a1cb8d0f3a3fc1076cd5f4f8f5 100644 (file)
@@ -115,6 +115,8 @@ typedef struct md_srv_conf_t {
     const char *proxy_url;             /* Proxy URL, override global command */
     const char *ca_certs;              /* root certificates to use for connections,
                                           override global command */
+    const char *proxy_ca_certs;        /* root certificates to use for proxy connections,
+                                          override global command */
 
     md_t *current;                     /* md currently defined in <MDomainSet xxx> section */
     struct apr_array_header_t *assigned; /* post_config: MDs that apply to this server */