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