diff options
author | Stefan Eissing <icing@apache.org> | 2021-07-12 07:52:28 +0000 |
---|---|---|
committer | Stefan Eissing <icing@apache.org> | 2021-07-12 07:52:28 +0000 |
commit | c07608101f0700fb93001eb32935445777c6dab5 (patch) | |
tree | 5dc8ee307619310ccafc2fc18627661de5ec48a3 /modules/md | |
parent | f087735b4d6e0dbefb74abe583b0ca44a9d81d37 (diff) | |
download | httpd-c07608101f0700fb93001eb32935445777c6dab5.tar.gz |
*) mod_md: fixed a potential null pointer dereference if ACME/OCSP
server returned 2xx responses without content type. Reported by chuangwen.
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1891470 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'modules/md')
-rw-r--r-- | modules/md/md_acme.c | 3 | ||||
-rw-r--r-- | modules/md/md_acme_authz.c | 4 | ||||
-rw-r--r-- | modules/md/md_crypt.c | 57 | ||||
-rw-r--r-- | modules/md/md_crypt.h | 4 | ||||
-rw-r--r-- | modules/md/md_curl.c | 6 | ||||
-rw-r--r-- | modules/md/md_json.c | 11 | ||||
-rw-r--r-- | modules/md/md_jws.c | 8 | ||||
-rw-r--r-- | modules/md/md_ocsp.c | 126 | ||||
-rw-r--r-- | modules/md/md_store_fs.c | 57 | ||||
-rw-r--r-- | modules/md/md_util.c | 57 | ||||
-rw-r--r-- | modules/md/md_util.h | 37 | ||||
-rw-r--r-- | modules/md/md_version.h | 4 | ||||
-rw-r--r-- | modules/md/mod_md.c | 9 | ||||
-rw-r--r-- | modules/md/mod_md.h | 27 | ||||
-rw-r--r-- | modules/md/mod_md_ocsp.c | 68 | ||||
-rw-r--r-- | modules/md/mod_md_ocsp.h | 6 |
16 files changed, 246 insertions, 238 deletions
diff --git a/modules/md/md_acme.c b/modules/md/md_acme.c index 52fab0af1e..82e16125a4 100644 --- a/modules/md/md_acme.c +++ b/modules/md/md_acme.c @@ -227,7 +227,8 @@ static apr_status_t inspect_problem(md_acme_req_t *req, const md_http_response_t static apr_status_t acmev2_req_init(md_acme_req_t *req, md_json_t *jpayload) { md_data_t payload; - + + md_data_null(&payload); if (!req->acme->acct) { return APR_EINVAL; } diff --git a/modules/md/md_acme_authz.c b/modules/md/md_acme_authz.c index 883e319b48..bfbd67c11c 100644 --- a/modules/md/md_acme_authz.c +++ b/modules/md/md_acme_authz.c @@ -321,7 +321,7 @@ static apr_status_t cha_tls_alpn_01_setup(md_acme_authz_cha_t *cha, md_acme_auth * The server will need to answer a TLS connection with SNI == authz->domain * and ALPN procotol "acme-tls/1" with this certificate. */ - MD_DATA_SET_STR(&data, cha->key_authz); + md_data_init_str(&data, cha->key_authz); rv = md_crypt_sha256_digest_hex(&token, p, &data); if (APR_SUCCESS != rv) { md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: create tls-alpn-01 validation token", @@ -420,7 +420,7 @@ static apr_status_t cha_dns_01_setup(md_acme_authz_cha_t *cha, md_acme_authz_t * goto out; } - MD_DATA_SET_STR(&data, cha->key_authz); + md_data_init_str(&data, cha->key_authz); rv = md_crypt_sha256_digest64(&token, p, &data); if (APR_SUCCESS != rv) { md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: create dns-01 token for %s", diff --git a/modules/md/md_crypt.c b/modules/md/md_crypt.c index 3992c6b12e..13c7edde5b 100644 --- a/modules/md/md_crypt.c +++ b/modules/md/md_crypt.c @@ -677,6 +677,7 @@ static apr_status_t pkey_to_buffer(md_data_t *buf, md_pkey_t *pkey, apr_pool_t * return APR_EINVAL; } + md_data_null(buf); i = BIO_pending(bio); if (i > 0) { buf->data = apr_palloc(p, (apr_size_t)i); @@ -904,8 +905,7 @@ static const char *bn64(const BIGNUM *b, apr_pool_t *p) if (b) { md_data_t buffer; - buffer.len = (apr_size_t)BN_num_bytes(b); - buffer.data = apr_pcalloc(p, buffer.len); + md_data_pinit(&buffer, (apr_size_t)BN_num_bytes(b), p); if (buffer.data) { BN_bn2bin(b, (unsigned char *)buffer.data); return md_util_base64url_encode(&buffer, p); @@ -946,9 +946,8 @@ apr_status_t md_crypt_sign64(const char **psign64, md_pkey_t *pkey, apr_pool_t * unsigned int blen; const char *sign64 = NULL; apr_status_t rv = APR_ENOMEM; - - buffer.len = (apr_size_t)EVP_PKEY_size(pkey->pkey); - buffer.data = apr_pcalloc(p, buffer.len); + + md_data_pinit(&buffer, (apr_size_t)EVP_PKEY_size(pkey->pkey), p); if (buffer.data) { ctx = EVP_MD_CTX_create(); if (ctx) { @@ -987,11 +986,9 @@ static apr_status_t sha256_digest(md_data_t **pdigest, apr_pool_t *p, const md_d apr_status_t rv = APR_ENOMEM; unsigned int dlen; - digest = apr_palloc(p, sizeof(*digest)); + digest = md_data_pmake(EVP_MAX_MD_SIZE, p); if (!digest) goto leave; - digest->data = apr_pcalloc(p, EVP_MAX_MD_SIZE); - if (!digest->data) goto leave; - + ctx = EVP_MD_CTX_create(); if (ctx) { rv = APR_ENOTIMPL; @@ -1303,7 +1300,8 @@ apr_status_t md_cert_fsave(md_cert_t *cert, apr_pool_t *p, { md_data_t buffer; apr_status_t rv; - + + md_data_null(&buffer); if (APR_SUCCESS == (rv = cert_to_buffer(&buffer, cert, p))) { return md_util_freplace(fname, perms, p, fwrite_buffer, &buffer); } @@ -1314,7 +1312,8 @@ apr_status_t md_cert_to_base64url(const char **ps64, const md_cert_t *cert, apr_ { md_data_t buffer; apr_status_t rv; - + + md_data_null(&buffer); if (APR_SUCCESS == (rv = cert_to_buffer(&buffer, cert, p))) { *ps64 = md_util_base64url_encode(&buffer, p); return APR_SUCCESS; @@ -1328,11 +1327,9 @@ apr_status_t md_cert_to_sha256_digest(md_data_t **pdigest, const md_cert_t *cert md_data_t *digest; unsigned int dlen; apr_status_t rv = APR_ENOMEM; - - digest = apr_palloc(p, sizeof(*digest)); + + digest = md_data_pmake(EVP_MAX_MD_SIZE, p); if (!digest) goto leave; - digest->data = apr_pcalloc(p, EVP_MAX_MD_SIZE); - if (!digest->data) goto leave; X509_digest(cert->x509, EVP_sha256(), (unsigned char*)digest->data, &dlen); digest->len = dlen; @@ -1346,7 +1343,7 @@ apr_status_t md_cert_to_sha256_fingerprint(const char **pfinger, const md_cert_t { md_data_t *digest; apr_status_t rv; - + rv = md_cert_to_sha256_digest(&digest, cert, p); if (APR_SUCCESS == rv) { return md_data_to_hex(pfinger, 0, p, digest); @@ -1679,7 +1676,8 @@ apr_status_t md_cert_req_create(const char **pcsr_der_64, const char *name, int csr_der_len; assert(domains->nelts > 0); - + md_data_null(&csr_der); + if (NULL == (csr = X509_REQ_new()) || NULL == (exts = sk_X509_EXTENSION_new_null()) || NULL == (n = X509_NAME_new())) { @@ -1975,10 +1973,10 @@ apr_status_t md_cert_get_ct_scts(apr_array_header_t *scts, apr_pool_t *p, const sct->version = SCT_get_version(sct_handle); sct->timestamp = apr_time_from_msec(SCT_get_timestamp(sct_handle)); len = SCT_get0_log_id(sct_handle, (unsigned char**)&data); - sct->logid = md_data_create(p, data, len); + sct->logid = md_data_make_pcopy(p, data, len); sct->signature_type_nid = SCT_get_signature_nid(sct_handle); len = SCT_get0_signature(sct_handle, (unsigned char**)&data); - sct->signature = md_data_create(p, data, len); + sct->signature = md_data_make_pcopy(p, data, len); APR_ARRAY_PUSH(scts, md_sct*) = sct; } @@ -1995,3 +1993,24 @@ apr_status_t md_cert_get_ct_scts(apr_array_header_t *scts, apr_pool_t *p, const return APR_ENOTIMPL; #endif } + +apr_status_t md_cert_get_ocsp_responder_url(const char **purl, apr_pool_t *p, const md_cert_t *cert) +{ + STACK_OF(OPENSSL_STRING) *ssk; + apr_status_t rv = APR_SUCCESS; + const char *url = NULL; + + ssk = X509_get1_ocsp(md_cert_get_X509(cert)); + if (!ssk) { + rv = APR_ENOENT; + goto cleanup; + } + url = apr_pstrdup(p, sk_OPENSSL_STRING_value(ssk, 0)); + md_log_perror(MD_LOG_MARK, MD_LOG_TRACE2, 0, p, "ocsp responder found '%s'", url); + +cleanup: + if (ssk) X509_email_free(ssk); + *purl = url; + return rv; +} + diff --git a/modules/md/md_crypt.h b/modules/md/md_crypt.h index cd1db29441..3aa03fc5a8 100644 --- a/modules/md/md_crypt.h +++ b/modules/md/md_crypt.h @@ -41,8 +41,6 @@ apr_status_t md_crypt_sha256_digest64(const char **pdigest64, apr_pool_t *p, apr_status_t md_crypt_sha256_digest_hex(const char **pdigesthex, apr_pool_t *p, const struct md_data_t *data); -#define MD_DATA_SET_STR(d, s) do { (d)->data = (s); (d)->len = strlen(s); } while(0) - /**************************************************************************************************/ /* private keys */ @@ -218,6 +216,8 @@ apr_status_t md_cert_make_tls_alpn_01(md_cert_t **pcert, const char *domain, apr_status_t md_cert_get_ct_scts(apr_array_header_t *scts, apr_pool_t *p, const md_cert_t *cert); +apr_status_t md_cert_get_ocsp_responder_url(const char **purl, apr_pool_t *p, const md_cert_t *cert); + /**************************************************************************************************/ /* X509 certificate transparency */ diff --git a/modules/md/md_curl.c b/modules/md/md_curl.c index e93bea4d42..59d83e52e8 100644 --- a/modules/md/md_curl.c +++ b/modules/md/md_curl.c @@ -213,8 +213,7 @@ static int curl_debug_log(CURL *curl, curl_infotype type, char *data, size_t siz if (md_log_is_level(req->pool, MD_LOG_TRACE5)) { md_data_t d; const char *s; - d.data = data; - d.len = size; + md_data_init(&d, data, size); md_data_to_hex(&s, 0, req->pool, &d); md_log_perror(MD_LOG_MARK, MD_LOG_TRACE5, 0, req->pool, "req[%d]: data(hex) --> %s", req->id, s); @@ -226,8 +225,7 @@ static int curl_debug_log(CURL *curl, curl_infotype type, char *data, size_t siz if (md_log_is_level(req->pool, MD_LOG_TRACE5)) { md_data_t d; const char *s; - d.data = data; - d.len = size; + md_data_init(&d, data, size); md_data_to_hex(&s, 0, req->pool, &d); md_log_perror(MD_LOG_MARK, MD_LOG_TRACE5, 0, req->pool, "req[%d]: data(hex) <-- %s", req->id, s); diff --git a/modules/md/md_json.c b/modules/md/md_json.c index c81fb0f786..52187168cd 100644 --- a/modules/md/md_json.c +++ b/modules/md/md_json.c @@ -1185,15 +1185,18 @@ apr_status_t md_json_readf(md_json_t **pjson, apr_pool_t *p, const char *fpath) apr_status_t md_json_read_http(md_json_t **pjson, apr_pool_t *pool, const md_http_response_t *res) { apr_status_t rv = APR_ENOENT; - const char *ctype = apr_table_get(res->headers, "content-type"), *p; + const char *ctype, *p; *pjson = NULL; - ctype = md_util_parse_ct(res->req->pool, ctype); + if (!res->body) goto cleanup; + ctype = md_util_parse_ct(res->req->pool, apr_table_get(res->headers, "content-type")); + if (!ctype) goto cleanup; p = ctype + strlen(ctype) +1; - if (ctype && res->body && (!strcmp(p - sizeof("/json"), "/json") || - !strcmp(p - sizeof("+json"), "+json"))) { + if (!strcmp(p - sizeof("/json"), "/json") + || !strcmp(p - sizeof("+json"), "+json")) { rv = md_json_readb(pjson, pool, res->body); } +cleanup: return rv; } diff --git a/modules/md/md_jws.c b/modules/md/md_jws.c index cfbe8da89b..4bdd99a125 100644 --- a/modules/md/md_jws.c +++ b/modules/md/md_jws.c @@ -38,7 +38,6 @@ apr_status_t md_jws_sign(md_json_t **pmsg, apr_pool_t *p, md_json_t *msg, *jprotected; const char *prot64, *pay64, *sign64, *sign, *prot; apr_status_t rv = APR_SUCCESS; - md_data_t data; *pmsg = NULL; @@ -64,8 +63,9 @@ apr_status_t md_jws_sign(md_json_t **pmsg, apr_pool_t *p, } if (rv == APR_SUCCESS) { - data.data = prot; - data.len = strlen(prot); + md_data_t data; + + md_data_init(&data, prot, strlen(prot)); prot64 = md_util_base64url_encode(&data, p); md_json_sets(prot64, msg, "protected", NULL); pay64 = md_util_base64url_encode(payload, p); @@ -104,7 +104,7 @@ apr_status_t md_jws_pkey_thumb(const char **pthumb, apr_pool_t *p, struct md_pke /* whitespace and order is relevant, since we hand out a digest of this */ s = apr_psprintf(p, "{\"e\":\"%s\",\"kty\":\"RSA\",\"n\":\"%s\"}", e64, n64); - MD_DATA_SET_STR(&data, s); + md_data_init_str(&data, s); rv = md_crypt_sha256_digest64(pthumb, p, &data); return rv; } diff --git a/modules/md/md_ocsp.c b/modules/md/md_ocsp.c index d3f0e1577e..95ecaa3a68 100644 --- a/modules/md/md_ocsp.c +++ b/modules/md/md_ocsp.c @@ -99,6 +99,11 @@ struct md_ocsp_id_map_t { md_data_t external_id; }; +static void md_openssl_free(void *d) +{ + OPENSSL_free(d); +} + const char *md_ocsp_cert_stat_name(md_ocsp_cert_stat_t stat) { switch (stat) { @@ -121,11 +126,11 @@ apr_status_t md_ocsp_init_id(md_data_t *id, apr_pool_t *p, const md_cert_t *cert X509 *x = md_cert_get_X509(cert); unsigned int ulen = 0; + md_data_null(id); if (X509_digest(x, EVP_sha1(), iddata, &ulen) != 1) { return APR_EGENERAL; } - id->len = ulen; - id->data = apr_pmemdup(p, iddata, id->len); + md_data_assign_pcopy(id, (const char*)iddata, ulen, p); return APR_SUCCESS; } @@ -135,11 +140,7 @@ static void ostat_req_cleanup(md_ocsp_status_t *ostat) OCSP_REQUEST_free(ostat->ocsp_req); ostat->ocsp_req = NULL; } - if (ostat->req_der.data) { - OPENSSL_free((void*)ostat->req_der.data); - ostat->req_der.data = NULL; - ostat->req_der.len = 0; - } + md_data_clear(&ostat->req_der); } static int ostat_cleanup(void *ctx, const void *key, apr_ssize_t klen, const void *val) @@ -155,11 +156,7 @@ static int ostat_cleanup(void *ctx, const void *key, apr_ssize_t klen, const voi OCSP_CERTID_free(ostat->certid); ostat->certid = NULL; } - if (ostat->resp_der.data) { - OPENSSL_free((void*)ostat->resp_der.data); - ostat->resp_der.data = NULL; - ostat->resp_der.len = 0; - } + md_data_clear(&ostat->resp_der); return 1; } @@ -174,27 +171,12 @@ static int ostat_should_renew(md_ocsp_status_t *ostat) static apr_status_t ostat_set(md_ocsp_status_t *ostat, md_ocsp_cert_stat_t stat, md_data_t *der, md_timeperiod_t *valid, apr_time_t mtime) { - apr_status_t rv = APR_SUCCESS; - char *s = (char*)der->data; - - if (der->len) { - s = OPENSSL_malloc(der->len); - if (!s) { - rv = APR_ENOMEM; - goto cleanup; - } - memcpy((char*)s, der->data, der->len); - } - - if (ostat->resp_der.data) { - OPENSSL_free((void*)ostat->resp_der.data); - ostat->resp_der.data = NULL; - ostat->resp_der.len = 0; - } - + apr_status_t rv; + + rv = md_data_assign_copy(&ostat->resp_der, der->data, der->len); + if (APR_SUCCESS != rv) goto cleanup; + ostat->resp_stat = stat; - ostat->resp_der.data = s; - ostat->resp_der.len = der->len; ostat->resp_valid = *valid; ostat->resp_mtime = mtime; @@ -328,8 +310,7 @@ apr_status_t md_ocsp_prime(md_ocsp_reg_t *reg, const char *ext_id, apr_size_t ex md_cert_t *cert, md_cert_t *issuer, const md_t *md) { md_ocsp_status_t *ostat; - STACK_OF(OPENSSL_STRING) *ssk = NULL; - const char *name, *s; + const char *name; md_data_t id; apr_status_t rv = APR_SUCCESS; @@ -355,19 +336,13 @@ apr_status_t md_ocsp_prime(md_ocsp_reg_t *reg, const char *ext_id, apr_size_t ex md_log_perror(MD_LOG_MARK, MD_LOG_TRACE2, 0, reg->p, "md[%s]: getting ocsp responder from cert", name); - ssk = X509_get1_ocsp(md_cert_get_X509(cert)); - if (!ssk) { - rv = APR_ENOENT; - md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, reg->p, - "md[%s]: certificate with serial %s has not OCSP responder URL", + rv = md_cert_get_ocsp_responder_url(&ostat->responder_url, reg->p, cert); + if (APR_SUCCESS != rv) { + md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, reg->p, + "md[%s]: certificate with serial %s has not OCSP responder URL", name, md_cert_get_serial_number(cert, reg->p)); goto cleanup; } - s = sk_OPENSSL_STRING_value(ssk, 0); - md_log_perror(MD_LOG_MARK, MD_LOG_TRACE2, 0, reg->p, - "md[%s]: ocsp responder found '%s'", name, s); - ostat->responder_url = apr_pstrdup(reg->p, s); - X509_email_free(ssk); ostat->certid = OCSP_cert_to_id(NULL, md_cert_get_X509(cert), md_cert_get_X509(issuer)); if (!ostat->certid) { @@ -529,8 +504,9 @@ static const char *certid_as_hex(const OCSP_CERTID *certid, apr_pool_t *p) memset(&der, 0, sizeof(der)); der.len = (apr_size_t)i2d_OCSP_CERTID((OCSP_CERTID*)certid, (unsigned char**)&der.data); + der.free_data = md_openssl_free; md_data_to_hex(&hex, 0, p, &der); - OPENSSL_free((void*)der.data); + md_data_clear(&der); return hex; } @@ -716,8 +692,9 @@ static apr_status_t ostat_on_resp(const md_http_response_t *resp, void *baton) md_result_log(update->result, MD_LOG_WARNING); goto cleanup; } - nstat = (bstatus == V_OCSP_CERTSTATUS_GOOD)? MD_OCSP_CERT_ST_GOOD : MD_OCSP_CERT_ST_REVOKED; new_der.len = (apr_size_t)n; + new_der.free_data = md_openssl_free; + nstat = (bstatus == V_OCSP_CERTSTATUS_GOOD)? MD_OCSP_CERT_ST_GOOD : MD_OCSP_CERT_ST_REVOKED; valid.start = bup? md_asn1_generalized_time_get(bup) : apr_time_now(); valid.end = md_asn1_generalized_time_get(bnextup); @@ -740,7 +717,7 @@ static apr_status_t ostat_on_resp(const md_http_response_t *resp, void *baton) md_result_log(update->result, MD_LOG_DEBUG); cleanup: - if (new_der.data) OPENSSL_free((void*)new_der.data); + md_data_clear(&new_der); if (basic_resp) OCSP_BASICRESP_free(basic_resp); if (ocsp_resp) OCSP_RESPONSE_free(ocsp_resp); return rv; @@ -781,18 +758,52 @@ typedef struct { int max_parallel; } md_ocsp_todo_ctx_t; +static apr_status_t ocsp_req_make(OCSP_REQUEST **pocsp_req, OCSP_CERTID *certid) +{ + OCSP_REQUEST *req = NULL; + OCSP_CERTID *id_copy = NULL; + apr_status_t rv = APR_ENOMEM; + + req = OCSP_REQUEST_new(); + if (!req) goto cleanup; + id_copy = OCSP_CERTID_dup(certid); + if (!id_copy) goto cleanup; + if (!OCSP_request_add0_id(req, id_copy)) goto cleanup; + id_copy = NULL; + OCSP_request_add1_nonce(req, 0, -1); + rv = APR_SUCCESS; +cleanup: + if (id_copy) OCSP_CERTID_free(id_copy); + if (APR_SUCCESS != rv && req) { + OCSP_REQUEST_free(req); + req = NULL; + } + *pocsp_req = req; + return rv; +} + +static apr_status_t ocsp_req_assign_der(md_data_t *d, OCSP_REQUEST *ocsp_req) +{ + int len; + + md_data_clear(d); + len = i2d_OCSP_REQUEST(ocsp_req, (unsigned char**)&d->data); + if (len < 0) return APR_ENOMEM; + d->len = (apr_size_t)len; + d->free_data = md_openssl_free; + return APR_SUCCESS; +} + static apr_status_t next_todo(md_http_request_t **preq, void *baton, md_http_t *http, int in_flight) { md_ocsp_todo_ctx_t *ctx = baton; md_ocsp_update_t *update, **pupdate; md_ocsp_status_t *ostat; - OCSP_CERTID *certid = NULL; md_http_request_t *req = NULL; apr_status_t rv = APR_ENOENT; apr_table_t *headers; - int len; - + if (in_flight < ctx->max_parallel) { pupdate = apr_array_pop(ctx->todos); if (pupdate) { @@ -804,18 +815,12 @@ static apr_status_t next_todo(md_http_request_t **preq, void *baton, md_job_start_run(update->job, update->result, ctx->reg->store); if (!ostat->ocsp_req) { - ostat->ocsp_req = OCSP_REQUEST_new(); - if (!ostat->ocsp_req) goto cleanup; - certid = OCSP_CERTID_dup(ostat->certid); - if (!certid) goto cleanup; - if (!OCSP_request_add0_id(ostat->ocsp_req, certid)) goto cleanup; - OCSP_request_add1_nonce(ostat->ocsp_req, 0, -1); - certid = NULL; + rv = ocsp_req_make(&ostat->ocsp_req, ostat->certid); + if (APR_SUCCESS != rv) goto cleanup; } if (0 == ostat->req_der.len) { - len = i2d_OCSP_REQUEST(ostat->ocsp_req, (unsigned char**)&ostat->req_der.data); - if (len < 0) goto cleanup; - ostat->req_der.len = (apr_size_t)len; + rv = ocsp_req_assign_der(&ostat->req_der, ostat->ocsp_req); + if (APR_SUCCESS != rv) goto cleanup; } md_result_activity_printf(update->result, "status of certid %s, " "contacting %s", ostat->hexid, ostat->responder_url); @@ -831,7 +836,6 @@ static apr_status_t next_todo(md_http_request_t **preq, void *baton, } cleanup: *preq = (APR_SUCCESS == rv)? req : NULL; - if (certid) OCSP_CERTID_free(certid); return rv; } diff --git a/modules/md/md_store_fs.c b/modules/md/md_store_fs.c index 7ba822a4e2..038bcc50c4 100644 --- a/modules/md/md_store_fs.c +++ b/modules/md/md_store_fs.c @@ -110,8 +110,7 @@ static apr_status_t init_store_file(md_store_fs_t *s_fs, const char *fname, md_json_setn(MD_STORE_VERSION, json, MD_KEY_STORE, MD_KEY_VERSION, NULL); - s_fs->key.len = FS_STORE_KLEN; - s_fs->key.data = apr_pcalloc(p, FS_STORE_KLEN); + md_data_pinit(&s_fs->key, FS_STORE_KLEN, p); if (APR_SUCCESS != (rv = md_rand_bytes((unsigned char*)s_fs->key.data, s_fs->key.len, p))) { return rv; } @@ -316,18 +315,29 @@ apr_status_t md_store_fs_init(md_store_t **pstore, apr_pool_t *p, const char *pa s_fs->group_perms[MD_SG_OCSP].file = MD_FPROT_F_UALL_WREAD; s_fs->base = apr_pstrdup(p, path); - - if (APR_STATUS_IS_ENOENT(rv = md_util_is_dir(s_fs->base, p)) - && MD_OK(apr_dir_make_recursive(s_fs->base, s_fs->def_perms.dir, p))) { + + rv = md_util_is_dir(s_fs->base, p); + if (APR_STATUS_IS_ENOENT(rv)) { + md_log_perror(MD_LOG_MARK, MD_LOG_INFO, rv, p, + "store directory does not exist, creating %s", s_fs->base); + rv = apr_dir_make_recursive(s_fs->base, s_fs->def_perms.dir, p); + if (APR_SUCCESS != rv) goto cleanup; rv = apr_file_perms_set(s_fs->base, MD_FPROT_D_UALL_WREAD); if (APR_STATUS_IS_ENOTIMPL(rv)) { rv = APR_SUCCESS; } + if (APR_SUCCESS != rv) goto cleanup; } - - if ((APR_SUCCESS != rv) || !MD_OK(md_util_pool_vdo(setup_store_file, s_fs, p, NULL))) { - md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "init fs store at %s", path); + else if (APR_SUCCESS != rv) { + md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p, + "not a plain directory, maybe a symlink? %s", s_fs->base); } + + rv = md_util_pool_vdo(setup_store_file, s_fs, p, NULL); + if (APR_SUCCESS != rv) { + md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "init fs store at %s", s_fs->base); + } +cleanup: *pstore = (rv == APR_SUCCESS)? &(s_fs->s) : NULL; return rv; } @@ -493,21 +503,24 @@ static apr_status_t mk_group_dir(const char **pdir, md_store_fs_t *s_fs, perms = gperms(s_fs, group); - if (MD_OK(fs_get_dname(pdir, &s_fs->s, group, name, p)) && (MD_SG_NONE != group)) { - if ( !MD_OK(md_util_is_dir(*pdir, p)) - && MD_OK(apr_dir_make_recursive(*pdir, perms->dir, p))) { - rv = dispatch(s_fs, MD_S_FS_EV_CREATED, group, *pdir, APR_DIR, p); - } - - if (APR_SUCCESS == rv) { - rv = apr_file_perms_set(*pdir, perms->dir); - md_log_perror(MD_LOG_MARK, MD_LOG_TRACE3, 0, p, "mk_group_dir %s perm set", *pdir); - if (APR_STATUS_IS_ENOTIMPL(rv)) { - rv = APR_SUCCESS; - } - } + rv = fs_get_dname(pdir, &s_fs->s, group, name, p); + if ((APR_SUCCESS != rv) || (MD_SG_NONE == group)) goto cleanup; + + rv = md_util_is_dir(*pdir, p); + if (APR_STATUS_IS_ENOENT(rv)) { + md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p, "not a directory, creating %s", *pdir); + rv = apr_dir_make_recursive(*pdir, perms->dir, p); + if (APR_SUCCESS != rv) goto cleanup; + dispatch(s_fs, MD_S_FS_EV_CREATED, group, *pdir, APR_DIR, p); + } + + rv = apr_file_perms_set(*pdir, perms->dir); + md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p, "mk_group_dir %s perm set", *pdir); + if (APR_STATUS_IS_ENOTIMPL(rv)) { + rv = APR_SUCCESS; } - md_log_perror(MD_LOG_MARK, MD_LOG_TRACE3, 0, p, "mk_group_dir %d %s", group, name); +cleanup: + md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p, "mk_group_dir %d %s", group, name); return rv; } diff --git a/modules/md/md_util.c b/modules/md/md_util.c index 34e891d1ce..23923c8b2e 100644 --- a/modules/md/md_util.c +++ b/modules/md/md_util.c @@ -76,28 +76,73 @@ apr_status_t md_util_pool_vdo(md_util_vaction *cb, void *baton, apr_pool_t *p, . /**************************************************************************************************/ /* data chunks */ -md_data_t *md_data_create(apr_pool_t *p, const char *data, apr_size_t len) +void md_data_pinit(md_data_t *d, apr_size_t len, apr_pool_t *p) +{ + md_data_null(d); + d->data = apr_pcalloc(p, len); + d->len = len; +} + +md_data_t *md_data_pmake(apr_size_t len, apr_pool_t *p) { md_data_t *d; d = apr_palloc(p, sizeof(*d)); - d->len = len; - d->data = len? apr_pstrndup(p, data, len) : NULL; + md_data_pinit(d, len, p); return d; } -md_data_t *md_data_make(apr_pool_t *p, apr_size_t len) +void md_data_init(md_data_t *d, const char *data, apr_size_t len) +{ + md_data_null(d); + d->len = len; + d->data = data; +} + +void md_data_init_str(md_data_t *d, const char *str) +{ + md_data_init(d, str, strlen(str)); +} + +void md_data_null(md_data_t *d) +{ + memset(d, 0, sizeof(*d)); +} + +void md_data_clear(md_data_t *d) +{ + if (d) { + if (d->data && d->free_data) d->free_data((void*)d->data); + memset(d, 0, sizeof(*d)); + } +} + +md_data_t *md_data_make_pcopy(apr_pool_t *p, const char *data, apr_size_t len) { md_data_t *d; - + d = apr_palloc(p, sizeof(*d)); d->len = len; - d->data = apr_pcalloc(p, len); + d->data = len? apr_pmemdup(p, data, len) : NULL; return d; } +apr_status_t md_data_assign_copy(md_data_t *dest, const char *src, apr_size_t src_len) +{ + md_data_clear(dest); + if (src && src_len) { + dest->data = malloc(src_len); + if (!dest->data) return APR_ENOMEM; + memcpy((void*)dest->data, src, src_len); + dest->len = src_len; + dest->free_data = free; + } + return APR_SUCCESS; +} + void md_data_assign_pcopy(md_data_t *dest, const char *src, apr_size_t src_len, apr_pool_t *p) { + md_data_clear(dest); dest->data = (src && src_len)? apr_pmemdup(p, src, src_len) : NULL; dest->len = dest->data? src_len : 0; } diff --git a/modules/md/md_util.h b/modules/md/md_util.h index 67d0e5128a..71e66eb500 100644 --- a/modules/md/md_util.h +++ b/modules/md/md_util.h @@ -35,17 +35,48 @@ apr_status_t md_util_pool_vdo(md_util_vaction *cb, void *baton, apr_pool_t *p, . /**************************************************************************************************/ /* data chunks */ +typedef void md_data_free_fn(void *data); + typedef struct md_data_t md_data_t; struct md_data_t { const char *data; apr_size_t len; + md_data_free_fn *free_data; }; -#define MD_DATA_CWRAP(d, buffer) md_data_t d = { buffer, sizeof(buffer) } +/** + * Init the data to empty, overwriting any content. + */ +void md_data_null(md_data_t *d); + +/** + * Create a new md_data_t, providing `len` bytes allocated from pool `p`. + */ +md_data_t *md_data_pmake(apr_size_t len, apr_pool_t *p); +/** + * Initialize md_data_t 'd', providing `len` bytes allocated from pool `p`. + */ +void md_data_pinit(md_data_t *d, apr_size_t len, apr_pool_t *p); +/** + * Initialize md_data_t 'd', by borrowing 'len' bytes in `data` without copying. + * `d` will not take ownership. + */ +void md_data_init(md_data_t *d, const char *data, apr_size_t len); + +/** + * Initialize md_data_t 'd', by borrowing the NUL-terminated `str`. + * `d` will not take ownership. + */ +void md_data_init_str(md_data_t *d, const char *str); + +/** + * Free any present data and clear (NULL) it. Passing NULL is permitted. + */ +void md_data_clear(md_data_t *d); -md_data_t *md_data_make(apr_pool_t *p, apr_size_t len); -md_data_t *md_data_create(apr_pool_t *p, const char *data, apr_size_t len); +md_data_t *md_data_make_pcopy(apr_pool_t *p, const char *data, apr_size_t len); +apr_status_t md_data_assign_copy(md_data_t *dest, const char *src, apr_size_t src_len); void md_data_assign_pcopy(md_data_t *dest, const char *src, apr_size_t src_len, apr_pool_t *p); apr_status_t md_data_to_hex(const char **phex, char separator, diff --git a/modules/md/md_version.h b/modules/md/md_version.h index 909258c3f8..5cef365c3d 100644 --- a/modules/md/md_version.h +++ b/modules/md/md_version.h @@ -27,7 +27,7 @@ * @macro * Version number of the md module as c string */ -#define MOD_MD_VERSION "2.4.2" +#define MOD_MD_VERSION "2.4.3" /** * @macro @@ -35,7 +35,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 0x020402 +#define MOD_MD_VERSION_NUM 0x020403 #define MD_ACME_DEF_URL "https://acme-v02.api.letsencrypt.org/directory" diff --git a/modules/md/mod_md.c b/modules/md/mod_md.c index 647b5ba2ee..180cfd2c68 100644 --- a/modules/md/mod_md.c +++ b/modules/md/mod_md.c @@ -1501,16 +1501,11 @@ static void md_hooks(apr_pool_t *pool) ap_hook_ssl_add_cert_files(md_add_cert_files, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_ssl_add_fallback_cert_files(md_add_fallback_cert_files, NULL, NULL, APR_HOOK_MIDDLE); -#if AP_MODULE_MAGIC_AT_LEAST(20210420, 0) +#if AP_MODULE_MAGIC_AT_LEAST(20120211, 105) ap_hook_ssl_ocsp_prime_hook(md_ocsp_prime_status, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_ssl_ocsp_get_resp_hook(md_ocsp_provide_status, NULL, NULL, APR_HOOK_MIDDLE); #else - -#ifndef SSL_CERT_HOOKS -#error "This version of mod_md requires Apache httpd 2.4.41 or newer." -#endif - APR_OPTIONAL_HOOK(ssl, init_stapling_status, md_ocsp_init_stapling_status, NULL, NULL, APR_HOOK_MIDDLE); - APR_OPTIONAL_HOOK(ssl, get_stapling_status, md_ocsp_get_stapling_status, NULL, NULL, APR_HOOK_MIDDLE); +#error "This version of mod_md requires Apache httpd 2.4.48 or newer." #endif /* AP_MODULE_MAGIC_AT_LEAST() */ } diff --git a/modules/md/mod_md.h b/modules/md/mod_md.h index 39b62f853f..805737d19e 100644 --- a/modules/md/mod_md.h +++ b/modules/md/mod_md.h @@ -17,31 +17,4 @@ #ifndef mod_md_mod_md_h #define mod_md_mod_md_h -#include <openssl/evp.h> -#include <openssl/x509v3.h> - -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 certificate 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)); - -APR_DECLARE_OPTIONAL_FN(int, - md_is_challenge, (struct conn_rec *, const char *, - X509 **pcert, EVP_PKEY **pkey)); - -APR_DECLARE_OPTIONAL_FN(apr_status_t, - md_answer_challenges, (conn_rec *c, const char *servername, - apr_array_header_t *certs, - apr_array_header_t *pkeys)); - #endif /* mod_md_mod_md_h */ diff --git a/modules/md/mod_md_ocsp.c b/modules/md/mod_md_ocsp.c index 0f64676025..1d1e2827de 100644 --- a/modules/md/mod_md_ocsp.c +++ b/modules/md/mod_md_ocsp.c @@ -53,29 +53,6 @@ static int staple_here(md_srv_conf_t *sc) && md_config_geti(sc, MD_CONFIG_STAPLE_OTHERS)); } -int md_ocsp_init_stapling_status(server_rec *s, apr_pool_t *p, - X509 *cert, X509 *issuer) -{ - md_srv_conf_t *sc; - const md_t *md; - apr_status_t rv; - - sc = md_config_get(s); - if (!staple_here(sc)) goto declined; - md = ((sc->assigned && sc->assigned->nelts == 1)? - APR_ARRAY_IDX(sc->assigned, 0, const md_t*) : NULL); - - rv = md_ocsp_prime(sc->mc->ocsp, NULL, 0, md_cert_wrap(p, cert), - md_cert_wrap(p, issuer), md); - ap_log_error(APLOG_MARK, APLOG_TRACE1, rv, s, "init stapling for: %s", - md? md->name : s->server_hostname); - if (APR_SUCCESS == rv) { - return OK; - } -declined: - return DECLINED; -} - int md_ocsp_prime_status(server_rec *s, apr_pool_t *p, const char *id, apr_size_t id_len, const char *pem) { @@ -118,51 +95,6 @@ typedef struct { apr_size_t der_len; } ocsp_copy_ctx_t; -static void ocsp_copy_der(const unsigned char *der, apr_size_t der_len, void *userdata) -{ - ocsp_copy_ctx_t *ctx = userdata; - - memset(ctx, 0, sizeof(*ctx)); - if (der && der_len > 0) { - ctx->der = OPENSSL_malloc(der_len); - if (ctx->der != NULL) { - ctx->der_len = der_len; - memcpy(ctx->der, der, der_len); - } - } -} - -int md_ocsp_get_stapling_status(unsigned char **pder, int *pderlen, - conn_rec *c, server_rec *s, X509 *x) -{ - md_srv_conf_t *sc; - const md_t *md; - md_cert_t *cert; - md_data_t id; - apr_status_t rv; - ocsp_copy_ctx_t ctx; - - sc = md_config_get(s); - if (!staple_here(sc)) goto declined; - - md = ((sc->assigned && sc->assigned->nelts == 1)? - APR_ARRAY_IDX(sc->assigned, 0, const md_t*) : NULL); - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, "get stapling for: %s", - md? md->name : s->server_hostname); - cert = md_cert_wrap(c->pool, x); - rv = md_ocsp_init_id(&id, c->pool, cert); - if (APR_SUCCESS != rv) goto declined; - - rv = md_ocsp_get_status(ocsp_copy_der, &ctx, sc->mc->ocsp, id.data, id.len, c->pool, md); - if (APR_STATUS_IS_ENOENT(rv)) goto declined; - *pder = ctx.der; - *pderlen = (int)ctx.der_len; - return OK; - -declined: - return DECLINED; -} - int md_ocsp_provide_status(server_rec *s, conn_rec *c, const char *id, apr_size_t id_len, ap_ssl_ocsp_copy_resp *cb, void *userdata) diff --git a/modules/md/mod_md_ocsp.h b/modules/md/mod_md_ocsp.h index dcc6e49c5a..a3f95027cb 100644 --- a/modules/md/mod_md_ocsp.h +++ b/modules/md/mod_md_ocsp.h @@ -18,12 +18,6 @@ #define mod_md_md_ocsp_h -int md_ocsp_init_stapling_status(server_rec *s, apr_pool_t *p, - X509 *cert, X509 *issuer); - -int md_ocsp_get_stapling_status(unsigned char **pder, int *pderlen, - conn_rec *c, server_rec *s, X509 *cert); - int md_ocsp_prime_status(server_rec *s, apr_pool_t *p, const char *id, apr_size_t id_len, const char *pem); |