svn commit: r1935438 - httpd/httpd/trunk/modules/md

[email protected] Tue, 16 Jun 2026 19:13:58 -0000
Newsgroups gmane.comp.apache.cvs
Message-ID <178163723839.2529217.12608257113781826428@svn03-he-fi>
Author: rjung
Date: Tue Jun 16 19:13:58 2026
New Revision: 1935438

Log:
mod_md: Support CA-specific connection root certificates
    
Allow the MDCACertificateFile setting to be set per MDomain.
The global MDCACertificateFile setting is used by default.

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

Modified:
   httpd/httpd/trunk/modules/md/md.h
   httpd/httpd/trunk/modules/md/md_acme.h
   httpd/httpd/trunk/modules/md/md_acme_drive.c
   httpd/httpd/trunk/modules/md/md_core.c
   httpd/httpd/trunk/modules/md/md_reg.c
   httpd/httpd/trunk/modules/md/md_reg.h
   httpd/httpd/trunk/modules/md/mod_md.c
   httpd/httpd/trunk/modules/md/mod_md_config.c
   httpd/httpd/trunk/modules/md/mod_md_config.h

Modified: httpd/httpd/trunk/modules/md/md.h
==============================================================================
--- httpd/httpd/trunk/modules/md/md.h	Tue Jun 16 19:11:07 2026	(r1935437)
+++ httpd/httpd/trunk/modules/md/md.h	Tue Jun 16 19:13:58 2026	(r1935438)
@@ -101,7 +101,8 @@ struct md_t {
     struct apr_array_header_t *acme_tls_1_domains; /* domains supporting "acme-tls/1" protocol */
     const char *dns01_cmd;          /* DNS challenge command, override global command */
     const char *proxy_url;          /* Proxy URL, override global command */
-
+    const char *ca_certs;           /* root certificates to use for 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 */
@@ -126,6 +127,7 @@ struct md_t {
 #define MD_KEY_AUTHORIZATIONS   "authorizations"
 #define MD_KEY_BITS             "bits"
 #define MD_KEY_CA               "ca"
+#define MD_KEY_CA_CERTS         "ca-certs"
 #define MD_KEY_CA_URL           "ca-url"
 #define MD_KEY_CERT             "cert"
 #define MD_KEY_CERT_FILES       "cert-files"

Modified: httpd/httpd/trunk/modules/md/md_acme.h
==============================================================================
--- httpd/httpd/trunk/modules/md/md_acme.h	Tue Jun 16 19:11:07 2026	(r1935437)
+++ httpd/httpd/trunk/modules/md/md_acme.h	Tue Jun 16 19:13:58 2026	(r1935438)
@@ -151,6 +151,7 @@ apr_status_t md_acme_init(apr_pool_t *po
  * @param p       pool to used
  * @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
  */
 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);

Modified: httpd/httpd/trunk/modules/md/md_acme_drive.c
==============================================================================
--- httpd/httpd/trunk/modules/md/md_acme_drive.c	Tue Jun 16 19:11:07 2026	(r1935437)
+++ httpd/httpd/trunk/modules/md/md_acme_drive.c	Tue Jun 16 19:13:58 2026	(r1935438)
@@ -772,7 +772,7 @@ static apr_status_t acme_renew(md_proto_
                               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,
-                                            d->ca_file))) {
+                                            ad->md->ca_certs ? ad->md->ca_certs : d->ca_certs))) {
         md_result_printf(result, rv, "setup ACME communications");
         md_result_log(result, MD_LOG_ERR);
         goto out;
@@ -1035,7 +1035,7 @@ static apr_status_t acme_preload(md_prot
         
         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->ca_file))) {
+                                                d->md->ca_certs ? d->md->ca_certs : d->ca_certs))) {
             md_result_set(result, rv, "error setting up acme");
             goto leave;
         }
@@ -1145,7 +1145,7 @@ static apr_status_t acme_get_ari(md_prot
 
     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->ca_file))) {
+                                            d->md->ca_certs ? d->md->ca_certs : d->ca_certs))) {
         md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, d->p,
                       "create ACME communications");
         goto out;

Modified: httpd/httpd/trunk/modules/md/md_core.c
==============================================================================
--- httpd/httpd/trunk/modules/md/md_core.c	Tue Jun 16 19:11:07 2026	(r1935437)
+++ httpd/httpd/trunk/modules/md/md_core.c	Tue Jun 16 19:13:58 2026	(r1935438)
@@ -259,6 +259,7 @@ md_t *md_clone(apr_pool_t *p, const md_t
         md->stapling = src->stapling;
         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->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);
     }    
@@ -317,6 +318,7 @@ md_json_t *md_to_json(const md_t *md, ap
         md_json_setb(md->stapling > 0, json, MD_KEY_STAPLING, NULL);
         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->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);
@@ -387,6 +389,7 @@ md_t *md_from_json(md_json_t *json, apr_
         md->stapling = (int)md_json_getb(json, MD_KEY_STAPLING, NULL);
         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);
         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);

Modified: httpd/httpd/trunk/modules/md/md_reg.c
==============================================================================
--- httpd/httpd/trunk/modules/md/md_reg.c	Tue Jun 16 19:11:07 2026	(r1935437)
+++ httpd/httpd/trunk/modules/md/md_reg.c	Tue Jun 16 19:13:58 2026	(r1935438)
@@ -47,7 +47,7 @@ struct md_reg_t {
     int can_http;
     int can_https;
     const char *proxy_url;
-    const char *ca_file;
+    const char *ca_certs;
     int domains_frozen;
     md_timeslice_t *renew_window;
     md_timeslice_t *warn_window;
@@ -96,7 +96,7 @@ static apr_status_t load_props(md_reg_t
 }
 
 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_file,
+                           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)
 {
@@ -111,8 +111,8 @@ apr_status_t md_reg_create(md_reg_t **pr
     reg->can_http = 1;
     reg->can_https = 1;
     reg->proxy_url = apr_pstrdup(p, proxy_url);
-    reg->ca_file = (ca_file && apr_cstr_casecmp("none", ca_file))?
-                    apr_pstrdup(p, ca_file) : NULL;
+    reg->ca_certs = (ca_certs && apr_cstr_casecmp("none", ca_certs))?
+                    apr_pstrdup(p, ca_certs) : NULL;
     reg->min_delay = min_delay;
     reg->retry_failover = retry_failover;
     reg->use_store_locks = use_store_locks;
@@ -1109,7 +1109,7 @@ static apr_status_t run_init(void *baton
     driver->reg = reg;
     driver->store = md_reg_store_get(reg);
     driver->proxy_url = reg->proxy_url;
-    driver->ca_file = reg->ca_file;
+    driver->ca_certs = reg->ca_certs;
     driver->md = md;
     driver->can_http = reg->can_http;
     driver->can_https = reg->can_https;

Modified: httpd/httpd/trunk/modules/md/md_reg.h
==============================================================================
--- httpd/httpd/trunk/modules/md/md_reg.h	Tue Jun 16 19:11:07 2026	(r1935437)
+++ httpd/httpd/trunk/modules/md/md_reg.h	Tue Jun 16 19:13:58 2026	(r1935438)
@@ -39,12 +39,12 @@ typedef struct md_reg_t md_reg_t;
  * @param pm memory pool to use for creation
  * @param store the store to base on
  * @param proxy_url optional URL of a proxy to use for requests
- * @param ca_file  optioinal CA trust anchor file to use
+ * @param ca_certs optional CA trust anchor file to use
  * @param min_delay minimum delay between renewal attempts for a domain
- * @param retry_failover numer of failed renewals attempt to fail over to alternate ACME ca
+ * @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_file,
+                           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);
 
@@ -224,7 +224,7 @@ struct md_proto_driver_t {
     md_reg_t *reg;
     md_store_t *store;
     const char *proxy_url;
-    const char *ca_file;
+    const char *ca_certs;
     const md_t *md;
 
     int can_http;

Modified: httpd/httpd/trunk/modules/md/mod_md.c
==============================================================================
--- httpd/httpd/trunk/modules/md/mod_md.c	Tue Jun 16 19:11:07 2026	(r1935437)
+++ httpd/httpd/trunk/modules/md/mod_md.c	Tue Jun 16 19:13:58 2026	(r1935438)
@@ -856,6 +856,7 @@ static apr_status_t md_post_config_befor
     int dry_run = 0, log_level = APLOG_DEBUG;
     md_store_t *store;
     const char *proxy_url;
+    const char *ca_certs;
 
     apr_pool_userdata_get(&data, mod_md_init_key, s->process->pool);
     if (data == NULL) {
@@ -895,8 +896,9 @@ static apr_status_t md_post_config_befor
     if (APR_SUCCESS != rv) goto leave;
 
     proxy_url = apr_table_get(mc->env, MD_KEY_PROXY_URL);
+    ca_certs = apr_table_get(mc->env, MD_KEY_CA_CERTS);
 
-    rv = md_reg_create(&mc->reg, p, store, proxy_url, mc->ca_certs,
+    rv = md_reg_create(&mc->reg, p, store, proxy_url, ca_certs,
                        mc->min_delay, mc->retry_failover,
                        mc->use_store_locks, mc->lock_wait_timeout);
     if (APR_SUCCESS != rv) {

Modified: httpd/httpd/trunk/modules/md/mod_md_config.c
==============================================================================
--- httpd/httpd/trunk/modules/md/mod_md_config.c	Tue Jun 16 19:11:07 2026	(r1935437)
+++ httpd/httpd/trunk/modules/md/mod_md_config.c	Tue Jun 16 19:13:58 2026	(r1935438)
@@ -82,7 +82,6 @@ static md_mod_conf_t defmc = {
     &def_ocsp_renew_window,    /* default time to renew ocsp responses */
     "crt.sh",                  /* default cert checker site name */
     "https://crt.sh?q=",       /* default cert checker site url */
-    NULL,                      /* CA cert file to use */
     APR_TIME_C(0),             /* initial cert check delay */
     apr_time_from_sec(MD_SECS_PER_DAY/2), /* default time between cert checks */
     apr_time_from_sec(30),     /* minimum delay for retries */
@@ -127,6 +126,7 @@ static md_srv_conf_t defconf = {
     1,                         /* ACME ARI renewals */
     NULL,                      /* dns01_cmd */
     NULL,                      /* proxy URL */
+    NULL,                      /* CA cert file to use */
     NULL,                      /* currently defined md */
     NULL,                      /* assigned md, post config */
     0,                         /* is_ssl, set during mod_ssl post_config */
@@ -186,6 +186,7 @@ static void srv_conf_props_clear(md_srv_
     sc->ari_renewals = DEF_VAL;
     sc->dns01_cmd = NULL;
     sc->proxy_url = NULL;
+    sc->ca_certs = NULL;
 }
 
 static void srv_conf_props_copy(md_srv_conf_t *to, const md_srv_conf_t *from)
@@ -211,6 +212,7 @@ static void srv_conf_props_copy(md_srv_c
     to->ari_renewals = from->ari_renewals;
     to->dns01_cmd = from->dns01_cmd;
     to->proxy_url = from->proxy_url;
+    to->ca_certs = from->ca_certs;
 }
 
 static void srv_conf_props_apply(md_t *md, const md_srv_conf_t *from, apr_pool_t *p)
@@ -239,6 +241,7 @@ static void srv_conf_props_apply(md_t *m
     if (from->stapling != DEF_VAL) md->stapling = from->stapling;
     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;
 }
 
 void *md_config_create_svr(apr_pool_t *pool, server_rec *s)
@@ -289,6 +292,7 @@ static void *md_config_merge(apr_pool_t
     nsc->ari_renewals = (add->ari_renewals != DEF_VAL)? add->ari_renewals : base->ari_renewals;
     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->current = NULL;
     
     return nsc;
@@ -1250,12 +1254,22 @@ static const char *md_config_set_activat
     return NULL;
 }
 
-static const char *md_config_set_ca_certs(cmd_parms *cmd, void *dc, const char *path)
+static const char *md_config_set_ca_certs(cmd_parms *cmd, void *arg, const char *value)
 {
     md_srv_conf_t *sc = md_config_get(cmd->server);
+    const char *err;
 
-    (void)dc;
-    sc->mc->ca_certs = path;
+    if ((err = md_conf_check_location(cmd, MD_LOC_ALL))) {
+        return err;
+    }
+
+    if (inside_md_section(cmd)) {
+        sc->ca_certs = value;
+    } else {
+        apr_table_set(sc->mc->env, MD_KEY_CA_CERTS, value);
+    }
+
+    (void)arg;
     return NULL;
 }
 

Modified: httpd/httpd/trunk/modules/md/mod_md_config.h
==============================================================================
--- httpd/httpd/trunk/modules/md/mod_md_config.h	Tue Jun 16 19:11:07 2026	(r1935437)
+++ httpd/httpd/trunk/modules/md/mod_md_config.h	Tue Jun 16 19:13:58 2026	(r1935438)
@@ -75,7 +75,6 @@ struct md_mod_conf_t {
     md_timeslice_t *ocsp_renew_window; /* time before exp. that we start renewing ocsp resp. */
     const char *cert_check_name;       /* name of the linked certificate check site */
     const char *cert_check_url;        /* url "template for" checking a certificate */
-    const char *ca_certs;              /* root certificates to use for connections */
     apr_time_t initial_delay;          /* how long to delay the first cert renewal check */
     apr_time_t check_interval;         /* duration between cert renewal checks */
     apr_time_t min_delay;              /* minimum delay for retries */
@@ -114,6 +113,8 @@ typedef struct md_srv_conf_t {
 
     const char *dns01_cmd;             /* DNS challenge command, override global command */
     const char *proxy_url;             /* Proxy URL, override global command */
+    const char *ca_certs;              /* root certificates to use for 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 */