From: Rainer Jung
And the `tls-alpn-01` challenge type is available.
-
Use the given http forward proxy URL to connect to the
+ Use the given http forward proxy URL to connect to the
+ This is used for connections to the HTTPS forward proxy (
+ The certificate of the ACME server is verified with the root certificates set by
+
+ Use "none" as path to disable explicitly. +
+
+ This can be configured separately for each
This is mainly used in test setups where the module needs to
diff --git a/modules/md/md.h b/modules/md/md.h
index 415a9dde72..da6bdefc9b 100644
--- a/modules/md/md.h
+++ b/modules/md/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/modules/md/md_acme.c b/modules/md/md_acme.c
index 2225ca96ee..3b102e65e5 100644
--- a/modules/md/md_acme.c
+++ b/modules/md/md_acme.c
@@ -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);
diff --git a/modules/md/md_acme.h b/modules/md/md_acme.h
index 6f9c9aa019..76c27a88dd 100644
--- a/modules/md/md_acme.h
+++ b/modules/md/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/modules/md/md_acme_drive.c b/modules/md/md_acme_drive.c
index 76e59bfe3d..bef07e52d9 100644
--- a/modules/md/md_acme_drive.c
+++ b/modules/md/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/modules/md/md_core.c b/modules/md/md_core.c
index ac3336671e..704212365e 100644
--- a/modules/md/md_core.c
+++ b/modules/md/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/modules/md/md_curl.c b/modules/md/md_curl.c
index 2484faf51a..ee1c3cabd2 100644
--- a/modules/md/md_curl.c
+++ b/modules/md/md_curl.c
@@ -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;
diff --git a/modules/md/md_http.c b/modules/md/md_http.c
index 11f10a6b1b..4884dcaa66 100644
--- a/modules/md/md_http.c
+++ b/modules/md/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/modules/md/md_http.h b/modules/md/md_http.h
index 2f250f6d76..a777c14983 100644
--- a/modules/md/md_http.h
+++ b/modules/md/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/modules/md/md_reg.c b/modules/md/md_reg.c
index 5dd0dddf90..c461fc2b61 100644
--- a/modules/md/md_reg.c
+++ b/modules/md/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/modules/md/md_reg.h b/modules/md/md_reg.h
index 0299272c2e..452b58ec3d 100644
--- a/modules/md/md_reg.h
+++ b/modules/md/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/modules/md/mod_md.c b/modules/md/mod_md.c
index f8107f44b0..03862c2298 100644
--- a/modules/md/mod_md.c
+++ b/modules/md/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/modules/md/mod_md_config.c b/modules/md/mod_md_config.c
index 7f109781cc..a691b1d016 100644
--- a/modules/md/mod_md_config.c
+++ b/modules/md/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/modules/md/mod_md_config.h b/modules/md/mod_md_config.h
index 8e685f08db..3bff6c4c7d 100644
--- a/modules/md/mod_md_config.h
+++ b/modules/md/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