</highlight>
<p>
And the `tls-alpn-01` challenge type is available.
- </p>
+ </p>
</note>
<note><title>Wildcard Certificates</title>
</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>
<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
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 */
#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"
/* 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;
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);
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);
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 */
* @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.
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;
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;
}
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;
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);
}
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);
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);
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) {
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);
}
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;
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;
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;
}
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;
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;
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;
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.
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;
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;
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;
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;
* @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);
md_store_t *store;
const char *proxy_url;
const char *ca_certs;
+ const char *proxy_ca_certs;
const md_t *md;
int can_http;
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) {
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) {
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 */
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)
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)
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)
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;
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)
{
"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,
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 */