diff --git a/README.md b/README.md index f836b70..4e2ff0e 100644 --- a/README.md +++ b/README.md @@ -1755,6 +1755,7 @@ checks by mod_md in v1.1.x which are now eliminated. If you have many domains, t * [MDProfile](#mdprofile) * [MDProfileMandatory](#mdprofilemandatory) * [MDHttpProxy](#mdhttpproxy) +* [MDHttpProxyCACertificateFile](#mdhttpproxycacertificatefile) * [MDRenewViaARI](#mdrenewviaari) * [MDRenewMode](#mdrenewmode--renew-mode) * [MDRenewWindow](#mdrenewwindow--when-to-renew) @@ -2101,10 +2102,24 @@ best matching your client's capabilities. ***The URL of the http-proxy to use***
`MDHttpProxy url` -Use a proxy (on `url`) to connect to the MDCertificateAuthority url. Use if your webserver has no outbound connectivity in combination with your forward proxy. +Use a proxy (on `url`) to connect to the `MDCertificateAuthority` url. Use if your webserver has no outbound connectivity in combination with your forward proxy. Since version 2.6.11, a proxy can be configured separately for each `MDomain`. +## MDHttpProxyCACertificateFile + +***Sets the root (CA) certificates to use for TLS connections to the http-proxy***
+`MDHttpProxyCACertificateFile path-to-pem-file`
+Default: none + +This is used for connections to the HTTPS proxy (`MDHttpProxy`). 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. +The certificate of the ACME server is verified with the root certificates set by `MDCACertificateFile`, so you might need to use both settings. + +Use "none" as path to disable explicitly. + +This can be configured separately for each `MDomain`. + ## MDRenewMode / Renew Mode ***Controls when `mod_md` will try to obtain/renew certificates***
@@ -2340,6 +2355,8 @@ store already and there is no special need. Use "none" as path to disable explicitly. +Since version 2.6.11, this can be configured separately for each `MDomain`. + ## MDExternalAccountBinding ***Sets the external account binding (EAB) information to use***
`MDExternalAccountBinding key-id hmac-value | json-file` diff --git a/src/md.h b/src/md.h index 415a9dd..da6bdef 100644 --- a/src/md.h +++ b/src/md.h @@ -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" diff --git a/src/md_acme.c b/src/md_acme.c index f9beefb..25750ad 100644 --- a/src/md_acme.c +++ b/src/md_acme.c @@ -622,7 +622,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; @@ -648,6 +649,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); @@ -800,6 +802,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); diff --git a/src/md_acme.h b/src/md_acme.h index 6f9c9aa..76c27a8 100644 --- a/src/md_acme.h +++ b/src/md_acme.h @@ -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. diff --git a/src/md_acme_drive.c b/src/md_acme_drive.c index 76e59bf..bef07e5 100644 --- a/src/md_acme_drive.c +++ b/src/md_acme_drive.c @@ -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; diff --git a/src/md_cmd_main.c b/src/md_cmd_main.c index 6580422..e814d83 100644 --- a/src/md_cmd_main.c +++ b/src/md_cmd_main.c @@ -186,7 +186,7 @@ static apr_status_t cmd_process(md_cmd_ctx *ctx, const md_cmd_t *cmd) } if (APR_SUCCESS != (rv = md_reg_create(&ctx->reg, ctx->p, ctx->store, md_cmd_ctx_get_option(ctx, MD_CMD_OPT_PROXY_URL), - ctx->ca_file, apr_time_from_sec(15), 10, + ctx->ca_file, NULL, apr_time_from_sec(15), 10, 0, apr_time_from_sec(5)))) { fprintf(stderr, "error %d creating registry from store: %s\n", rv, ctx->base_dir); return APR_EINVAL; @@ -199,7 +199,7 @@ static apr_status_t cmd_process(md_cmd_ctx *ctx, const md_cmd_t *cmd) } rv = md_acme_create(&ctx->acme, ctx->p, ctx->ca_url, md_cmd_ctx_get_option(ctx, MD_CMD_OPT_PROXY_URL), - ctx->ca_file); + ctx->ca_file, NULL); if (APR_SUCCESS != rv) { fprintf(stderr, "error creating acme instance %s (%s)\n", ctx->ca_url, ctx->base_dir); diff --git a/src/md_core.c b/src/md_core.c index ac33366..7042123 100644 --- a/src/md_core.c +++ b/src/md_core.c @@ -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); diff --git a/src/md_curl.c b/src/md_curl.c index fac2ab8..240c698 100644 --- a/src/md_curl.c +++ b/src/md_curl.c @@ -246,6 +246,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) { @@ -313,6 +314,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); } @@ -354,6 +365,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; diff --git a/src/md_http.c b/src/md_http.c index 11f10a6..4884dca 100644 --- a/src/md_http.c +++ b/src/md_http.c @@ -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; diff --git a/src/md_http.h b/src/md_http.h index 2f250f6..a777c14 100644 --- a/src/md_http.h +++ b/src/md_http.h @@ -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. diff --git a/src/md_reg.c b/src/md_reg.c index 5dd0ddd..c461fc2 100644 --- a/src/md_reg.c +++ b/src/md_reg.c @@ -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; diff --git a/src/md_reg.h b/src/md_reg.h index 0299272..452b58e 100644 --- a/src/md_reg.h +++ b/src/md_reg.h @@ -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; diff --git a/src/mod_md.c b/src/mod_md.c index f8107f4..03862c2 100644 --- a/src/mod_md.c +++ b/src/mod_md.c @@ -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) { diff --git a/src/mod_md_config.c b/src/mod_md_config.c index f6179b9..7a1b48c 100644 --- a/src/mod_md_config.c +++ b/src/mod_md_config.c @@ -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, diff --git a/src/mod_md_config.h b/src/mod_md_config.h index 8e685f0..3bff6c4 100644 --- a/src/mod_md_config.h +++ b/src/mod_md_config.h @@ -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 section */ struct apr_array_header_t *assigned; /* post_config: MDs that apply to this server */