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/04 14:07:30 UTC
svn commit: r1807228 - in /httpd/httpd/trunk: CHANGES modules/md/md.h
modules/md/md_acme_drive.c modules/md/md_reg.c modules/md/md_reg.h
modules/md/md_store_fs.c modules/md/md_version.h modules/md/mod_md.c
modules/md/mod_md.h
Author: icing
Date: Mon Sep 4 14:07:29 2017
New Revision: 1807228
URL: http://svn.apache.org/viewvc?rev=1807228&view=rev
Log:
On the trunk:
mod_md:
* Improved interface to mod_ssl for fallback handling. Backward compatible to previous mod_ssl
patch, but fallbacks will not work.
* Provide a temporary, self-signed certificate with a speaking command and domain name if we
have no other cert for a Managed Domain, yet. Refs github issue #32
* Continue to provide expired or not-completely matching, existing certificate for a Managed
Domain until the renewal was successful. This is helpful when one adds a DNS name to
a MD, so the previous domains can be served while a new cert is requested.
* All files necessary to run tests are not in the release package.
* Making "http-01" the preferred challenge type again, as people "tls-sni-01" requires at least
one working certificate vhost right now - which not everyone has.
* moved part of the MD sanity checks from post_config to check_config phase, allowing for error
detection in check-only runs.
Modified:
httpd/httpd/trunk/CHANGES
httpd/httpd/trunk/modules/md/md.h
httpd/httpd/trunk/modules/md/md_acme_drive.c
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_version.h
httpd/httpd/trunk/modules/md/mod_md.c
httpd/httpd/trunk/modules/md/mod_md.h
Modified: httpd/httpd/trunk/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/CHANGES?rev=1807228&r1=1807227&r2=1807228&view=diff
==============================================================================
--- httpd/httpd/trunk/CHANGES [utf-8] (original)
+++ httpd/httpd/trunk/CHANGES [utf-8] Mon Sep 4 14:07:29 2017
@@ -1,39 +1,9 @@
-*- coding: utf-8 -*-
Changes with Apache 2.5.0
- *) mod_md: v0.8.1:
- - New directive ```MDPrivateKeys``` to specify the type and parameter to private key generation.
- Currently only 'RSA' is supported as type with an option number of bits >= 2048 as parameter.
- Simple test cases for config handling added.
- - Private RSA keys are now generated with 2048 bits by default. Use ```MDPrivateKeys``` for
- higher security.
- - IMPORTANT: store format change. The following changes will be made to an existing md store on
- first start with a new version (be it by mod_md in the server or a run by a new 'a2md'):
- - pkey.pem will be renamed to privkey.pem
- - cert.pem and chain.pem will be concatenated to pubcert.pem. The former files will remain,
- but no longer be used. They will disappear on next renewal.
- ADVICE: If the current store data is vital to you, please make a backup first!
- - Fixed test case clearing of store to keep key alive, enabling true random store key again.
- - Removed pun "Something, like certbot" from the User-Agent request header. Refs issue #34
- - Cleaned up reporting of missing/mismatched MDCertificateAgreement in the logs. This will
- no longer trigger early retries.
- - badNonce encounters are no longer reported as errors. Retries are attempted now silently.
- Refs github issue #35
- - new default MDRenewWindow. Instead of 14 days, the default is now a third before the end of
- the certificates lifetime. For the usual 90 days of Let's Encrypt certificates, this makes
- an effective renewal window of 30 days - as recommended by LE. Refs issue #30
- - Enabled conversion warnings if supported by compiler, eliminated several signed/unsigned
- warnings.
- - LIVE: the real Let's Encrypt CA is now live by default! If you need to experiment, configure
- MDCertificateAuthority https://acme-staging.api.letsencrypt.org/directory
- - When existing, complete certificates are renewed, the activation of the new ones is
- delayed by 24 hours (or until the existing ones expire, whatever is earler) to accomodate
- for clients with weird clocks, refs #1.
- - Fixed store sync when MDCAChallenges was removed again from an MD.
- - Fixed crash when MD matched the base server, fixes #23
- - Fixed watchgod resetting staging when server processes disappeared (e.g. reached
- max requests or other limits).
- [Stefan Eissing]
+ *) mod_md: v0.9.0:
+ Certificate provisioning from Let's Encrypt (and other ACME CAs) for mod_ssl virtual hosts.
+ [Stefan Eissing]
*) mod_proxy: loadfactor parameter can now be a decimal number (eg: 1.25).
[Jim Jagielski]
Modified: httpd/httpd/trunk/modules/md/md.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/md/md.h?rev=1807228&r1=1807227&r2=1807228&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/md/md.h (original)
+++ httpd/httpd/trunk/modules/md/md.h Mon Sep 4 14:07:29 2017
@@ -143,6 +143,9 @@ struct md_t {
#define MD_FN_CHAIN "chain.pem"
#define MD_FN_HTTPD_JSON "httpd.json"
+#define MD_FN_FALLBACK_PKEY "fallback-privkey.pem"
+#define MD_FN_FALLBACK_CERT "fallback-cert.pem"
+
/* Check if a string member of a new MD (n) has
* a value and if it differs from the old MD o
*/
Modified: httpd/httpd/trunk/modules/md/md_acme_drive.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/md/md_acme_drive.c?rev=1807228&r1=1807227&r2=1807228&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/md/md_acme_drive.c (original)
+++ httpd/httpd/trunk/modules/md/md_acme_drive.c Mon Sep 4 14:07:29 2017
@@ -617,8 +617,8 @@ static apr_status_t acme_driver_init(md_
}
else {
/* free to chose. Add all we support and see what we get offered */
- APR_ARRAY_PUSH(ad->ca_challenges, const char*) = MD_AUTHZ_TYPE_TLSSNI01;
APR_ARRAY_PUSH(ad->ca_challenges, const char*) = MD_AUTHZ_TYPE_HTTP01;
+ APR_ARRAY_PUSH(ad->ca_challenges, const char*) = MD_AUTHZ_TYPE_TLSSNI01;
}
if (!d->can_http && !d->can_https) {
Modified: httpd/httpd/trunk/modules/md/md_reg.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/md/md_reg.c?rev=1807228&r1=1807227&r2=1807228&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/md/md_reg.c (original)
+++ httpd/httpd/trunk/modules/md/md_reg.c Mon Sep 4 14:07:29 2017
@@ -424,12 +424,10 @@ md_t *md_reg_find_overlap(md_reg_t *reg,
}
apr_status_t md_reg_get_cred_files(md_reg_t *reg, const md_t *md, apr_pool_t *p,
- const char **pkeyfile, const char **pcertfile,
- const char **pchainfile)
+ const char **pkeyfile, const char **pcertfile)
{
apr_status_t rv;
- *pchainfile = NULL;
rv = md_store_get_fname(pkeyfile, reg->store, MD_SG_DOMAINS, md->name, MD_FN_PRIVKEY, p);
if (APR_SUCCESS == rv) {
rv = md_store_get_fname(pcertfile, reg->store, MD_SG_DOMAINS, md->name, MD_FN_PUBCERT, p);
Modified: httpd/httpd/trunk/modules/md/md_reg.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/md/md_reg.h?rev=1807228&r1=1807227&r2=1807228&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/md/md_reg.h (original)
+++ httpd/httpd/trunk/modules/md/md_reg.h Mon Sep 4 14:07:29 2017
@@ -108,8 +108,7 @@ apr_status_t md_reg_creds_get(const md_c
md_store_group_t group, const md_t *md, apr_pool_t *p);
apr_status_t md_reg_get_cred_files(md_reg_t *reg, const md_t *md, apr_pool_t *p,
- const char **pkeyfile, const char **pcertfile,
- const char **pchainfile);
+ const char **pkeyfile, const char **pcertfile);
/**
* Synchronise the give master mds with the store.
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=1807228&r1=1807227&r2=1807228&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/md/md_store_fs.c (original)
+++ httpd/httpd/trunk/modules/md/md_store_fs.c Mon Sep 4 14:07:29 2017
@@ -258,6 +258,57 @@ 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;
@@ -302,6 +353,9 @@ 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_version.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/md/md_version.h?rev=1807228&r1=1807227&r2=1807228&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/md/md_version.h (original)
+++ httpd/httpd/trunk/modules/md/md_version.h Mon Sep 4 14:07:29 2017
@@ -26,7 +26,7 @@
* @macro
* Version number of the md module as c string
*/
-#define MOD_MD_VERSION "0.8.1"
+#define MOD_MD_VERSION "0.9.0"
/**
* @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 0x000801
+#define MOD_MD_VERSION_NUM 0x000900
#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=1807228&r1=1807227&r2=1807228&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/md/mod_md.c (original)
+++ httpd/httpd/trunk/modules/md/mod_md.c Mon Sep 4 14:07:29 2017
@@ -741,18 +741,11 @@ static void load_stage_sets(apr_array_he
return;
}
-static apr_status_t md_post_config(apr_pool_t *p, apr_pool_t *plog,
- apr_pool_t *ptemp, server_rec *s)
+static apr_status_t md_check_config(apr_pool_t *p, apr_pool_t *plog,
+ apr_pool_t *ptemp, server_rec *s)
{
const char *mod_md_init_key = "mod_md_init_counter";
void *data = NULL;
- md_srv_conf_t *sc;
- md_mod_conf_t *mc;
- apr_array_header_t *drive_names;
- md_reg_t *reg;
- apr_status_t rv = APR_SUCCESS;
- const md_t *md;
- int i;
apr_pool_userdata_get(&data, mod_md_init_key, s->process->pool);
if (data == NULL) {
@@ -767,20 +760,29 @@ static apr_status_t md_post_config(apr_p
}
init_setups(p, s);
-
md_log_set(log_is_level, log_print, NULL);
- sc = md_config_get(s);
- mc = sc->mc;
-
- /* 1. Check uniqueness of MDs, calculate global, configured MD list.
+ /* Check uniqueness of MDs, calculate global, configured MD list.
* If successful, we have a list of MD definitions that do not overlap. */
/* We also need to find out if we can be reached on 80/443 from the outside (e.g. the CA) */
- if (APR_SUCCESS != (rv = md_calc_md_list(p, plog, ptemp, s))) {
- goto out;
- }
+ return md_calc_md_list(p, plog, ptemp, s);
+}
+
+static apr_status_t md_post_config(apr_pool_t *p, apr_pool_t *plog,
+ apr_pool_t *ptemp, server_rec *s)
+{
+ md_srv_conf_t *sc;
+ md_mod_conf_t *mc;
+ md_reg_t *reg;
+ const md_t *md;
+ apr_array_header_t *drive_names;
+ apr_status_t rv = APR_SUCCESS;
+ int i;
+
+ sc = md_config_get(s);
+ mc = sc->mc;
- /* 2. Synchronize the defintions we now have with the store via a registry (reg). */
+ /* Synchronize the defintions we now have with the store via a registry (reg). */
if (APR_SUCCESS != (rv = setup_reg(®, p, s, 1))) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(10072)
"setup md registry");
@@ -790,10 +792,9 @@ static apr_status_t md_post_config(apr_p
mc->can_http, mc->can_https))) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(10073)
"synching %d mds to registry", mc->mds->nelts);
- goto out;
}
- /* 3. Determine the managed domains that are in auto drive_mode. For those,
+ /* Determine the managed domains that are in auto drive_mode. For those,
* determine in which state they are:
* - UNKNOWN: should not happen, report, dont drive
* - ERROR: something we do not know how to fix, report, dont drive
@@ -820,7 +821,7 @@ static apr_status_t md_post_config(apr_p
}
}
- /* 4. I there are MDs to drive, start a watchdog to check on them regularly */
+ /* 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)
"%d out of %d mds are configured for auto-drive",
@@ -834,7 +835,7 @@ static apr_status_t md_post_config(apr_p
ap_log_error( APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(10075)
"no mds to auto drive, no watchdog needed");
}
-out:
+out:
return rv;
}
@@ -855,9 +856,8 @@ static int md_is_managed(server_rec *s)
return 0;
}
-static apr_status_t md_get_credentials(server_rec *s, apr_pool_t *p,
- const char **pkeyfile, const char **pcertfile,
- const char **pchainfile)
+static apr_status_t md_get_certificate(server_rec *s, apr_pool_t *p,
+ const char **pkeyfile, const char **pcertfile)
{
apr_status_t rv = APR_ENOENT;
md_srv_conf_t *sc;
@@ -866,26 +866,53 @@ static apr_status_t md_get_credentials(s
*pkeyfile = NULL;
*pcertfile = NULL;
- *pchainfile = NULL;
sc = md_config_get(s);
if (sc && sc->assigned) {
assert(sc->mc);
assert(sc->mc->store);
- if (APR_SUCCESS == (rv = md_reg_init(®, p, sc->mc->store))) {
- md = md_reg_get(reg, sc->assigned->name, p);
- if (md->state != MD_S_COMPLETE) {
- return APR_EAGAIN;
- }
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(10077)
- "%s: loading credentials for server %s", md->name, s->server_hostname);
- return md_reg_get_cred_files(reg, md, p, pkeyfile, pcertfile, pchainfile);
+ if (APR_SUCCESS != (rv = md_reg_init(®, p, sc->mc->store))) {
+ 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))) {
+ return rv;
+ }
+
+ if (!*pkeyfile || !*pcertfile
+ || APR_SUCCESS != md_util_is_file(*pkeyfile, p)
+ || APR_SUCCESS != md_util_is_file(*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);
+
+ return APR_EAGAIN;
+ }
+
+ /* We have key and cert files, but they might no longer be valid or not
+ * match all domain names. Still use these files for now, but indicate that
+ * resources should no longer be served until we have a new certificate again. */
+ if (md->state != MD_S_COMPLETE) {
+ return APR_EAGAIN;
+ }
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(10077)
+ "%s: providing certificate for server %s", md->name, s->server_hostname);
}
return rv;
}
+static apr_status_t md_get_credentials(server_rec *s, apr_pool_t *p,
+ const char **pkeyfile, const char **pcertfile,
+ const char **pchainfile)
+{
+ *pchainfile = NULL;
+ return md_get_certificate(s, p, pkeyfile, pcertfile);
+}
static int md_is_challenge(conn_rec *c, const char *servername,
X509 **pcert, EVP_PKEY **pkey)
@@ -1005,6 +1032,7 @@ static void md_hooks(apr_pool_t *pool)
/* Run once after configuration is set, before mod_ssl.
*/
+ ap_hook_check_config(md_check_config, NULL, mod_ssl, APR_HOOK_MIDDLE);
ap_hook_post_config(md_post_config, NULL, mod_ssl, APR_HOOK_MIDDLE);
/* Run once after a child process has been created.
@@ -1015,6 +1043,7 @@ static void md_hooks(apr_pool_t *pool)
ap_hook_post_read_request(md_http_challenge_pr, NULL, NULL, APR_HOOK_MIDDLE);
APR_REGISTER_OPTIONAL_FN(md_is_managed);
+ APR_REGISTER_OPTIONAL_FN(md_get_certificate);
APR_REGISTER_OPTIONAL_FN(md_get_credentials);
APR_REGISTER_OPTIONAL_FN(md_is_challenge);
}
Modified: httpd/httpd/trunk/modules/md/mod_md.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/md/mod_md.h?rev=1807228&r1=1807227&r2=1807228&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/md/mod_md.h (original)
+++ httpd/httpd/trunk/modules/md/mod_md.h Mon Sep 4 14:07:29 2017
@@ -24,6 +24,17 @@ struct server_rec;
APR_DECLARE_OPTIONAL_FN(int,
md_is_managed, (struct server_rec *));
+/**
+ * Get the certificate/key for the managed domain (md_is_managed != 0).
+ *
+ * @return APR_EAGAIN if the real certicate is not available yet
+ */
+APR_DECLARE_OPTIONAL_FN(apr_status_t,
+ md_get_certificate, (struct server_rec *, apr_pool_t *,
+ const char **pkeyfile,
+ const char **pcertfile));
+
+/* previous version for md_get_certificate, to be phased out soon */
APR_DECLARE_OPTIONAL_FN(apr_status_t,
md_get_credentials, (struct server_rec *, apr_pool_t *,
const char **pkeyfile,