]> granicus.if.org Git - apache/blob - modules/ssl/ssl_ct_sct.c
mod_cache: Don't add cached/revalidated entity headers to a 304 response.
[apache] / modules / ssl / ssl_ct_sct.c
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
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17
18 #include "ssl_ct_sct.h"
19 #include "ssl_ct_util.h"
20
21 #include "http_log.h"
22
23 APLOG_USE_MODULE(ssl_ct);
24
25 static apr_status_t verify_signature(sct_fields_t *sctf,
26                                      EVP_PKEY *pkey)
27 {
28     EVP_MD_CTX ctx;
29     int rc;
30
31     if (sctf->signed_data == NULL) {
32         return APR_EINVAL;
33     }
34
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);
41
42     return rc == 1 ? APR_SUCCESS : APR_EINVAL;
43 }
44
45 apr_status_t sct_verify_signature(conn_rec *c, sct_fields_t *sctf,
46                                   apr_array_header_t *log_config)
47 {
48     apr_status_t rv = APR_EINVAL;
49     int i;
50     ct_log_config **config_elts;
51     int nelts = log_config->nelts;
52
53     ap_assert(sctf->signed_data != NULL);
54
55     config_elts = (ct_log_config **)log_config->elts;
56
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;
60
61         if (!pubkey || !logid) {
62             continue;
63         }
64
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");
69                 return APR_EINVAL;
70             }
71             rv = verify_signature(sctf, pubkey);
72             if (rv != APR_SUCCESS) {
73                 ap_log_cerror(APLOG_MARK, 
74                               APLOG_ERR,
75                               rv, c,
76                               "verify_signature failed");
77             }
78             else {
79                 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
80                               "verify_signature succeeded");
81             }
82             return rv;
83         }
84     }
85
86     return APR_NOTFOUND;
87 }
88
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,
92                        sct_fields_t *fields)
93 {
94     const unsigned char *cur;
95     apr_size_t orig_len = len;
96     apr_status_t rv;
97
98     memset(fields, 0, sizeof *fields);
99
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",
104                      len);
105         return APR_EINVAL;
106     }
107
108     cur = sct;
109
110     fields->version = *cur;
111     cur++;
112     len -= 1;
113     memcpy(fields->logid, cur, LOG_ID_SIZE);
114     cur += LOG_ID_SIZE;
115     len -= LOG_ID_SIZE;
116     rv = ctutil_deserialize_uint64(&cur, &len, &fields->timestamp);
117     ap_assert(rv == APR_SUCCESS);
118
119     fields->time = apr_time_from_msec(fields->timestamp);
120
121     /* XXX maybe do this only if log level is such that we'll
122      *     use it later?
123      */
124     apr_rfc822_date(fields->timestr, fields->time);
125
126
127     if (len < 2) {
128         ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
129                      "SCT size %" APR_SIZE_T_FMT " has no space for extension "
130                      "len", orig_len);
131         return APR_EINVAL;
132     }
133
134     rv = ctutil_deserialize_uint16(&cur, &len, &fields->extlen);
135     ap_assert(rv == APR_SUCCESS);
136
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);
143             return APR_EINVAL;
144         }
145
146         fields->extensions = cur;
147         cur += fields->extlen;
148         len -= fields->extlen;
149     }
150     else {
151         fields->extensions = 0;
152     }
153
154     if (len < 4) {
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",
158                      orig_len);
159         return APR_EINVAL;
160     }
161
162     fields->hash_alg = *cur;
163     cur += 1;
164     len -= 1;
165     fields->sig_alg = *cur;
166     cur += 1;
167     len -= 1;
168     rv = ctutil_deserialize_uint16(&cur, &len, &fields->siglen);
169     ap_assert(rv == APR_SUCCESS);
170
171     if (fields->siglen < len) {
172         ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
173                      "SCT has no space for signature");
174         return APR_EINVAL;
175     }
176
177     fields->sig = cur;
178     cur += fields->siglen;
179     len -= fields->siglen;
180
181     if (cc) {
182         /* If we have the server certificate, we can construct the
183          * data over which the signature is computed.
184          */
185
186         /* XXX Which part is signed? */
187         /* See certificate-transparency/src/proto/serializer.cc,
188          * method Serializer::SerializeV1CertSCTSignatureInput()
189          */
190
191         apr_size_t orig_len;
192         apr_size_t avail;
193         int der_length;
194         unsigned char *mem;
195         unsigned char *orig_mem;
196
197         der_length = i2d_X509(cc->leaf, NULL);
198         if (der_length < 0) {
199             rv = APR_EINVAL;
200         }
201
202         if (rv == APR_SUCCESS) {
203             orig_len = 0
204                 + 1 /* version 1 */
205                 + 1 /* CERTIFICATE_TIMESTAMP */
206                 + 8 /* timestamp */
207                 + 2 /* X509_ENTRY */
208                 + 3 + der_length /* 24-bit length + X509 */
209                 + 2 + fields->extlen /* 16-bit length + extensions */
210                 ;
211             avail = orig_len;
212             mem = malloc(avail);
213             orig_mem = mem;
214             
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 */
218             }
219             if (rv == APR_SUCCESS) {
220                 rv = ctutil_serialize_uint64(&mem, &avail, fields->timestamp);
221             }
222             if (rv == APR_SUCCESS) {
223                 rv = ctutil_serialize_uint16(&mem, &avail, 0); /* X509_ENTRY */
224             }
225             if (rv == APR_SUCCESS) {
226                 /* Get DER encoding of leaf certificate */
227                 unsigned char *der_buf
228                     /* get OpenSSL to allocate: */
229                     = NULL;
230
231                 der_length = i2d_X509(cc->leaf, &der_buf);
232                 if (der_length < 0) {
233                     rv = APR_EINVAL;
234                 }
235                 else {
236                     rv = ctutil_write_var24_bytes(&mem, &avail,
237                                                   der_buf, der_length);
238                     OPENSSL_free(der_buf);
239                 }
240             }
241             if (rv == APR_SUCCESS) {
242                 rv = ctutil_write_var16_bytes(&mem, &avail, fields->extensions,
243                                               fields->extlen);
244             }
245         }
246
247         if (rv != APR_SUCCESS) {
248             ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
249                          "Failed to reconstruct signed data for SCT");
250             free(orig_mem);
251         }
252         else {
253             if (avail != 0) {
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 ")",
257                              orig_len, avail);
258             }
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; */
262         }
263     }
264
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() */
277
278     ap_assert(!(fields->signed_data && rv != APR_SUCCESS));
279
280     return rv;
281 }
282
283 void sct_release(sct_fields_t *sctf)
284 {
285     if (sctf->signed_data) {
286         free((void *)sctf->signed_data);
287         sctf->signed_data = NULL;
288     }
289 }
290
291 apr_status_t sct_verify_timestamp(conn_rec *c, sct_fields_t *sctf)
292 {
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)",
296                       sctf->timestr);
297         return APR_EINVAL;
298     }
299     return APR_SUCCESS;
300 }