Skip to content

Commit

Permalink
* fixes error in renew window calculation that may lead to mod_md ru…
Browse files Browse the repository at this point in the history
…nning

    watchdog in a tight loop until actual renewal becomes necessary.
  * /.well-known/acme-challenge requests that cannot be answered for hostnames
    outside the configured MDs are free to be answered by other handlers. This allows
    co-existance between mod_md and other ACME clients on the same server (implements PR62189).
    Suggested by Arkadiusz Miskiewicz <[email protected]>.
  • Loading branch information
Stefan Eissing committed Mar 19, 2018
1 parent a47b6fd commit 9b0b50f
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 42 deletions.
9 changes: 9 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
v1.1.10
----------------------------------------------------------------------------------------------------
* fixes error in renew window calculation that may lead to mod_md running
watchdog in a tight loop until actual renewal becomes necessary.
* /.well-known/acme-challenge requests that cannot be answered for hostnames
outside the configured MDs are free to be answered by other handlers. This allows
co-existance between mod_md and other ACME clients on the same server (implements PR62189).
Suggested by Arkadiusz Miskiewicz <[email protected]>.

v1.1.9
----------------------------------------------------------------------------------------------------
* Removed bould check from configure. Not everone building the module needs it installed.
Expand Down
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#

AC_PREREQ([2.69])
AC_INIT([mod_md], [1.1.9], [[email protected]])
AC_INIT([mod_md], [1.1.10], [[email protected]])

LT_PREREQ([2.2.6])
LT_INIT()
Expand Down
2 changes: 1 addition & 1 deletion src/md_crypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ static int pem_passwd(char *buf, int size, int rwflag, void *baton)
*/
static apr_time_t md_asn1_time_get(const ASN1_TIME* time)
{
#ifdef LIBRESSL_VERSION_NUMBER
#if OPENSSL_VERSION_NUMBER < 0x10002000L || defined(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;
Expand Down
4 changes: 2 additions & 2 deletions src/md_version.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@
* @macro
* Version number of the md module as c string
*/
#define MOD_MD_VERSION "1.1.9-git"
#define MOD_MD_VERSION "1.1.10-git"

/**
* @macro
* Numerical representation of the version number of the md module
* 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 0x010109
#define MOD_MD_VERSION_NUM 0x01010a

#define MD_ACME_DEF_URL "https://acme-v01.api.letsencrypt.org/directory"

Expand Down
89 changes: 51 additions & 38 deletions src/mod_md.c
Original file line number Diff line number Diff line change
Expand Up @@ -698,11 +698,11 @@ static apr_status_t check_job(md_watchdog *wd, md_job_t *job, apr_pool_t *ptemp)
}
}
else {
job->next_check = job->md->expires - job->md->renew_window;

/* Renew is not necessary yet, leave job->next_check as 0 since
* that keeps the default schedule of running twice a day. */
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", job->md->name, ts);
"md(%s): no need to renew yet, cert expires %s", job->md->name, ts);
}
}

Expand Down Expand Up @@ -1302,48 +1302,61 @@ static int md_http_challenge_pr(request_rec *r)
const md_srv_conf_t *sc;
const char *name, *data;
md_reg_t *reg;
int configured;
apr_status_t rv;

if (!strncmp(ACME_CHALLENGE_PREFIX, r->parsed_uri.path, sizeof(ACME_CHALLENGE_PREFIX)-1)) {
if (r->method_number == M_GET) {

sc = ap_get_module_config(r->server->module_config, &md_module);
reg = sc && sc->mc? sc->mc->reg : NULL;
name = r->parsed_uri.path + sizeof(ACME_CHALLENGE_PREFIX)-1;

r->status = HTTP_NOT_FOUND;
if (!ap_strchr_c(name, '/') && reg) {
md_store_t *store = md_reg_store_get(reg);
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
"Challenge for %s (%s)", r->hostname, r->uri);

rv = md_store_load(store, MD_SG_CHALLENGES, r->hostname,
MD_FN_HTTP01, MD_SV_TEXT, (void**)&data, r->pool);
if (APR_SUCCESS == rv) {
apr_size_t len = strlen(data);

r->status = HTTP_OK;
apr_table_setn(r->headers_out, "Content-Length", apr_ltoa(r->pool, (long)len));
sc = ap_get_module_config(r->server->module_config, &md_module);
if (sc && sc->mc) {
configured = (NULL != md_get_by_domain(sc->mc->mds, r->hostname));
if (r->method_number == M_GET) {
name = r->parsed_uri.path + sizeof(ACME_CHALLENGE_PREFIX)-1;
reg = sc && sc->mc? sc->mc->reg : NULL;

r->status = HTTP_NOT_FOUND;
if (!ap_strchr_c(name, '/') && reg) {
md_store_t *store = md_reg_store_get(reg);
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
"Challenge for %s (%s)", r->hostname, r->uri);

bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
apr_brigade_write(bb, NULL, NULL, data, len);
ap_pass_brigade(r->output_filters, bb);
apr_brigade_cleanup(bb);
}
else if (APR_STATUS_IS_ENOENT(rv)) {
return HTTP_NOT_FOUND;
}
else if (APR_ENOENT != rv) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(10081)
"loading challenge %s from store", name);
return HTTP_INTERNAL_SERVER_ERROR;
rv = md_store_load(store, MD_SG_CHALLENGES, r->hostname,
MD_FN_HTTP01, MD_SV_TEXT, (void**)&data, r->pool);
if (APR_SUCCESS == rv) {
apr_size_t len = strlen(data);

r->status = HTTP_OK;
apr_table_setn(r->headers_out, "Content-Length", apr_ltoa(r->pool, (long)len));

bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
apr_brigade_write(bb, NULL, NULL, data, len);
ap_pass_brigade(r->output_filters, bb);
apr_brigade_cleanup(bb);
}
else if (!configured) {
/* The request hostname is not for a configured domain. We are not
* the sole authority here for /.well-known/acme-challenge (see PR62189).
* So, we decline to handle this and let others step in.
*/
return DECLINED;
}
else if (APR_STATUS_IS_ENOENT(rv)) {
return HTTP_NOT_FOUND;
}
else if (APR_ENOENT != rv) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(10081)
"loading challenge %s from store", name);
return HTTP_INTERNAL_SERVER_ERROR;
}
}
return r->status;
}
else if (configured) {
/* See comment above, we prevent any other access only for domains
* the have been configured for mod_md. */
return HTTP_NOT_IMPLEMENTED;
}
return r->status;
}
else {
return HTTP_NOT_IMPLEMENTED;
}

}
return DECLINED;
}
Expand Down

0 comments on commit 9b0b50f

Please sign in to comment.