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