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 /* This file implements an OCSP client including a toy HTTP/1.0
18 * client. Once httpd depends on a real HTTP client library, most of
19 * this can be thrown away. */
20
21 #include "ssl_private.h"
22
23 #ifndef OPENSSL_NO_OCSP
24
25 #include "apr_buckets.h"
26 #include "apr_uri.h"
27
28 /* Serialize an OCSP request which will be sent to the responder at
29 * given URI to a memory BIO object, which is returned. */
serialize_request(OCSP_REQUEST * req,const apr_uri_t * uri,const apr_uri_t * proxy_uri)30 static BIO *serialize_request(OCSP_REQUEST *req, const apr_uri_t *uri,
31 const apr_uri_t *proxy_uri)
32 {
33 BIO *bio;
34 int len;
35
36 len = i2d_OCSP_REQUEST(req, NULL);
37
38 bio = BIO_new(BIO_s_mem());
39
40 BIO_printf(bio, "POST ");
41 /* Use full URL instead of URI in case of a request through a proxy */
42 if (proxy_uri) {
43 BIO_printf(bio, "http://%s:%d",
44 uri->hostname, uri->port);
45 }
46 BIO_printf(bio, "%s%s%s HTTP/1.0\r\n"
47 "Host: %s:%d\r\n"
48 "Content-Type: application/ocsp-request\r\n"
49 "Connection: close\r\n"
50 "Content-Length: %d\r\n"
51 "\r\n",
52 uri->path ? uri->path : "/",
53 uri->query ? "?" : "", uri->query ? uri->query : "",
54 uri->hostname, uri->port, len);
55
56 if (i2d_OCSP_REQUEST_bio(bio, req) != 1) {
57 BIO_free(bio);
58 return NULL;
59 }
60
61 return bio;
62 }
63
64 /* Send the OCSP request serialized into BIO 'request' to the
65 * responder at given server given by URI. Returns socket object or
66 * NULL on error. */
send_request(BIO * request,const apr_uri_t * uri,apr_interval_time_t timeout,conn_rec * c,apr_pool_t * p,const apr_uri_t * proxy_uri)67 static apr_socket_t *send_request(BIO *request, const apr_uri_t *uri,
68 apr_interval_time_t timeout,
69 conn_rec *c, apr_pool_t *p,
70 const apr_uri_t *proxy_uri)
71 {
72 apr_status_t rv;
73 apr_sockaddr_t *sa;
74 apr_socket_t *sd;
75 char buf[HUGE_STRING_LEN];
76 int len;
77 const apr_uri_t *next_hop_uri;
78
79 if (proxy_uri) {
80 next_hop_uri = proxy_uri;
81 }
82 else {
83 next_hop_uri = uri;
84 }
85
86 rv = apr_sockaddr_info_get(&sa, next_hop_uri->hostname, APR_UNSPEC,
87 next_hop_uri->port, 0, p);
88 if (rv) {
89 ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(01972)
90 "could not resolve address of %s %s",
91 proxy_uri ? "proxy" : "OCSP responder",
92 next_hop_uri->hostinfo);
93 return NULL;
94 }
95
96 /* establish a connection to the OCSP responder */
97 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(01973)
98 "connecting to %s '%s'",
99 proxy_uri ? "proxy" : "OCSP responder",
100 uri->hostinfo);
101
102 /* Cycle through address until a connect() succeeds. */
103 for (; sa; sa = sa->next) {
104 rv = apr_socket_create(&sd, sa->family, SOCK_STREAM, APR_PROTO_TCP, p);
105 if (rv == APR_SUCCESS) {
106 apr_socket_timeout_set(sd, timeout);
107
108 rv = apr_socket_connect(sd, sa);
109 if (rv == APR_SUCCESS) {
110 break;
111 }
112 apr_socket_close(sd);
113 }
114 }
115
116 if (sa == NULL) {
117 ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(01974)
118 "could not connect to %s '%s'",
119 proxy_uri ? "proxy" : "OCSP responder",
120 next_hop_uri->hostinfo);
121 return NULL;
122 }
123
124 /* send the request and get a response */
125 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(01975)
126 "sending request to OCSP responder");
127
128 while ((len = BIO_read(request, buf, sizeof buf)) > 0) {
129 char *wbuf = buf;
130 apr_size_t remain = len;
131
132 do {
133 apr_size_t wlen = remain;
134
135 rv = apr_socket_send(sd, wbuf, &wlen);
136 wbuf += remain;
137 remain -= wlen;
138 } while (rv == APR_SUCCESS && remain > 0);
139
140 if (rv) {
141 apr_socket_close(sd);
142 ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(01976)
143 "failed to send request to OCSP responder '%s'",
144 uri->hostinfo);
145 return NULL;
146 }
147 }
148
149 return sd;
150 }
151
152 /* Return a pool-allocated NUL-terminated line, with CRLF stripped,
153 * read from brigade 'bbin' using 'bbout' as temporary storage. */
get_line(apr_bucket_brigade * bbout,apr_bucket_brigade * bbin,conn_rec * c,apr_pool_t * p)154 static char *get_line(apr_bucket_brigade *bbout, apr_bucket_brigade *bbin,
155 conn_rec *c, apr_pool_t *p)
156 {
157 apr_status_t rv;
158 apr_size_t len;
159 char *line;
160
161 apr_brigade_cleanup(bbout);
162
163 rv = apr_brigade_split_line(bbout, bbin, APR_BLOCK_READ, 8192);
164 if (rv) {
165 ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(01977)
166 "failed reading line from OCSP server");
167 return NULL;
168 }
169
170 rv = apr_brigade_pflatten(bbout, &line, &len, p);
171 if (rv) {
172 ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(01978)
173 "failed reading line from OCSP server");
174 return NULL;
175 }
176
177 if (len == 0) {
178 ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(02321)
179 "empty response from OCSP server");
180 return NULL;
181 }
182
183 if (line[len-1] != APR_ASCII_LF) {
184 ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(01979)
185 "response header line too long from OCSP server");
186 return NULL;
187 }
188
189 line[len-1] = '\0';
190 if (len > 1 && line[len-2] == APR_ASCII_CR) {
191 line[len-2] = '\0';
192 }
193
194 return line;
195 }
196
197 /* Maximum values to prevent eating RAM forever. */
198 #define MAX_HEADERS (256)
199 #define MAX_CONTENT (2048 * 1024)
200
201 /* Read the OCSP response from the socket 'sd', using temporary memory
202 * BIO 'bio', and return the decoded OCSP response object, or NULL on
203 * error. */
read_response(apr_socket_t * sd,BIO * bio,conn_rec * c,apr_pool_t * p)204 static OCSP_RESPONSE *read_response(apr_socket_t *sd, BIO *bio, conn_rec *c,
205 apr_pool_t *p)
206 {
207 apr_bucket_brigade *bb, *tmpbb;
208 OCSP_RESPONSE *response;
209 char *line;
210 apr_size_t count;
211 apr_int64_t code;
212
213 /* Using brigades for response parsing is much simpler than using
214 * apr_socket_* directly. */
215 bb = apr_brigade_create(p, c->bucket_alloc);
216 tmpbb = apr_brigade_create(p, c->bucket_alloc);
217 APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_socket_create(sd, c->bucket_alloc));
218
219 line = get_line(tmpbb, bb, c, p);
220 if (!line || strncmp(line, "HTTP/", 5)
221 || (line = ap_strchr(line, ' ')) == NULL
222 || (code = apr_atoi64(++line)) < 200 || code > 299) {
223 ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(01980)
224 "bad response from OCSP server: %s",
225 line ? line : "(none)");
226 return NULL;
227 }
228
229 /* Read till end of headers; don't have to even bother parsing the
230 * Content-Length since the server is obliged to close the
231 * connection after the response anyway for HTTP/1.0. */
232 count = 0;
233 while ((line = get_line(tmpbb, bb, c, p)) != NULL && line[0]
234 && ++count < MAX_HEADERS) {
235 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(01981)
236 "OCSP response header: %s", line);
237 }
238
239 if (count == MAX_HEADERS) {
240 ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(01982)
241 "could not read response headers from OCSP server, "
242 "exceeded maximum count (%u)", MAX_HEADERS);
243 return NULL;
244 }
245 else if (!line) {
246 ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(01983)
247 "could not read response header from OCSP server");
248 return NULL;
249 }
250
251 /* Read the response body into the memory BIO. */
252 count = 0;
253 while (!APR_BRIGADE_EMPTY(bb)) {
254 const char *data;
255 apr_size_t len;
256 apr_status_t rv;
257 apr_bucket *e = APR_BRIGADE_FIRST(bb);
258
259 rv = apr_bucket_read(e, &data, &len, APR_BLOCK_READ);
260 if (rv == APR_EOF) {
261 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(01984)
262 "OCSP response: got EOF");
263 break;
264 }
265 if (rv != APR_SUCCESS) {
266 ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(01985)
267 "error reading response from OCSP server");
268 return NULL;
269 }
270 if (len == 0) {
271 /* Ignore zero-length buckets (possible side-effect of
272 * line splitting). */
273 apr_bucket_delete(e);
274 continue;
275 }
276 count += len;
277 if (count > MAX_CONTENT) {
278 ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(01986)
279 "OCSP response size exceeds %u byte limit",
280 MAX_CONTENT);
281 return NULL;
282 }
283 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(01987)
284 "OCSP response: got %" APR_SIZE_T_FMT
285 " bytes, %" APR_SIZE_T_FMT " total", len, count);
286
287 BIO_write(bio, data, (int)len);
288 apr_bucket_delete(e);
289 }
290
291 apr_brigade_destroy(bb);
292 apr_brigade_destroy(tmpbb);
293
294 /* Finally decode the OCSP response from what's stored in the
295 * bio. */
296 response = d2i_OCSP_RESPONSE_bio(bio, NULL);
297 if (response == NULL) {
298 ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(01988)
299 "failed to decode OCSP response data");
300 ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, mySrvFromConn(c));
301 }
302
303 return response;
304 }
305
modssl_dispatch_ocsp_request(const apr_uri_t * uri,apr_interval_time_t timeout,OCSP_REQUEST * request,conn_rec * c,apr_pool_t * p)306 OCSP_RESPONSE *modssl_dispatch_ocsp_request(const apr_uri_t *uri,
307 apr_interval_time_t timeout,
308 OCSP_REQUEST *request,
309 conn_rec *c, apr_pool_t *p)
310 {
311 OCSP_RESPONSE *response = NULL;
312 apr_socket_t *sd;
313 BIO *bio;
314 const apr_uri_t *proxy_uri;
315
316 proxy_uri = (mySrvConfigFromConn(c))->server->proxy_uri;
317 bio = serialize_request(request, uri, proxy_uri);
318 if (bio == NULL) {
319 ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(01989)
320 "could not serialize OCSP request");
321 ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, mySrvFromConn(c));
322 return NULL;
323 }
324
325 sd = send_request(bio, uri, timeout, c, p, proxy_uri);
326 if (sd == NULL) {
327 /* Errors already logged. */
328 BIO_free(bio);
329 return NULL;
330 }
331
332 /* Clear the BIO contents, ready for the response. */
333 (void)BIO_reset(bio);
334
335 response = read_response(sd, bio, c, p);
336
337 apr_socket_close(sd);
338 BIO_free(bio);
339
340 return response;
341 }
342
343 /* _________________________________________________________________
344 **
345 ** OCSP other certificate support
346 ** _________________________________________________________________
347 */
348
349 /*
350 * Read a file that contains certificates in PEM format and
351 * return as a STACK.
352 */
353
STACK_OF(X509)354 static STACK_OF(X509) *modssl_read_ocsp_certificates(const char *file)
355 {
356 BIO *bio;
357 X509 *x509;
358 unsigned long err;
359 STACK_OF(X509) *other_certs = NULL;
360
361 if ((bio = BIO_new(BIO_s_file())) == NULL)
362 return NULL;
363 if (BIO_read_filename(bio, file) <= 0) {
364 BIO_free(bio);
365 return NULL;
366 }
367
368 /* create new extra chain by loading the certs */
369 ERR_clear_error();
370 while ((x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) {
371 if (!other_certs) {
372 other_certs = sk_X509_new_null();
373 if (!other_certs)
374 return NULL;
375 }
376
377 if (!sk_X509_push(other_certs, x509)) {
378 X509_free(x509);
379 sk_X509_pop_free(other_certs, X509_free);
380 BIO_free(bio);
381 return NULL;
382 }
383 }
384 /* Make sure that only the error is just an EOF */
385 if ((err = ERR_peek_error()) > 0) {
386 if (!( ERR_GET_LIB(err) == ERR_LIB_PEM
387 && ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) {
388 BIO_free(bio);
389 sk_X509_pop_free(other_certs, X509_free);
390 return NULL;
391 }
392 while (ERR_get_error() > 0) ;
393 }
394 BIO_free(bio);
395 return other_certs;
396 }
397
ssl_init_ocsp_certificates(server_rec * s,modssl_ctx_t * mctx)398 void ssl_init_ocsp_certificates(server_rec *s, modssl_ctx_t *mctx)
399 {
400 /*
401 * Configure Trusted OCSP certificates.
402 */
403
404 if (!mctx->ocsp_certs_file) {
405 return;
406 }
407
408 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
409 "Configuring Trusted OCSP certificates");
410
411 mctx->ocsp_certs = modssl_read_ocsp_certificates(mctx->ocsp_certs_file);
412
413 if (!mctx->ocsp_certs) {
414 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
415 "Unable to configure OCSP Trusted Certificates");
416 ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s);
417 ssl_die(s);
418 }
419 mctx->ocsp_verify_flags |= OCSP_TRUSTOTHER;
420 }
421
422 #endif /* HAVE_OCSP */
423