]> granicus.if.org Git - apache/blob - modules/ssl/ssl_util_ocsp.c
Add lots of unique tags to error log messages
[apache] / modules / ssl / ssl_util_ocsp.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 /* 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. */
30 static 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. */
59 static 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         apr_socket_close(sd);
100         return NULL;
101     }
102
103     /* send the request and get a response */
104     ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(01975)
105                  "sending request to OCSP responder");
106
107     while ((len = BIO_read(request, buf, sizeof buf)) > 0) {
108         char *wbuf = buf;
109         apr_size_t remain = len;
110
111         do {
112             apr_size_t wlen = remain;
113
114             rv = apr_socket_send(sd, wbuf, &wlen);
115             wbuf += remain;
116             remain -= wlen;
117         } while (rv == APR_SUCCESS && remain > 0);
118
119         if (rv) {
120             apr_socket_close(sd);
121             ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(01976)
122                           "failed to send request to OCSP responder '%s'",
123                           uri->hostinfo);
124             return NULL;
125         }
126     }
127
128     return sd;
129 }
130
131 /* Return a pool-allocated NUL-terminated line, with CRLF stripped,
132  * read from brigade 'bbin' using 'bbout' as temporary storage. */
133 static char *get_line(apr_bucket_brigade *bbout, apr_bucket_brigade *bbin,
134                       conn_rec *c, apr_pool_t *p)
135 {
136     apr_status_t rv;
137     apr_size_t len;
138     char *line;
139
140     apr_brigade_cleanup(bbout);
141
142     rv = apr_brigade_split_line(bbout, bbin, APR_BLOCK_READ, 8192);
143     if (rv) {
144         ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(01977)
145                       "failed reading line from OCSP server");
146         return NULL;
147     }
148
149     rv = apr_brigade_pflatten(bbout, &line, &len, p);
150     if (rv) {
151         ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(01978)
152                       "failed reading line from OCSP server");
153         return NULL;
154     }
155
156     if (len && line[len-1] != APR_ASCII_LF) {
157         ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(01979)
158                       "response header line too long from OCSP server");
159         return NULL;
160     }
161
162     line[len-1] = '\0';
163     if (len > 1 && line[len-2] == APR_ASCII_CR) {
164         line[len-2] = '\0';
165     }
166
167     return line;
168 }
169
170 /* Maximum values to prevent eating RAM forever. */
171 #define MAX_HEADERS (256)
172 #define MAX_CONTENT (2048 * 1024)
173
174 /* Read the OCSP response from the socket 'sd', using temporary memory
175  * BIO 'bio', and return the decoded OCSP response object, or NULL on
176  * error. */
177 static OCSP_RESPONSE *read_response(apr_socket_t *sd, BIO *bio, conn_rec *c,
178                                     apr_pool_t *p)
179 {
180     apr_bucket_brigade *bb, *tmpbb;
181     OCSP_RESPONSE *response;
182     char *line;
183     apr_size_t count;
184     apr_int64_t code;
185
186     /* Using brigades for response parsing is much simpler than using
187      * apr_socket_* directly. */
188     bb = apr_brigade_create(p, c->bucket_alloc);
189     tmpbb = apr_brigade_create(p, c->bucket_alloc);
190     APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_socket_create(sd, c->bucket_alloc));
191
192     line = get_line(tmpbb, bb, c, p);
193     if (!line || strncmp(line, "HTTP/", 5)
194         || (line = ap_strchr(line, ' ')) == NULL
195         || (code = apr_atoi64(++line)) < 200 || code > 299) {
196         ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(01980)
197                       "bad response from OCSP server: %s",
198                       line ? line : "(none)");
199         return NULL;
200     }
201
202     /* Read till end of headers; don't have to even bother parsing the
203      * Content-Length since the server is obliged to close the
204      * connection after the response anyway for HTTP/1.0. */
205     count = 0;
206     while ((line = get_line(tmpbb, bb, c, p)) != NULL && line[0]
207            && ++count < MAX_HEADERS) {
208         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(01981)
209                       "OCSP response header: %s", line);
210     }
211
212     if (count == MAX_HEADERS) {
213         ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(01982)
214                       "could not read response headers from OCSP server, "
215                       "exceeded maximum count (%u)", MAX_HEADERS);
216         return NULL;
217     }
218     else if (!line) {
219         ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(01983)
220                       "could not read response header from OCSP server");
221         return NULL;
222     }
223
224     /* Read the response body into the memory BIO. */
225     count = 0;
226     while (!APR_BRIGADE_EMPTY(bb)) {
227         const char *data;
228         apr_size_t len;
229         apr_status_t rv;
230         apr_bucket *e = APR_BRIGADE_FIRST(bb);
231
232         rv = apr_bucket_read(e, &data, &len, APR_BLOCK_READ);
233         if (rv == APR_EOF || (rv == APR_SUCCESS && len == 0)) {
234             ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(01984)
235                           "OCSP response: got EOF");
236             break;
237         }
238         if (rv != APR_SUCCESS) {
239             ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(01985)
240                           "error reading response from OCSP server");
241             return NULL;
242         }
243         count += len;
244         if (count > MAX_CONTENT) {
245             ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(01986)
246                           "OCSP response size exceeds %u byte limit",
247                           MAX_CONTENT);
248             return NULL;
249         }
250         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(01987)
251                       "OCSP response: got %" APR_SIZE_T_FMT
252                       " bytes, %" APR_SIZE_T_FMT " total", len, count);
253
254         BIO_write(bio, data, (int)len);
255         apr_bucket_delete(e);
256     }
257
258     apr_brigade_destroy(bb);
259     apr_brigade_destroy(tmpbb);
260
261     /* Finally decode the OCSP response from what's stored in the
262      * bio. */
263     response = d2i_OCSP_RESPONSE_bio(bio, NULL);
264     if (response == NULL) {
265         ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, mySrvFromConn(c));
266         ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(01988)
267                       "failed to decode OCSP response data");
268     }
269
270     return response;
271 }
272
273 OCSP_RESPONSE *modssl_dispatch_ocsp_request(const apr_uri_t *uri,
274                                             apr_interval_time_t timeout,
275                                             OCSP_REQUEST *request,
276                                             conn_rec *c, apr_pool_t *p)
277 {
278     OCSP_RESPONSE *response = NULL;
279     apr_socket_t *sd;
280     BIO *bio;
281
282     bio = serialize_request(request, uri);
283     if (bio == NULL) {
284         ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, mySrvFromConn(c));
285         ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(01989)
286                       "could not serialize OCSP request");
287         return NULL;
288     }
289
290     sd = send_request(bio, uri, timeout, c, p);
291     if (sd == NULL) {
292         /* Errors already logged. */
293         BIO_free(bio);
294         return NULL;
295     }
296
297     /* Clear the BIO contents, ready for the response. */
298     (void)BIO_reset(bio);
299
300     response = read_response(sd, bio, c, p);
301
302     apr_socket_close(sd);
303     BIO_free(bio);
304
305     return response;
306 }
307
308 #endif /* HAVE_OCSP */