1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
20 * + Known low-level code kludges/problems
21 * . proxy: an httpd child process validates SCTs from a server only on the
22 * first time the data is received; but it could fail once due to invalid
23 * timestamp, and not be rechecked later after (potentially) time elapses
24 * and the timestamp is now in a valid range
25 * . server: shouldn't have to read file of server SCTs on every handshake
26 * (shared memory or cached file?)
27 * . split mod_ssl_ct.c into more pieces
28 * . research: Is it possible to send an SCT that is outside of the known
29 * valid interval for the log?
33 #define HAVE_SCT_DAEMON_THREAD
35 #define HAVE_SCT_DAEMON_CHILD
40 #if defined(HAVE_SCT_DAEMON_CHILD)
44 #include "apr_version.h"
45 #if !APR_VERSION_AT_LEAST(1,5,0)
46 #error mod_ssl_ct requires APR 1.5.0 or later! (for apr_escape.h)
49 #include "apr_escape.h"
50 #include "apr_global_mutex.h"
51 #include "apr_signal.h"
52 #include "apr_strings.h"
53 #include "apr_thread_rwlock.h"
58 #include "http_config.h"
59 #include "http_core.h"
61 #include "http_main.h"
62 #include "http_protocol.h"
63 #include "mpm_common.h"
64 #include "util_mutex.h"
65 #include "ap_listen.h"
68 #if AP_NEED_SET_MUTEX_PERMS
72 #include "mod_proxy.h"
74 #include "mod_ssl_openssl.h"
76 #include "ssl_ct_util.h"
77 #include "ssl_ct_sct.h"
79 #include "openssl/x509v3.h"
80 #include "openssl/ocsp.h"
82 #if OPENSSL_VERSION_NUMBER < 0x10002001L
83 #error "mod_ssl_ct requires OpenSSL 1.0.2-beta1 or later"
92 #define STATUS_VAR "SSL_CT_PEER_STATUS"
93 #define STATUS_VAR_AWARE_VAL "peer-aware"
94 #define STATUS_VAR_UNAWARE_VAL "peer-unaware"
96 #define PROXY_SCT_SOURCES_VAR "SSL_PROXY_SCT_SOURCES"
98 #define DAEMON_NAME "SCT maintenance daemon"
99 #define DAEMON_THREAD_NAME DAEMON_NAME " thread"
100 #define SERVICE_THREAD_NAME "service thread"
102 /** Limit on size of stored SCTs for a certificate (individual SCTs as well
105 #define MAX_SCTS_SIZE 10000
107 /** Limit on size of log URL list for a certificate
109 #define MAX_LOGLIST_SIZE 1000
111 typedef struct ct_server_config {
112 apr_array_header_t *db_log_config;
113 apr_pool_t *db_log_config_pool;
114 apr_array_header_t *static_log_config;
115 apr_array_header_t *server_cert_info; /* ct_server_cert_info */
116 apr_hash_t *static_cert_sct_dirs;
117 const char *sct_storage;
118 const char *audit_storage;
120 const char *log_config_fname;
121 apr_time_t max_sct_age;
123 #define PROXY_AWARENESS_UNSET -1
124 #define PROXY_OBLIVIOUS 1
125 #define PROXY_AWARE 2 /* default */
126 #define PROXY_REQUIRE 3
130 typedef struct ct_conn_config {
132 /* proxy mode only */
134 int server_cert_has_sct_list;
136 apr_size_t cert_sct_list_size;
137 int serverhello_has_sct_list;
138 void *serverhello_sct_list;
139 apr_size_t serverhello_sct_list_size;
140 int ocsp_has_sct_list;
142 apr_size_t ocsp_sct_list_size;
143 apr_array_header_t *all_scts; /* array of ct_sct_data */
146 typedef struct ct_server_cert_info {
147 const char *fingerprint;
149 } ct_server_cert_info;
151 typedef struct ct_sct_data {
156 typedef struct ct_callback_info {
159 ct_conn_config *conncfg;
162 typedef struct ct_cached_server_data {
163 apr_status_t validation_result;
164 } ct_cached_server_data;
166 /* the log configuration in use -- either db_log_config or static_log_config */
167 static apr_array_header_t *active_log_config;
169 module AP_MODULE_DECLARE_DATA ssl_ct_module;
171 #define SSL_CT_MUTEX_TYPE "ssl-ct-sct-update"
173 static apr_global_mutex_t *ssl_ct_sct_update;
175 static int refresh_all_scts(server_rec *s_main, apr_pool_t *p,
176 apr_array_header_t *log_config);
178 static apr_thread_t *service_thread;
180 static apr_hash_t *cached_server_data;
182 static const char *audit_fn_perm, *audit_fn_active;
183 static apr_file_t *audit_file;
184 static int audit_file_nonempty;
185 static apr_thread_mutex_t *audit_file_mutex;
186 static apr_thread_mutex_t *cached_server_data_mutex;
187 static apr_thread_rwlock_t *log_config_rwlock;
189 #ifdef HAVE_SCT_DAEMON_CHILD
191 /* The APR other-child API doesn't tell us how the daemon exited
192 * (SIGSEGV vs. exit(1)). The other-child maintenance function
193 * needs to decide whether to restart the daemon after a failure
194 * based on whether or not it exited due to a fatal startup error
195 * or something that happened at steady-state. This exit status
196 * is unlikely to collide with exit signals.
198 #define DAEMON_STARTUP_ERROR 254
200 static int daemon_start(apr_pool_t *p, server_rec *main_server, apr_proc_t *procnew);
201 static server_rec *root_server = NULL;
202 static apr_pool_t *root_pool = NULL;
203 static pid_t daemon_pid;
204 static int daemon_should_exit = 0;
206 #endif /* HAVE_SCT_DAEMON_CHILD */
208 static apr_pool_t *pdaemon = NULL;
210 #ifdef HAVE_SCT_DAEMON_THREAD
211 static apr_thread_t *daemon_thread;
212 #endif /* HAVE_SCT_DAEMON_THREAD */
214 static const char *get_cert_fingerprint(apr_pool_t *p, const X509 *x)
216 const EVP_MD *digest;
217 unsigned char md[EVP_MAX_MD_SIZE];
219 digest = EVP_get_digestbyname("sha256");
220 X509_digest(x, digest, md, &n);
222 return apr_pescape_hex(p, md, n, 0);
225 /* a server's SCT-related storage on disk:
227 * <rootdir>/<fingerprint>/servercerts.pem
228 * Concatenation of leaf certificate and any
229 * configured intermediate certificates
231 * <rootdir>/<fingerprint>/logs
232 * List of log URLs, one per line; this is
233 * used to recognize when a log URL configuration
234 * change makes our current SCT set invalid
236 * <rootdir>/<fingerprint>/AUTO_hostname_port_uri.sct
237 * SCT for cert with this fingerprint
238 * from this log (could be any number
241 * <rootdir>/<fingerprint>/<anything>.sct
242 * (file is optional; could be any number
243 * of these; should not start with "AUTO_")
244 * Note that the administrator should store
245 * statically maintained SCTs in a different
246 * directory for the server certificate (specified
247 * by the CTStaticSCTs directive). A hypothetical
248 * external mechanism for maintaining SCTs following
249 * some other model could store them here for use
252 * <rootdir>/<fingerprint>/collated
253 * one or more SCTs ready to send
254 * (this is all that the web server
255 * processes care about)
257 * Additionally, the CTStaticSCTs directive specifies a certificate-
258 * specific directory of statically-maintained SCTs to be sent.
261 #define SERVERCERTS_BASENAME "servercerts.pem"
262 #define COLLATED_SCTS_BASENAME "collated"
263 #define LOGLIST_BASENAME "logs"
264 #define LOG_SCT_PREFIX "AUTO_" /* to distinguish from admin-created .sct
268 static apr_status_t collate_scts(server_rec *s, apr_pool_t *p,
269 const char *cert_sct_dir,
270 const char *static_cert_sct_dir,
273 /* Read the various .sct files and stick them together in a single file */
274 apr_array_header_t *arr;
275 apr_status_t rv, tmprv;
277 apr_size_t bytes_written;
278 apr_uint16_t overall_len = 0;
279 char *tmp_collated_fn, *collated_fn;
280 const char *cur_sct_file;
281 const char * const *elts;
282 int i, scts_written = 0, skipped = 0;
284 rv = ctutil_path_join(&collated_fn, cert_sct_dir, COLLATED_SCTS_BASENAME, p, s);
285 if (rv != APR_SUCCESS) {
289 /* Note: We rebuild the file that combines the SCTs every time this
290 * code runs, even if no individual SCTs are new (or at least
292 * That allows the admin to see the last processing by looking
294 * Rechecking even if no SCTs are new allows SCTs which were not
295 * yet valid originally (just submitted to a log) to be used as
298 tmp_collated_fn = apr_pstrcat(p, collated_fn, ".tmp", NULL);
300 rv = apr_file_open(&tmpfile, tmp_collated_fn,
301 APR_FOPEN_WRITE|APR_FOPEN_CREATE|APR_FOPEN_TRUNCATE
302 |APR_FOPEN_BINARY|APR_FOPEN_BUFFERED,
303 APR_FPROT_OS_DEFAULT, p);
304 if (rv != APR_SUCCESS) {
305 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
306 "can't create %s", tmp_collated_fn);
310 /* stick a 0 len (for the list) at the start of the file;
311 * we'll have to patch that later
313 rv = ctutil_file_write_uint16(s, tmpfile, overall_len);
314 if (rv != APR_SUCCESS) {
315 apr_file_close(tmpfile);
319 arr = NULL; /* Build list from scratch, creating array */
320 rv = ctutil_read_dir(p, s, cert_sct_dir, "*.sct", &arr);
321 if (rv != APR_SUCCESS) {
322 apr_file_close(tmpfile);
326 if (static_cert_sct_dir) {
327 /* Add in any SCTs that the administrator has configured */
328 rv = ctutil_read_dir(p, s, static_cert_sct_dir, "*.sct", &arr);
329 if (rv != APR_SUCCESS) {
330 apr_file_close(tmpfile);
335 elts = (const char * const *)arr->elts;
337 for (i = 0; i < arr->nelts; i++) {
339 apr_size_t scts_size_wide;
340 apr_uint16_t scts_size;
343 cur_sct_file = elts[i];
345 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
346 "Adding SCT from file %s", cur_sct_file);
348 rv = ctutil_read_file(p, s, cur_sct_file, MAX_SCTS_SIZE, &scts,
350 if (rv != APR_SUCCESS) {
353 ap_assert(scts_size_wide <= USHRT_MAX);
354 scts_size = (apr_uint16_t)scts_size_wide;
356 rv = sct_parse(cur_sct_file,
357 s, (const unsigned char *)scts, scts_size, NULL, &fields);
358 if (rv != APR_SUCCESS) {
359 sct_release(&fields);
363 /* If the SCT has a timestamp in the future, it may have just been
364 * created by the log.
366 if (fields.time > apr_time_now()) {
367 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
368 "SCT in file %s has timestamp in future (%s), skipping",
369 cur_sct_file, fields.timestr);
370 sct_release(&fields);
374 sct_release(&fields);
376 /* Only now do we know that the SCT is valid to send, so
377 * see if it has to be skipped by configured limit.
379 if (scts_written >= max_sh_sct) {
384 overall_len += scts_size + 2; /* include size header */
386 rv = ctutil_file_write_uint16(s, tmpfile, (apr_uint16_t)scts_size);
387 if (rv != APR_SUCCESS) {
391 rv = apr_file_write_full(tmpfile, scts, scts_size, &bytes_written);
392 if (rv != APR_SUCCESS) {
393 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
394 "can't write %hu bytes to %s",
395 scts_size, tmp_collated_fn);
402 if (rv == APR_SUCCESS && skipped) {
403 ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
404 "SCTs sent in ServerHello are limited to %d by "
405 "CTServerHelloSCTLimit (ignoring %d)",
410 if (rv == APR_SUCCESS) {
411 apr_off_t offset = 0;
413 rv = apr_file_seek(tmpfile, APR_SET, &offset);
414 if (rv == APR_SUCCESS) {
415 rv = ctutil_file_write_uint16(s, tmpfile, overall_len);
417 if (rv != APR_SUCCESS) {
418 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
419 "could not write the SCT list length at the start of the file");
423 tmprv = apr_file_close(tmpfile);
424 if (tmprv != APR_SUCCESS) {
425 ap_log_error(APLOG_MARK, APLOG_ERR, tmprv, s,
426 "error flushing and closing %s", tmp_collated_fn);
427 if (rv == APR_SUCCESS) {
432 if (rv == APR_SUCCESS && scts_written) {
433 int replacing = ctutil_file_exists(p, collated_fn);
436 if ((rv = apr_global_mutex_lock(ssl_ct_sct_update)) != APR_SUCCESS) {
437 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
438 "global mutex lock failed");
441 apr_file_remove(collated_fn, p);
443 rv = apr_file_rename(tmp_collated_fn, collated_fn, p);
444 if (rv != APR_SUCCESS) {
445 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
446 "couldn't rename %s to %s, no SCTs to send for now",
447 tmp_collated_fn, collated_fn);
450 if ((tmprv = apr_global_mutex_unlock(ssl_ct_sct_update)) != APR_SUCCESS) {
451 ap_log_error(APLOG_MARK, APLOG_ERR, tmprv, s,
452 "global mutex unlock failed");
453 if (rv == APR_SUCCESS) {
463 static const char *url_to_fn(apr_pool_t *p, const apr_uri_t *log_url)
465 char *fn = apr_psprintf(p, LOG_SCT_PREFIX "%s_%s_%s.sct",
466 log_url->hostname, log_url->port_str, log_url->path);
472 /* chars that shouldn't be used in a filename */
489 static apr_status_t submission(server_rec *s, apr_pool_t *p, const char *ct_exe,
490 const apr_uri_t *log_url, const char *cert_file,
499 args[i++] = apr_pstrcat(p, "--ct_server=", log_url->hostinfo, NULL);
500 args[i++] = "--http_log";
501 args[i++] = "--logtostderr";
502 args[i++] = apr_pstrcat(p, "--ct_server_submission=", cert_file, NULL);
503 args[i++] = apr_pstrcat(p, "--ct_server_response_out=", sct_fn, NULL);
504 args[i++] = "upload";
506 ap_assert(i == sizeof args / sizeof args[0]);
508 rv = ctutil_run_to_log(p, s, args, "log client");
513 static apr_status_t fetch_sct(server_rec *s, apr_pool_t *p,
514 const char *cert_file,
515 const char *cert_sct_dir,
516 const apr_uri_t *log_url,
517 const char *ct_exe, apr_time_t max_sct_age)
522 const char *log_url_basename;
524 log_url_basename = url_to_fn(p, log_url);
526 rv = ctutil_path_join(&sct_fn, cert_sct_dir, log_url_basename, p, s);
527 if (rv != APR_SUCCESS) {
531 rv = apr_stat(&finfo, sct_fn, APR_FINFO_MTIME, p);
532 if (rv == APR_SUCCESS) {
533 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
534 "Found SCT for %s in %s",
537 if (finfo.mtime + max_sct_age < apr_time_now()) {
538 ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
539 "SCT for %s is older than %d seconds, must refresh",
541 (int)(apr_time_sec(max_sct_age)));
548 ap_log_error(APLOG_MARK, APLOG_INFO,
549 /* no need to print error string for file-not-found err */
550 APR_STATUS_IS_ENOENT(rv) ? 0 : rv,
552 "Did not find SCT for %s in %s, must fetch",
556 rv = submission(s, p, ct_exe, log_url, cert_file, sct_fn);
561 static apr_status_t record_log_urls(server_rec *s, apr_pool_t *p,
562 const char *listfile, apr_array_header_t *log_config)
565 apr_status_t rv, tmprv;
566 ct_log_config **config_elts;
569 rv = apr_file_open(&f, listfile,
570 APR_FOPEN_WRITE|APR_FOPEN_CREATE|APR_FOPEN_TRUNCATE
572 APR_FPROT_OS_DEFAULT, p);
573 if (rv != APR_SUCCESS) {
574 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
575 "can't create %s", listfile);
579 config_elts = (ct_log_config **)log_config->elts;
581 for (i = 0; i < log_config->nelts; i++) {
582 if (!config_elts[i]->uri_str) {
585 if (!log_valid_for_sent_sct(config_elts[i])) {
588 rv = apr_file_puts(config_elts[i]->uri_str, f);
589 if (rv == APR_SUCCESS) {
590 rv = apr_file_puts("\n", f);
592 if (rv != APR_SUCCESS) {
593 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
594 "error writing to %s", listfile);
599 tmprv = apr_file_close(f);
600 if (tmprv != APR_SUCCESS) {
601 ap_log_error(APLOG_MARK, APLOG_ERR, tmprv, s,
602 "error flushing and closing %s", listfile);
603 if (rv == APR_SUCCESS) {
611 static int uri_in_config(const char *needle, const apr_array_header_t *haystack)
613 ct_log_config **elts;
616 elts = (ct_log_config **)haystack->elts;
617 for (i = 0; i < haystack->nelts; i++) {
618 if (!elts[i]->uri_str) {
621 if (!log_valid_for_sent_sct(elts[i])) {
624 if (!strcmp(needle, elts[i]->uri_str)) {
632 static apr_status_t update_log_list_for_cert(server_rec *s, apr_pool_t *p,
633 const char *cert_sct_dir,
634 apr_array_header_t *log_config)
636 apr_array_header_t *old_urls;
637 apr_size_t contents_size;
639 char *contents, *listfile;
641 /* The set of logs can change, and we need to remove SCTs retrieved
642 * from logs that we no longer trust. To track changes we'll use a
643 * file in the directory for the server certificate.
645 * (When can the set change? Right now they can only change at [re]start,
646 * but in the future we should be able to find the set of trusted logs
650 rv = ctutil_path_join(&listfile, cert_sct_dir, LOGLIST_BASENAME, p, s);
651 if (rv != APR_SUCCESS) {
655 if (ctutil_file_exists(p, listfile)) {
659 rv = ctutil_read_file(p, s, listfile, MAX_LOGLIST_SIZE, &contents, &contents_size);
660 if (rv != APR_SUCCESS) {
664 ctutil_buffer_to_array(p, contents, contents_size, &old_urls);
666 elts = (char **)old_urls->elts;
667 for (i = 0; i < old_urls->nelts; i++) {
668 if (!uri_in_config(elts[i], log_config)) {
673 rv = apr_uri_parse(p, elts[i], &uri);
674 if (rv != APR_SUCCESS) {
675 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
676 "unparseable log URL %s in file %s - ignoring",
678 /* some garbage in the file? can't map to an auto-maintained SCT,
684 rv = ctutil_path_join(&sct_for_log, cert_sct_dir, url_to_fn(p, &uri), p, s);
685 ap_assert(rv == APR_SUCCESS);
686 exists = ctutil_file_exists(p, sct_for_log);
688 ap_log_error(APLOG_MARK,
689 exists ? APLOG_NOTICE : APLOG_DEBUG, 0, s,
690 "Log %s is no longer enabled%s",
692 exists ? ", removing SCT" : ", no SCT was present");
695 rv = apr_file_remove(sct_for_log, p);
696 if (rv != APR_SUCCESS) {
697 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
698 "can't remove SCT %s from previously trusted log %s",
699 sct_for_log, elts[i]);
707 /* can't tell what was trusted before; just remove everything
708 * that was created automatically
710 apr_array_header_t *arr;
711 const char * const *elts;
714 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
715 "List of previous logs doesn't exist (%s), removing previously obtained SCTs",
718 arr = NULL; /* Build list from scratch, creating array */
719 rv = ctutil_read_dir(p, s, cert_sct_dir, LOG_SCT_PREFIX "*.sct", &arr);
720 if (rv != APR_SUCCESS) {
724 elts = (const char * const *)arr->elts;
725 for (i = 0; i < arr->nelts; i++) {
726 const char *cur_sct_file = elts[i];
728 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
729 "Removing %s", cur_sct_file);
731 rv = apr_file_remove(cur_sct_file, p);
732 if (rv != APR_SUCCESS) {
733 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
734 "can't remove %s", cur_sct_file);
739 if (rv == APR_SUCCESS) {
740 rv = record_log_urls(s, p, listfile, log_config);
746 static apr_status_t refresh_scts_for_cert(server_rec *s, apr_pool_t *p,
747 const char *cert_sct_dir,
748 const char *static_cert_sct_dir,
749 apr_array_header_t *log_config,
751 apr_time_t max_sct_age,
755 ct_log_config **config_elts;
759 rv = ctutil_path_join(&cert_fn, cert_sct_dir, SERVERCERTS_BASENAME, p, s);
760 if (rv != APR_SUCCESS) {
764 config_elts = (ct_log_config **)log_config->elts;
767 rv = update_log_list_for_cert(s, p, cert_sct_dir, log_config);
768 if (rv != APR_SUCCESS) {
772 for (i = 0; i < log_config->nelts; i++) {
773 if (!config_elts[i]->url) {
776 if (!log_valid_for_sent_sct(config_elts[i])) {
779 rv = fetch_sct(s, p, cert_fn,
781 &config_elts[i]->uri,
784 if (rv != APR_SUCCESS) {
790 /* Log client tool (from certificate-transparency open source project)
791 * not configured; we can only use admin-managed SCTs
795 rv = collate_scts(s, p, cert_sct_dir, static_cert_sct_dir, max_sh_sct);
796 if (rv != APR_SUCCESS) {
803 static void *run_service_thread(apr_thread_t *me, void *data)
805 server_rec *s = data;
806 ct_server_config *sconf = ap_get_module_config(s->module_config,
812 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
813 SERVICE_THREAD_NAME " started");
816 if ((rv = ap_mpm_query(AP_MPMQ_MPM_STATE, &mpmq_s)) != APR_SUCCESS) {
819 if (mpmq_s == AP_MPMQ_STOPPING) {
822 apr_sleep(apr_time_from_sec(1));
825 if (sconf->db_log_config) {
826 /* Reload log config DB */
827 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
828 SERVICE_THREAD_NAME " - reloading config");
829 ap_assert(apr_thread_rwlock_wrlock(log_config_rwlock) == 0);
830 active_log_config = NULL;
831 apr_pool_clear(sconf->db_log_config_pool);
832 sconf->db_log_config =
833 apr_array_make(sconf->db_log_config_pool, 2,
834 sizeof(ct_log_config *));
835 rv = read_config_db(sconf->db_log_config_pool,
836 s, sconf->log_config_fname,
837 sconf->db_log_config);
838 ap_assert(apr_thread_rwlock_unlock(log_config_rwlock) == 0);
839 if (rv != APR_SUCCESS) {
840 /* specific issue already logged */
841 ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s,
842 SERVICE_THREAD_NAME " - no active configuration until "
843 "log config DB is corrected");
846 active_log_config = sconf->db_log_config;
852 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, s,
853 SERVICE_THREAD_NAME " exiting");
858 static apr_status_t wait_for_thread(void *data)
860 apr_thread_t *thd = data;
863 apr_thread_join(&retval, thd);
867 static void sct_daemon_cycle(ct_server_config *sconf, server_rec *s_main,
868 apr_pool_t *ptemp, const char *daemon_name)
872 if (sconf->db_log_config) { /* not using static config */
873 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s_main,
874 "%s - reloading config", daemon_name);
875 apr_pool_clear(sconf->db_log_config_pool);
876 active_log_config = NULL;
877 sconf->db_log_config =
878 apr_array_make(sconf->db_log_config_pool, 2,
879 sizeof(ct_log_config *));
880 rv = read_config_db(sconf->db_log_config_pool,
881 s_main, sconf->log_config_fname,
882 sconf->db_log_config);
883 if (rv != APR_SUCCESS) {
884 ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s_main,
885 "%s - no active configuration until "
886 "log config DB is corrected", daemon_name);
889 active_log_config = sconf->db_log_config;
891 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s_main,
892 "%s - refreshing SCTs as needed", daemon_name);
893 rv = refresh_all_scts(s_main, ptemp, active_log_config);
894 if (rv != APR_SUCCESS) {
895 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s_main,
896 "%s - SCT refresh failed; will try again later",
901 #ifdef HAVE_SCT_DAEMON_CHILD
903 static void daemon_signal_handler(int sig)
906 ++daemon_should_exit;
910 #if APR_HAS_OTHER_CHILD
911 static void daemon_maint(int reason, void *data, apr_wait_t status)
913 apr_proc_t *proc = data;
918 case APR_OC_REASON_DEATH:
919 apr_proc_other_child_unregister(data);
920 /* If apache is not terminating or restarting,
923 stopping = 1; /* if MPM doesn't support query,
924 * assume we shouldn't restart daemon
926 if (ap_mpm_query(AP_MPMQ_MPM_STATE, &mpm_state) == APR_SUCCESS &&
927 mpm_state != AP_MPMQ_STOPPING) {
931 if (status == DAEMON_STARTUP_ERROR) {
932 ap_log_error(APLOG_MARK, APLOG_CRIT, 0, ap_server_conf, APLOGNO(01238)
933 DAEMON_NAME " failed to initialize");
936 ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, APLOGNO(01239)
937 DAEMON_NAME " process died, restarting");
938 daemon_start(root_pool, root_server, proc);
942 case APR_OC_REASON_RESTART:
943 /* don't do anything; server is stopping or restarting */
944 apr_proc_other_child_unregister(data);
946 case APR_OC_REASON_LOST:
947 /* Restart the child cgid daemon process */
948 apr_proc_other_child_unregister(data);
949 daemon_start(root_pool, root_server, proc);
951 case APR_OC_REASON_UNREGISTER:
952 /* we get here when pcgi is cleaned up; pcgi gets cleaned
953 * up when pconf gets cleaned up
955 kill(proc->pid, SIGHUP); /* send signal to daemon telling it to die */
961 static int sct_daemon(server_rec *s_main)
965 ct_server_config *sconf = ap_get_module_config(s_main->module_config,
969 /* Ignoring SIGCHLD results in errno ECHILD returned from apr_proc_wait().
970 * apr_signal(SIGCHLD, SIG_IGN);
972 apr_signal(SIGHUP, daemon_signal_handler);
974 /* Close our copy of the listening sockets */
975 ap_close_listeners();
977 rv = apr_global_mutex_child_init(&ssl_ct_sct_update,
978 apr_global_mutex_lockfile(ssl_ct_sct_update), pdaemon);
979 if (rv != APR_SUCCESS) {
980 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, root_server,
981 "could not initialize " SSL_CT_MUTEX_TYPE
982 " mutex in " DAEMON_NAME);
983 return DAEMON_STARTUP_ERROR;
987 /* Fix up permissions of the directories written to by the daemon
990 apr_array_header_t *subdirs = apr_array_make(pdaemon, 5, sizeof(char *));
992 *(const char **)apr_array_push(subdirs) = sconf->sct_storage;
993 if (sconf->audit_storage) {
994 *(const char **)apr_array_push(subdirs) = sconf->audit_storage;
997 rv = ctutil_read_dir(pdaemon, root_server, sconf->sct_storage, "*",
999 if (rv == APR_SUCCESS && subdirs->nelts > 0) {
1000 const char * const *elts = (const char * const *)subdirs->elts;
1002 for (i = 0; i < subdirs->nelts; i++) {
1003 if (elts[i] && chown(elts[i], ap_unixd_config.user_id,
1004 ap_unixd_config.group_id) < 0) {
1005 ap_log_error(APLOG_MARK, APLOG_ERR, errno, root_server,
1006 "Couldn't change owner or group of directory %s",
1013 ap_log_error(APLOG_MARK, APLOG_WARNING, rv, root_server,
1014 "Did not read any entries from %s (no server certificate?)",
1015 sconf->sct_storage);
1019 /* if running as root, switch to configured user/group */
1020 if ((rc = ap_run_drop_privileges(pdaemon, ap_server_conf)) != 0) {
1024 /* ptemp - temporary pool for refresh cycles */
1025 apr_pool_create(&ptemp, pdaemon);
1027 while (!daemon_should_exit) {
1028 sct_daemon_cycle(sconf, s_main, ptemp, DAEMON_NAME);
1029 apr_sleep(apr_time_from_sec(30)); /* SIGHUP at restart/stop will break out */
1032 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s_main,
1033 DAEMON_NAME " - exiting");
1038 static int daemon_start(apr_pool_t *p, server_rec *main_server,
1039 apr_proc_t *procnew)
1041 daemon_should_exit = 0; /* clear setting from previous generation */
1042 if ((daemon_pid = fork()) < 0) {
1043 ap_log_error(APLOG_MARK, APLOG_ERR, errno, main_server,
1044 "Couldn't create " DAEMON_NAME " process");
1047 else if (daemon_pid == 0) {
1048 if (pdaemon == NULL) {
1049 apr_pool_create(&pdaemon, p);
1051 exit(sct_daemon(main_server) > 0 ? DAEMON_STARTUP_ERROR : -1);
1053 procnew->pid = daemon_pid;
1054 procnew->err = procnew->in = procnew->out = NULL;
1055 apr_pool_note_subprocess(p, procnew, APR_KILL_AFTER_TIMEOUT);
1056 #if APR_HAS_OTHER_CHILD
1057 apr_proc_other_child_register(procnew, daemon_maint, procnew, NULL, p);
1061 #endif /* HAVE_SCT_DAEMON_CHILD */
1063 #ifdef HAVE_SCT_DAEMON_THREAD
1064 static void *sct_daemon_thread(apr_thread_t *me, void *data)
1066 server_rec *s = data;
1067 ct_server_config *sconf = ap_get_module_config(s->module_config,
1074 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
1075 DAEMON_THREAD_NAME " started");
1077 /* ptemp - temporary pool for refresh cycles */
1078 apr_pool_create(&ptemp, pdaemon);
1081 if ((rv = ap_mpm_query(AP_MPMQ_MPM_STATE, &mpmq_s)) != APR_SUCCESS) {
1084 if (mpmq_s == AP_MPMQ_STOPPING) {
1087 apr_sleep(apr_time_from_sec(1));
1088 if (++count >= 30) {
1090 sct_daemon_cycle(sconf, s, ptemp, DAEMON_THREAD_NAME);
1094 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
1095 DAEMON_THREAD_NAME " - exiting");
1100 static int daemon_thread_start(apr_pool_t *pconf, server_rec *s_main)
1104 apr_pool_create(&pdaemon, pconf);
1105 rv = apr_thread_create(&daemon_thread, NULL, sct_daemon_thread, s_main,
1107 if (rv != APR_SUCCESS) {
1108 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s_main,
1109 "could not create " DAEMON_THREAD_NAME " in parent");
1110 return HTTP_INTERNAL_SERVER_ERROR;
1113 apr_pool_cleanup_register(pconf, daemon_thread, wait_for_thread,
1114 apr_pool_cleanup_null);
1118 #endif /* HAVE_SCT_DAEMON_THREAD */
1120 static apr_status_t ssl_ct_mutex_remove(void *data)
1122 apr_global_mutex_destroy(ssl_ct_sct_update);
1123 ssl_ct_sct_update = NULL;
1127 static int refresh_all_scts(server_rec *s_main, apr_pool_t *p,
1128 apr_array_header_t *log_config)
1130 apr_hash_t *already_processed;
1131 apr_status_t rv = APR_SUCCESS;
1134 already_processed = apr_hash_make(p);
1138 ct_server_config *sconf = ap_get_module_config(s->module_config,
1141 const ct_server_cert_info *cert_info_elts;
1143 if (sconf && sconf->server_cert_info) {
1145 (const ct_server_cert_info *)sconf->server_cert_info->elts;
1146 for (i = 0; i < sconf->server_cert_info->nelts; i++) {
1147 /* we may have already processed this cert for another
1150 if (!apr_hash_get(already_processed, cert_info_elts[i].sct_dir,
1151 APR_HASH_KEY_STRING)) {
1152 const char *static_cert_sct_dir =
1153 apr_hash_get(sconf->static_cert_sct_dirs,
1154 cert_info_elts[i].fingerprint,
1155 APR_HASH_KEY_STRING);
1157 apr_hash_set(already_processed, cert_info_elts[i].sct_dir,
1158 APR_HASH_KEY_STRING, "done");
1159 rv = refresh_scts_for_cert(s_main, p,
1160 cert_info_elts[i].sct_dir,
1161 static_cert_sct_dir,
1166 if (rv != APR_SUCCESS) {
1179 static int num_server_certs(server_rec *s_main)
1186 ct_server_config *sconf = ap_get_module_config(s->module_config,
1189 if (sconf && sconf->server_cert_info) {
1190 num += sconf->server_cert_info->nelts;
1198 static int ssl_ct_post_config(apr_pool_t *pconf, apr_pool_t *plog,
1199 apr_pool_t *ptemp, server_rec *s_main)
1201 ct_server_config *sconf = ap_get_module_config(s_main->module_config,
1204 #ifdef HAVE_SCT_DAEMON_CHILD
1205 apr_proc_t *procnew = NULL;
1206 const char *userdata_key = "sct_daemon_init";
1208 root_server = s_main;
1211 procnew = ap_retained_data_get(userdata_key);
1213 procnew = ap_retained_data_create(userdata_key, sizeof(*procnew));
1215 procnew->err = procnew->in = procnew->out = NULL;
1217 #endif /* HAVE_SCT_DAEMON_CHILD */
1219 if (num_server_certs(s_main) == 0) {
1220 /* Theoretically this module could operate in a proxy-only
1221 * configuration, where httpd does not act as a TLS server but proxy is
1222 * configured as a TLS client. That isn't currently implemented.
1224 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s_main,
1225 "No server certificates were found.");
1226 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s_main,
1227 "mod_ssl_ct only supports configurations with a TLS server.");
1228 return HTTP_INTERNAL_SERVER_ERROR;
1231 rv = ap_global_mutex_create(&ssl_ct_sct_update, NULL,
1232 SSL_CT_MUTEX_TYPE, NULL, s_main, pconf, 0);
1233 if (rv != APR_SUCCESS) {
1234 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s_main,
1235 "could not create global mutex");
1236 return HTTP_INTERNAL_SERVER_ERROR;
1239 apr_pool_cleanup_register(pconf, (void *)s_main, ssl_ct_mutex_remove,
1240 apr_pool_cleanup_null);
1242 if (sconf->log_config_fname) {
1243 if (!sconf->db_log_config) {
1244 /* log config db in separate pool that can be cleared */
1245 apr_pool_create(&sconf->db_log_config_pool, pconf);
1246 sconf->db_log_config =
1247 apr_array_make(sconf->db_log_config_pool, 2,
1248 sizeof(ct_log_config *));
1250 rv = read_config_db(sconf->db_log_config_pool,
1251 s_main, sconf->log_config_fname,
1252 sconf->db_log_config);
1253 if (rv != APR_SUCCESS) {
1254 return HTTP_INTERNAL_SERVER_ERROR;
1258 if (sconf->static_log_config && sconf->db_log_config) {
1259 if (sconf->static_log_config->nelts > 0
1260 && sconf->db_log_config->nelts > 0) {
1261 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s_main,
1262 "Either the static log configuration or the db log "
1263 "configuration must be empty");
1264 return HTTP_INTERNAL_SERVER_ERROR;
1268 if (sconf->static_log_config && sconf->static_log_config->nelts > 0) {
1269 active_log_config = sconf->static_log_config;
1271 else if (sconf->db_log_config && sconf->db_log_config->nelts > 0) {
1272 active_log_config = sconf->db_log_config;
1275 ap_log_error(APLOG_MARK, APLOG_INFO, 0, s_main,
1276 "No log URLs were configured; only admin-managed SCTs can be sent");
1277 /* if a db is configured, it could be updated later */
1278 if (!sconf->db_log_config) { /* no DB configured, need permanently
1280 active_log_config = apr_array_make(pconf, 1,
1281 sizeof(ct_log_config *));
1285 /* Ensure that we already have, or can fetch, fresh SCTs for each
1286 * certificate. If so, start the daemon to maintain these and let
1287 * startup continue. (Otherwise abort startup.)
1289 * Except when we start up as root. We don't want to run external
1290 * certificate-transparency tools as root, and we don't want to have
1291 * to fix up the permissions of everything we created so that the
1292 * SCT maintenance daemon can continue to maintain the SCTs as the
1293 * configured User/Group.
1296 #if AP_NEED_SET_MUTEX_PERMS /* Unix :) */
1297 if (!geteuid()) { /* root */
1298 ap_log_error(APLOG_MARK, APLOG_INFO, 0, s_main,
1299 "SCTs will be fetched from configured logs as needed "
1300 "and may not be available immediately");
1304 rv = refresh_all_scts(s_main, pconf, active_log_config);
1305 if (rv != APR_SUCCESS) {
1306 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s_main,
1307 "refresh_all_scts() failed");
1308 return HTTP_INTERNAL_SERVER_ERROR;
1310 #if AP_NEED_SET_MUTEX_PERMS
1314 #ifdef HAVE_SCT_DAEMON_CHILD
1315 if (ap_state_query(AP_SQ_MAIN_STATE) != AP_SQ_MS_CREATE_PRE_CONFIG) {
1316 int ret = daemon_start(pconf, s_main, procnew);
1321 #endif /* HAVE_SCT_DAEMON_CHILD */
1323 #ifdef HAVE_SCT_DAEMON_THREAD
1324 /* WIN32-ism: ensure this is the parent by checking AP_PARENT_PID,
1325 * which is only set in WinNT children.
1327 if (ap_state_query(AP_SQ_MAIN_STATE) != AP_SQ_MS_CREATE_PRE_CONFIG
1328 && !getenv("AP_PARENT_PID")) {
1329 int ret = daemon_thread_start(pconf, s_main);
1334 #endif /* HAVE_SCT_DAEMON_THREAD */
1339 static int ssl_ct_check_config(apr_pool_t *pconf, apr_pool_t *plog,
1340 apr_pool_t *ptemp, server_rec *s_main)
1342 ct_server_config *sconf = ap_get_module_config(s_main->module_config,
1345 if (!sconf->sct_storage) {
1346 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s_main,
1347 "Directive CTSCTStorage is required");
1348 return HTTP_INTERNAL_SERVER_ERROR;
1351 if (!sconf->audit_storage) {
1352 /* umm, hard to tell if needed... must have server with
1353 * SSL proxy enabled and server-specific-sconf->proxy_awareness
1354 * != PROXY_OBLIVIOUS...
1356 ap_log_error(APLOG_MARK, APLOG_INFO, 0, s_main,
1357 "Directive CTAuditStorage isn't set; proxy will not save "
1358 "data for off-line audit");
1361 if (!sconf->ct_exe) {
1362 ap_log_error(APLOG_MARK, APLOG_INFO, 0, s_main,
1363 "Directive CTLogClient isn't set; server certificates "
1364 "can't be submitted to configured logs; only admin-"
1365 "managed SCTs can be provided to clients");
1368 if (sconf->log_config_fname) {
1369 const char *msg = NULL;
1370 if (!log_config_readable(pconf, sconf->log_config_fname, &msg)) {
1371 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s_main,
1372 "Log config file %s cannot be read",
1373 sconf->log_config_fname);
1375 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s_main,
1378 return HTTP_INTERNAL_SERVER_ERROR;
1385 static apr_status_t read_scts(apr_pool_t *p, const char *fingerprint,
1386 const char *sct_dir,
1388 char **scts, apr_size_t *scts_len)
1390 apr_status_t rv, tmprv;
1391 char *cert_dir, *sct_fn;
1393 rv = ctutil_path_join(&cert_dir, sct_dir, fingerprint, p, s);
1394 if (rv != APR_SUCCESS) {
1398 rv = ctutil_path_join(&sct_fn, cert_dir, COLLATED_SCTS_BASENAME, p, s);
1399 if (rv != APR_SUCCESS) {
1403 if ((rv = apr_global_mutex_lock(ssl_ct_sct_update)) != APR_SUCCESS) {
1404 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
1405 "global mutex lock failed");
1409 rv = ctutil_read_file(p, s, sct_fn, MAX_SCTS_SIZE, scts, scts_len);
1411 if ((tmprv = apr_global_mutex_unlock(ssl_ct_sct_update)) != APR_SUCCESS) {
1412 ap_log_error(APLOG_MARK, APLOG_ERR, tmprv, s,
1413 "global mutex unlock failed");
1419 static void look_for_server_certs(server_rec *s, SSL_CTX *ctx, const char *sct_dir)
1421 ct_server_config *sconf = ap_get_module_config(s->module_config,
1423 apr_pool_t *p = s->process->pool;
1427 STACK_OF(X509) *chain;
1429 char *cert_sct_dir, *servercerts_pem;
1430 const char *fingerprint;
1431 ct_server_cert_info *cert_info;
1433 sconf->server_cert_info = apr_array_make(p, 2, sizeof(ct_server_cert_info));
1435 rc = SSL_CTX_set_current_cert(ctx, SSL_CERT_SET_FIRST);
1437 x = SSL_CTX_get0_certificate(ctx); /* UNDOC */
1439 fingerprint = get_cert_fingerprint(s->process->pool, x);
1440 rv = ctutil_path_join(&cert_sct_dir, sct_dir, fingerprint, p, s);
1441 ap_assert(rv == APR_SUCCESS);
1443 if (!ctutil_dir_exists(p, cert_sct_dir)) {
1444 rv = apr_dir_make(cert_sct_dir, APR_FPROT_OS_DEFAULT, p);
1445 if (rv != APR_SUCCESS) {
1446 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
1447 "can't create directory %s",
1449 ap_assert(rv == APR_SUCCESS);
1453 rv = ctutil_path_join(&servercerts_pem, cert_sct_dir,
1454 SERVERCERTS_BASENAME, p, s);
1455 ap_assert(rv == APR_SUCCESS);
1457 rv = ctutil_fopen(servercerts_pem, "wb", &concat);
1458 ap_assert(rv == APR_SUCCESS);
1460 ap_assert(1 == PEM_write_X509(concat, x)); /* leaf */
1464 /* Not this: SSL_CTX_get0_chain_certs(ctx, &chain);
1467 * http://mail-archives.apache.org/mod_mbox/httpd-dev/
1468 * 201402.mbox/%3CCAKUrXK5-2_Sg8FokxBP8nW7tmSuTZZWL-%3
1469 * DBDhNnwyK-Z4dmQiQ%40mail.gmail.com%3E
1471 SSL_CTX_get_extra_chain_certs(ctx, &chain); /* UNDOC */
1474 for (i = 0; i < sk_X509_num(chain); i++) { /* UNDOC */
1475 X509 *x = sk_X509_value(chain, i); /* UNDOC */
1476 ap_assert(1 == PEM_write_X509(concat, x));
1479 ap_assert(0 == fclose(concat));
1481 ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
1482 "wrote server cert and chain to %s", servercerts_pem);
1484 cert_info = (ct_server_cert_info *)apr_array_push(sconf->server_cert_info);
1485 cert_info->sct_dir = cert_sct_dir;
1486 cert_info->fingerprint = fingerprint;
1489 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
1490 "could not find leaf certificate");
1492 rc = SSL_CTX_set_current_cert(ctx, SSL_CERT_SET_NEXT);
1496 static ct_conn_config *get_conn_config(conn_rec *c)
1498 ct_conn_config *conncfg =
1499 ap_get_module_config(c->conn_config, &ssl_ct_module);
1502 conncfg = apr_pcalloc(c->pool, sizeof *conncfg);
1503 ap_set_module_config(c->conn_config, &ssl_ct_module, conncfg);
1509 static void client_is_ct_aware(conn_rec *c)
1511 ct_conn_config *conncfg = get_conn_config(c);
1512 conncfg->peer_ct_aware = 1;
1515 static int is_client_ct_aware(conn_rec *c)
1517 ct_conn_config *conncfg = get_conn_config(c);
1519 return conncfg->peer_ct_aware;
1522 static void server_cert_has_sct_list(conn_rec *c)
1524 ct_conn_config *conncfg = get_conn_config(c);
1525 conncfg->server_cert_has_sct_list = 1;
1526 conncfg->peer_ct_aware = 1;
1529 /* Look at SSLClient::VerifyCallback() and WriteSSLClientCTData()
1530 * for validation and saving of data for auditing in a form that
1531 * the c-t tools can use.
1534 static cert_chain *cert_chain_init(apr_pool_t *p, STACK_OF(X509) *chain)
1536 cert_chain *cc = apr_pcalloc(p, sizeof(cert_chain));
1539 cc->cert_arr = apr_array_make(p, 4, sizeof(X509 *));
1541 for (i = 0; i < sk_X509_num(chain); i++) {
1542 X509 **spot = apr_array_push(cc->cert_arr);
1543 *spot = X509_dup(sk_X509_value(chain, i)); /* UNDOC */
1552 static void cert_chain_free(cert_chain *cc) {
1553 X509 **elts = (X509 **)cc->cert_arr->elts;
1556 for (i = 0; i < cc->cert_arr->nelts; i++) {
1561 /* Create hash of leaf certificate and any SCTs so that
1562 * we can determine whether or not we've seen this exact
1563 * info from the server before.
1565 static const char *gen_key(conn_rec *c, cert_chain *cc,
1566 ct_conn_config *conncfg)
1569 SHA256_CTX sha256ctx;
1570 unsigned char digest[SHA256_DIGEST_LENGTH];
1572 fp = get_cert_fingerprint(c->pool, cc->leaf);
1574 SHA256_Init(&sha256ctx); /* UNDOC */
1575 SHA256_Update(&sha256ctx, (unsigned char *)fp, strlen(fp)); /* UNDOC */
1576 if (conncfg->cert_sct_list) {
1577 SHA256_Update(&sha256ctx, conncfg->cert_sct_list,
1578 conncfg->cert_sct_list_size);
1580 if (conncfg->serverhello_sct_list) {
1581 SHA256_Update(&sha256ctx, conncfg->serverhello_sct_list,
1582 conncfg->serverhello_sct_list_size);
1584 if (conncfg->ocsp_sct_list) {
1585 SHA256_Update(&sha256ctx, conncfg->ocsp_sct_list,
1586 conncfg->ocsp_sct_list_size);
1588 SHA256_Final(digest, &sha256ctx); /* UNDOC */
1589 return apr_pescape_hex(c->pool, digest, sizeof digest, 0);
1592 static apr_status_t deserialize_SCTs(apr_pool_t *p,
1593 ct_conn_config *conncfg,
1595 apr_size_t sct_list_size)
1597 apr_size_t avail, len_of_data;
1599 const unsigned char *mem, *start_of_data;
1602 avail = sct_list_size;
1604 /* Make sure the overall length is correct */
1606 rv = ctutil_read_var_bytes((const unsigned char **)&mem,
1607 &avail, &start_of_data, &len_of_data);
1608 if (rv != APR_SUCCESS) {
1612 if (len_of_data + sizeof(apr_uint16_t) != sct_list_size) {
1616 /* add each SCT in the list to the all_scts array */
1618 mem = (unsigned char *)sct_list + sizeof(apr_uint16_t);
1619 avail = sct_list_size - sizeof(apr_uint16_t);
1621 while (rv == APR_SUCCESS && avail > 0) {
1622 rv = ctutil_read_var_bytes((const unsigned char **)&mem, &avail,
1623 &start_of_data, &len_of_data);
1624 if (rv == APR_SUCCESS) {
1625 ct_sct_data *sct = (ct_sct_data *)apr_array_push(conncfg->all_scts);
1627 sct->data = start_of_data;
1628 ap_assert(len_of_data <= USHRT_MAX);
1629 sct->len = (apr_uint16_t)len_of_data;
1633 if (rv == APR_SUCCESS && avail != 0) {
1640 /* perform quick sanity check of server SCT(s) during handshake;
1641 * errors should result in fatal alert
1643 static apr_status_t validate_server_data(apr_pool_t *p, conn_rec *c,
1644 cert_chain *cc, ct_conn_config *conncfg,
1645 ct_server_config *sconf)
1647 apr_status_t rv = APR_SUCCESS;
1649 #if AP_MODULE_MAGIC_AT_LEAST(20130702,2)
1650 if (conncfg->serverhello_sct_list) {
1651 ap_log_cdata(APLOG_MARK, APLOG_TRACE6, c, "SCT(s) from ServerHello",
1652 conncfg->serverhello_sct_list,
1653 conncfg->serverhello_sct_list_size,
1654 AP_LOG_DATA_SHOW_OFFSET);
1657 if (conncfg->cert_sct_list) {
1658 ap_log_cdata(APLOG_MARK, APLOG_TRACE6, c, "SCT(s) from certificate",
1659 conncfg->cert_sct_list,
1660 conncfg->cert_sct_list_size,
1661 AP_LOG_DATA_SHOW_OFFSET);
1664 if (conncfg->ocsp_sct_list) {
1665 ap_log_cdata(APLOG_MARK, APLOG_TRACE6, c, "SCT(s) from stapled OCSP response",
1666 conncfg->ocsp_sct_list,
1667 conncfg->ocsp_sct_list_size,
1668 AP_LOG_DATA_SHOW_OFFSET);
1670 #endif /* httpd has ap_log_*data() */
1672 if (!conncfg->all_scts) {
1673 conncfg->all_scts = apr_array_make(p, 4, sizeof(ct_sct_data));
1676 /* deserialize all the SCTs */
1677 if (conncfg->cert_sct_list) {
1678 rv = deserialize_SCTs(p, conncfg, conncfg->cert_sct_list,
1679 conncfg->cert_sct_list_size);
1680 if (rv != APR_SUCCESS) {
1681 ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c,
1682 "couldn't deserialize SCT list from certificate");
1685 if (rv == APR_SUCCESS && conncfg->serverhello_sct_list) {
1686 rv = deserialize_SCTs(p, conncfg, conncfg->serverhello_sct_list,
1687 conncfg->serverhello_sct_list_size);
1688 if (rv != APR_SUCCESS) {
1689 ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c,
1690 "couldn't deserialize SCT list from ServerHello");
1693 if (rv == APR_SUCCESS && conncfg->ocsp_sct_list) {
1694 rv = deserialize_SCTs(p, conncfg, conncfg->ocsp_sct_list,
1695 conncfg->ocsp_sct_list_size);
1696 if (rv != APR_SUCCESS) {
1697 ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c,
1698 "couldn't deserialize SCT list from stapled OCSP response");
1702 if (rv == APR_SUCCESS) {
1703 if (conncfg->all_scts->nelts < 1) {
1704 /* How did we get here without at least one SCT? */
1705 ap_log_cerror(APLOG_MARK, APLOG_CRIT, 0, c,
1706 "SNAFU: No deserialized SCTs found in validate_server_data()");
1711 int i, verification_failures, verification_successes, unknown_log_ids;
1712 ct_sct_data *sct_elts;
1714 sct_fields_t fields;
1716 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
1717 "%d SCTs received total", conncfg->all_scts->nelts);
1719 verification_failures = verification_successes = unknown_log_ids = 0;
1720 sct_elts = (ct_sct_data *)conncfg->all_scts->elts;
1721 for (i = 0; i < conncfg->all_scts->nelts; i++) {
1723 tmprv = sct_parse("backend server", c->base_server,
1724 sct.data, sct.len, cc,
1726 if (tmprv != APR_SUCCESS) {
1730 tmprv = sct_verify_timestamp(c, &fields);
1731 if (tmprv != APR_SUCCESS) {
1732 verification_failures++;
1735 if (active_log_config) {
1736 /* will only block if we have a DB-based log
1737 * configuration which is currently being refreshed
1739 ap_assert(apr_thread_rwlock_rdlock(log_config_rwlock)
1741 tmprv = sct_verify_signature(c, &fields,
1743 ap_assert(apr_thread_rwlock_unlock(log_config_rwlock)
1745 if (tmprv == APR_NOTFOUND) {
1746 ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c,
1747 "Server sent SCT from unrecognized log");
1750 else if (tmprv != APR_SUCCESS) {
1751 ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c,
1752 "Server sent SCT with invalid signature");
1754 verification_failures++;
1757 verification_successes++;
1762 ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c,
1763 "Signature of SCT from server could not be "
1764 "verified (no configured log public keys)");
1767 sct_release(&fields);
1769 if (verification_failures && !verification_successes) {
1770 /* If no SCTs are valid, don't communicate. */
1773 ap_log_cerror(APLOG_MARK,
1774 rv != APR_SUCCESS ? APLOG_ERR : APLOG_INFO, 0, c,
1775 "Signature/timestamp validation for %d SCTs: %d successes, "
1776 "%d failures, %d from unknown logs",
1777 conncfg->all_scts->nelts, verification_successes,
1778 verification_failures, unknown_log_ids);
1785 /* Enqueue data from server for off-line audit (cert, SCT(s))
1786 * We already filtered out duplicate data being saved from this
1787 * process. (With reverse proxy it will be the same data over
1790 #define SERVER_START 0x0001
1791 #define KEY_START 0x0002
1792 #define CERT_START 0x0003
1793 #define SCT_START 0x0004
1795 static void save_server_data(conn_rec *c, cert_chain *cc,
1796 ct_conn_config *conncfg,
1799 if (audit_file_mutex && audit_file) { /* child init successful, no
1802 apr_size_t bytes_written;
1805 ct_sct_data *sct_elts;
1807 server_rec *s = c->base_server;
1809 /* Any error in this function is a file I/O error;
1810 * if such an error occurs, the audit file will be closed
1811 * and removed, and this child won't be able to queue
1812 * anything for audit. (It is likely that other child
1813 * processes will have the same problem.)
1816 ctutil_thread_mutex_lock(audit_file_mutex);
1818 if (audit_file) { /* no error just occurred... */
1819 audit_file_nonempty = 1;
1821 rv = ctutil_file_write_uint16(s, audit_file,
1824 if (rv == APR_SUCCESS) {
1825 rv = ctutil_file_write_uint16(s, audit_file, KEY_START);
1828 if (rv == APR_SUCCESS) {
1829 ap_assert(strlen(key) <= USHRT_MAX);
1830 rv = ctutil_file_write_uint16(s, audit_file,
1831 (apr_uint16_t)strlen(key));
1834 if (rv == APR_SUCCESS) {
1835 rv = apr_file_write_full(audit_file, key, strlen(key),
1839 /* Write each certificate, starting with leaf */
1840 x509elts = (X509 **)cc->cert_arr->elts;
1841 for (i = 0; rv == APR_SUCCESS && i < cc->cert_arr->nelts; i++) {
1842 unsigned char *der_buf = NULL;
1845 rv = ctutil_file_write_uint16(s, audit_file, CERT_START);
1847 /* now write the cert!!! */
1849 if (rv == APR_SUCCESS) {
1850 der_length = i2d_X509(x509elts[i], &der_buf);
1851 ap_assert(der_length > 0);
1853 rv = ctutil_file_write_uint24(s, audit_file, der_length);
1856 if (rv == APR_SUCCESS) {
1857 rv = apr_file_write_full(audit_file, der_buf, der_length,
1861 OPENSSL_free(der_buf);
1864 /* Write each SCT */
1865 sct_elts = (ct_sct_data *)conncfg->all_scts->elts;
1866 for (i = 0; rv == APR_SUCCESS && i < conncfg->all_scts->nelts; i++) {
1869 rv = ctutil_file_write_uint16(s, audit_file, SCT_START);
1873 if (rv == APR_SUCCESS) {
1874 rv = ctutil_file_write_uint16(s, audit_file, sct.len);
1877 if (rv == APR_SUCCESS) {
1878 rv = apr_file_write_full(audit_file, sct.data, sct.len,
1883 if (rv != APR_SUCCESS) {
1884 /* an I/O error occurred; file is not usable */
1885 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,
1886 "Failed to write to %s, disabling audit for this "
1887 "child", audit_fn_active);
1888 apr_file_close(audit_file);
1890 apr_file_remove(audit_fn_active,
1891 /* not used in current implementations */
1896 ctutil_thread_mutex_unlock(audit_file_mutex);
1900 /* signed_certificate_timestamp */
1901 static const unsigned short CT_EXTENSION_TYPE = 18;
1903 /* See function of this name in openssl/apps/s_client.c */
1904 static int ocsp_resp_cb(SSL *ssl, void *arg)
1906 conn_rec *c = (conn_rec *)SSL_get_app_data(ssl);
1907 ct_conn_config *conncfg = get_conn_config(c);
1908 const unsigned char *p;
1913 OCSP_SINGLERESP *single;
1914 STACK_OF(X509_EXTENSION) *exts;
1916 len = SSL_get_tlsext_status_ocsp_resp(ssl, &p); /* UNDOC */
1919 ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
1920 "OCSP response callback called but no stapled response from server");
1924 rsp = d2i_OCSP_RESPONSE(NULL, &p, len); /* UNDOC */
1926 ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c,
1927 "Error parsing OCSP response");
1931 br = OCSP_response_get1_basic(rsp); /* UNDOC */
1933 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
1934 "no OCSP basic response");
1938 rd = br->tbsResponseData;
1940 for (i = 0; i < sk_OCSP_SINGLERESP_num(rd->responses); i++) { /* UNDOC */
1941 X509_EXTENSION *ext;
1943 ASN1_OCTET_STRING *oct;
1945 single = sk_OCSP_SINGLERESP_value(rd->responses, i); /* UNDOC */
1950 idx = OCSP_SINGLERESP_get_ext_by_NID(single,
1951 NID_ct_cert_scts, -1); /* UNDOC */
1957 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
1958 "index of NID_ct_cert_scts: %d", idx);
1960 exts = single->singleExtensions;
1962 ext = sk_X509_EXTENSION_value(exts, idx); /* UNDOC */
1963 oct = X509_EXTENSION_get_data(ext); /* UNDOC */
1965 conncfg->ocsp_has_sct_list = 1;
1966 conncfg->peer_ct_aware = 1;
1967 conncfg->ocsp_sct_list_size = oct->length - 2;
1968 conncfg->ocsp_sct_list = apr_pmemdup(c->pool, oct->data + 2,
1969 conncfg->ocsp_sct_list_size);
1972 OCSP_RESPONSE_free(rsp); /* UNDOC */
1977 /* Callbacks and structures for handling custom TLS Extensions:
1978 * cli_ext_first_cb - sends data for ClientHello TLS Extension
1979 * cli_ext_second_cb - receives data from ServerHello TLS Extension
1981 static int client_extension_callback_1(SSL *ssl, unsigned short ext_type,
1982 const unsigned char **out,
1983 unsigned short *outlen, int *al,
1986 conn_rec *c = (conn_rec *)SSL_get_app_data(ssl);
1988 /* nothing to send in ClientHello */
1990 ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
1991 "client_extension_callback_1 called, "
1992 "ext %hu will be in ClientHello",
1998 /* Get SCT(s) from ServerHello */
1999 static int client_extension_callback_2(SSL *ssl, unsigned short ext_type,
2000 const unsigned char *in, unsigned short inlen,
2003 conn_rec *c = (conn_rec *)SSL_get_app_data(ssl);
2004 ct_conn_config *conncfg = get_conn_config(c);
2006 ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
2007 "client_extension_callback_2 called, "
2008 "ext %hu was in ServerHello (len %hu)",
2011 /* Note: Peer certificate is not available in this callback via
2012 * SSL_get_peer_certificate(ssl)
2015 conncfg->serverhello_has_sct_list = 1;
2016 conncfg->peer_ct_aware = 1;
2017 conncfg->serverhello_sct_list = apr_pmemdup(c->pool, in, inlen);
2018 conncfg->serverhello_sct_list_size = inlen;
2022 /* See SSLClient::VerifyCallback() in c-t/src/client/ssl_client.cc
2023 * (That's a beast and hard to duplicate in depth when you consider
2024 * all the support classes it relies on; mod_ssl_ct needs to be a
2025 * C++ module so that the bugs are fixed in one place.)
2027 * . This code should care about stapled SCTs but doesn't.
2028 * . This code, unlike SSLClient::VerifyCallback(), doesn't look
2029 * at the OpenSSL "input" chain.
2031 static int ssl_ct_ssl_proxy_verify(server_rec *s, conn_rec *c,
2032 STACK_OF(X509) *chain)
2034 apr_pool_t *p = c->pool;
2035 ct_conn_config *conncfg = get_conn_config(c);
2036 ct_server_config *sconf = ap_get_module_config(s->module_config,
2038 int chain_size = sk_X509_num(chain);
2039 int extension_index;
2042 if (sconf->proxy_awareness == PROXY_OBLIVIOUS) {
2046 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
2047 "ssl_ct_ssl_proxy_verify() - get server certificate info");
2049 if (chain_size < 1) {
2050 ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c,
2051 "odd chain size %d -- cannot proceed", chain_size);
2055 /* Note: SSLClient::Verify looks in both the input chain and the
2059 certs = cert_chain_init(p, chain);
2060 conncfg->certs = certs;
2063 X509_get_ext_by_NID(certs->leaf,
2064 NID_ct_precert_scts,
2066 /* use X509_get_ext(certs->leaf, extension_index) to obtain X509_EXTENSION * */
2068 if (extension_index >= 0) {
2071 server_cert_has_sct_list(c);
2072 /* as in Cert::ExtensionStructure() */
2073 ext_struct = X509_get_ext_d2i(certs->leaf,
2074 NID_ct_precert_scts,
2075 NULL, /* ignore criticality of extension */
2078 if (ext_struct == NULL) {
2079 ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c,
2080 "Could not retrieve SCT list from certificate (unexpected)");
2083 /* as in Cert::OctetStringExtensionData */
2084 ASN1_OCTET_STRING *octet = (ASN1_OCTET_STRING *)ext_struct;
2085 conncfg->cert_sct_list = apr_pmemdup(p,
2088 conncfg->cert_sct_list_size = octet->length;
2089 ASN1_OCTET_STRING_free(octet); /* UNDOC */
2096 static int ssl_ct_proxy_post_handshake(conn_rec *c, SSL *ssl)
2098 apr_pool_t *p = c->pool;
2099 apr_status_t rv = APR_SUCCESS;
2101 ct_cached_server_data *cached;
2102 ct_conn_config *conncfg = get_conn_config(c);
2103 server_rec *s = c->base_server;
2104 ct_server_config *sconf = ap_get_module_config(s->module_config,
2106 int validation_error = 0, missing_sct_error = 0;
2107 STACK_OF(X509) *chain = SSL_get_peer_cert_chain(ssl);
2109 if (sconf->proxy_awareness == PROXY_OBLIVIOUS) {
2113 ssl_ct_ssl_proxy_verify(s, c, chain);
2115 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
2116 "finally at the point where we can see where SCTs came from"
2117 " %pp/%pp/%pp (c %pp)",
2118 conncfg->cert_sct_list, conncfg->serverhello_sct_list,
2119 conncfg->ocsp_sct_list, c);
2121 /* At this point we have the SCTs from the cert (if any) and the
2122 * SCTs from the TLS extension (if any) in ct_conn_config.
2125 if (conncfg->cert_sct_list || conncfg->serverhello_sct_list
2126 || conncfg->ocsp_sct_list) {
2128 /* The key is critical to avoiding validating and queueing of
2129 * the same stuff over and over.
2131 * Is there any cheaper check than server cert and SCTs all exactly
2132 * the same as before?
2135 key = gen_key(c, conncfg->certs, conncfg);
2137 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
2138 "key for server data: %s", key);
2140 ctutil_thread_mutex_lock(cached_server_data_mutex);
2142 cached = apr_hash_get(cached_server_data, key, APR_HASH_KEY_STRING);
2144 ctutil_thread_mutex_unlock(cached_server_data_mutex);
2147 ct_cached_server_data *new_server_data =
2148 (ct_cached_server_data *)calloc(1, sizeof(ct_cached_server_data));
2150 new_server_data->validation_result =
2151 rv = validate_server_data(p, c, conncfg->certs, conncfg, sconf);
2153 if (rv != APR_SUCCESS) {
2154 validation_error = 1;
2157 ctutil_thread_mutex_lock(cached_server_data_mutex);
2159 if ((cached = apr_hash_get(cached_server_data, key, APR_HASH_KEY_STRING))) {
2160 /* some other thread snuck in
2161 * we assume that the other thread got the same validation
2162 * result that we did
2164 free(new_server_data);
2165 new_server_data = NULL;
2168 /* no other thread snuck in */
2169 apr_hash_set(cached_server_data, key, APR_HASH_KEY_STRING,
2171 new_server_data = NULL;
2174 ctutil_thread_mutex_unlock(cached_server_data_mutex);
2176 if (rv == APR_SUCCESS && !cached) {
2177 save_server_data(c, conncfg->certs, conncfg, key);
2182 rv = cached->validation_result;
2183 if (rv != APR_SUCCESS) {
2184 validation_error = 1;
2185 ap_log_cerror(APLOG_MARK, APLOG_INFO, rv, c, "bad cached validation result");
2190 /* No SCTs at all; consult configuration to know what to do. */
2191 missing_sct_error = 1;
2194 if (conncfg->certs) {
2195 cert_chain_free(conncfg->certs);
2196 conncfg->certs = NULL;
2199 ap_log_cerror(APLOG_MARK,
2200 rv == APR_SUCCESS ? APLOG_DEBUG : APLOG_ERR, rv, c,
2201 "SCT list received in: %s%s%s(%s) (c %pp)",
2202 conncfg->serverhello_has_sct_list ? "ServerHello " : "",
2203 conncfg->server_cert_has_sct_list ? "certificate-extension " : "",
2204 conncfg->ocsp_has_sct_list ? "OCSP " : "",
2205 cached ? "already saved" : "seen for the first time",
2208 if (sconf->proxy_awareness == PROXY_REQUIRE) {
2209 if (missing_sct_error || validation_error) {
2210 ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c,
2211 "Forbidding access to backend server; no valid SCTs");
2212 return HTTP_FORBIDDEN;
2219 static int server_extension_callback_1(SSL *ssl, unsigned short ext_type,
2220 const unsigned char *in,
2221 unsigned short inlen, int *al,
2224 conn_rec *c = (conn_rec *)SSL_get_app_data(ssl);
2226 /* this callback tells us that client is CT-aware;
2227 * there's nothing of interest in the extension data
2229 client_is_ct_aware(c);
2231 ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
2232 "server_extension_callback_1 called, "
2233 "ext %hu was in ClientHello (len %hu)",
2239 static int server_extension_callback_2(SSL *ssl, unsigned short ext_type,
2240 const unsigned char **out,
2241 unsigned short *outlen, int *al,
2244 conn_rec *c = (conn_rec *)SSL_get_app_data(ssl);
2245 ct_server_config *sconf = ap_get_module_config(c->base_server->module_config,
2248 const char *fingerprint;
2249 const unsigned char *scts;
2250 apr_size_t scts_len;
2253 if (!is_client_ct_aware(c)) {
2254 /* Hmmm... Is this actually called if the client doesn't include
2255 * the extension in the ClientHello? I don't think so.
2257 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
2258 "server_extension_callback_2: client isn't CT-aware");
2259 /* Skip this extension for ServerHello */
2263 /* need to reply with SCT */
2265 server_cert = SSL_get_certificate(ssl); /* no need to free! */
2266 fingerprint = get_cert_fingerprint(c->pool, server_cert);
2268 ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
2269 "server_extension_callback_2 called, "
2270 "ext %hu will be in ServerHello",
2273 rv = read_scts(c->pool, fingerprint,
2275 c->base_server, (char **)&scts, &scts_len);
2276 if (rv == APR_SUCCESS) {
2278 ap_assert(scts_len <= USHRT_MAX);
2279 *outlen = (unsigned short)scts_len;
2282 /* Skip this extension for ServerHello */
2289 static void tlsext_cb(SSL *ssl, int client_server, int type,
2290 unsigned char *data, int len,
2295 if (type == CT_EXTENSION_TYPE) {
2296 ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
2297 "tlsext_cb called, got CT TLS extension");
2299 client_is_ct_aware(c);
2303 static int ssl_ct_pre_handshake(conn_rec *c, SSL *ssl)
2305 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, "client connected (pre-handshake)");
2307 SSL_set_tlsext_status_type(ssl, TLSEXT_STATUSTYPE_ocsp); /* UNDOC */
2309 /* This callback is needed only to determine that the peer is CT-aware
2310 * when resuming a session. For an initial handshake, the callbacks
2311 * registered via SSL_CTX_set_custom_srv_ext() are sufficient.
2313 SSL_set_tlsext_debug_callback(ssl, tlsext_cb); /* UNDOC */
2314 SSL_set_tlsext_debug_arg(ssl, c); /* UNDOC */
2319 static int ssl_ct_init_server(server_rec *s, apr_pool_t *p, int is_proxy,
2322 ct_callback_info *cbi = apr_pcalloc(p, sizeof *cbi);
2323 ct_server_config *sconf = ap_get_module_config(s->module_config,
2328 if (is_proxy && sconf->proxy_awareness != PROXY_OBLIVIOUS) {
2329 /* _cli_ = "client" */
2330 if (!SSL_CTX_set_custom_cli_ext(ssl_ctx, CT_EXTENSION_TYPE,
2331 client_extension_callback_1,
2332 client_extension_callback_2, cbi)) { /* UNDOC */
2333 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
2334 "Unable to initalize Certificate Transparency client "
2335 "extension callbacks (callback for %d already registered?)",
2337 return HTTP_INTERNAL_SERVER_ERROR;
2340 /* Uhh, hopefully this doesn't collide with anybody else. mod_ssl
2341 * currently only sets this on the server SSL_CTX, when OCSP is
2344 SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_resp_cb); /* UNDOC */
2345 SSL_CTX_set_tlsext_status_arg(ssl_ctx, cbi); /* UNDOC */
2347 else if (!is_proxy) {
2348 look_for_server_certs(s, ssl_ctx, sconf->sct_storage);
2350 /* _srv_ = "server" */
2351 if (!SSL_CTX_set_custom_srv_ext(ssl_ctx, CT_EXTENSION_TYPE,
2352 server_extension_callback_1,
2353 server_extension_callback_2, cbi)) { /* UNDOC */
2354 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
2355 "Unable to initalize Certificate Transparency server "
2356 "extension callback (callbacks for %d already registered?)",
2358 return HTTP_INTERNAL_SERVER_ERROR;
2365 static int ssl_ct_post_read_request(request_rec *r)
2367 ct_conn_config *conncfg =
2368 ap_get_module_config(r->connection->conn_config, &ssl_ct_module);
2370 if (conncfg && conncfg->peer_ct_aware) {
2371 apr_table_set(r->subprocess_env, STATUS_VAR, STATUS_VAR_AWARE_VAL);
2374 apr_table_set(r->subprocess_env, STATUS_VAR, STATUS_VAR_UNAWARE_VAL);
2380 static int ssl_ct_pre_config(apr_pool_t *pconf, apr_pool_t *plog,
2383 apr_status_t rv = ap_mutex_register(pconf, SSL_CT_MUTEX_TYPE, NULL,
2384 APR_LOCK_DEFAULT, 0);
2385 if (rv != APR_SUCCESS) {
2389 apr_dbd_init(pconf);
2391 ctutil_run_internal_tests(ptemp);
2396 static apr_status_t inactivate_audit_file(void *data)
2399 server_rec *s = data;
2401 if (!audit_file) { /* something bad happened after child init */
2405 /* the normal cleanup was disabled in the call to apr_file_open */
2406 rv = apr_file_close(audit_file);
2408 if (rv == APR_SUCCESS) {
2409 if (audit_file_nonempty) {
2410 rv = apr_file_rename(audit_fn_active, audit_fn_perm,
2411 /* not used in current implementations */
2415 /* No data written; just remove the file */
2416 apr_file_remove(audit_fn_active,
2417 /* not used in current implementations */
2421 if (rv != APR_SUCCESS) {
2422 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
2423 "error flushing/closing %s or renaming it to %s",
2424 audit_fn_active, audit_fn_perm);
2427 return APR_SUCCESS; /* what, you think anybody cares? */
2430 static void ssl_ct_child_init(apr_pool_t *p, server_rec *s)
2433 const char *audit_basename;
2434 ct_server_config *sconf = ap_get_module_config(s->module_config,
2437 cached_server_data = apr_hash_make(p);
2439 rv = apr_global_mutex_child_init(&ssl_ct_sct_update,
2440 apr_global_mutex_lockfile(ssl_ct_sct_update), p);
2441 if (rv != APR_SUCCESS) {
2442 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
2443 "could not initialize " SSL_CT_MUTEX_TYPE
2445 /* might crash otherwise due to lack of checking for initialized data
2446 * in all the right places, but this is going to skip pchild cleanup
2448 exit(APEXIT_CHILDSICK);
2451 rv = apr_thread_rwlock_create(&log_config_rwlock, p);
2452 if (rv != APR_SUCCESS) {
2453 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
2454 "could not create rwlock in child");
2455 exit(APEXIT_CHILDSICK);
2458 rv = apr_thread_create(&service_thread, NULL, run_service_thread, s, p);
2459 if (rv != APR_SUCCESS) {
2460 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
2461 "could not create " SERVICE_THREAD_NAME " in child");
2462 /* might crash otherwise due to lack of checking for initialized data
2463 * in all the right places, but this is going to skip pchild cleanup
2465 exit(APEXIT_CHILDSICK);
2468 apr_pool_cleanup_register(p, service_thread, wait_for_thread,
2469 apr_pool_cleanup_null);
2471 if (sconf->proxy_awareness != PROXY_OBLIVIOUS) {
2472 rv = apr_thread_mutex_create(&cached_server_data_mutex,
2473 APR_THREAD_MUTEX_DEFAULT,
2475 if (rv != APR_SUCCESS) {
2476 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
2477 "could not allocate a thread mutex");
2478 /* might crash otherwise due to lack of checking for initialized data
2479 * in all the right places, but this is going to skip pchild cleanup
2481 exit(APEXIT_CHILDSICK);
2485 if (sconf->proxy_awareness != PROXY_OBLIVIOUS && sconf->audit_storage) {
2486 rv = apr_thread_mutex_create(&audit_file_mutex,
2487 APR_THREAD_MUTEX_DEFAULT, p);
2488 if (rv != APR_SUCCESS) {
2489 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
2490 "could not allocate a thread mutex");
2491 /* might crash otherwise due to lack of checking for initialized data
2492 * in all the right places, but this is going to skip pchild cleanup
2494 exit(APEXIT_CHILDSICK);
2497 audit_basename = apr_psprintf(p, "audit_%" APR_PID_T_FMT,
2499 rv = ctutil_path_join((char **)&audit_fn_perm, sconf->audit_storage,
2500 audit_basename, p, s);
2501 if (rv != APR_SUCCESS) {
2502 /* might crash otherwise due to lack of checking for initialized data
2503 * in all the right places, but this is going to skip pchild cleanup
2505 exit(APEXIT_CHILDSICK);
2508 audit_fn_active = apr_pstrcat(p, audit_fn_perm, ".tmp", NULL);
2509 audit_fn_perm = apr_pstrcat(p, audit_fn_perm, ".out", NULL);
2511 if (ctutil_file_exists(p, audit_fn_active)) {
2512 ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s,
2513 "ummm, pid-specific file %s was reused before audit grabbed it! (removing)",
2515 apr_file_remove(audit_fn_active, p);
2518 if (ctutil_file_exists(p, audit_fn_perm)) {
2519 ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s,
2520 "ummm, pid-specific file %s was reused before audit grabbed it! (removing)",
2522 apr_file_remove(audit_fn_perm, p);
2525 rv = apr_file_open(&audit_file, audit_fn_active,
2526 APR_FOPEN_WRITE|APR_FOPEN_CREATE|APR_FOPEN_TRUNCATE
2527 |APR_FOPEN_BINARY|APR_FOPEN_BUFFERED|APR_FOPEN_NOCLEANUP,
2528 APR_FPROT_OS_DEFAULT, p);
2529 if (rv != APR_SUCCESS) {
2530 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
2531 "can't create %s", audit_fn_active);
2536 apr_pool_cleanup_register(p, s, inactivate_audit_file, apr_pool_cleanup_null);
2538 } /* !PROXY_OBLIVIOUS */
2541 static void *create_ct_server_config(apr_pool_t *p, server_rec *s)
2543 ct_server_config *conf =
2544 (ct_server_config *)apr_pcalloc(p, sizeof(ct_server_config));
2546 conf->max_sct_age = apr_time_from_sec(3600 * 24);
2547 conf->proxy_awareness = PROXY_AWARENESS_UNSET;
2548 conf->max_sh_sct = 100;
2549 conf->static_cert_sct_dirs = apr_hash_make(p);
2554 static void *merge_ct_server_config(apr_pool_t *p, void *basev, void *virtv)
2556 ct_server_config *base = (ct_server_config *)basev;
2557 ct_server_config *virt = (ct_server_config *)virtv;
2558 ct_server_config *conf;
2560 conf = (ct_server_config *)apr_pmemdup(p, virt, sizeof(ct_server_config));
2562 conf->sct_storage = base->sct_storage;
2563 conf->audit_storage = base->audit_storage;
2564 conf->ct_exe = base->ct_exe;
2565 conf->max_sct_age = base->max_sct_age;
2566 conf->log_config_fname = base->log_config_fname;
2567 conf->db_log_config = base->db_log_config;
2568 conf->static_log_config = base->static_log_config;
2569 conf->max_sh_sct = base->max_sh_sct;
2570 conf->static_cert_sct_dirs = base->static_cert_sct_dirs;
2572 conf->proxy_awareness = (virt->proxy_awareness != PROXY_AWARENESS_UNSET)
2573 ? virt->proxy_awareness
2574 : base->proxy_awareness;
2579 static int ssl_ct_detach_backend(request_rec *r,
2580 proxy_conn_rec *backend)
2582 conn_rec *origin = backend->connection;
2585 ct_conn_config *conncfg = get_conn_config(origin);
2588 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
2589 "ssl_ct_detach_backend, %d%d%d",
2590 conncfg->server_cert_has_sct_list,
2591 conncfg->serverhello_has_sct_list,
2592 conncfg->ocsp_has_sct_list);
2594 apr_table_set(r->subprocess_env, STATUS_VAR,
2595 conncfg->peer_ct_aware ? STATUS_VAR_AWARE_VAL : STATUS_VAR_UNAWARE_VAL);
2597 list = apr_pstrcat(r->pool,
2598 conncfg->server_cert_has_sct_list ? "certext," : "",
2599 conncfg->serverhello_has_sct_list ? "tlsext," : "",
2600 conncfg->ocsp_has_sct_list ? "ocsp" : "",
2603 last = list + strlen(list) - 1;
2609 apr_table_set(r->subprocess_env, PROXY_SCT_SOURCES_VAR, list);
2612 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
2613 "No backend connection available in "
2614 "ssl_ct_detach_backend(); assuming peer unaware");
2615 apr_table_set(r->subprocess_env, STATUS_VAR,
2616 STATUS_VAR_UNAWARE_VAL);
2622 static void ct_register_hooks(apr_pool_t *p)
2624 static const char * const run_after_mod_ssl[] = {"mod_ssl.c", NULL};
2626 ap_hook_pre_config(ssl_ct_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
2627 ap_hook_check_config(ssl_ct_check_config, NULL, NULL, APR_HOOK_MIDDLE);
2628 ap_hook_post_config(ssl_ct_post_config, run_after_mod_ssl, NULL,
2630 ap_hook_post_read_request(ssl_ct_post_read_request, NULL, NULL, APR_HOOK_MIDDLE);
2631 ap_hook_child_init(ssl_ct_child_init, NULL, NULL, APR_HOOK_MIDDLE);
2632 APR_OPTIONAL_HOOK(proxy, detach_backend, ssl_ct_detach_backend, NULL, NULL,
2634 APR_OPTIONAL_HOOK(ssl, init_server, ssl_ct_init_server, NULL, NULL,
2636 APR_OPTIONAL_HOOK(ssl, pre_handshake,
2637 ssl_ct_pre_handshake,
2638 NULL, NULL, APR_HOOK_MIDDLE);
2639 APR_OPTIONAL_HOOK(ssl, proxy_post_handshake, ssl_ct_proxy_post_handshake,
2640 NULL, NULL, APR_HOOK_MIDDLE);
2643 static const char *parse_num(apr_pool_t *p,
2644 const char *arg, long min_val,
2645 long max_val, long *val,
2646 const char *cmd_name)
2651 *val = strtol(arg, &endptr, 10);
2655 || *val > max_val) {
2656 return apr_psprintf(p, "%s must be between %ld "
2657 "and %ld (was '%s')", cmd_name, min_val,
2664 static const char *ct_audit_storage(cmd_parms *cmd, void *x, const char *arg)
2666 ct_server_config *sconf = ap_get_module_config(cmd->server->module_config,
2668 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2674 sconf->audit_storage = ap_runtime_dir_relative(cmd->pool, arg);
2676 if (!ctutil_dir_exists(cmd->pool, sconf->audit_storage)) {
2677 return apr_pstrcat(cmd->pool, "CTAuditStorage: Directory ",
2678 sconf->audit_storage,
2679 " does not exist", NULL);
2685 static const char *ct_log_config_db(cmd_parms *cmd, void *x, const char *arg)
2687 ct_server_config *sconf = ap_get_module_config(cmd->server->module_config,
2689 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2695 sconf->log_config_fname = ap_server_root_relative(cmd->pool, arg);
2700 static const char *ct_max_sct_age(cmd_parms *cmd, void *x, const char *arg)
2702 ct_server_config *sconf = ap_get_module_config(cmd->server->module_config,
2704 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2711 err = parse_num(cmd->pool, arg, 10, 3600 * 12, &val, "CTMaxSCTAge");
2716 sconf->max_sct_age = apr_time_from_sec(val);
2720 static const char *ct_proxy_awareness(cmd_parms *cmd, void *x, const char *arg)
2722 ct_server_config *sconf = ap_get_module_config(cmd->server->module_config,
2725 if (!strcasecmp(arg, "oblivious")) {
2726 sconf->proxy_awareness = PROXY_OBLIVIOUS;
2728 else if (!strcasecmp(arg, "aware")) {
2729 sconf->proxy_awareness = PROXY_AWARE;
2731 else if (!strcasecmp(arg, "require")) {
2732 sconf->proxy_awareness = PROXY_REQUIRE;
2735 return apr_pstrcat(cmd->pool, "CTProxyAwareness: Invalid argument \"",
2742 static const char *ct_sct_storage(cmd_parms *cmd, void *x, const char *arg)
2744 ct_server_config *sconf = ap_get_module_config(cmd->server->module_config,
2746 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2752 sconf->sct_storage = ap_runtime_dir_relative(cmd->pool, arg);
2754 if (!ctutil_dir_exists(cmd->pool, sconf->sct_storage)) {
2755 return apr_pstrcat(cmd->pool, "CTSCTStorage: Directory ",
2757 " does not exist", NULL);
2763 static const char *ct_sct_limit(cmd_parms *cmd, void *x, const char *arg)
2765 ct_server_config *sconf = ap_get_module_config(cmd->server->module_config,
2767 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2774 err = parse_num(cmd->pool, arg, 1, 100, &val,
2775 "CTServerHelloSCTLimit");
2780 sconf->max_sh_sct = val;
2784 static const char *ct_static_log_config(cmd_parms *cmd, void *x, int argc,
2788 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2789 const char *log_id, *public_key, *distrusted, *min_valid_time,
2790 *max_valid_time, *url;
2791 ct_server_config *sconf = ap_get_module_config(cmd->server->module_config,
2800 return "CTStaticLogConfig: 6 arguments are required";
2804 log_id = argv[cur_arg++];
2805 if (!strcmp(log_id, "-")) {
2809 public_key = argv[cur_arg++];
2810 if (!strcmp(public_key, "-")) {
2814 public_key = ap_server_root_relative(cmd->pool, public_key);
2817 distrusted = argv[cur_arg++];
2818 if (!strcmp(distrusted, "-")) {
2822 min_valid_time = argv[cur_arg++];
2823 if (!strcmp(min_valid_time, "-")) {
2824 min_valid_time = NULL;
2827 max_valid_time = argv[cur_arg++];
2828 if (!strcmp(max_valid_time, "-")) {
2829 max_valid_time = NULL;
2832 url = argv[cur_arg++];
2833 if (!strcmp(url, "-")) {
2837 if (!sconf->static_log_config) {
2838 sconf->static_log_config =
2839 apr_array_make(cmd->pool, 2, sizeof(ct_log_config *));
2841 rv = save_log_config_entry(sconf->static_log_config, cmd->pool,
2842 log_id, public_key, distrusted,
2843 min_valid_time, max_valid_time, url);
2844 if (rv != APR_SUCCESS) {
2845 return "Error processing static log configuration";
2851 static const char *ct_static_scts(cmd_parms *cmd, void *x, const char *cert_fn,
2854 apr_pool_t *p = cmd->pool;
2856 ct_server_config *sconf = ap_get_module_config(cmd->server->module_config,
2858 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2859 const char *fingerprint;
2867 cert_fn = ap_server_root_relative(cmd->pool, cert_fn);
2868 sct_dn = ap_server_root_relative(cmd->pool, sct_dn);
2870 rv = ctutil_fopen(cert_fn, "r", &pemfile);
2871 if (rv != APR_SUCCESS) {
2872 return apr_psprintf(p, "could not open certificate file %s (%pm)",
2876 cert = PEM_read_X509(pemfile, NULL, NULL, NULL);
2878 return apr_psprintf(p, "could not read certificate from file %s",
2884 fingerprint = get_cert_fingerprint(cmd->pool, cert);
2887 if (!ctutil_dir_exists(p, sct_dn)) {
2888 return apr_pstrcat(p, "CTStaticSCTs: Directory ", sct_dn,
2889 " does not exist", NULL);
2892 apr_hash_set(sconf->static_cert_sct_dirs, fingerprint,
2893 APR_HASH_KEY_STRING, sct_dn);
2898 static const char *ct_log_client(cmd_parms *cmd, void *x, const char *arg)
2900 ct_server_config *sconf = ap_get_module_config(cmd->server->module_config,
2902 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2908 if (strcmp(DOTEXE, "")) {
2909 if (!ctutil_file_exists(cmd->pool, arg)) {
2910 arg = apr_pstrcat(cmd->pool, arg, DOTEXE, NULL);
2914 if (!ctutil_file_exists(cmd->pool, arg)) {
2915 return apr_pstrcat(cmd->pool,
2916 "CTLogClient: File ",
2922 sconf->ct_exe = arg;
2927 static const command_rec ct_cmds[] =
2929 AP_INIT_TAKE1("CTAuditStorage", ct_audit_storage, NULL,
2930 RSRC_CONF, /* GLOBAL_ONLY - audit data spans servers */
2931 "Location to store files of audit data"),
2932 AP_INIT_TAKE1("CTLogConfigDB", ct_log_config_db, NULL,
2933 RSRC_CONF, /* GLOBAL_ONLY - otherwise, you couldn't share
2934 * the same SCT list for a cert used by two
2935 * different vhosts (and the SCT maintenance daemon
2936 * would be more complex)
2938 "Log configuration database"),
2939 AP_INIT_TAKE1("CTMaxSCTAge", ct_max_sct_age, NULL,
2940 RSRC_CONF, /* GLOBAL_ONLY - otherwise, you couldn't share
2941 * the same SCT list for a cert used by two
2944 "Max age of SCT obtained from log before refresh"),
2945 AP_INIT_TAKE1("CTProxyAwareness", ct_proxy_awareness, NULL,
2946 RSRC_CONF, /* per-server */
2947 "\"oblivious\" to neither ask for nor check SCTs, "
2948 "\"aware\" to ask for and process SCTs but allow all connections, "
2949 "or \"require\" to abort backend connections if an acceptable "
2950 "SCT is not provided"),
2951 AP_INIT_TAKE1("CTServerHelloSCTLimit", ct_sct_limit, NULL,
2952 RSRC_CONF, /* GLOBAL_ONLY - otherwise, you couldn't share
2953 * the same SCT list for a cert used by two
2956 "Limit on number of SCTs sent in ServerHello"),
2957 AP_INIT_TAKE1("CTSCTStorage", ct_sct_storage, NULL,
2958 RSRC_CONF, /* GLOBAL_ONLY - otherwise, you couldn't share
2959 * the same SCT list for a cert used by two
2960 * different vhosts (and the SCT maintenance daemon
2961 * would be more complex)
2963 "Location to store SCTs obtained from logs"),
2964 AP_INIT_TAKE_ARGV("CTStaticLogConfig", ct_static_log_config, NULL,
2965 RSRC_CONF, /* GLOBAL_ONLY */
2966 "Static log configuration record"),
2967 AP_INIT_TAKE2("CTStaticSCTs", ct_static_scts, NULL,
2968 RSRC_CONF, /* GLOBAL_ONLY - otherwise, you couldn't share
2969 * the same SCT list for a cert used by two
2970 * different vhosts (and the SCT maintenance daemon
2971 * would be more complex)
2973 "Point to directory with static SCTs corresponding to the "
2974 "specified certificate"),
2975 AP_INIT_TAKE1("CTLogClient", ct_log_client, NULL,
2976 RSRC_CONF, /* GLOBAL_ONLY - otherwise, you couldn't share
2977 * the same SCTs for a cert used by two
2978 * different vhosts (and it would be just plain
2981 "Location of certificate-transparency.org (or compatible) log client tool"),
2985 AP_DECLARE_MODULE(ssl_ct) =
2987 STANDARD20_MODULE_STUFF,
2990 create_ct_server_config,
2991 merge_ct_server_config,