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. */
30static BIO *serialize_request(OCSP_REQUEST *req, const apr_uri_t *uri)
31{
32    BIO *bio;
33    int len;
34
35    len = i2d_OCSP_REQUEST(req, NULL);
36
37    bio = BIO_new(BIO_s_mem());
38
39    BIO_printf(bio, "POST %s%s%s HTTP/1.0\r\n"
40               "Host: %s:%d\r\n"
41               "Content-Type: application/ocsp-request\r\n"
42               "Content-Length: %d\r\n"
43               "\r\n",
44               uri->path ? uri->path : "/",
45               uri->query ? "?" : "", uri->query ? uri->query : "",
46               uri->hostname, uri->port, len);
47
48    if (i2d_OCSP_REQUEST_bio(bio, req) != 1) {
49        BIO_free(bio);
50        return NULL;
51    }
52
53    return bio;
54}
55
56/* Send the OCSP request serialized into BIO 'request' to the
57 * responder at given server given by URI.  Returns socket object or
58 * NULL on error. */
59static apr_socket_t *send_request(BIO *request, const apr_uri_t *uri,
60                                  apr_interval_time_t timeout,
61                                  conn_rec *c, apr_pool_t *p)
62{
63    apr_status_t rv;
64    apr_sockaddr_t *sa;
65    apr_socket_t *sd;
66    char buf[HUGE_STRING_LEN];
67    int len;
68
69    rv = apr_sockaddr_info_get(&sa, uri->hostname, APR_UNSPEC, uri->port, 0, p);
70    if (rv) {
71        ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(01972)
72                      "could not resolve address of OCSP responder %s",
73                      uri->hostinfo);
74        return NULL;
75    }
76
77    /* establish a connection to the OCSP responder */
78    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(01973)
79                  "connecting to OCSP responder '%s'", uri->hostinfo);
80
81    /* Cycle through address until a connect() succeeds. */
82    for (; sa; sa = sa->next) {
83        rv = apr_socket_create(&sd, sa->family, SOCK_STREAM, APR_PROTO_TCP, p);
84        if (rv == APR_SUCCESS) {
85            apr_socket_timeout_set(sd, timeout);
86
87            rv = apr_socket_connect(sd, sa);
88            if (rv == APR_SUCCESS) {
89                break;
90            }
91            apr_socket_close(sd);
92        }
93    }
94
95    if (sa == NULL) {
96        ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(01974)
97                      "could not connect to OCSP responder '%s'",
98                      uri->hostinfo);
99        return NULL;
100    }
101
102    /* send the request and get a response */
103    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(01975)
104                 "sending request to OCSP responder");
105
106    while ((len = BIO_read(request, buf, sizeof buf)) > 0) {
107        char *wbuf = buf;
108        apr_size_t remain = len;
109
110        do {
111            apr_size_t wlen = remain;
112
113            rv = apr_socket_send(sd, wbuf, &wlen);
114            wbuf += remain;
115            remain -= wlen;
116        } while (rv == APR_SUCCESS && remain > 0);
117
118        if (rv) {
119            apr_socket_close(sd);
120            ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(01976)
121                          "failed to send request to OCSP responder '%s'",
122                          uri->hostinfo);
123            return NULL;
124        }
125    }
126
127    return sd;
128}
129
130/* Return a pool-allocated NUL-terminated line, with CRLF stripped,
131 * read from brigade 'bbin' using 'bbout' as temporary storage. */
132static char *get_line(apr_bucket_brigade *bbout, apr_bucket_brigade *bbin,
133                      conn_rec *c, apr_pool_t *p)
134{
135    apr_status_t rv;
136    apr_size_t len;
137    char *line;
138
139    apr_brigade_cleanup(bbout);
140
141    rv = apr_brigade_split_line(bbout, bbin, APR_BLOCK_READ, 8192);
142    if (rv) {
143        ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(01977)
144                      "failed reading line from OCSP server");
145        return NULL;
146    }
147
148    rv = apr_brigade_pflatten(bbout, &line, &len, p);
149    if (rv) {
150        ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(01978)
151                      "failed reading line from OCSP server");
152        return NULL;
153    }
154
155    if (len == 0) {
156        ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(02321)
157                      "empty response from OCSP server");
158        return NULL;
159    }
160
161    if (line[len-1] != APR_ASCII_LF) {
162        ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(01979)
163                      "response header line too long from OCSP server");
164        return NULL;
165    }
166
167    line[len-1] = '\0';
168    if (len > 1 && line[len-2] == APR_ASCII_CR) {
169        line[len-2] = '\0';
170    }
171
172    return line;
173}
174
175/* Maximum values to prevent eating RAM forever. */
176#define MAX_HEADERS (256)
177#define MAX_CONTENT (2048 * 1024)
178
179/* Read the OCSP response from the socket 'sd', using temporary memory
180 * BIO 'bio', and return the decoded OCSP response object, or NULL on
181 * error. */
182static OCSP_RESPONSE *read_response(apr_socket_t *sd, BIO *bio, conn_rec *c,
183                                    apr_pool_t *p)
184{
185    apr_bucket_brigade *bb, *tmpbb;
186    OCSP_RESPONSE *response;
187    char *line;
188    apr_size_t count;
189    apr_int64_t code;
190
191    /* Using brigades for response parsing is much simpler than using
192     * apr_socket_* directly. */
193    bb = apr_brigade_create(p, c->bucket_alloc);
194    tmpbb = apr_brigade_create(p, c->bucket_alloc);
195    APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_socket_create(sd, c->bucket_alloc));
196
197    line = get_line(tmpbb, bb, c, p);
198    if (!line || strncmp(line, "HTTP/", 5)
199        || (line = ap_strchr(line, ' ')) == NULL
200        || (code = apr_atoi64(++line)) < 200 || code > 299) {
201        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(01980)
202                      "bad response from OCSP server: %s",
203                      line ? line : "(none)");
204        return NULL;
205    }
206
207    /* Read till end of headers; don't have to even bother parsing the
208     * Content-Length since the server is obliged to close the
209     * connection after the response anyway for HTTP/1.0. */
210    count = 0;
211    while ((line = get_line(tmpbb, bb, c, p)) != NULL && line[0]
212           && ++count < MAX_HEADERS) {
213        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(01981)
214                      "OCSP response header: %s", line);
215    }
216
217    if (count == MAX_HEADERS) {
218        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(01982)
219                      "could not read response headers from OCSP server, "
220                      "exceeded maximum count (%u)", MAX_HEADERS);
221        return NULL;
222    }
223    else if (!line) {
224        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(01983)
225                      "could not read response header from OCSP server");
226        return NULL;
227    }
228
229    /* Read the response body into the memory BIO. */
230    count = 0;
231    while (!APR_BRIGADE_EMPTY(bb)) {
232        const char *data;
233        apr_size_t len;
234        apr_status_t rv;
235        apr_bucket *e = APR_BRIGADE_FIRST(bb);
236
237        rv = apr_bucket_read(e, &data, &len, APR_BLOCK_READ);
238        if (rv == APR_EOF) {
239            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(01984)
240                          "OCSP response: got EOF");
241            break;
242        }
243        if (rv != APR_SUCCESS) {
244            ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(01985)
245                          "error reading response from OCSP server");
246            return NULL;
247        }
248        if (len == 0) {
249            /* Ignore zero-length buckets (possible side-effect of
250             * line splitting). */
251            apr_bucket_delete(e);
252            continue;
253        }
254        count += len;
255        if (count > MAX_CONTENT) {
256            ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(01986)
257                          "OCSP response size exceeds %u byte limit",
258                          MAX_CONTENT);
259            return NULL;
260        }
261        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(01987)
262                      "OCSP response: got %" APR_SIZE_T_FMT
263                      " bytes, %" APR_SIZE_T_FMT " total", len, count);
264
265        BIO_write(bio, data, (int)len);
266        apr_bucket_delete(e);
267    }
268
269    apr_brigade_destroy(bb);
270    apr_brigade_destroy(tmpbb);
271
272    /* Finally decode the OCSP response from what's stored in the
273     * bio. */
274    response = d2i_OCSP_RESPONSE_bio(bio, NULL);
275    if (response == NULL) {
276        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(01988)
277                      "failed to decode OCSP response data");
278        ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, mySrvFromConn(c));
279    }
280
281    return response;
282}
283
284OCSP_RESPONSE *modssl_dispatch_ocsp_request(const apr_uri_t *uri,
285                                            apr_interval_time_t timeout,
286                                            OCSP_REQUEST *request,
287                                            conn_rec *c, apr_pool_t *p)
288{
289    OCSP_RESPONSE *response = NULL;
290    apr_socket_t *sd;
291    BIO *bio;
292
293    bio = serialize_request(request, uri);
294    if (bio == NULL) {
295        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(01989)
296                      "could not serialize OCSP request");
297        ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, mySrvFromConn(c));
298        return NULL;
299    }
300
301    sd = send_request(bio, uri, timeout, c, p);
302    if (sd == NULL) {
303        /* Errors already logged. */
304        BIO_free(bio);
305        return NULL;
306    }
307
308    /* Clear the BIO contents, ready for the response. */
309    (void)BIO_reset(bio);
310
311    response = read_response(sd, bio, c, p);
312
313    apr_socket_close(sd);
314    BIO_free(bio);
315
316    return response;
317}
318
319#endif /* HAVE_OCSP */
320