Generalise OCSP I/O functions to support dowloading of other ASN1
[openssl.git] / crypto / ocsp / ocsp_ht.c
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         unsigned long max_resp_len; /* Maximum length of response */
84         };
85
86 #define OCSP_MAX_RESP_LENGTH    (100 * 1024)
87 #define OCSP_MAX_LINE_LEN       4096;
88
89 /* OCSP states */
90
91 /* If set no reading should be performed */
92 #define OHS_NOREAD              0x1000
93 /* Error condition */
94 #define OHS_ERROR               (0 | OHS_NOREAD)
95 /* First line being read */
96 #define OHS_FIRSTLINE           1
97 /* MIME headers being read */
98 #define OHS_HEADERS             2
99 /* OCSP initial header (tag + length) being read */
100 #define OHS_ASN1_HEADER         3
101 /* OCSP content octets being read */
102 #define OHS_ASN1_CONTENT        4
103 /* First call: ready to start I/O */
104 #define OHS_ASN1_WRITE_INIT     (5 | OHS_NOREAD)
105 /* Request being sent */
106 #define OHS_ASN1_WRITE          (6 | OHS_NOREAD)
107 /* Request being flushed */
108 #define OHS_ASN1_FLUSH          (7 | OHS_NOREAD)
109 /* Completed */
110 #define OHS_DONE                (8 | OHS_NOREAD)
111 /* Headers set, no final \r\n included */
112 #define OHS_HTTP_HEADER         (9 | OHS_NOREAD)
113
114
115 static int parse_http_line1(char *line);
116
117 OCSP_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                 {
135                 OCSP_REQ_CTX_free(rctx);
136                 return NULL;
137                 }
138         return rctx;
139         }
140
141 void OCSP_REQ_CTX_free(OCSP_REQ_CTX *rctx)
142         {
143         if (rctx->mem)
144                 BIO_free(rctx->mem);
145         if (rctx->iobuf)
146                 OPENSSL_free(rctx->iobuf);
147         OPENSSL_free(rctx);
148         }
149
150 BIO *OCSP_REQ_CTX_get0_mem_bio(OCSP_REQ_CTX *rctx)
151         {
152         return rctx->mem;
153         }
154
155 void OCSP_set_max_response_length(OCSP_REQ_CTX *rctx, unsigned long len)
156         {
157         if (len == 0)
158                 rctx->max_resp_len = OCSP_MAX_RESP_LENGTH;
159         else
160                 rctx->max_resp_len = len;
161         }
162
163 int OCSP_REQ_CTX_i2d(OCSP_REQ_CTX *rctx, const ASN1_ITEM *it, ASN1_VALUE *val)
164         {
165         static const char req_hdr[] =
166                         "Content-Type: application/ocsp-request\r\n"
167                         "Content-Length: %d\r\n\r\n";
168         int reqlen = ASN1_item_i2d(val, NULL, it);
169         if (BIO_printf(rctx->mem, req_hdr, reqlen) <= 0)
170                 return 0;
171         if (ASN1_item_i2d_bio(it, rctx->mem, val) <= 0)
172                 return 0;
173         rctx->state = OHS_ASN1_WRITE_INIT;
174         return 1;
175         }
176
177 int OCSP_REQ_CTX_nbio_d2i(OCSP_REQ_CTX *rctx,
178                                         ASN1_VALUE **pval, const ASN1_ITEM *it)
179         {
180         int rv, len;
181         const unsigned char *p;
182
183         rv = OCSP_REQ_CTX_nbio(rctx);
184         if (rv != 1)
185                 return rv;
186
187         len = BIO_get_mem_data(rctx->mem, &p);
188         *pval = ASN1_item_d2i(NULL, &p, len, it);
189         if (*pval == NULL)
190                 {
191                 rctx->state = OHS_ERROR;
192                 return 0;
193                 }
194         return 1;
195         }
196
197 int OCSP_REQ_CTX_http(OCSP_REQ_CTX *rctx, const char *op, const char *path)
198         {
199         static const char http_hdr[] = "%s %s HTTP/1.0\r\n";
200
201         if (!path)
202                 path = "/";
203
204         if (BIO_printf(rctx->mem, http_hdr, op, path) <= 0)
205                 return 0;
206         rctx->state = OHS_HTTP_HEADER;
207         return 1;
208         }
209
210 int OCSP_REQ_CTX_set1_req(OCSP_REQ_CTX *rctx, OCSP_REQUEST *req)
211         {
212         return OCSP_REQ_CTX_i2d(rctx, ASN1_ITEM_rptr(OCSP_REQUEST),
213                                                         (ASN1_VALUE *)req);
214         }
215
216 int OCSP_REQ_CTX_add1_header(OCSP_REQ_CTX *rctx,
217                 const char *name, const char *value)
218         {
219         if (!name)
220                 return 0;
221         if (BIO_puts(rctx->mem, name) <= 0)
222                 return 0;
223         if (value)
224                 {
225                 if (BIO_write(rctx->mem, ": ", 2) != 2)
226                         return 0;
227                 if (BIO_puts(rctx->mem, value) <= 0)
228                         return 0;
229                 }
230         if (BIO_write(rctx->mem, "\r\n", 2) != 2)
231                 return 0;
232         rctx->state = OHS_HTTP_HEADER;
233         return 1;
234         }
235
236 OCSP_REQ_CTX *OCSP_sendreq_new(BIO *io, char *path, OCSP_REQUEST *req,
237                                                                 int maxline)
238         {
239
240         OCSP_REQ_CTX *rctx = NULL;
241         rctx = OCSP_REQ_CTX_new(io, maxline);
242         if (!rctx)
243                 return NULL;
244
245         if (!OCSP_REQ_CTX_http(rctx, "POST", path))
246                 goto err;
247
248         if (req && !OCSP_REQ_CTX_set1_req(rctx, req))
249                 goto err;
250
251         return rctx;
252         
253         err:
254         OCSP_REQ_CTX_free(rctx);
255         return NULL;
256         }
257
258 /* Parse the HTTP response. This will look like this:
259  * "HTTP/1.0 200 OK". We need to obtain the numeric code and
260  * (optional) informational message.
261  */
262
263 static int parse_http_line1(char *line)
264         {
265         int retcode;
266         char *p, *q, *r;
267         /* Skip to first white space (passed protocol info) */
268
269         for(p = line; *p && !isspace((unsigned char)*p); p++)
270                 continue;
271         if(!*p)
272                 {
273                 OCSPerr(OCSP_F_PARSE_HTTP_LINE1,
274                                         OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
275                 return 0;
276                 }
277
278         /* Skip past white space to start of response code */
279         while(*p && isspace((unsigned char)*p))
280                 p++;
281
282         if(!*p)
283                 {
284                 OCSPerr(OCSP_F_PARSE_HTTP_LINE1,
285                                         OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
286                 return 0;
287                 }
288
289         /* Find end of response code: first whitespace after start of code */
290         for(q = p; *q && !isspace((unsigned char)*q); q++)
291                 continue;
292
293         if(!*q)
294                 {
295                 OCSPerr(OCSP_F_PARSE_HTTP_LINE1,
296                                         OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
297                 return 0;
298                 }
299
300         /* Set end of response code and start of message */ 
301         *q++ = 0;
302
303         /* Attempt to parse numeric code */
304         retcode = strtoul(p, &r, 10);
305
306         if(*r)
307                 return 0;
308
309         /* Skip over any leading white space in message */
310         while(*q && isspace((unsigned char)*q))
311                 q++;
312
313         if(*q)
314                 {
315                 /* Finally zap any trailing white space in message (include
316                  * CRLF) */
317
318                 /* We know q has a non white space character so this is OK */
319                 for(r = q + strlen(q) - 1; isspace((unsigned char)*r); r--)
320                         *r = 0;
321                 }
322         if(retcode != 200)
323                 {
324                 OCSPerr(OCSP_F_PARSE_HTTP_LINE1, OCSP_R_SERVER_RESPONSE_ERROR);
325                 if(!*q)
326                         ERR_add_error_data(2, "Code=", p);
327                 else
328                         ERR_add_error_data(4, "Code=", p, ",Reason=", q);
329                 return 0;
330                 }
331
332
333         return 1;
334
335         }
336
337 int OCSP_REQ_CTX_nbio(OCSP_REQ_CTX *rctx)
338         {
339         int i, n;
340         const unsigned char *p;
341         next_io:
342         if (!(rctx->state & OHS_NOREAD))
343                 {
344                 n = BIO_read(rctx->io, rctx->iobuf, rctx->iobuflen);
345
346                 if (n <= 0)
347                         {
348                         if (BIO_should_retry(rctx->io))
349                                 return -1;
350                         return 0;
351                         }
352
353                 /* Write data to memory BIO */
354
355                 if (BIO_write(rctx->mem, rctx->iobuf, n) != n)
356                         return 0;
357                 }
358
359         switch(rctx->state)
360                 {
361                 case OHS_HTTP_HEADER:
362                 /* Last operation was adding headers: need a final \r\n */
363                 if (BIO_write(rctx->mem, "\r\n", 2) != 2)
364                         {
365                         rctx->state = OHS_ERROR;
366                         return 0;
367                         }
368                 rctx->state = OHS_ASN1_WRITE_INIT;
369
370                 case OHS_ASN1_WRITE_INIT:
371                 rctx->asn1_len = BIO_get_mem_data(rctx->mem, NULL);
372                 rctx->state = OHS_ASN1_WRITE;
373
374                 case OHS_ASN1_WRITE:
375                 n = BIO_get_mem_data(rctx->mem, &p);
376
377                 i = BIO_write(rctx->io,
378                         p + (n - rctx->asn1_len), rctx->asn1_len);
379
380                 if (i <= 0)
381                         {
382                         if (BIO_should_retry(rctx->io))
383                                 return -1;
384                         rctx->state = OHS_ERROR;
385                         return 0;
386                         }
387
388                 rctx->asn1_len -= i;
389
390                 if (rctx->asn1_len > 0)
391                         goto next_io;
392
393                 rctx->state = OHS_ASN1_FLUSH;
394
395                 (void)BIO_reset(rctx->mem);
396
397                 case OHS_ASN1_FLUSH:
398
399                 i = BIO_flush(rctx->io);
400
401                 if (i > 0)
402                         {
403                         rctx->state = OHS_FIRSTLINE;
404                         goto next_io;
405                         }
406
407                 if (BIO_should_retry(rctx->io))
408                         return -1;
409
410                 rctx->state = OHS_ERROR;
411                 return 0;
412
413                 case OHS_ERROR:
414                 return 0;
415
416                 case OHS_FIRSTLINE:
417                 case OHS_HEADERS:
418
419                 /* Attempt to read a line in */
420
421                 next_line:
422                 /* Due to &%^*$" memory BIO behaviour with BIO_gets we
423                  * have to check there's a complete line in there before
424                  * calling BIO_gets or we'll just get a partial read.
425                  */
426                 n = BIO_get_mem_data(rctx->mem, &p);
427                 if ((n <= 0) || !memchr(p, '\n', n))
428                         {
429                         if (n >= rctx->iobuflen)
430                                 {
431                                 rctx->state = OHS_ERROR;
432                                 return 0;
433                                 }
434                         goto next_io;
435                         }
436                 n = BIO_gets(rctx->mem, (char *)rctx->iobuf, rctx->iobuflen);
437
438                 if (n <= 0)
439                         {
440                         if (BIO_should_retry(rctx->mem))
441                                 goto next_io;
442                         rctx->state = OHS_ERROR;
443                         return 0;
444                         }
445
446                 /* Don't allow excessive lines */
447                 if (n == rctx->iobuflen)
448                         {
449                         rctx->state = OHS_ERROR;
450                         return 0;
451                         }
452
453                 /* First line */
454                 if (rctx->state == OHS_FIRSTLINE)
455                         {
456                         if (parse_http_line1((char *)rctx->iobuf))
457                                 {
458                                 rctx->state = OHS_HEADERS;
459                                 goto next_line;
460                                 }
461                         else
462                                 {
463                                 rctx->state = OHS_ERROR;
464                                 return 0;
465                                 }
466                         }
467                 else
468                         {
469                         /* Look for blank line: end of headers */
470                         for (p = rctx->iobuf; *p; p++)
471                                 {
472                                 if ((*p != '\r') && (*p != '\n'))
473                                         break;
474                                 }
475                         if (*p)
476                                 goto next_line;
477
478                         rctx->state = OHS_ASN1_HEADER;
479
480                         }
481  
482                 /* Fall thru */
483
484
485                 case OHS_ASN1_HEADER:
486                 /* Now reading ASN1 header: can read at least 2 bytes which
487                  * is enough for ASN1 SEQUENCE header and either length field
488                  * or at least the length of the length field.
489                  */
490                 n = BIO_get_mem_data(rctx->mem, &p);
491                 if (n < 2)
492                         goto next_io;
493
494                 /* Check it is an ASN1 SEQUENCE */
495                 if (*p++ != (V_ASN1_SEQUENCE|V_ASN1_CONSTRUCTED))
496                         {
497                         rctx->state = OHS_ERROR;
498                         return 0;
499                         }
500
501                 /* Check out length field */
502                 if (*p & 0x80)
503                         {
504                         /* If MSB set on initial length octet we can now
505                          * always read 6 octets: make sure we have them.
506                          */
507                         if (n < 6)
508                                 goto next_io;
509                         n = *p & 0x7F;
510                         /* Not NDEF or excessive length */
511                         if (!n || (n > 4))
512                                 {
513                                 rctx->state = OHS_ERROR;
514                                 return 0;
515                                 }
516                         p++;
517                         rctx->asn1_len = 0;
518                         for (i = 0; i < n; i++)
519                                 {
520                                 rctx->asn1_len <<= 8;
521                                 rctx->asn1_len |= *p++;
522                                 }
523
524                         if (rctx->asn1_len > rctx->max_resp_len)
525                                 {
526                                 rctx->state = OHS_ERROR;
527                                 return 0;
528                                 }
529
530                         rctx->asn1_len += n + 2;
531                         }
532                 else
533                         rctx->asn1_len = *p + 2;
534
535                 rctx->state = OHS_ASN1_CONTENT;
536
537                 /* Fall thru */
538                 
539                 case OHS_ASN1_CONTENT:
540                 n = BIO_get_mem_data(rctx->mem, NULL);
541                 if (n < (int)rctx->asn1_len)
542                         goto next_io;
543
544                 rctx->state = OHS_DONE;
545                 return 1;
546
547                 break;
548
549                 case OHS_DONE:
550                 return 1;
551
552                 }
553
554         return 0;
555
556         }
557
558 int OCSP_sendreq_nbio(OCSP_RESPONSE **presp, OCSP_REQ_CTX *rctx)
559         {
560         return OCSP_REQ_CTX_nbio_d2i(rctx,
561                         (ASN1_VALUE **)presp, ASN1_ITEM_rptr(OCSP_RESPONSE));
562         }
563
564 /* Blocking OCSP request handler: now a special case of non-blocking I/O */
565
566 OCSP_RESPONSE *OCSP_sendreq_bio(BIO *b, char *path, OCSP_REQUEST *req)
567         {
568         OCSP_RESPONSE *resp = NULL;
569         OCSP_REQ_CTX *ctx;
570         int rv;
571
572         ctx = OCSP_sendreq_new(b, path, req, -1);
573
574         do
575                 {
576                 rv = OCSP_sendreq_nbio(&resp, ctx);
577                 } while ((rv == -1) && BIO_should_retry(b));
578
579         OCSP_REQ_CTX_free(ctx);
580
581         if (rv)
582                 return resp;
583
584         return NULL;
585         }