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