/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License.
*/
md_log_perror(MD_LOG_MARK, MD_LOG_TRACE2, 0, reg->p, "md[%s]: getting ocsp responder from cert", name);
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_DEBUG, rv, reg->p, "md[%s]: certificate with serial %s has no OCSP responder URL",
name, md_cert_get_serial_number(cert, reg->p)); goto cleanup;
}
ostat->certid = OCSP_cert_to_id(NULL, md_cert_get_X509(cert), md_cert_get_X509(issuer)); if (!ostat->certid) {
rv = APR_EGENERAL;
md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, reg->p, "md[%s]: unable to create OCSP certid for certificate with serial %s",
name, md_cert_get_serial_number(cert, reg->p)); goto cleanup;
}
/* See, if we have something in store */
ocsp_status_refresh(ostat, reg->p);
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, reg->p, "md[%s]: adding ocsp info (responder=%s)",
name, ostat->responder_url);
apr_hash_set(reg->ostat_by_id, ostat->id.data, (apr_ssize_t)ostat->id.len, ostat); if (ext_id) {
md_ocsp_id_map_t *id_map;
/* While the ostat instance itself always exists, the response data it holds
* may vary over time and we need locked access to make a copy. */
apr_thread_mutex_lock(reg->mutex);
locked = 1;
if (ostat->resp_der.len <= 0) { /* No response known, check store for new response. */
ocsp_status_refresh(ostat, p); if (ostat->resp_der.len <= 0) {
md_log_perror(MD_LOG_MARK, MD_LOG_TRACE2, 0, reg->p, "md[%s]: OCSP, no response available", name);
cb(NULL, 0, userdata); goto cleanup;
}
} /* We have a response */ if (ostat_should_renew(ostat)) { /* But it is up for renewal. A watchdog should be busy with * retrieving a new one. In case of outages, this might take * a while, however. Pace the frequency of checks with the
* urgency of a new response based on the remaining time. */ long secs = (long)apr_time_sec(md_timeperiod_remaining(&ostat->resp_valid, apr_time_now()));
apr_time_t waiting_time;
/* every hour, every minute, every second */
waiting_time = ((secs >= MD_SECS_PER_DAY)?
apr_time_from_sec(60 * 60) : ((secs >= 60)?
apr_time_from_sec(60) : apr_time_from_sec(1))); if ((apr_time_now() - ostat->resp_last_check) >= waiting_time) {
ostat->resp_last_check = apr_time_now();
ocsp_status_refresh(ostat, p);
}
}
md_result_set(update->result, rv,
apr_psprintf(req->pool, "req[%d] response body does not parse as " "OCSP response, status=%d, body brigade length=%ld",
resp->req->id, resp->status, (long)der.len));
md_result_log(update->result, MD_LOG_DEBUG); goto cleanup;
} /* got a response! but what does it say? */
n = OCSP_response_status(ocsp_resp); if (OCSP_RESPONSE_STATUS_SUCCESSFUL != n) {
rv = APR_EINVAL;
md_result_printf(update->result, rv, "OCSP response status is, unsuccessfully, %d", n);
md_result_log(update->result, MD_LOG_DEBUG); goto cleanup;
}
basic_resp = OCSP_response_get1_basic(ocsp_resp); if (!basic_resp) {
rv = APR_EINVAL;
md_result_set(update->result, rv, "OCSP response has no basicresponse");
md_result_log(update->result, MD_LOG_DEBUG); goto cleanup;
} /* The notion of nonce enabled freshness in OCSP responses, e.g. that the response * contains the signed nonce we sent to the responder, does not scale well. Responders * like to return cached response bytes and therefore do not add a nonce to it. * So, in reality, we can only detect a mismatch when present and otherwise have
* to accept it. */ switch ((n = OCSP_check_nonce(ostat->ocsp_req, basic_resp))) { case 1:
md_log_perror(MD_LOG_MARK, MD_LOG_TRACE3, 0, req->pool, "req[%d]: OCSP response nonce does match", req->id); break; case 0:
rv = APR_EINVAL;
md_result_printf(update->result, rv, "OCSP nonce mismatch in response", n);
md_result_log(update->result, MD_LOG_WARNING); goto cleanup;
case -1:
md_log_perror(MD_LOG_MARK, MD_LOG_TRACE3, 0, req->pool, "req[%d]: OCSP response did not return the nonce", req->id); break; default: break;
}
if (!OCSP_resp_find_status(basic_resp, ostat->certid, &bstatus,
&breason, NULL, &bup, &bnextup)) { constchar *prefix, *slist = "", *sep = ""; int i;
rv = APR_EINVAL;
prefix = apr_psprintf(req->pool, "OCSP response, no matching status reported for %s",
certid_summary(ostat->certid, req->pool)); for (i = 0; i < OCSP_resp_count(basic_resp); ++i) {
single_resp = OCSP_resp_get0(basic_resp, i);
slist = apr_psprintf(req->pool, "%s%s%s", slist, sep,
single_resp_summary(single_resp, req->pool));
sep = ", ";
}
md_result_printf(update->result, rv, "%s, status list [%s]", prefix, slist);
md_result_log(update->result, MD_LOG_DEBUG); goto cleanup;
} if (V_OCSP_CERTSTATUS_UNKNOWN == bstatus) {
rv = APR_ENOENT;
md_result_set(update->result, rv, "OCSP basicresponse says cert is unknown");
md_result_log(update->result, MD_LOG_DEBUG); goto cleanup;
}
/* Coming here, we have a response for our certid and it is either GOOD
* or REVOKED. Both cases we want to remember and use in stapling. */
n = i2d_OCSP_RESPONSE(ocsp_resp, (unsignedchar**)&new_der.data); if (n <= 0) {
rv = APR_EGENERAL;
md_result_set(update->result, rv, "error DER encoding OCSP response");
md_result_log(update->result, MD_LOG_WARNING); goto cleanup;
}
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(); if (bnextup) {
valid.end = md_asn1_generalized_time_get(bnextup);
} else { /* nextUpdate not set; default to 12 hours.
* Refresh attempts will be started some time earlier. */
valid.end = valid.start + apr_time_from_sec(MD_SECS_PER_DAY / 2);
}
/* First, update the instance with a copy */
apr_thread_mutex_lock(ostat->reg->mutex);
ostat_set(ostat, nstat, &new_der, &valid, apr_time_now());
apr_thread_mutex_unlock(ostat->reg->mutex);
/* Next, save the original response */
rv = ocsp_status_save(nstat, &new_der, &valid, ostat, req->pool); if (APR_SUCCESS != rv) {
md_result_set(update->result, rv, "error saving OCSP status");
md_result_log(update->result, MD_LOG_ERR); goto cleanup;
}
md_result_printf(update->result, rv, "certificate status is %s, status valid %s",
(nstat == MD_OCSP_CERT_ST_GOOD)? "GOOD" : "REVOKED",
md_timeperiod_print(req->pool, &ostat->resp_valid));
md_result_log(update->result, MD_LOG_DEBUG);
cleanup:
md_data_clear(&new_der); if (basic_resp) OCSP_BASICRESP_free(basic_resp); if (ocsp_resp) OCSP_RESPONSE_free(ocsp_resp); return rv;
}
ctx.reg = reg;
ctx.ptemp = ptemp;
ctx.todos = apr_array_make(ptemp, (int)md_ocsp_count(reg), sizeof(md_ocsp_status_t*));
ctx.max_parallel = 6; /* the magic number in HTTP */
/* Create a list of update tasks that are needed now or in the next minute */
ctx.time = apr_time_now() + apr_time_from_sec(60);;
apr_hash_do(select_updates, &ctx, reg->ostat_by_id);
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, p, "OCSP status updates due: %d", ctx.todos->nelts); if (!ctx.todos->nelts) goto cleanup;
cleanup: /* When do we need to run next? *pnext_run contains the planned schedule from
* the watchdog. We can make that earlier if we need it. */
ctx.time = *pnext_run;
apr_hash_do(select_next_run, &ctx, reg->ostat_by_id);
/* sanity check and return */ if (ctx.time < apr_time_now()) ctx.time = apr_time_now() + apr_time_from_sec(1);
*pnext_run = ctx.time;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.