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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
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. */
21 #include "ssl_private.h"
23 #ifndef OPENSSL_NO_OCSP
25 #include "apr_buckets.h"
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)
35 len = i2d_OCSP_REQUEST(req, NULL);
37 bio = BIO_new(BIO_s_mem());
39 BIO_printf(bio, "POST %s%s%s HTTP/1.0\r\n"
41 "Content-Type: application/ocsp-request\r\n"
42 "Content-Length: %d\r\n"
44 uri->path ? uri->path : "/",
45 uri->query ? "?" : "", uri->query ? uri->query : "",
46 uri->hostname, uri->port, len);
48 if (i2d_OCSP_REQUEST_bio(bio, req) != 1) {
56 /* Send the OCSP request serialized into BIO 'request' to the
57 * responder at given server given by URI. Returns socket object or
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)
66 char buf[HUGE_STRING_LEN];
69 rv = apr_sockaddr_info_get(&sa, uri->hostname, APR_UNSPEC, uri->port, 0, p);
71 ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c,
72 "could not resolve address of OCSP responder %s",
77 /* establish a connection to the OCSP responder */
78 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
79 "connecting to OCSP responder '%s'", uri->hostinfo);
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);
87 rv = apr_socket_connect(sd, sa);
88 if (rv == APR_SUCCESS) {
96 ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c,
97 "could not connect to OCSP responder '%s'",
103 /* send the request and get a response */
104 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
105 "sending request to OCSP responder");
107 while ((len = BIO_read(request, buf, sizeof buf)) > 0) {
109 apr_size_t remain = len;
112 apr_size_t wlen = remain;
114 rv = apr_socket_send(sd, wbuf, &wlen);
117 } while (rv == APR_SUCCESS && remain > 0);
120 apr_socket_close(sd);
121 ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c,
122 "failed to send request to OCSP responder '%s'",
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)
140 apr_brigade_cleanup(bbout);
142 rv = apr_brigade_split_line(bbout, bbin, APR_BLOCK_READ, 8192);
144 ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c,
145 "failed reading line from OCSP server");
149 rv = apr_brigade_pflatten(bbout, &line, &len, p);
151 ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c,
152 "failed reading line from OCSP server");
156 if (len && line[len-1] != APR_ASCII_LF) {
157 ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c,
158 "response header line too long from OCSP server");
163 if (len > 1 && line[len-2] == APR_ASCII_CR) {
170 /* Maximum values to prevent eating RAM forever. */
171 #define MAX_HEADERS (256)
172 #define MAX_CONTENT (2048 * 1024)
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
177 static OCSP_RESPONSE *read_response(apr_socket_t *sd, BIO *bio, conn_rec *c,
180 apr_bucket_brigade *bb, *tmpbb;
181 OCSP_RESPONSE *response;
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));
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,
197 "bad response from OCSP server: %s",
198 line ? line : "(none)");
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. */
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,
209 "OCSP response header: %s", line);
212 if (count == MAX_HEADERS) {
213 ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c,
214 "could not read response headers from OCSP server, "
215 "exceeded maximum count (%u)", MAX_HEADERS);
219 ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c,
220 "could not read response header from OCSP server");
224 /* Read the response body into the memory BIO. */
226 while (!APR_BRIGADE_EMPTY(bb)) {
230 apr_bucket *e = APR_BRIGADE_FIRST(bb);
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,
235 "OCSP response: got EOF");
238 if (rv != APR_SUCCESS) {
239 ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c,
240 "error reading response from OCSP server");
244 if (count > MAX_CONTENT) {
245 ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c,
246 "OCSP response size exceeds %u byte limit",
250 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
251 "OCSP response: got %" APR_SIZE_T_FMT
252 " bytes, %" APR_SIZE_T_FMT " total", len, count);
254 BIO_write(bio, data, (int)len);
255 apr_bucket_delete(e);
258 apr_brigade_destroy(bb);
259 apr_brigade_destroy(tmpbb);
261 /* Finally decode the OCSP response from what's stored in the
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,
267 "failed to decode OCSP response data");
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)
278 OCSP_RESPONSE *response = NULL;
282 bio = serialize_request(request, uri);
284 ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, mySrvFromConn(c));
285 ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c,
286 "could not serialize OCSP request");
290 sd = send_request(bio, uri, timeout, c, p);
292 /* Errors already logged. */
297 /* Clear the BIO contents, ready for the response. */
298 (void)BIO_reset(bio);
300 response = read_response(sd, bio, c, p);
302 apr_socket_close(sd);
308 #endif /* HAVE_OCSP */