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.
18 #include "ssl_ct_sct.h"
19 #include "ssl_ct_util.h"
23 APLOG_USE_MODULE(ssl_ct);
25 static apr_status_t verify_signature(sct_fields_t *sctf,
31 if (sctf->signed_data == NULL) {
35 EVP_MD_CTX_init(&ctx);
36 ap_assert(1 == EVP_VerifyInit(&ctx, EVP_sha256()));
37 ap_assert(1 == EVP_VerifyUpdate(&ctx, sctf->signed_data,
38 sctf->signed_data_len));
39 rc = EVP_VerifyFinal(&ctx, sctf->sig, sctf->siglen, pkey);
40 EVP_MD_CTX_cleanup(&ctx);
42 return rc == 1 ? APR_SUCCESS : APR_EINVAL;
45 apr_status_t sct_verify_signature(conn_rec *c, sct_fields_t *sctf,
46 apr_array_header_t *log_config)
48 apr_status_t rv = APR_EINVAL;
50 ct_log_config **config_elts;
51 int nelts = log_config->nelts;
53 ap_assert(sctf->signed_data != NULL);
55 config_elts = (ct_log_config **)log_config->elts;
57 for (i = 0; i < nelts; i++) {
58 EVP_PKEY *pubkey = config_elts[i]->public_key;
59 const char *logid = config_elts[i]->log_id;
61 if (!pubkey || !logid) {
65 if (!memcmp(logid, sctf->logid, LOG_ID_SIZE)) {
66 if (!log_valid_for_received_sct(config_elts[i], sctf->time)) {
67 ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c,
68 "Got SCT from distrusted log, or out of trusted time interval");
71 rv = verify_signature(sctf, pubkey);
72 if (rv != APR_SUCCESS) {
73 ap_log_cerror(APLOG_MARK,
76 "verify_signature failed");
79 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
80 "verify_signature succeeded");
89 apr_status_t sct_parse(const char *source,
90 server_rec *s, const unsigned char *sct,
91 apr_size_t len, cert_chain *cc,
94 const unsigned char *cur;
95 apr_size_t orig_len = len;
98 memset(fields, 0, sizeof *fields);
100 if (len < 1 + LOG_ID_SIZE + 8) {
101 /* no room for header */
102 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
103 "SCT size %" APR_SIZE_T_FMT " is too small",
110 fields->version = *cur;
113 memcpy(fields->logid, cur, LOG_ID_SIZE);
116 rv = ctutil_deserialize_uint64(&cur, &len, &fields->timestamp);
117 ap_assert(rv == APR_SUCCESS);
119 fields->time = apr_time_from_msec(fields->timestamp);
121 /* XXX maybe do this only if log level is such that we'll
124 apr_rfc822_date(fields->timestr, fields->time);
128 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
129 "SCT size %" APR_SIZE_T_FMT " has no space for extension "
134 rv = ctutil_deserialize_uint16(&cur, &len, &fields->extlen);
135 ap_assert(rv == APR_SUCCESS);
137 if (fields->extlen != 0) {
138 if (fields->extlen < len) {
139 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
140 "SCT size %" APR_SIZE_T_FMT " has no space for "
141 "%hu bytes of extensions",
142 orig_len, fields->extlen);
146 fields->extensions = cur;
147 cur += fields->extlen;
148 len -= fields->extlen;
151 fields->extensions = 0;
155 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
156 "SCT size %" APR_SIZE_T_FMT " has no space for "
157 "hash algorithm, signature algorithm, and signature len",
162 fields->hash_alg = *cur;
165 fields->sig_alg = *cur;
168 rv = ctutil_deserialize_uint16(&cur, &len, &fields->siglen);
169 ap_assert(rv == APR_SUCCESS);
171 if (fields->siglen < len) {
172 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
173 "SCT has no space for signature");
178 cur += fields->siglen;
179 len -= fields->siglen;
182 /* If we have the server certificate, we can construct the
183 * data over which the signature is computed.
186 /* XXX Which part is signed? */
187 /* See certificate-transparency/src/proto/serializer.cc,
188 * method Serializer::SerializeV1CertSCTSignatureInput()
195 unsigned char *orig_mem;
197 der_length = i2d_X509(cc->leaf, NULL);
198 if (der_length < 0) {
202 if (rv == APR_SUCCESS) {
205 + 1 /* CERTIFICATE_TIMESTAMP */
208 + 3 + der_length /* 24-bit length + X509 */
209 + 2 + fields->extlen /* 16-bit length + extensions */
215 rv = ctutil_serialize_uint8(&mem, &avail, 0); /* version 1 */
216 if (rv == APR_SUCCESS) {
217 rv = ctutil_serialize_uint8(&mem, &avail, 0); /* CERTIFICATE_TIMESTAMP */
219 if (rv == APR_SUCCESS) {
220 rv = ctutil_serialize_uint64(&mem, &avail, fields->timestamp);
222 if (rv == APR_SUCCESS) {
223 rv = ctutil_serialize_uint16(&mem, &avail, 0); /* X509_ENTRY */
225 if (rv == APR_SUCCESS) {
226 /* Get DER encoding of leaf certificate */
227 unsigned char *der_buf
228 /* get OpenSSL to allocate: */
231 der_length = i2d_X509(cc->leaf, &der_buf);
232 if (der_length < 0) {
236 rv = ctutil_write_var24_bytes(&mem, &avail,
237 der_buf, der_length);
238 OPENSSL_free(der_buf);
241 if (rv == APR_SUCCESS) {
242 rv = ctutil_write_var16_bytes(&mem, &avail, fields->extensions,
247 if (rv != APR_SUCCESS) {
248 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
249 "Failed to reconstruct signed data for SCT");
254 ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s,
255 "length miscalculation for signed data (%" APR_SIZE_T_FMT
256 " vs. %" APR_SIZE_T_FMT ")",
259 fields->signed_data_len = orig_len - avail;
260 fields->signed_data = orig_mem;
261 /* Force invalid signature error: orig_mem[0] = orig_mem[0] + 1; */
265 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
266 "SCT from %s: version %d timestamp %s hash alg %d sig alg %d",
267 source, fields->version, fields->timestr,
268 fields->hash_alg, fields->sig_alg);
269 #if AP_MODULE_MAGIC_AT_LEAST(20130702,2)
270 ap_log_data(APLOG_MARK, APLOG_DEBUG, s, "Log Id",
271 fields->logid, sizeof(fields->logid),
272 AP_LOG_DATA_SHOW_OFFSET);
273 ap_log_data(APLOG_MARK, APLOG_DEBUG, s, "Signature",
274 fields->sig, fields->siglen,
275 AP_LOG_DATA_SHOW_OFFSET);
276 #endif /* httpd has ap_log_*data() */
278 ap_assert(!(fields->signed_data && rv != APR_SUCCESS));
283 void sct_release(sct_fields_t *sctf)
285 if (sctf->signed_data) {
286 free((void *)sctf->signed_data);
287 sctf->signed_data = NULL;
291 apr_status_t sct_verify_timestamp(conn_rec *c, sct_fields_t *sctf)
293 if (sctf->time > apr_time_now()) {
294 ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c,
295 "Server sent SCT not yet valid (timestamp %s)",