summaryrefslogtreecommitdiff
path: root/modules/md/md_core.c
diff options
context:
space:
mode:
authorStefan Eissing <icing@apache.org>2021-10-29 09:04:38 +0000
committerStefan Eissing <icing@apache.org>2021-10-29 09:04:38 +0000
commit51a214821cdceb0ae4153accf0d5f8c5207f6549 (patch)
tree1cf12feca8d899c0c59d356dfbc040a44406e549 /modules/md/md_core.c
parent7b83bd03a93b28ec21be973936ad06c606fbf54f (diff)
downloadhttpd-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.c84
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;
+}