diff options
author | Stefan Eissing <icing@apache.org> | 2021-10-29 09:04:38 +0000 |
---|---|---|
committer | Stefan Eissing <icing@apache.org> | 2021-10-29 09:04:38 +0000 |
commit | 51a214821cdceb0ae4153accf0d5f8c5207f6549 (patch) | |
tree | 1cf12feca8d899c0c59d356dfbc040a44406e549 /modules/md/md_core.c | |
parent | 7b83bd03a93b28ec21be973936ad06c606fbf54f (diff) | |
download | httpd-51a214821cdceb0ae4153accf0d5f8c5207f6549.tar.gz |
*) mod_md: adding v2.4.8 with the following changes
- Added support for ACME External Account Binding (EAB).
Use the new directive `MDExternalAccountBinding` to provide the
server with the value for key identifier and hmac as provided by
your CA.
While working on some servers, EAB handling is not uniform
across CAs. First tests with a Sectigo Certificate Manager in
demo mode are successful. But ZeroSSL, for example, seems to
regard EAB values as a one-time-use-only thing, which makes them
fail if you create a seconde account or retry the creation of the
first account with the same EAB.
- The directive 'MDCertificateAuthority' now checks if its parameter
is a http/https url or one of a set of known names. Those are
'LetsEncrypt', 'LetsEncrypt-Test', 'Buypass' and 'Buypass-Test'
for now and they are not case-sensitive.
The default of LetsEncrypt is unchanged.
- `MDContactEmail` can now be specified inside a `<MDomain dnsname>`
section.
- Treating 401 HTTP status codes for orders like 403, since some ACME
servers seem to prefer that for accessing oders from other accounts.
- When retrieving certificate chains, try to read the repsonse even
if the HTTP Content-Type is unrecognized.
- Fixed a bug that reset the error counter of a certificate renewal
and prevented the increasing delays in further attempts.
- Fixed the renewal process giving up every time on an already existing
order with some invalid domains. Now, if such are seen in a previous
order, a new order is created for a clean start over again.
See <https://github.com/icing/mod_md/issues/268>
- Fixed a mixup in md-status handler when static certificate files
and renewal was configured at the same time.
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1894610 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'modules/md/md_core.c')
-rw-r--r-- | modules/md/md_core.c | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/modules/md/md_core.c b/modules/md/md_core.c index 9b696e2b99..620b809984 100644 --- a/modules/md/md_core.c +++ b/modules/md/md_core.c @@ -19,6 +19,7 @@ #include <apr_lib.h> #include <apr_strings.h> +#include <apr_uri.h> #include <apr_tables.h> #include <apr_time.h> #include <apr_date.h> @@ -277,6 +278,8 @@ md_json_t *md_to_json(const md_t *md, apr_pool_t *p) md_json_setj(md_pkeys_spec_to_json(md->pks, p), json, MD_KEY_PKEY, NULL); } md_json_setl(md->state, json, MD_KEY_STATE, NULL); + if (md->state_descr) + md_json_sets(md->state_descr, json, MD_KEY_STATE_DESCR, NULL); md_json_setl(md->renew_mode, json, MD_KEY_RENEW_MODE, NULL); if (md->renew_window) md_json_sets(md_timeslice_format(md->renew_window, p), json, MD_KEY_RENEW_WINDOW, NULL); @@ -302,6 +305,10 @@ md_json_t *md_to_json(const md_t *md, apr_pool_t *p) if (md->cert_files) md_json_setsa(md->cert_files, json, MD_KEY_CERT_FILES, NULL); if (md->pkey_files) md_json_setsa(md->pkey_files, json, MD_KEY_PKEY_FILES, NULL); md_json_setb(md->stapling > 0, json, MD_KEY_STAPLING, 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); + } return json; } return NULL; @@ -323,6 +330,7 @@ md_t *md_from_json(md_json_t *json, apr_pool_t *p) md->pks = md_pkeys_spec_from_json(md_json_getj(json, MD_KEY_PKEY, NULL), p); } md->state = (md_state_t)md_json_getl(json, MD_KEY_STATE, NULL); + md->state_descr = md_json_dups(p, json, MD_KEY_STATE_DESCR, NULL); if (MD_S_EXPIRED_DEPRECATED == md->state) md->state = MD_S_COMPLETE; md->renew_mode = (int)md_json_getl(json, MD_KEY_RENEW_MODE, NULL); md->domains = md_array_str_compact(p, md->domains, 0); @@ -354,8 +362,84 @@ md_t *md_from_json(md_json_t *json, apr_pool_t *p) } md->stapling = (int)md_json_getb(json, MD_KEY_STAPLING, 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); + } return md; } return NULL; } +md_json_t *md_to_public_json(const md_t *md, apr_pool_t *p) +{ + md_json_t *json = md_to_json(md, p); + if (md_json_has_key(json, MD_KEY_EAB, MD_KEY_HMAC, NULL)) { + md_json_sets("***", json, MD_KEY_EAB, MD_KEY_HMAC, NULL); + } + return json; +} + +typedef struct { + const char *name; + const char *url; +} md_ca_t; + +#define LE_ACMEv2_PROD "https://acme-v02.api.letsencrypt.org/directory" +#define LE_ACMEv2_STAGING "https://acme-staging-v02.api.letsencrypt.org/directory" +#define BUYPASS_ACME "https://api.buypass.com/acme/directory" +#define BUYPASS_ACME_TEST "https://api.test4.buypass.no/acme/directory" + +static md_ca_t KNOWN_CAs[] = { + { "LetsEncrypt", LE_ACMEv2_PROD }, + { "LetsEncrypt-Test", LE_ACMEv2_STAGING }, + { "Buypass", BUYPASS_ACME }, + { "Buypass-Test", BUYPASS_ACME_TEST }, +}; + +const char *md_get_ca_name_from_url(apr_pool_t *p, const char *url) +{ + apr_uri_t uri_parsed; + unsigned int i; + + for (i = 0; i < sizeof(KNOWN_CAs)/sizeof(KNOWN_CAs[0]); ++i) { + if (!apr_strnatcasecmp(KNOWN_CAs[i].url, url)) { + return KNOWN_CAs[i].name; + } + } + if (APR_SUCCESS == apr_uri_parse(p, url, &uri_parsed)) { + return uri_parsed.hostname; + } + return apr_pstrdup(p, url); +} + +apr_status_t md_get_ca_url_from_name(const char **purl, apr_pool_t *p, const char *name) +{ + const char *err; + unsigned int i; + apr_status_t rv = APR_SUCCESS; + + *purl = NULL; + for (i = 0; i < sizeof(KNOWN_CAs)/sizeof(KNOWN_CAs[0]); ++i) { + if (!apr_strnatcasecmp(KNOWN_CAs[i].name, name)) { + *purl = KNOWN_CAs[i].url; + goto leave; + } + } + *purl = name; + rv = md_util_abs_http_uri_check(p, name, &err); + if (APR_SUCCESS != rv) { + apr_array_header_t *names; + + names = apr_array_make(p, 10, sizeof(const char*)); + for (i = 0; i < sizeof(KNOWN_CAs)/sizeof(KNOWN_CAs[0]); ++i) { + APR_ARRAY_PUSH(names, const char *) = KNOWN_CAs[i].name; + } + *purl = apr_psprintf(p, + "The CA name '%s' is not known and it is not a URL either (%s). " + "Known CA names are: %s.", + name, err, apr_array_pstrcat(p, names, ' ')); + } +leave: + return rv; +} |