1/* ocsp_ht.c */ 2/* 3 * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project 4 * 2006. 5 */ 6/* ==================================================================== 7 * Copyright (c) 2006 The OpenSSL Project. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * 21 * 3. All advertising materials mentioning features or use of this 22 * software must display the following acknowledgment: 23 * "This product includes software developed by the OpenSSL Project 24 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 25 * 26 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 27 * endorse or promote products derived from this software without 28 * prior written permission. For written permission, please contact 29 * licensing@OpenSSL.org. 30 * 31 * 5. Products derived from this software may not be called "OpenSSL" 32 * nor may "OpenSSL" appear in their names without prior written 33 * permission of the OpenSSL Project. 34 * 35 * 6. Redistributions of any form whatsoever must retain the following 36 * acknowledgment: 37 * "This product includes software developed by the OpenSSL Project 38 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 39 * 40 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 41 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 43 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 44 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 47 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 49 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 51 * OF THE POSSIBILITY OF SUCH DAMAGE. 52 * ==================================================================== 53 * 54 * This product includes cryptographic software written by Eric Young 55 * (eay@cryptsoft.com). This product includes software written by Tim 56 * Hudson (tjh@cryptsoft.com). 57 * 58 */ 59 60#include <stdio.h> 61#include <stdlib.h> 62#include <ctype.h> 63#include <string.h> 64#include "e_os.h" 65#include <openssl/asn1.h> 66#include <openssl/ocsp.h> 67#include <openssl/err.h> 68#include <openssl/buffer.h> 69#ifdef OPENSSL_SYS_SUNOS 70# define strtoul (unsigned long)strtol 71#endif /* OPENSSL_SYS_SUNOS */ 72 73/* Stateful OCSP request code, supporting non-blocking I/O */ 74 75/* Opaque OCSP request status structure */ 76 77struct ocsp_req_ctx_st { 78 int state; /* Current I/O state */ 79 unsigned char *iobuf; /* Line buffer */ 80 int iobuflen; /* Line buffer length */ 81 BIO *io; /* BIO to perform I/O with */ 82 BIO *mem; /* Memory BIO response is built into */ 83 unsigned long asn1_len; /* ASN1 length of response */ 84 unsigned long max_resp_len; /* Maximum length of response */ 85}; 86 87#define OCSP_MAX_RESP_LENGTH (100 * 1024) 88#define OCSP_MAX_LINE_LEN 4096; 89 90/* OCSP states */ 91 92/* If set no reading should be performed */ 93#define OHS_NOREAD 0x1000 94/* Error condition */ 95#define OHS_ERROR (0 | OHS_NOREAD) 96/* First line being read */ 97#define OHS_FIRSTLINE 1 98/* MIME headers being read */ 99#define OHS_HEADERS 2 100/* OCSP initial header (tag + length) being read */ 101#define OHS_ASN1_HEADER 3 102/* OCSP content octets being read */ 103#define OHS_ASN1_CONTENT 4 104/* First call: ready to start I/O */ 105#define OHS_ASN1_WRITE_INIT (5 | OHS_NOREAD) 106/* Request being sent */ 107#define OHS_ASN1_WRITE (6 | OHS_NOREAD) 108/* Request being flushed */ 109#define OHS_ASN1_FLUSH (7 | OHS_NOREAD) 110/* Completed */ 111#define OHS_DONE (8 | OHS_NOREAD) 112/* Headers set, no final \r\n included */ 113#define OHS_HTTP_HEADER (9 | OHS_NOREAD) 114 115static int parse_http_line1(char *line); 116 117OCSP_REQ_CTX *OCSP_REQ_CTX_new(BIO *io, int maxline) 118{ 119 OCSP_REQ_CTX *rctx; 120 rctx = OPENSSL_malloc(sizeof(OCSP_REQ_CTX)); 121 if (!rctx) 122 return NULL; 123 rctx->state = OHS_ERROR; 124 rctx->max_resp_len = OCSP_MAX_RESP_LENGTH; 125 rctx->mem = BIO_new(BIO_s_mem()); 126 rctx->io = io; 127 rctx->asn1_len = 0; 128 if (maxline > 0) 129 rctx->iobuflen = maxline; 130 else 131 rctx->iobuflen = OCSP_MAX_LINE_LEN; 132 rctx->iobuf = OPENSSL_malloc(rctx->iobuflen); 133 if (!rctx->iobuf || !rctx->mem) { 134 OCSP_REQ_CTX_free(rctx); 135 return NULL; 136 } 137 return rctx; 138} 139 140void OCSP_REQ_CTX_free(OCSP_REQ_CTX *rctx) 141{ 142 if (rctx->mem) 143 BIO_free(rctx->mem); 144 if (rctx->iobuf) 145 OPENSSL_free(rctx->iobuf); 146 OPENSSL_free(rctx); 147} 148 149BIO *OCSP_REQ_CTX_get0_mem_bio(OCSP_REQ_CTX *rctx) 150{ 151 return rctx->mem; 152} 153 154void OCSP_set_max_response_length(OCSP_REQ_CTX *rctx, unsigned long len) 155{ 156 if (len == 0) 157 rctx->max_resp_len = OCSP_MAX_RESP_LENGTH; 158 else 159 rctx->max_resp_len = len; 160} 161 162int OCSP_REQ_CTX_i2d(OCSP_REQ_CTX *rctx, const ASN1_ITEM *it, ASN1_VALUE *val) 163{ 164 static const char req_hdr[] = 165 "Content-Type: application/ocsp-request\r\n" 166 "Content-Length: %d\r\n\r\n"; 167 int reqlen = ASN1_item_i2d(val, NULL, it); 168 if (BIO_printf(rctx->mem, req_hdr, reqlen) <= 0) 169 return 0; 170 if (ASN1_item_i2d_bio(it, rctx->mem, val) <= 0) 171 return 0; 172 rctx->state = OHS_ASN1_WRITE_INIT; 173 return 1; 174} 175 176int OCSP_REQ_CTX_nbio_d2i(OCSP_REQ_CTX *rctx, 177 ASN1_VALUE **pval, const ASN1_ITEM *it) 178{ 179 int rv, len; 180 const unsigned char *p; 181 182 rv = OCSP_REQ_CTX_nbio(rctx); 183 if (rv != 1) 184 return rv; 185 186 len = BIO_get_mem_data(rctx->mem, &p); 187 *pval = ASN1_item_d2i(NULL, &p, len, it); 188 if (*pval == NULL) { 189 rctx->state = OHS_ERROR; 190 return 0; 191 } 192 return 1; 193} 194 195int OCSP_REQ_CTX_http(OCSP_REQ_CTX *rctx, const char *op, const char *path) 196{ 197 static const char http_hdr[] = "%s %s HTTP/1.0\r\n"; 198 199 if (!path) 200 path = "/"; 201 202 if (BIO_printf(rctx->mem, http_hdr, op, path) <= 0) 203 return 0; 204 rctx->state = OHS_HTTP_HEADER; 205 return 1; 206} 207 208int OCSP_REQ_CTX_set1_req(OCSP_REQ_CTX *rctx, OCSP_REQUEST *req) 209{ 210 return OCSP_REQ_CTX_i2d(rctx, ASN1_ITEM_rptr(OCSP_REQUEST), 211 (ASN1_VALUE *)req); 212} 213 214int OCSP_REQ_CTX_add1_header(OCSP_REQ_CTX *rctx, 215 const char *name, const char *value) 216{ 217 if (!name) 218 return 0; 219 if (BIO_puts(rctx->mem, name) <= 0) 220 return 0; 221 if (value) { 222 if (BIO_write(rctx->mem, ": ", 2) != 2) 223 return 0; 224 if (BIO_puts(rctx->mem, value) <= 0) 225 return 0; 226 } 227 if (BIO_write(rctx->mem, "\r\n", 2) != 2) 228 return 0; 229 rctx->state = OHS_HTTP_HEADER; 230 return 1; 231} 232 233OCSP_REQ_CTX *OCSP_sendreq_new(BIO *io, const char *path, OCSP_REQUEST *req, 234 int maxline) 235{ 236 237 OCSP_REQ_CTX *rctx = NULL; 238 rctx = OCSP_REQ_CTX_new(io, maxline); 239 if (!rctx) 240 return NULL; 241 242 if (!OCSP_REQ_CTX_http(rctx, "POST", path)) 243 goto err; 244 245 if (req && !OCSP_REQ_CTX_set1_req(rctx, req)) 246 goto err; 247 248 return rctx; 249 250 err: 251 OCSP_REQ_CTX_free(rctx); 252 return NULL; 253} 254 255/* 256 * Parse the HTTP response. This will look like this: "HTTP/1.0 200 OK". We 257 * need to obtain the numeric code and (optional) informational message. 258 */ 259 260static int parse_http_line1(char *line) 261{ 262 int retcode; 263 char *p, *q, *r; 264 /* Skip to first white space (passed protocol info) */ 265 266 for (p = line; *p && !isspace((unsigned char)*p); p++) 267 continue; 268 if (!*p) { 269 OCSPerr(OCSP_F_PARSE_HTTP_LINE1, OCSP_R_SERVER_RESPONSE_PARSE_ERROR); 270 return 0; 271 } 272 273 /* Skip past white space to start of response code */ 274 while (*p && isspace((unsigned char)*p)) 275 p++; 276 277 if (!*p) { 278 OCSPerr(OCSP_F_PARSE_HTTP_LINE1, OCSP_R_SERVER_RESPONSE_PARSE_ERROR); 279 return 0; 280 } 281 282 /* Find end of response code: first whitespace after start of code */ 283 for (q = p; *q && !isspace((unsigned char)*q); q++) 284 continue; 285 286 if (!*q) { 287 OCSPerr(OCSP_F_PARSE_HTTP_LINE1, OCSP_R_SERVER_RESPONSE_PARSE_ERROR); 288 return 0; 289 } 290 291 /* Set end of response code and start of message */ 292 *q++ = 0; 293 294 /* Attempt to parse numeric code */ 295 retcode = strtoul(p, &r, 10); 296 297 if (*r) 298 return 0; 299 300 /* Skip over any leading white space in message */ 301 while (*q && isspace((unsigned char)*q)) 302 q++; 303 304 if (*q) { 305 /* 306 * Finally zap any trailing white space in message (include CRLF) 307 */ 308 309 /* We know q has a non white space character so this is OK */ 310 for (r = q + strlen(q) - 1; isspace((unsigned char)*r); r--) 311 *r = 0; 312 } 313 if (retcode != 200) { 314 OCSPerr(OCSP_F_PARSE_HTTP_LINE1, OCSP_R_SERVER_RESPONSE_ERROR); 315 if (!*q) 316 ERR_add_error_data(2, "Code=", p); 317 else 318 ERR_add_error_data(4, "Code=", p, ",Reason=", q); 319 return 0; 320 } 321 322 return 1; 323 324} 325 326int OCSP_REQ_CTX_nbio(OCSP_REQ_CTX *rctx) 327{ 328 int i, n; 329 const unsigned char *p; 330 next_io: 331 if (!(rctx->state & OHS_NOREAD)) { 332 n = BIO_read(rctx->io, rctx->iobuf, rctx->iobuflen); 333 334 if (n <= 0) { 335 if (BIO_should_retry(rctx->io)) 336 return -1; 337 return 0; 338 } 339 340 /* Write data to memory BIO */ 341 342 if (BIO_write(rctx->mem, rctx->iobuf, n) != n) 343 return 0; 344 } 345 346 switch (rctx->state) { 347 case OHS_HTTP_HEADER: 348 /* Last operation was adding headers: need a final \r\n */ 349 if (BIO_write(rctx->mem, "\r\n", 2) != 2) { 350 rctx->state = OHS_ERROR; 351 return 0; 352 } 353 rctx->state = OHS_ASN1_WRITE_INIT; 354 355 case OHS_ASN1_WRITE_INIT: 356 rctx->asn1_len = BIO_get_mem_data(rctx->mem, NULL); 357 rctx->state = OHS_ASN1_WRITE; 358 359 case OHS_ASN1_WRITE: 360 n = BIO_get_mem_data(rctx->mem, &p); 361 362 i = BIO_write(rctx->io, p + (n - rctx->asn1_len), rctx->asn1_len); 363 364 if (i <= 0) { 365 if (BIO_should_retry(rctx->io)) 366 return -1; 367 rctx->state = OHS_ERROR; 368 return 0; 369 } 370 371 rctx->asn1_len -= i; 372 373 if (rctx->asn1_len > 0) 374 goto next_io; 375 376 rctx->state = OHS_ASN1_FLUSH; 377 378 (void)BIO_reset(rctx->mem); 379 380 case OHS_ASN1_FLUSH: 381 382 i = BIO_flush(rctx->io); 383 384 if (i > 0) { 385 rctx->state = OHS_FIRSTLINE; 386 goto next_io; 387 } 388 389 if (BIO_should_retry(rctx->io)) 390 return -1; 391 392 rctx->state = OHS_ERROR; 393 return 0; 394 395 case OHS_ERROR: 396 return 0; 397 398 case OHS_FIRSTLINE: 399 case OHS_HEADERS: 400 401 /* Attempt to read a line in */ 402 403 next_line: 404 /* 405 * Due to &%^*$" memory BIO behaviour with BIO_gets we have to check 406 * there's a complete line in there before calling BIO_gets or we'll 407 * just get a partial read. 408 */ 409 n = BIO_get_mem_data(rctx->mem, &p); 410 if ((n <= 0) || !memchr(p, '\n', n)) { 411 if (n >= rctx->iobuflen) { 412 rctx->state = OHS_ERROR; 413 return 0; 414 } 415 goto next_io; 416 } 417 n = BIO_gets(rctx->mem, (char *)rctx->iobuf, rctx->iobuflen); 418 419 if (n <= 0) { 420 if (BIO_should_retry(rctx->mem)) 421 goto next_io; 422 rctx->state = OHS_ERROR; 423 return 0; 424 } 425 426 /* Don't allow excessive lines */ 427 if (n == rctx->iobuflen) { 428 rctx->state = OHS_ERROR; 429 return 0; 430 } 431 432 /* First line */ 433 if (rctx->state == OHS_FIRSTLINE) { 434 if (parse_http_line1((char *)rctx->iobuf)) { 435 rctx->state = OHS_HEADERS; 436 goto next_line; 437 } else { 438 rctx->state = OHS_ERROR; 439 return 0; 440 } 441 } else { 442 /* Look for blank line: end of headers */ 443 for (p = rctx->iobuf; *p; p++) { 444 if ((*p != '\r') && (*p != '\n')) 445 break; 446 } 447 if (*p) 448 goto next_line; 449 450 rctx->state = OHS_ASN1_HEADER; 451 452 } 453 454 /* Fall thru */ 455 456 case OHS_ASN1_HEADER: 457 /* 458 * Now reading ASN1 header: can read at least 2 bytes which is enough 459 * for ASN1 SEQUENCE header and either length field or at least the 460 * length of the length field. 461 */ 462 n = BIO_get_mem_data(rctx->mem, &p); 463 if (n < 2) 464 goto next_io; 465 466 /* Check it is an ASN1 SEQUENCE */ 467 if (*p++ != (V_ASN1_SEQUENCE | V_ASN1_CONSTRUCTED)) { 468 rctx->state = OHS_ERROR; 469 return 0; 470 } 471 472 /* Check out length field */ 473 if (*p & 0x80) { 474 /* 475 * If MSB set on initial length octet we can now always read 6 476 * octets: make sure we have them. 477 */ 478 if (n < 6) 479 goto next_io; 480 n = *p & 0x7F; 481 /* Not NDEF or excessive length */ 482 if (!n || (n > 4)) { 483 rctx->state = OHS_ERROR; 484 return 0; 485 } 486 p++; 487 rctx->asn1_len = 0; 488 for (i = 0; i < n; i++) { 489 rctx->asn1_len <<= 8; 490 rctx->asn1_len |= *p++; 491 } 492 493 if (rctx->asn1_len > rctx->max_resp_len) { 494 rctx->state = OHS_ERROR; 495 return 0; 496 } 497 498 rctx->asn1_len += n + 2; 499 } else 500 rctx->asn1_len = *p + 2; 501 502 rctx->state = OHS_ASN1_CONTENT; 503 504 /* Fall thru */ 505 506 case OHS_ASN1_CONTENT: 507 n = BIO_get_mem_data(rctx->mem, NULL); 508 if (n < (int)rctx->asn1_len) 509 goto next_io; 510 511 rctx->state = OHS_DONE; 512 return 1; 513 514 break; 515 516 case OHS_DONE: 517 return 1; 518 519 } 520 521 return 0; 522 523} 524 525int OCSP_sendreq_nbio(OCSP_RESPONSE **presp, OCSP_REQ_CTX *rctx) 526{ 527 return OCSP_REQ_CTX_nbio_d2i(rctx, 528 (ASN1_VALUE **)presp, 529 ASN1_ITEM_rptr(OCSP_RESPONSE)); 530} 531 532/* Blocking OCSP request handler: now a special case of non-blocking I/O */ 533 534OCSP_RESPONSE *OCSP_sendreq_bio(BIO *b, const char *path, OCSP_REQUEST *req) 535{ 536 OCSP_RESPONSE *resp = NULL; 537 OCSP_REQ_CTX *ctx; 538 int rv; 539 540 ctx = OCSP_sendreq_new(b, path, req, -1); 541 542 if (!ctx) 543 return NULL; 544 545 do { 546 rv = OCSP_sendreq_nbio(&resp, ctx); 547 } while ((rv == -1) && BIO_should_retry(b)); 548 549 OCSP_REQ_CTX_free(ctx); 550 551 if (rv) 552 return resp; 553 554 return NULL; 555} 556