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