You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ic...@apache.org on 2017/09/13 14:16:49 UTC
svn commit: r1808241 - in /httpd/httpd/trunk: ./ modules/md/
Author: icing
Date: Wed Sep 13 14:16:49 2017
New Revision: 1808241
URL: http://svn.apache.org/viewvc?rev=1808241&view=rev
Log:
On the trunk:
mod_md: v0.9.5:
- New directive (srly: what do you expect at this point?) "MDMustStaple on|off" to control if
new certificates are requested with the OCSP Must Staple extension.
- Known limitation: when the server is configured to ditch and restart child processes, for example
after a certain number of connections/requests, the mod_md watchdog instance might migrate
to a new child process. Since not all its state is persisted, some messsages might appear a
second time in the logs.
- Adding checks when 'MDRequireHttps' is used. It is considered an error when 'MDPortMap 443:-'
is used - which negates that a https: port exists. Also, a warning is logged if no
VirtualHost can be found for a Managed Domain that has port 443 (or the mapped one) in
its address list.
- New directive 'MDRequireHttps' for redirecting http: traffic to a Managed Domain, permanently
or temporarily.
- Fix for using a fallback certificate on initial signup of a Managed Domain. Requires also
a changed mod_ssl patch (v5) to take effect.
- compatibility with libressl
Modified:
httpd/httpd/trunk/CHANGES
httpd/httpd/trunk/modules/md/md.h
httpd/httpd/trunk/modules/md/md_acme_authz.c
httpd/httpd/trunk/modules/md/md_core.c
httpd/httpd/trunk/modules/md/md_crypt.c
httpd/httpd/trunk/modules/md/md_crypt.h
httpd/httpd/trunk/modules/md/md_reg.c
httpd/httpd/trunk/modules/md/md_reg.h
httpd/httpd/trunk/modules/md/md_store_fs.c
httpd/httpd/trunk/modules/md/md_util.c
httpd/httpd/trunk/modules/md/md_util.h
httpd/httpd/trunk/modules/md/md_version.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/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/CHANGES?rev=1808241&r1=1808240&r2=1808241&view=diff
==============================================================================
--- httpd/httpd/trunk/CHANGES [utf-8] (original)
+++ httpd/httpd/trunk/CHANGES [utf-8] Wed Sep 13 14:16:49 2017
@@ -1,6 +1,24 @@
-*- coding: utf-8 -*-
Changes with Apache 2.5.0
+ *) mod_md: v0.9.5:
+ - New directive (srly: what do you expect at this point?) "MDMustStaple on|off" to control if
+ new certificates are requested with the OCSP Must Staple extension.
+ - Known limitation: when the server is configured to ditch and restart child processes, for example
+ after a certain number of connections/requests, the mod_md watchdog instance might migrate
+ to a new child process. Since not all its state is persisted, some messsages might appear a
+ second time in the logs.
+ - Adding checks when 'MDRequireHttps' is used. It is considered an error when 'MDPortMap 443:-'
+ is used - which negates that a https: port exists. Also, a warning is logged if no
+ VirtualHost can be found for a Managed Domain that has port 443 (or the mapped one) in
+ its address list.
+ - New directive 'MDRequireHttps' for redirecting http: traffic to a Managed Domain, permanently
+ or temporarily.
+ - Fix for using a fallback certificate on initial signup of a Managed Domain. Requires also
+ a changed mod_ssl patch (v5) to take effect.
+ - compatibility with libressl
+ [Stefan Eissing]
+
*) htdigest: prevent a buffer overflow when a string exceeds the allowed max
length in a password file.
[Luca Toscano, Hanno Böck <hanno hboeck de>]
Modified: httpd/httpd/trunk/modules/md/md.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/md/md.h?rev=1808241&r1=1808240&r2=1808241&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/md/md.h (original)
+++ httpd/httpd/trunk/modules/md/md.h Wed Sep 13 14:16:49 2017
@@ -42,6 +42,13 @@ typedef enum {
} md_state_t;
typedef enum {
+ MD_REQUIRE_UNSET = -1,
+ MD_REQUIRE_OFF,
+ MD_REQUIRE_TEMPORARY,
+ MD_REQUIRE_PERMANENT,
+} md_require_t;
+
+typedef enum {
MD_SV_TEXT,
MD_SV_JSON,
MD_SV_CERT,
@@ -74,6 +81,8 @@ struct md_t {
struct apr_array_header_t *contacts; /* list of contact uris, e.g. mailto:xxx */
int transitive; /* != 0 iff VirtualHost names/aliases are auto-added */
+ md_require_t require_https; /* Iff https: is required for this MD */
+
int drive_mode; /* mode of obtaining credentials */
struct md_pkey_spec_t *pkey_spec;/* specification for generating new private keys */
int must_staple; /* certificates should set the OCSP Must Staple extension */
@@ -119,16 +128,20 @@ struct md_t {
#define MD_KEY_KEY "key"
#define MD_KEY_KEYAUTHZ "keyAuthorization"
#define MD_KEY_LOCATION "location"
+#define MD_KEY_MUST_STAPLE "must-staple"
#define MD_KEY_NAME "name"
+#define MD_KEY_PERMANENT "permanent"
#define MD_KEY_PKEY "privkey"
#define MD_KEY_PROTO "proto"
#define MD_KEY_REGISTRATION "registration"
#define MD_KEY_RENEW "renew"
#define MD_KEY_RENEW_WINDOW "renew-window"
+#define MD_KEY_REQUIRE_HTTPS "require-https"
#define MD_KEY_RESOURCE "resource"
#define MD_KEY_STATE "state"
#define MD_KEY_STATUS "status"
#define MD_KEY_STORE "store"
+#define MD_KEY_TEMPORARY "temporary"
#define MD_KEY_TOKEN "token"
#define MD_KEY_TRANSITIVE "transitive"
#define MD_KEY_TYPE "type"
Modified: httpd/httpd/trunk/modules/md/md_acme_authz.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/md/md_acme_authz.c?rev=1808241&r1=1808240&r2=1808241&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/md/md_acme_authz.c (original)
+++ httpd/httpd/trunk/modules/md/md_acme_authz.c Wed Sep 13 14:16:49 2017
@@ -356,6 +356,7 @@ static apr_status_t cha_tls_sni_01_setup
const char *cha_dns;
apr_status_t rv;
int notify_server;
+ apr_array_header_t *domains;
if ( APR_SUCCESS != (rv = setup_key_authz(cha, authz, acme, p, ¬ify_server))
|| APR_SUCCESS != (rv = setup_cha_dns(&cha_dns, cha, p))) {
@@ -374,7 +375,9 @@ static apr_status_t cha_tls_sni_01_setup
}
/* setup a certificate containing the challenge dns */
- rv = md_cert_self_sign(&cha_cert, authz->domain, cha_dns, cha_key,
+ domains = apr_array_make(p, 5, sizeof(const char*));
+ APR_ARRAY_PUSH(domains, const char*) = cha_dns;
+ rv = md_cert_self_sign(&cha_cert, authz->domain, domains, cha_key,
apr_time_from_sec(7 * MD_SECS_PER_DAY), p);
if (APR_SUCCESS != rv) {
Modified: httpd/httpd/trunk/modules/md/md_core.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/md/md_core.c?rev=1808241&r1=1808240&r2=1808241&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/md/md_core.c (original)
+++ httpd/httpd/trunk/modules/md/md_core.c Wed Sep 13 14:16:49 2017
@@ -85,6 +85,8 @@ md_t *md_create_empty(apr_pool_t *p)
md->domains = apr_array_make(p, 5, sizeof(const char *));
md->contacts = apr_array_make(p, 5, sizeof(const char *));
md->drive_mode = MD_DRIVE_DEFAULT;
+ md->require_https = MD_REQUIRE_UNSET;
+ md->must_staple = -1;
md->transitive = -1;
md->defn_name = "unknown";
md->defn_line_number = 0;
@@ -256,6 +258,8 @@ md_t *md_clone(apr_pool_t *p, const md_t
if (md) {
md->state = src->state;
md->name = apr_pstrdup(p, src->name);
+ md->require_https = src->require_https;
+ md->must_staple = src->must_staple;
md->drive_mode = src->drive_mode;
md->domains = md_array_str_compact(p, src->domains, 0);
md->pkey_spec = src->pkey_spec;
@@ -283,6 +287,8 @@ md_t *md_merge(apr_pool_t *p, const md_t
n->ca_url = add->ca_url? add->ca_url : base->ca_url;
n->ca_proto = add->ca_proto? add->ca_proto : base->ca_proto;
n->ca_agreement = add->ca_agreement? add->ca_agreement : base->ca_agreement;
+ n->require_https = (add->require_https != MD_REQUIRE_UNSET)? add->require_https : base->require_https;
+ n->must_staple = (add->must_staple >= 0)? add->must_staple : base->must_staple;
n->drive_mode = (add->drive_mode != MD_DRIVE_DEFAULT)? add->drive_mode : base->drive_mode;
n->pkey_spec = add->pkey_spec? add->pkey_spec : base->pkey_spec;
n->renew_norm = (add->renew_norm > 0)? add->renew_norm : base->renew_norm;
@@ -344,6 +350,17 @@ md_json_t *md_to_json(const md_t *md, ap
na = md_array_str_compact(p, md->ca_challenges, 0);
md_json_setsa(na, json, MD_KEY_CA, MD_KEY_CHALLENGES, NULL);
}
+ switch (md->require_https) {
+ case MD_REQUIRE_TEMPORARY:
+ md_json_sets(MD_KEY_TEMPORARY, json, MD_KEY_REQUIRE_HTTPS, NULL);
+ break;
+ case MD_REQUIRE_PERMANENT:
+ md_json_sets(MD_KEY_PERMANENT, json, MD_KEY_REQUIRE_HTTPS, NULL);
+ break;
+ default:
+ break;
+ }
+ md_json_setb(md->must_staple > 0, json, MD_KEY_MUST_STAPLE, NULL);
return json;
}
return NULL;
@@ -380,7 +397,7 @@ md_t *md_from_json(md_json_t *json, apr_
md->renew_norm = 0;
md->renew_window = apr_time_from_sec(md_json_getl(json, MD_KEY_RENEW_WINDOW, NULL));
if (md->renew_window <= 0) {
- const char *s = md_json_gets(json, MD_KEY_RENEW_WINDOW, NULL);
+ s = md_json_gets(json, MD_KEY_RENEW_WINDOW, NULL);
if (s && strchr(s, '%')) {
int percent = atoi(s);
if (0 < percent && percent < 100) {
@@ -393,6 +410,16 @@ md_t *md_from_json(md_json_t *json, apr_
md->ca_challenges = apr_array_make(p, 5, sizeof(const char*));
md_json_dupsa(md->ca_challenges, p, json, MD_KEY_CA, MD_KEY_CHALLENGES, NULL);
}
+ md->require_https = MD_REQUIRE_OFF;
+ s = md_json_gets(json, MD_KEY_REQUIRE_HTTPS, NULL);
+ if (s && !strcmp(MD_KEY_TEMPORARY, s)) {
+ md->require_https = MD_REQUIRE_TEMPORARY;
+ }
+ else if (s && !strcmp(MD_KEY_PERMANENT, s)) {
+ md->require_https = MD_REQUIRE_PERMANENT;
+ }
+ md->must_staple = (int)md_json_getb(json, MD_KEY_MUST_STAPLE, NULL);
+
return md;
}
return NULL;
Modified: httpd/httpd/trunk/modules/md/md_crypt.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/md/md_crypt.c?rev=1808241&r1=1808240&r2=1808241&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/md/md_crypt.c (original)
+++ httpd/httpd/trunk/modules/md/md_crypt.c Wed Sep 13 14:16:49 2017
@@ -179,6 +179,66 @@ static int pem_passwd(char *buf, int siz
}
/**************************************************************************************************/
+/* date time things */
+
+/* Get the apr time (micro seconds, since 1970) from an ASN1 time, as stored in X509
+ * certificates. OpenSSL now has a utility function, but other *SSL derivatives have
+ * not caughts up yet or chose to ignore. An alternative is implemented, we prefer
+ * however the *SSL to maintain such things.
+ */
+static apr_time_t md_asn1_time_get(const ASN1_TIME* time)
+{
+#ifdef LIBRESSL_VERSION_NUMBER
+ /* courtesy: https://stackoverflow.com/questions/10975542/asn1-time-to-time-t-conversion#11263731
+ * all bugs are mine */
+ apr_time_exp_t t;
+ apr_time_t ts;
+ const char* str = (const char*) time->data;
+ apr_size_t i = 0;
+
+ memset(&t, 0, sizeof(t));
+
+ if (time->type == V_ASN1_UTCTIME) {/* two digit year */
+ t.tm_year = (str[i++] - '0') * 10;
+ t.tm_year += (str[i++] - '0');
+ if (t.tm_year < 70)
+ t.tm_year += 100;
+ }
+ else if (time->type == V_ASN1_GENERALIZEDTIME) {/* four digit year */
+ t.tm_year = (str[i++] - '0') * 1000;
+ t.tm_year+= (str[i++] - '0') * 100;
+ t.tm_year+= (str[i++] - '0') * 10;
+ t.tm_year+= (str[i++] - '0');
+ t.tm_year -= 1900;
+ }
+ t.tm_mon = (str[i++] - '0') * 10;
+ t.tm_mon += (str[i++] - '0') - 1; /* -1 since January is 0 not 1. */
+ t.tm_mday = (str[i++] - '0') * 10;
+ t.tm_mday+= (str[i++] - '0');
+ t.tm_hour = (str[i++] - '0') * 10;
+ t.tm_hour+= (str[i++] - '0');
+ t.tm_min = (str[i++] - '0') * 10;
+ t.tm_min += (str[i++] - '0');
+ t.tm_sec = (str[i++] - '0') * 10;
+ t.tm_sec += (str[i++] - '0');
+
+ if (APR_SUCCESS == apr_time_exp_gmt_get(&ts, &t)) {
+ return ts;
+ }
+ return 0;
+#else
+ int secs, days;
+ apr_time_t ts = apr_time_now();
+
+ if (ASN1_TIME_diff(&days, &secs, NULL, time)) {
+ ts += apr_time_from_sec((days * MD_SECS_PER_DAY) + secs);
+ }
+ return ts;
+#endif
+}
+
+
+/**************************************************************************************************/
/* private keys */
md_json_t *md_pkey_spec_to_json(const md_pkey_spec_t *spec, apr_pool_t *p)
@@ -409,7 +469,7 @@ apr_status_t md_pkey_gen(md_pkey_t **ppk
}
}
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
#ifndef NID_tlsfeature
#define NID_tlsfeature 1020
@@ -658,26 +718,12 @@ int md_cert_has_expired(const md_cert_t
apr_time_t md_cert_get_not_after(md_cert_t *cert)
{
- int secs, days;
- apr_time_t time = apr_time_now();
- ASN1_TIME *not_after = X509_get_notAfter(cert->x509);
-
- if (ASN1_TIME_diff(&days, &secs, NULL, not_after)) {
- time += apr_time_from_sec((days * MD_SECS_PER_DAY) + secs);
- }
- return time;
+ return md_asn1_time_get(X509_get_notAfter(cert->x509));
}
apr_time_t md_cert_get_not_before(md_cert_t *cert)
{
- int secs, days;
- apr_time_t time = apr_time_now();
- ASN1_TIME *not_after = X509_get_notBefore(cert->x509);
-
- if (ASN1_TIME_diff(&days, &secs, NULL, not_after)) {
- time += apr_time_from_sec((days * MD_SECS_PER_DAY) + secs);
- }
- return time;
+ return md_asn1_time_get(X509_get_notBefore(cert->x509));
}
int md_cert_covers_domain(md_cert_t *cert, const char *domain_name)
@@ -991,11 +1037,6 @@ apr_status_t md_chain_fsave(apr_array_he
/**************************************************************************************************/
/* certificate signing requests */
-static const char *alt_name(const char *domain, apr_pool_t *p)
-{
- return apr_psprintf(p, "DNS:%s", domain);
-}
-
static const char *alt_names(apr_array_header_t *domains, apr_pool_t *p)
{
const char *alts = "", *sep = "", *domain;
@@ -1051,9 +1092,19 @@ static apr_status_t add_must_staple(STAC
{
if (md->must_staple) {
- X509_EXTENSION *x = X509V3_EXT_conf_nid(NULL, NULL,
- NID_tlsfeature, (char*)"DER:30:03:02:01:05");
+ X509_EXTENSION *x;
+ int nid;
+
+ nid = OBJ_create("1.3.6.1.5.5.7.1.24", "OCSPReq", "OCSP Request");
+ if (NID_undef == nid) {
+ md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p,
+ "%s: unable to get NID for must-staple", md->name);
+ return APR_EGENERAL;
+ }
+ x = X509V3_EXT_conf_nid(NULL, NULL, nid, (char*)"DER:30:03:02:01:05");
if (NULL == x) {
+ md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p,
+ "%s: unable to get x509 extension for must-staple", md->name);
return APR_EGENERAL;
}
sk_X509_EXTENSION_push(exts, x);
@@ -1140,7 +1191,7 @@ out:
}
apr_status_t md_cert_self_sign(md_cert_t **pcert, const char *cn,
- const char *domain, md_pkey_t *pkey,
+ apr_array_header_t *domains, md_pkey_t *pkey,
apr_interval_time_t valid_for, apr_pool_t *p)
{
X509 *x;
@@ -1152,45 +1203,45 @@ apr_status_t md_cert_self_sign(md_cert_t
ASN1_INTEGER *asn1_rnd = NULL;
unsigned char rnd[20];
- assert(domain);
+ assert(domains);
if (NULL == (x = X509_new())
|| NULL == (n = X509_NAME_new())) {
rv = APR_ENOMEM;
- md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "%s: openssl alloc X509 things", domain);
+ md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "%s: openssl alloc X509 things", cn);
goto out;
}
if (APR_SUCCESS != (rv = md_rand_bytes(rnd, sizeof(rnd), p))
|| !(big_rnd = BN_bin2bn(rnd, sizeof(rnd), NULL))
|| !(asn1_rnd = BN_to_ASN1_INTEGER(big_rnd, NULL))) {
- md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "%s: setup random serial", domain);
+ md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "%s: setup random serial", cn);
rv = APR_EGENERAL; goto out;
}
if (!X509_set_serialNumber(x, asn1_rnd)) {
- md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "%s: set serial number", domain);
+ md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "%s: set serial number", cn);
rv = APR_EGENERAL; goto out;
}
/* set common name and issue */
if (!X509_NAME_add_entry_by_txt(n, "CN", MBSTRING_ASC, (const unsigned char*)cn, -1, -1, 0)
|| !X509_set_subject_name(x, n)
|| !X509_set_issuer_name(x, n)) {
- md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "%s: name add entry", domain);
+ md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "%s: name add entry", cn);
rv = APR_EGENERAL; goto out;
}
/* cert are uncontrained (but not very trustworthy) */
if (APR_SUCCESS != (rv = add_ext(x, NID_basic_constraints, "CA:TRUE, pathlen:0", p))) {
- md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: set basic constraints ext", domain);
+ md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: set basic constraints ext", cn);
goto out;
}
/* add the domain as alt name */
- if (APR_SUCCESS != (rv = add_ext(x, NID_subject_alt_name, alt_name(domain, p), p))) {
- md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: set alt_name ext", domain);
+ if (APR_SUCCESS != (rv = add_ext(x, NID_subject_alt_name, alt_names(domains, p), p))) {
+ md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: set alt_name ext", cn);
goto out;
}
/* add our key */
if (!X509_set_pubkey(x, pkey->pkey)) {
- md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: set pkey in x509", domain);
+ md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: set pkey in x509", cn);
rv = APR_EGENERAL; goto out;
}
@@ -1204,7 +1255,7 @@ apr_status_t md_cert_self_sign(md_cert_t
/* sign with same key */
if (!X509_sign(x, pkey->pkey, EVP_sha256())) {
- md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: sign x509", domain);
+ md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: sign x509", cn);
rv = APR_EGENERAL; goto out;
}
Modified: httpd/httpd/trunk/modules/md/md_crypt.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/md/md_crypt.h?rev=1808241&r1=1808240&r2=1808241&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/md/md_crypt.h (original)
+++ httpd/httpd/trunk/modules/md/md_crypt.h Wed Sep 13 14:16:49 2017
@@ -127,7 +127,7 @@ apr_status_t md_cert_req_create(const ch
md_pkey_t *pkey, apr_pool_t *p);
apr_status_t md_cert_self_sign(md_cert_t **pcert, const char *cn,
- const char *domain, md_pkey_t *pkey,
+ struct apr_array_header_t *domains, md_pkey_t *pkey,
apr_interval_time_t valid_for, apr_pool_t *p);
#endif /* md_crypt_h */
Modified: httpd/httpd/trunk/modules/md/md_reg.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/md/md_reg.c?rev=1808241&r1=1808240&r2=1808241&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/md/md_reg.c (original)
+++ httpd/httpd/trunk/modules/md/md_reg.c Wed Sep 13 14:16:49 2017
@@ -506,6 +506,18 @@ static apr_status_t p_md_update(void *ba
nmd->pkey_spec = apr_pmemdup(p, updates->pkey_spec, sizeof(md_pkey_spec_t));
}
}
+ if (MD_UPD_REQUIRE_HTTPS & fields) {
+ md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, ptemp, "update require-https: %s", name);
+ nmd->require_https = updates->require_https;
+ }
+ if (MD_UPD_TRANSITIVE & fields) {
+ md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, ptemp, "update transitive: %s", name);
+ nmd->transitive = updates->transitive;
+ }
+ if (MD_UPD_MUST_STAPLE & fields) {
+ md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, ptemp, "update must-staple: %s", name);
+ nmd->must_staple = updates->must_staple;
+ }
if (fields && APR_SUCCESS == (rv = md_save(reg->store, p, MD_SG_DOMAINS, nmd, 0))) {
rv = state_init(reg, ptemp, nmd, 0);
@@ -743,6 +755,10 @@ apr_status_t md_reg_sync(md_reg_t *reg,
smd->ca_agreement = md->ca_agreement;
fields |= MD_UPD_AGREEMENT;
}
+ if (MD_VAL_UPDATE(md, smd, transitive)) {
+ smd->transitive = md->transitive;
+ fields |= MD_UPD_TRANSITIVE;
+ }
if (MD_VAL_UPDATE(md, smd, drive_mode)) {
smd->drive_mode = md->drive_mode;
fields |= MD_UPD_DRIVE_MODE;
@@ -780,6 +796,14 @@ apr_status_t md_reg_sync(md_reg_t *reg,
smd->pkey_spec = apr_pmemdup(p, md->pkey_spec, sizeof(md_pkey_spec_t));
}
}
+ if (MD_VAL_UPDATE(md, smd, require_https)) {
+ smd->require_https = md->require_https;
+ fields |= MD_UPD_REQUIRE_HTTPS;
+ }
+ if (MD_VAL_UPDATE(md, smd, must_staple)) {
+ smd->must_staple = md->must_staple;
+ fields |= MD_UPD_MUST_STAPLE;
+ }
if (fields) {
rv = md_reg_update(reg, ptemp, smd->name, smd, fields);
Modified: httpd/httpd/trunk/modules/md/md_reg.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/md/md_reg.h?rev=1808241&r1=1808240&r2=1808241&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/md/md_reg.h (original)
+++ httpd/httpd/trunk/modules/md/md_reg.h Wed Sep 13 14:16:49 2017
@@ -82,18 +82,21 @@ int md_reg_do(md_reg_do_cb *cb, void *ba
/**
* Bitmask for fields that are updated.
*/
-#define MD_UPD_DOMAINS 0x0001
-#define MD_UPD_CA_URL 0x0002
-#define MD_UPD_CA_PROTO 0x0004
-#define MD_UPD_CA_ACCOUNT 0x0008
-#define MD_UPD_CONTACTS 0x0010
-#define MD_UPD_AGREEMENT 0x0020
-#define MD_UPD_CERT_URL 0x0040
-#define MD_UPD_DRIVE_MODE 0x0080
-#define MD_UPD_RENEW_WINDOW 0x0100
+#define MD_UPD_DOMAINS 0x0001
+#define MD_UPD_CA_URL 0x0002
+#define MD_UPD_CA_PROTO 0x0004
+#define MD_UPD_CA_ACCOUNT 0x0008
+#define MD_UPD_CONTACTS 0x0010
+#define MD_UPD_AGREEMENT 0x0020
+#define MD_UPD_CERT_URL 0x0040
+#define MD_UPD_DRIVE_MODE 0x0080
+#define MD_UPD_RENEW_WINDOW 0x0100
#define MD_UPD_CA_CHALLENGES 0x0200
-#define MD_UPD_PKEY_SPEC 0x0400
-#define MD_UPD_ALL 0x7FFFFFFF
+#define MD_UPD_PKEY_SPEC 0x0400
+#define MD_UPD_REQUIRE_HTTPS 0x0800
+#define MD_UPD_TRANSITIVE 0x1000
+#define MD_UPD_MUST_STAPLE 0x2000
+#define MD_UPD_ALL 0x7FFFFFFF
/**
* Update the given fields for the managed domain. Take the new
Modified: httpd/httpd/trunk/modules/md/md_store_fs.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/md/md_store_fs.c?rev=1808241&r1=1808240&r2=1808241&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/md/md_store_fs.c (original)
+++ httpd/httpd/trunk/modules/md/md_store_fs.c Wed Sep 13 14:16:49 2017
@@ -261,57 +261,6 @@ read:
return rv;
}
-static apr_status_t setup_fallback_cert(void *baton, apr_pool_t *p, apr_pool_t *ptemp, va_list ap)
-{
- md_store_fs_t *s_fs = baton;
- md_pkey_t *fallback_key;
- md_cert_t *fallback_cert;
- md_pkey_spec_t spec;
- apr_status_t rv;
-
- if (APR_SUCCESS == (rv = fs_load(&s_fs->s, MD_SG_NONE, NULL, MD_FN_FALLBACK_PKEY,
- MD_SV_PKEY, (void**)&fallback_key, ptemp))
- && APR_SUCCESS == (rv = fs_load(&s_fs->s, MD_SG_NONE, NULL, MD_FN_FALLBACK_CERT,
- MD_SV_CERT, (void**)&fallback_cert, ptemp))) {
- apr_time_t not_after = md_cert_get_not_after(fallback_cert);
- if (not_after > apr_time_now() + apr_time_from_sec(7 * MD_SECS_PER_DAY)) {
- /* at least a week more valid, expect drive and restart way before that */
- return APR_SUCCESS;
- }
- }
-
- spec.type = MD_PKEY_TYPE_RSA;
- spec.params.rsa.bits = MD_PKEY_RSA_BITS_DEF;
-
- if (APR_SUCCESS != (rv = md_pkey_gen(&fallback_key, ptemp, &spec))) {
- md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, ptemp, "create fallback key");
- return rv;
- }
-
- if (APR_SUCCESS != (rv = md_store_save(&s_fs->s, ptemp, MD_SG_NONE, NULL,
- MD_FN_FALLBACK_PKEY, MD_SV_PKEY,
- (void*)fallback_key, 0))) {
- md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, ptemp, "save fallback key");
- return rv;
- }
-
- if (APR_SUCCESS != (rv = md_cert_self_sign(&fallback_cert, "Apache Managed Domain Fallback",
- "temporary.invalid.certificate", fallback_key,
- apr_time_from_sec(14 * MD_SECS_PER_DAY), ptemp))) {
- md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, ptemp, "create fallback certificate");
- return rv;
- }
-
- if (APR_SUCCESS != (rv = md_store_save(&s_fs->s, ptemp, MD_SG_NONE, NULL,
- MD_FN_FALLBACK_CERT, MD_SV_CERT,
- (void*)fallback_cert, 0))) {
- md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, ptemp, "save fallback certificate");
- return rv;
- }
-
- return rv;
-}
-
apr_status_t md_store_fs_init(md_store_t **pstore, apr_pool_t *p, const char *path)
{
md_store_fs_t *s_fs;
@@ -356,9 +305,6 @@ apr_status_t md_store_fs_init(md_store_t
}
}
rv = md_util_pool_vdo(setup_store_file, s_fs, p, NULL);
- if (APR_SUCCESS == rv) {
- rv = md_util_pool_vdo(setup_fallback_cert, s_fs, p, NULL);
- }
if (APR_SUCCESS != rv) {
md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "init fs store at %s", path);
Modified: httpd/httpd/trunk/modules/md/md_util.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/md/md_util.c?rev=1808241&r1=1808240&r2=1808241&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/md/md_util.c (original)
+++ httpd/httpd/trunk/modules/md/md_util.c Wed Sep 13 14:16:49 2017
@@ -647,52 +647,54 @@ const char *md_util_schemify(apr_pool_t
return apr_psprintf(p, "%s:%s", def_scheme, s);
}
-apr_status_t md_util_abs_uri_check(apr_pool_t *p, const char *uri, const char **perr)
+static apr_status_t uri_check(apr_uri_t *uri_parsed, apr_pool_t *p,
+ const char *uri, const char **perr)
{
const char *s, *err = NULL;
- apr_uri_t uri_parsed;
apr_status_t rv;
- if (APR_SUCCESS != (rv = apr_uri_parse(p, uri, &uri_parsed))) {
+ if (APR_SUCCESS != (rv = apr_uri_parse(p, uri, uri_parsed))) {
err = "not an uri";
}
- else if (!uri_parsed.scheme) {
- err = "missing uri scheme";
- }
- else if (strlen(uri_parsed.scheme) + 1 >= strlen(uri)) {
- err = "missing uri identifier";
- }
- else if (strchr(uri, ' ') || strchr(uri, '\t') ) {
- err = "whitespace in uri";
- }
- else if (!strncmp("http", uri_parsed.scheme, 4)) {
- if (!uri_parsed.hostname) {
- err = "missing hostname";
- }
- else if (!md_util_is_dns_name(p, uri_parsed.hostname, 0)) {
- err = "invalid hostname";
- }
- if (uri_parsed.port_str && (uri_parsed.port == 0 || uri_parsed.port > 65353)) {
- err = "invalid port";
+ else if (uri_parsed->scheme) {
+ if (strlen(uri_parsed->scheme) + 1 >= strlen(uri)) {
+ err = "missing uri identifier";
+ }
+ else if (!strncmp("http", uri_parsed->scheme, 4)) {
+ if (!uri_parsed->hostname) {
+ err = "missing hostname";
+ }
+ else if (!md_util_is_dns_name(p, uri_parsed->hostname, 0)) {
+ err = "invalid hostname";
+ }
+ if (uri_parsed->port_str
+ && (!apr_isdigit(uri_parsed->port_str[0])
+ || uri_parsed->port == 0
+ || uri_parsed->port > 65353)) {
+ err = "invalid port";
+ }
+ }
+ else if (!strcmp("mailto", uri_parsed->scheme)) {
+ s = strchr(uri, '@');
+ if (!s) {
+ err = "missing @";
+ }
+ else if (strchr(s+1, '@')) {
+ err = "duplicate @";
+ }
+ else if (s == uri + strlen(uri_parsed->scheme) + 1) {
+ err = "missing local part";
+ }
+ else if (s == (uri + strlen(uri)-1)) {
+ err = "missing hostname";
+ }
+ else if (strstr(uri, "..")) {
+ err = "double period";
+ }
}
}
- else if (!strcmp("mailto", uri_parsed.scheme)) {
- s = strchr(uri, '@');
- if (!s) {
- err = "missing @";
- }
- else if (strchr(s+1, '@')) {
- err = "duplicate @";
- }
- else if (s == uri + strlen(uri_parsed.scheme) + 1) {
- err = "missing local part";
- }
- else if (s == (uri + strlen(uri)-1)) {
- err = "missing hostname";
- }
- else if (strstr(uri, "..")) {
- err = "double period";
- }
+ if (strchr(uri, ' ') || strchr(uri, '\t') ) {
+ err = "whitespace in uri";
}
if (err) {
@@ -702,6 +704,39 @@ apr_status_t md_util_abs_uri_check(apr_p
return rv;
}
+apr_status_t md_util_abs_uri_check(apr_pool_t *p, const char *uri, const char **perr)
+{
+ apr_uri_t uri_parsed;
+ apr_status_t rv;
+
+ if (APR_SUCCESS == (rv = uri_check(&uri_parsed, p, uri, perr))) {
+ if (!uri_parsed.scheme) {
+ *perr = "missing uri scheme";
+ return APR_EINVAL;
+ }
+ }
+ return rv;
+}
+
+apr_status_t md_util_abs_http_uri_check(apr_pool_t *p, const char *uri, const char **perr)
+{
+ apr_uri_t uri_parsed;
+ apr_status_t rv;
+
+ if (APR_SUCCESS == (rv = uri_check(&uri_parsed, p, uri, perr))) {
+ if (!uri_parsed.scheme) {
+ *perr = "missing uri scheme";
+ return APR_EINVAL;
+ }
+ if (apr_strnatcasecmp("http", uri_parsed.scheme)
+ && apr_strnatcasecmp("https", uri_parsed.scheme)) {
+ *perr = "uri scheme must be http or https";
+ return APR_EINVAL;
+ }
+ }
+ return rv;
+}
+
/* retry login ************************************************************************************/
apr_status_t md_util_try(md_util_try_fn *fn, void *baton, int ignore_errs,
Modified: httpd/httpd/trunk/modules/md/md_util.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/md/md_util.h?rev=1808241&r1=1808240&r2=1808241&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/md/md_util.h (original)
+++ httpd/httpd/trunk/modules/md/md_util.h Wed Sep 13 14:16:49 2017
@@ -117,7 +117,8 @@ apr_size_t md_util_base64url_decode(cons
const char *md_util_schemify(apr_pool_t *p, const char *s, const char *def_scheme);
apr_status_t md_util_abs_uri_check(apr_pool_t *p, const char *s, const char **perr);
-
+apr_status_t md_util_abs_http_uri_check(apr_pool_t *p, const char *uri, const char **perr);
+
const char *md_link_find_relation(const struct apr_table_t *headers,
apr_pool_t *pool, const char *relation);
Modified: httpd/httpd/trunk/modules/md/md_version.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/md/md_version.h?rev=1808241&r1=1808240&r2=1808241&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/md/md_version.h (original)
+++ httpd/httpd/trunk/modules/md/md_version.h Wed Sep 13 14:16:49 2017
@@ -26,7 +26,7 @@
* @macro
* Version number of the md module as c string
*/
-#define MOD_MD_VERSION "0.9.2-git"
+#define MOD_MD_VERSION "0.9.5"
/**
* @macro
@@ -34,7 +34,7 @@
* release. This is a 24 bit number with 8 bits for major number, 8 bits
* for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
*/
-#define MOD_MD_VERSION_NUM 0x000902
+#define MOD_MD_VERSION_NUM 0x000905
#define MD_EXPERIMENTAL 0
#define MD_ACME_DEF_URL "https://acme-v01.api.letsencrypt.org/directory"
Modified: httpd/httpd/trunk/modules/md/mod_md.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/md/mod_md.c?rev=1808241&r1=1808240&r2=1808241&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/md/mod_md.c (original)
+++ httpd/httpd/trunk/modules/md/mod_md.c Wed Sep 13 14:16:49 2017
@@ -14,11 +14,13 @@
*/
#include <assert.h>
+#include <apr_optional.h>
#include <apr_strings.h>
#include <ap_release.h>
#include <mpm_common.h>
#include <httpd.h>
+#include <http_core.h>
#include <http_protocol.h>
#include <http_request.h>
#include <http_log.h>
@@ -41,6 +43,7 @@
#include "mod_md.h"
#include "mod_md_config.h"
#include "mod_md_os.h"
+#include "mod_ssl.h"
#include "mod_watchdog.h"
static void md_hooks(apr_pool_t *pool);
@@ -92,6 +95,12 @@ static void md_merge_srv(md_t *md, md_sr
md->pkey_spec = md->sc->pkey_spec;
}
+ if (md->require_https < 0) {
+ md->require_https = md_config_geti(md->sc, MD_CONFIG_REQUIRE_HTTPS);
+ }
+ if (md->must_staple < 0) {
+ md->must_staple = md_config_geti(md->sc, MD_CONFIG_MUST_STAPLE);
+ }
}
static apr_status_t check_coverage(md_t *md, const char *domain, server_rec *s, apr_pool_t *p)
@@ -113,28 +122,61 @@ static apr_status_t check_coverage(md_t
}
}
-static apr_status_t apply_to_servers(md_t *md, server_rec *base_server,
+static apr_status_t md_covers_server(md_t *md, server_rec *s, apr_pool_t *p)
+{
+ apr_status_t rv;
+ const char *name;
+ int i;
+
+ if (APR_SUCCESS == (rv = check_coverage(md, s->server_hostname, s, p)) && s->names) {
+ for (i = 0; i < s->names->nelts; ++i) {
+ name = APR_ARRAY_IDX(s->names, i, const char*);
+ if (APR_SUCCESS != (rv = check_coverage(md, name, s, p))) {
+ break;
+ }
+ }
+ }
+ return rv;
+}
+
+static int matches_port_somewhere(server_rec *s, int port)
+{
+ server_addr_rec *sa;
+
+ for (sa = s->addrs; sa; sa = sa->next) {
+ if (sa->host_port == port) {
+ /* host_addr might be general (0.0.0.0) or specific, we count this as match */
+ return 1;
+ }
+ if (sa->host_port == 0) {
+ /* wildcard port, answers to all ports. Rare, but may work. */
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static apr_status_t assign_to_servers(md_t *md, server_rec *base_server,
apr_pool_t *p, apr_pool_t *ptemp)
{
- server_rec *s;
+ server_rec *s, *s_https;
request_rec r;
md_srv_conf_t *sc;
md_mod_conf_t *mc;
- apr_status_t rv = APR_SUCCESS, rv2;
- int i, j;
- const char *domain, *name;
+ apr_status_t rv = APR_SUCCESS;
+ int i;
+ const char *domain;
+ apr_array_header_t *servers;
sc = md_config_get(base_server);
mc = sc->mc;
-
- /* Find the (at most one) managed domain for each vhost/base server and
- * remember it at our config for it.
- * The config is not accepted, if a vhost matches 2 or more managed domains.
+
+ /* Assign the MD to all server_rec configs that it matches. If there already
+ * is an assigned MD not equal this one, the configuration is in error.
*/
memset(&r, 0, sizeof(r));
- sc = NULL;
+ servers = apr_array_make(ptemp, 5, sizeof(server_rec*));
- /* This MD may apply to 0, 1 or more sever_recs */
for (s = base_server; s; s = s->next) {
r.server = s;
@@ -142,8 +184,7 @@ static apr_status_t apply_to_servers(md_
domain = APR_ARRAY_IDX(md->domains, i, const char*);
if (ap_matches_request_vhost(&r, domain, s->port)) {
- /* Create a unique md_srv_conf_t record for this server.
- * We keep local information here. */
+ /* Create a unique md_srv_conf_t record for this server, if there is none yet */
sc = md_config_get_unique(s, p);
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, base_server, APLOGNO(10041)
@@ -158,54 +199,91 @@ static apr_status_t apply_to_servers(md_
ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, APLOGNO(10042)
"conflict: MD %s matches server %s, but MD %s also matches.",
md->name, s->server_hostname, sc->assigned->name);
- rv = APR_EINVAL;
- goto next_server;
+ return APR_EINVAL;
+ }
+
+ /* If server has name or an alias not covered,
+ * a generated certificate will not match.
+ */
+ if (APR_SUCCESS != (rv = md_covers_server(md, s, ptemp))) {
+ return rv;
}
+
+ sc->assigned = md;
+ APR_ARRAY_PUSH(servers, server_rec*) = s;
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, base_server, APLOGNO(10043)
"Managed Domain %s applies to vhost %s:%d", md->name,
s->server_hostname, s->port);
- /* If there is a non-default ServerAdmin defined for this vhost, take
- * that one as contact info */
+ goto next_server;
+ }
+ }
+ next_server:
+ continue;
+ }
+
+ if (APR_SUCCESS == rv) {
+ if (apr_is_empty_array(servers)) {
+ if (md->drive_mode != MD_DRIVE_ALWAYS) {
+ /* Not an error, but looks suspicious */
+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, base_server, APLOGNO(10045)
+ "No VirtualHost matches Managed Domain %s", md->name);
+ APR_ARRAY_PUSH(mc->unused_names, const char*) = md->name;
+ }
+ }
+ else {
+ const char *uri;
+
+ /* Found matching server_rec's. Collect all 'ServerAdmin's into MD's contact list */
+ apr_array_clear(md->contacts);
+ for (i = 0; i < servers->nelts; ++i) {
+ s = APR_ARRAY_IDX(servers, i, server_rec*);
if (s->server_admin && strcmp(DEFAULT_ADMIN, s->server_admin)) {
- apr_array_clear(md->contacts);
- APR_ARRAY_PUSH(md->contacts, const char *) =
- md_util_schemify(p, s->server_admin, "mailto");
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, base_server, APLOGNO(10044)
- "Managed Domain %s assigned server admin %s", md->name,
- s->server_admin);
+ uri = md_util_schemify(p, s->server_admin, "mailto");
+ if (md_array_str_index(md->contacts, uri, 0, 0) < 0) {
+ APR_ARRAY_PUSH(md->contacts, const char *) = uri;
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, base_server, APLOGNO(10044)
+ "%s: added contact %s", md->name, uri);
+ }
+ }
+ }
+
+ if (md->require_https > MD_REQUIRE_OFF) {
+ /* We require https for this MD, but do we have port 443 (or a mapped one)
+ * available? */
+ if (mc->local_443 <= 0) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, APLOGNO()
+ "MDPortMap says there is no port for https (443), "
+ "but MD %s is configured to require https. This "
+ "only works when a 443 port is available.", md->name);
+ return APR_EINVAL;
+
}
- /* remember */
- sc->assigned = md;
- /* This server matches a managed domain. If it contains names or
- * alias that are not in this md, a generated certificate will not match. */
- if (APR_SUCCESS == (rv2 = check_coverage(md, s->server_hostname, s, p))
- && s->names) {
- for (j = 0; j < s->names->nelts; ++j) {
- name = APR_ARRAY_IDX(s->names, j, const char*);
- if (APR_SUCCESS != (rv2 = check_coverage(md, name, s, p))) {
- break;
- }
+ /* Ok, we know which local port represents 443, do we have a server_rec
+ * for MD that has addresses with port 443? */
+ s_https = NULL;
+ for (i = 0; i < servers->nelts; ++i) {
+ s = APR_ARRAY_IDX(servers, i, server_rec*);
+ if (matches_port_somewhere(s, mc->local_443)) {
+ s_https = s;
+ break;
}
}
- if (APR_SUCCESS != rv2) {
- rv = rv2;
+ if (!s_https) {
+ /* Did not find any server_rec that matches this MD *and* has an
+ * s->addrs match for the https port. Suspicious. */
+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, base_server, APLOGNO()
+ "MD %s is configured to require https, but there seems to be "
+ "no VirtualHost for it that has port %d in its address list. "
+ "This looks as if it will not work.",
+ md->name, mc->local_443);
}
- goto next_server;
}
}
- next_server:
- continue;
- }
-
- if (sc == NULL && md->drive_mode != MD_DRIVE_ALWAYS) {
- /* Not an error, but looks suspicious */
- ap_log_error(APLOG_MARK, APLOG_WARNING, 0, base_server, APLOGNO(10045)
- "No VirtualHost matches Managed Domain %s", md->name);
- APR_ARRAY_PUSH(mc->unused_names, const char*) = md->name;
+
}
return rv;
}
@@ -267,9 +345,9 @@ static apr_status_t md_calc_md_list(apr_
}
}
- /* Apply to the vhost(s) that this MD matches - if any. Perform some
+ /* Assign MD to the server_rec configs that it matches. Perform some
* last finishing touches on the MD. */
- if (APR_SUCCESS != (rv = apply_to_servers(md, base_server, p, ptemp))) {
+ if (APR_SUCCESS != (rv = assign_to_servers(md, base_server, p, ptemp))) {
return rv;
}
@@ -433,6 +511,16 @@ static void init_setups(apr_pool_t *p, s
}
/**************************************************************************************************/
+/* mod_ssl interface */
+
+static APR_OPTIONAL_FN_TYPE(ssl_is_https) *opt_ssl_is_https;
+
+static void init_ssl(void)
+{
+ opt_ssl_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https);
+}
+
+/**************************************************************************************************/
/* watchdog based impl. */
#define MD_WATCHDOG_NAME "_md_"
@@ -442,72 +530,130 @@ static APR_OPTIONAL_FN_TYPE(ap_watchdog_
static APR_OPTIONAL_FN_TYPE(ap_watchdog_set_callback_interval) *wd_set_interval;
typedef struct {
+ md_t *md;
+
+ int stalled;
+ int renewed;
+ int renewal_notified;
+ apr_time_t restart_at;
+ int need_restart;
+ int restart_processed;
+
+ apr_status_t last_rv;
+ apr_time_t next_check;
+ int error_runs;
+} md_job_t;
+
+typedef struct {
apr_pool_t *p;
server_rec *s;
ap_watchdog_t *watchdog;
- int all_valid;
- apr_time_t valid_not_before;
- int error_count;
- int processed_count;
-
- int error_runs;
+
apr_time_t next_change;
- apr_time_t next_valid;
- apr_array_header_t *mds;
+ apr_array_header_t *jobs;
md_reg_t *reg;
} md_watchdog;
-static apr_status_t drive_md(md_watchdog *wd, md_t *md, apr_pool_t *ptemp)
+static void assess_renewal(md_watchdog *wd, md_job_t *job, apr_pool_t *ptemp)
+{
+ apr_time_t now = apr_time_now();
+ if (now >= job->restart_at) {
+ job->need_restart = 1;
+ ap_log_error( APLOG_MARK, APLOG_TRACE1, 0, wd->s,
+ "md(%s): has been renewed, needs restart now", job->md->name);
+ }
+ else {
+ job->next_check = job->restart_at;
+
+ if (job->renewal_notified) {
+ ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, wd->s,
+ "%s: renewed cert valid in %s",
+ job->md->name, md_print_duration(ptemp, job->restart_at - now));
+ }
+ else {
+ char ts[APR_RFC822_DATE_LEN];
+
+ apr_rfc822_date(ts, job->restart_at);
+ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, wd->s, APLOGNO(10051)
+ "%s: has been renewed successfully and should be activated at %s"
+ " (this requires a server restart latest in %s)",
+ job->md->name, ts, md_print_duration(ptemp, job->restart_at - now));
+ job->renewal_notified = 1;
+ }
+ }
+}
+
+static apr_status_t check_job(md_watchdog *wd, md_job_t *job, apr_pool_t *ptemp)
{
apr_status_t rv = APR_SUCCESS;
- apr_time_t renew_time, now, valid_from;
+ apr_time_t valid_from, delay;
int errored, renew;
char ts[APR_RFC822_DATE_LEN];
- if (md->state == MD_S_MISSING) {
- rv = APR_INCOMPLETE;
+ if (apr_time_now() < job->next_check) {
+ /* Job needs to wait */
+ return APR_EAGAIN;
+ }
+
+ job->next_check = 0;
+ if (job->md->state == MD_S_MISSING) {
+ job->stalled = 1;
}
- if (md->state == MD_S_COMPLETE && !md->expires) {
- /* This is our indicator that we did already renewed this managed domain
- * successfully and only wait on the next restart for it to activate */
- now = apr_time_now();
- ap_log_error( APLOG_MARK, APLOG_INFO, 0, wd->s, APLOGNO(10051)
- "md(%s): has been renewed, should be activated in %s",
- md->name, (md->valid_from <= now)? "about now" :
- md_print_duration(ptemp, md->valid_from - now));
+
+ if (job->stalled) {
+ /* Missing information, this will not change until configuration
+ * is changed and server restarted */
+ return APR_INCOMPLETE;
+ }
+ else if (job->renewed) {
+ assess_renewal(wd, job, ptemp);
}
- else if (APR_SUCCESS == (rv = md_reg_assess(wd->reg, md, &errored, &renew, wd->p))) {
+ else if (APR_SUCCESS == (rv = md_reg_assess(wd->reg, job->md, &errored, &renew, wd->p))) {
if (errored) {
ap_log_error( APLOG_MARK, APLOG_DEBUG, 0, wd->s, APLOGNO(10050)
- "md(%s): in error state", md->name);
+ "md(%s): in error state", job->md->name);
}
else if (renew) {
ap_log_error( APLOG_MARK, APLOG_DEBUG, 0, wd->s, APLOGNO(10052)
- "md(%s): state=%d, driving", md->name, md->state);
+ "md(%s): state=%d, driving", job->md->name, job->md->state);
- rv = md_reg_stage(wd->reg, md, NULL, 0, &valid_from, ptemp);
+ rv = md_reg_stage(wd->reg, job->md, NULL, 0, &valid_from, ptemp);
if (APR_SUCCESS == rv) {
- md->state = MD_S_COMPLETE;
- md->expires = 0;
- md->valid_from = valid_from;
- ++wd->processed_count;
- if (!wd->next_valid || wd->next_valid > valid_from) {
- wd->next_valid = valid_from;
- }
+ job->renewed = 1;
+ job->restart_at = valid_from;
+ assess_renewal(wd, job, ptemp);
}
}
else {
- apr_rfc822_date(ts, md->expires);
+ job->next_check = job->md->expires - job->md->renew_window;
+
+ apr_rfc822_date(ts, job->md->expires);
ap_log_error( APLOG_MARK, APLOG_DEBUG, 0, wd->s, APLOGNO(10053)
- "md(%s): is complete, cert expires %s", md->name, ts);
- renew_time = md->expires - md->renew_window;
- if (renew_time < wd->next_change) {
- wd->next_change = renew_time;
- }
+ "md(%s): is complete, cert expires %s", job->md->name, ts);
}
}
+
+ if (APR_SUCCESS == rv) {
+ job->error_runs = 0;
+ }
+ else {
+ ap_log_error( APLOG_MARK, APLOG_ERR, rv, wd->s, APLOGNO(10056)
+ "processing %s", job->md->name);
+ ++job->error_runs;
+ /* back off duration, depending on the errors we encounter in a row */
+ delay = apr_time_from_sec(5 << (job->error_runs - 1));
+ if (delay > apr_time_from_sec(60*60)) {
+ delay = apr_time_from_sec(60*60);
+ }
+ job->next_check = apr_time_now() + delay;
+ ap_log_error(APLOG_MARK, APLOG_INFO, 0, wd->s, APLOGNO(10057)
+ "%s: encountered error for the %d. time, next run in %s",
+ job->md->name, job->error_runs, md_print_duration(ptemp, delay));
+ }
+
+ job->last_rv = rv;
return rv;
}
@@ -515,97 +661,50 @@ static apr_status_t run_watchdog(int sta
{
md_watchdog *wd = baton;
apr_status_t rv = APR_SUCCESS;
- md_t *md;
+ md_job_t *job;
apr_time_t next_run, now;
+ int restart = 0;
int i;
switch (state) {
case AP_WATCHDOG_STATE_STARTING:
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, wd->s, APLOGNO(10054)
- "md watchdog start, auto drive %d mds", wd->mds->nelts);
+ "md watchdog start, auto drive %d mds", wd->jobs->nelts);
break;
case AP_WATCHDOG_STATE_RUNNING:
assert(wd->reg);
- wd->all_valid = 1;
- wd->valid_not_before = 0;
- wd->processed_count = 0;
- wd->error_count = 0;
wd->next_change = 0;
- wd->next_valid = 0;
-
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, wd->s, APLOGNO(10055)
- "md watchdog run, auto drive %d mds", wd->mds->nelts);
+ "md watchdog run, auto drive %d mds", wd->jobs->nelts);
- /* Check if all Managed Domains are ok or if we have to do something */
- for (i = 0; i < wd->mds->nelts; ++i) {
- md = APR_ARRAY_IDX(wd->mds, i, md_t *);
-
- rv = drive_md(wd, md, ptemp);
+ /* normally, we'd like to run at least twice a day */
+ next_run = apr_time_now() + apr_time_from_sec(MD_SECS_PER_DAY / 2);
+
+ /* Check on all the jobs we have */
+ for (i = 0; i < wd->jobs->nelts; ++i) {
+ job = APR_ARRAY_IDX(wd->jobs, i, md_job_t *);
- if (APR_STATUS_IS_INCOMPLETE(rv)) {
- /* configuration not complete, this MD cannot be driven further */
- wd->all_valid = 0;
+ rv = check_job(wd, job, ptemp);
+
+ if (job->need_restart && !job->restart_processed) {
+ restart = 1;
}
- else if (APR_SUCCESS != rv) {
- wd->all_valid = 0;
- ++wd->error_count;
- ap_log_error( APLOG_MARK, APLOG_ERR, rv, wd->s, APLOGNO(10056)
- "processing %s", md->name);
+ if (job->next_check && job->next_check < next_run) {
+ next_run = job->next_check;
}
}
- /* Determine when we want to run next */
- wd->error_runs = wd->error_count? (wd->error_runs + 1) : 0;
-
- if (wd->all_valid) {
- ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, wd->s, "all managed domains are valid");
- }
- else if (wd->error_count == 0) {
- ap_log_error(APLOG_MARK, APLOG_INFO, 0, wd->s, APLOGNO()
- "all managed domains driven as far as possible");
- }
-
now = apr_time_now();
- /* normally, we'd like to run at least twice a day */
- next_run = now + apr_time_from_sec(MD_SECS_PER_DAY / 2);
-
- /* Unless we know of an MD change before that */
- if (wd->next_change > 0 && wd->next_change < next_run) {
- next_run = wd->next_change;
- }
-
- /* Or have to activate a new cert even before that */
- if (wd->next_valid > now && wd->next_valid < next_run) {
- next_run = wd->next_valid;
- ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, wd->s,
- "Delaying activation of %d Managed Domain%s by %s",
- wd->processed_count, (wd->processed_count > 1)? "s have" : " has",
- md_print_duration(ptemp, next_run - now));
- }
-
- /* Or encountered errors and like to retry even before that */
- if (wd->error_count > 0) {
- apr_interval_time_t delay;
-
- /* back off duration, depending on the errors we encounter in a row */
- delay = apr_time_from_sec(5 << (wd->error_runs - 1));
- if (delay > apr_time_from_sec(60*60)) {
- delay = apr_time_from_sec(60*60);
- }
- if (now + delay < next_run) {
- ap_log_error(APLOG_MARK, APLOG_INFO, 0, wd->s, APLOGNO(10057)
- "encountered errors for the %d. time, next try by %s",
- wd->error_runs, md_print_duration(ptemp, delay));
- next_run = now + delay;
- }
- }
-
if (APLOGdebug(wd->s)) {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, wd->s, APLOGNO()
"next run in %s", md_print_duration(ptemp, next_run - now));
}
wd_set_interval(wd->watchdog, next_run - now, wd, run_watchdog);
+
+ for (i = 0; i < wd->jobs->nelts; ++i) {
+ job = APR_ARRAY_IDX(wd->jobs, i, md_job_t *);
+ }
break;
case AP_WATCHDOG_STATE_STOPPING:
@@ -614,31 +713,31 @@ static apr_status_t run_watchdog(int sta
break;
}
- if (wd->processed_count) {
- now = apr_time_now();
+ if (restart) {
+ const char *action, *names = "";
+ int n;
- if (wd->all_valid) {
- if (wd->next_valid <= now) {
- rv = md_server_graceful(ptemp, wd->s);
- if (APR_ENOTIMPL == rv) {
- /* self-graceful restart not supported in this setup */
- ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, wd->s, APLOGNO(10059)
- "%d Managed Domain%s been setup and changes will be "
- "activated on next (graceful) server restart.",
- wd->processed_count, (wd->processed_count > 1)? "s have" : " has");
- }
+ for (i = 0, n = 0; i < wd->jobs->nelts; ++i) {
+ job = APR_ARRAY_IDX(wd->jobs, i, md_job_t *);
+ if (job->need_restart && !job->restart_processed) {
+ names = apr_psprintf(ptemp, "%s%s%s", names, n? ", " : "", job->md->name);
+ ++n;
+ job->restart_processed = 1;
+ }
+ }
+
+ if (n > 0) {
+ rv = md_server_graceful(ptemp, wd->s);
+ if (APR_ENOTIMPL == rv) {
+ /* self-graceful restart not supported in this setup */
+ action = " and changes will be activated on next (graceful) server restart.";
}
else {
- /* activation is delayed */
+ action = " and server has been asked to restart now.";
}
- }
- else {
- ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, wd->s, APLOGNO(10060)
- "%d Managed Domain%s been setup, while %d%s "
- "still being worked on. You may activate the changes made "
- "by triggering a (graceful) restart at any time.",
- wd->processed_count, (wd->processed_count > 1)? "s have" : " has",
- wd->error_count, (wd->error_count > 1)? " are" : " is");
+ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, wd->s, APLOGNO(10059)
+ "The Managed Domain%s %s %s been setup%s",
+ (n > 1)? "s" : "", names, (n > 1)? "have" : "has", action);
}
}
@@ -654,6 +753,7 @@ static apr_status_t start_watchdog(apr_a
apr_status_t rv;
const char *name;
md_t *md;
+ md_job_t *job;
int i, errored, renew;
wd_get_instance = APR_RETRIEVE_OPTIONAL_FN(ap_watchdog_get_instance);
@@ -681,7 +781,7 @@ static apr_status_t start_watchdog(apr_a
wd->reg = reg;
wd->s = s;
- wd->mds = apr_array_make(wd->p, 10, sizeof(md_t *));
+ wd->jobs = apr_array_make(wd->p, 10, sizeof(md_job_t *));
for (i = 0; i < names->nelts; ++i) {
name = APR_ARRAY_IDX(names, i, const char *);
md = md_reg_get(wd->reg, name, wd->p);
@@ -692,14 +792,18 @@ static apr_status_t start_watchdog(apr_a
"md(%s): seems errored. Will not process this any further.", name);
}
else {
+ job = apr_pcalloc(wd->p, sizeof(*job));
+
+ job->md = md;
+ APR_ARRAY_PUSH(wd->jobs, md_job_t*) = job;
+
ap_log_error( APLOG_MARK, APLOG_DEBUG, 0, wd->s, APLOGNO(10064)
"md(%s): state=%d, driving", name, md->state);
- APR_ARRAY_PUSH(wd->mds, md_t*) = md;
}
}
}
- if (!wd->mds->nelts) {
+ if (!wd->jobs->nelts) {
ap_log_error( APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(10065)
"no managed domain in state to drive, no watchdog needed, "
"will check again on next server (graceful) restart");
@@ -819,6 +923,8 @@ static apr_status_t md_post_config(apr_p
}
}
+ init_ssl();
+
/* If there are MDs to drive, start a watchdog to check on them regularly */
if (drive_names->nelts > 0) {
ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, s, APLOGNO(10074)
@@ -854,6 +960,34 @@ static int md_is_managed(server_rec *s)
return 0;
}
+static apr_status_t setup_fallback_cert(md_store_t *store, const md_t *md, apr_pool_t *p)
+{
+ md_pkey_t *pkey;
+ md_cert_t *cert;
+ md_pkey_spec_t spec;
+ apr_status_t rv;
+
+ spec.type = MD_PKEY_TYPE_RSA;
+ spec.params.rsa.bits = MD_PKEY_RSA_BITS_DEF;
+
+ if ( APR_SUCCESS == (rv = md_pkey_gen(&pkey, p, &spec))
+ && APR_SUCCESS == (rv = md_store_save(store, p, MD_SG_DOMAINS, md->name,
+ MD_FN_FALLBACK_PKEY, MD_SV_PKEY, (void*)pkey, 0))
+ && APR_SUCCESS == (rv = md_cert_self_sign(&cert, "Apache Managed Domain Fallback",
+ md->domains, pkey,
+ apr_time_from_sec(14 * MD_SECS_PER_DAY), p))) {
+ rv = md_store_save(store, p, MD_SG_DOMAINS, md->name,
+ MD_FN_FALLBACK_CERT, MD_SV_CERT, (void*)cert, 0);
+ }
+
+ return rv;
+}
+
+static int fexists(const char *fname, apr_pool_t *p)
+{
+ return (*fname && APR_SUCCESS == md_util_is_file(fname, p));
+}
+
static apr_status_t md_get_certificate(server_rec *s, apr_pool_t *p,
const char **pkeyfile, const char **pcertfile)
{
@@ -871,24 +1005,38 @@ static apr_status_t md_get_certificate(s
assert(sc->mc);
assert(sc->mc->store);
if (APR_SUCCESS != (rv = md_reg_init(®, p, sc->mc->store, sc->mc->proxy_url))) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO() "init registry");
return rv;
}
md = md_reg_get(reg, sc->assigned->name, p);
if (APR_SUCCESS != (rv = md_reg_get_cred_files(reg, md, p, pkeyfile, pcertfile))) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO()
+ "retrieving credentials for MD %s", md->name);
return rv;
}
- if (!*pkeyfile || !*pcertfile
- || APR_SUCCESS != md_util_is_file(*pkeyfile, p)
- || APR_SUCCESS != md_util_is_file(*pcertfile, p)) {
+ if (!fexists(*pkeyfile, p) || !fexists(*pcertfile, p)) {
/* Provide temporary, self-signed certificate as fallback, so that
* clients do not get obscure TLS handshake errors or will see a fallback
* virtual host that is not intended to be served here. */
- md_store_get_fname(pkeyfile, sc->mc->store, MD_SG_NONE, NULL, MD_FN_FALLBACK_PKEY, p);
- md_store_get_fname(pcertfile, sc->mc->store, MD_SG_NONE, NULL, MD_FN_FALLBACK_CERT, p);
+
+ md_store_get_fname(pkeyfile, sc->mc->store, MD_SG_DOMAINS,
+ md->name, MD_FN_FALLBACK_PKEY, p);
+ md_store_get_fname(pcertfile, sc->mc->store, MD_SG_DOMAINS,
+ md->name, MD_FN_FALLBACK_CERT, p);
+ if (!fexists(*pkeyfile, p) || !fexists(*pcertfile, p)) {
+ if (APR_SUCCESS != (rv = setup_fallback_cert(sc->mc->store, md, p))) {
+ ap_log_error(APLOG_MARK, APLOG_TRACE1, rv, s,
+ "%s: setup fallback certificate", md->name);
+ return rv;
+ }
+ }
+ ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s,
+ "%s: providing fallback certificate for server %s",
+ md->name, s->server_hostname);
return APR_EAGAIN;
}
@@ -957,7 +1105,8 @@ static int md_is_challenge(conn_rec *c,
/**************************************************************************************************/
/* ACME challenge responses */
-#define ACME_CHALLENGE_PREFIX "/.well-known/acme-challenge/"
+#define WELL_KNOWN_PREFIX "/.well-known/"
+#define ACME_CHALLENGE_PREFIX WELL_KNOWN_PREFIX"acme-challenge/"
static int md_http_challenge_pr(request_rec *r)
{
@@ -965,14 +1114,13 @@ static int md_http_challenge_pr(request_
const md_srv_conf_t *sc;
const char *name, *data;
apr_status_t rv;
-
+
if (!strncmp(ACME_CHALLENGE_PREFIX, r->parsed_uri.path, sizeof(ACME_CHALLENGE_PREFIX)-1)) {
if (r->method_number == M_GET) {
md_store_t *store;
sc = ap_get_module_config(r->server->module_config, &md_module);
store = sc? sc->mc->store : NULL;
-
name = r->parsed_uri.path + sizeof(ACME_CHALLENGE_PREFIX)-1;
r->status = HTTP_NOT_FOUND;
@@ -1011,6 +1159,51 @@ static int md_http_challenge_pr(request_
return DECLINED;
}
+/**************************************************************************************************/
+/* Require Https hook */
+
+static int md_require_https_maybe(request_rec *r)
+{
+ const md_srv_conf_t *sc;
+ apr_uri_t uri;
+ const char *s;
+ int status;
+
+ if (strncmp(WELL_KNOWN_PREFIX, r->parsed_uri.path, sizeof(WELL_KNOWN_PREFIX)-1)) {
+ sc = ap_get_module_config(r->server->module_config, &md_module);
+ if (sc && sc->assigned && sc->assigned->require_https > MD_REQUIRE_OFF
+ && opt_ssl_is_https && !opt_ssl_is_https(r->connection)) {
+ /* Do not have https:, but require it. Redirect the request accordingly.
+ */
+ if (r->method_number == M_GET) {
+ /* safe to use the old-fashioned codes */
+ status = ((MD_REQUIRE_PERMANENT == sc->assigned->require_https)?
+ HTTP_MOVED_PERMANENTLY : HTTP_MOVED_TEMPORARILY);
+ }
+ else {
+ /* these should keep the method unchanged on retry */
+ status = ((MD_REQUIRE_PERMANENT == sc->assigned->require_https)?
+ HTTP_PERMANENT_REDIRECT : HTTP_TEMPORARY_REDIRECT);
+ }
+
+ s = ap_construct_url(r->pool, r->uri, r);
+ if (APR_SUCCESS == apr_uri_parse(r->pool, s, &uri)) {
+ uri.scheme = (char*)"https";
+ uri.port = 443;
+ uri.port_str = (char*)"443";
+ uri.query = r->parsed_uri.query;
+ uri.fragment = r->parsed_uri.fragment;
+ s = apr_uri_unparse(r->pool, &uri, APR_URI_UNP_OMITUSERINFO);
+ if (s && *s) {
+ apr_table_setn(r->headers_out, "Location", s);
+ return status;
+ }
+ }
+ }
+ }
+ return DECLINED;
+}
+
/* Runs once per created child process. Perform any process
* related initionalization here.
*/
@@ -1039,6 +1232,8 @@ static void md_hooks(apr_pool_t *pool)
/* answer challenges *very* early, before any configured authentication may strike */
ap_hook_post_read_request(md_http_challenge_pr, NULL, NULL, APR_HOOK_MIDDLE);
+ /* redirect to https if configured */
+ ap_hook_fixups(md_require_https_maybe, NULL, NULL, APR_HOOK_MIDDLE);
APR_REGISTER_OPTIONAL_FN(md_is_managed);
APR_REGISTER_OPTIONAL_FN(md_get_certificate);
Modified: httpd/httpd/trunk/modules/md/mod_md_config.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/md/mod_md_config.c?rev=1808241&r1=1808240&r2=1808241&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/md/mod_md_config.c (original)
+++ httpd/httpd/trunk/modules/md/mod_md_config.c Wed Sep 13 14:16:49 2017
@@ -39,10 +39,12 @@
#define MD_CMD_DRIVEMODE "MDDriveMode"
#define MD_CMD_MEMBER "MDMember"
#define MD_CMD_MEMBERS "MDMembers"
+#define MD_CMD_MUST_STAPLE "MDMustStaple"
#define MD_CMD_PORTMAP "MDPortMap"
#define MD_CMD_PKEYS "MDPrivateKeys"
#define MD_CMD_PROXY "MDHttpProxy"
#define MD_CMD_RENEWWINDOW "MDRenewWindow"
+#define MD_CMD_REQUIREHTTPS "MDRequireHttps"
#define MD_CMD_STOREDIR "MDStoreDir"
#define DEF_VAL (-1)
@@ -67,6 +69,7 @@ static md_srv_conf_t defconf = {
&defmc,
1,
+ MD_REQUIRE_OFF,
MD_DRIVE_AUTO,
0,
NULL,
@@ -112,6 +115,7 @@ static md_mod_conf_t *md_mod_conf_get(ap
static void srv_conf_props_clear(md_srv_conf_t *sc)
{
sc->transitive = DEF_VAL;
+ sc->require_https = MD_REQUIRE_UNSET;
sc->drive_mode = DEF_VAL;
sc->must_staple = DEF_VAL;
sc->pkey_spec = NULL;
@@ -126,6 +130,7 @@ static void srv_conf_props_clear(md_srv_
static void srv_conf_props_copy(md_srv_conf_t *to, const md_srv_conf_t *from)
{
to->transitive = from->transitive;
+ to->require_https = from->require_https;
to->drive_mode = from->drive_mode;
to->must_staple = from->must_staple;
to->pkey_spec = from->pkey_spec;
@@ -139,6 +144,7 @@ static void srv_conf_props_copy(md_srv_c
static void srv_conf_props_apply(md_t *md, const md_srv_conf_t *from, apr_pool_t *p)
{
+ if (from->require_https != MD_REQUIRE_UNSET) md->require_https = from->require_https;
if (from->transitive != DEF_VAL) md->transitive = from->transitive;
if (from->drive_mode != DEF_VAL) md->drive_mode = from->drive_mode;
if (from->must_staple != DEF_VAL) md->must_staple = from->must_staple;
@@ -176,6 +182,7 @@ static void *md_config_merge(apr_pool_t
nsc->name = name;
nsc->transitive = (add->transitive != DEF_VAL)? add->transitive : base->transitive;
+ nsc->require_https = (add->require_https != MD_REQUIRE_UNSET)? add->require_https : base->require_https;
nsc->drive_mode = (add->drive_mode != DEF_VAL)? add->drive_mode : base->drive_mode;
nsc->must_staple = (add->must_staple != DEF_VAL)? add->must_staple : base->must_staple;
nsc->pkey_spec = add->pkey_spec? add->pkey_spec : base->pkey_spec;
@@ -426,6 +433,55 @@ static const char *md_config_set_drive_m
return NULL;
}
+static const char *md_config_set_must_staple(cmd_parms *cmd, void *dc, const char *value)
+{
+ md_srv_conf_t *config = md_config_get(cmd->server);
+ const char *err;
+
+ if (!inside_section(cmd, MD_CMD_MD_SECTION)
+ && (err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
+ return err;
+ }
+
+ if (!apr_strnatcasecmp("off", value)) {
+ config->must_staple = 0;
+ }
+ else if (!apr_strnatcasecmp("on", value)) {
+ config->must_staple = 1;
+ }
+ else {
+ return apr_pstrcat(cmd->pool, "unknown '", value,
+ "', supported parameter values are 'on' and 'off'", NULL);
+ }
+ return NULL;
+}
+
+static const char *md_config_set_require_https(cmd_parms *cmd, void *dc, const char *value)
+{
+ md_srv_conf_t *config = md_config_get(cmd->server);
+ const char *err;
+
+ if (!inside_section(cmd, MD_CMD_MD_SECTION)
+ && (err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
+ return err;
+ }
+
+ if (!apr_strnatcasecmp("off", value)) {
+ config->require_https = MD_REQUIRE_OFF;
+ }
+ else if (!apr_strnatcasecmp(MD_KEY_TEMPORARY, value)) {
+ config->require_https = MD_REQUIRE_TEMPORARY;
+ }
+ else if (!apr_strnatcasecmp(MD_KEY_PERMANENT, value)) {
+ config->require_https = MD_REQUIRE_PERMANENT;
+ }
+ else {
+ return apr_pstrcat(cmd->pool, "unknown '", value,
+ "', supported parameter values are 'temporary' and 'permanent'", NULL);
+ }
+ return NULL;
+}
+
static apr_status_t duration_parse(const char *value, apr_interval_time_t *ptimeout,
const char *def_unit)
{
@@ -519,6 +575,10 @@ static const char *md_config_set_proxy(c
if (err) {
return err;
}
+ md_util_abs_http_uri_check(cmd->pool, value, &err);
+ if (err) {
+ return err;
+ }
sc->mc->proxy_url = value;
(void)arg;
return NULL;
@@ -690,6 +750,8 @@ const command_rec md_cmds[] = {
AP_INIT_TAKE_ARGV( MD_CMD_MEMBERS, md_config_sec_add_members, NULL, RSRC_CONF,
"Define domain name(s) part of the Managed Domain. Use 'auto' or "
"'manual' to enable/disable auto adding names from virtual hosts."),
+ AP_INIT_TAKE1( MD_CMD_MUST_STAPLE, md_config_set_must_staple, NULL, RSRC_CONF,
+ "Enable/Disable the Must-Staple flag for new certificates."),
AP_INIT_TAKE12( MD_CMD_PORTMAP, md_config_set_port_map, NULL, RSRC_CONF,
"Declare the mapped ports 80 and 443 on the local server. E.g. 80:8000 "
"to indicate that the server port 8000 is reachable as port 80 from the "
@@ -703,6 +765,8 @@ const command_rec md_cmds[] = {
"the directory for file system storage of managed domain data."),
AP_INIT_TAKE1( MD_CMD_RENEWWINDOW, md_config_set_renew_window, NULL, RSRC_CONF,
"Time length for renewal before certificate expires (defaults to days)"),
+ AP_INIT_TAKE1( MD_CMD_REQUIREHTTPS, md_config_set_require_https, NULL, RSRC_CONF,
+ "Redirect non-secure requests to the https: equivalent."),
AP_INIT_TAKE1(NULL, NULL, NULL, RSRC_CONF, NULL)
};
@@ -765,6 +829,10 @@ int md_config_geti(const md_srv_conf_t *
return sc->mc->local_443;
case MD_CONFIG_TRANSITIVE:
return (sc->transitive != DEF_VAL)? sc->transitive : defconf.transitive;
+ case MD_CONFIG_REQUIRE_HTTPS:
+ return (sc->require_https != MD_REQUIRE_UNSET)? sc->require_https : defconf.require_https;
+ case MD_CONFIG_MUST_STAPLE:
+ return (sc->must_staple != DEF_VAL)? sc->must_staple : defconf.must_staple;
default:
return 0;
}
Modified: httpd/httpd/trunk/modules/md/mod_md_config.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/md/mod_md_config.h?rev=1808241&r1=1808240&r2=1808241&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/md/mod_md_config.h (original)
+++ httpd/httpd/trunk/modules/md/mod_md_config.h Wed Sep 13 14:16:49 2017
@@ -31,6 +31,8 @@ typedef enum {
MD_CONFIG_RENEW_WINDOW,
MD_CONFIG_TRANSITIVE,
MD_CONFIG_PROXY,
+ MD_CONFIG_REQUIRE_HTTPS,
+ MD_CONFIG_MUST_STAPLE,
} md_config_var_t;
typedef struct {
@@ -53,6 +55,7 @@ typedef struct md_srv_conf_t {
md_mod_conf_t *mc; /* global config settings */
int transitive; /* != 0 iff VirtualHost names/aliases are auto-added */
+ md_require_t require_https; /* If MDs require https: access */
int drive_mode; /* mode of obtaining credentials */
int must_staple; /* certificates should set the OCSP Must Staple extension */
struct md_pkey_spec_t *pkey_spec; /* specification for generating private keys */