~ubuntu-branches/ubuntu/lucid/openssl/lucid-proposed

« back to all changes in this revision

Viewing changes to crypto/ocsp/ocsp_ht.c

  • Committer: Bazaar Package Importer
  • Author(s): Kurt Roeckx
  • Date: 2009-06-13 18:15:46 UTC
  • mto: (11.1.5 squeeze)
  • mto: This revision was merged to the branch mainline in revision 34.
  • Revision ID: james.westby@ubuntu.com-20090613181546-vbfntai3b009dl1u
Tags: upstream-0.9.8k
ImportĀ upstreamĀ versionĀ 0.9.8k

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* ocsp_ht.c */
2
 
/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
3
 
 * project 2000.
 
2
/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
 
3
 * project 2006.
4
4
 */
5
5
/* ====================================================================
6
 
 * Copyright (c) 2000 The OpenSSL Project.  All rights reserved.
 
6
 * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
7
7
 *
8
8
 * Redistribution and use in source and binary forms, with or without
9
9
 * modification, are permitted provided that the following conditions
56
56
 *
57
57
 */
58
58
 
59
 
#include <openssl/asn1.h>
60
59
#include <stdio.h>
61
60
#include <stdlib.h>
62
61
#include <ctype.h>
63
62
#include <string.h>
 
63
#include "e_os.h"
 
64
#include <openssl/asn1.h>
64
65
#include <openssl/ocsp.h>
65
66
#include <openssl/err.h>
66
67
#include <openssl/buffer.h>
68
69
#define strtoul (unsigned long)strtol
69
70
#endif /* OPENSSL_SYS_SUNOS */
70
71
 
71
 
/* Quick and dirty HTTP OCSP request handler.
72
 
 * Could make this a bit cleverer by adding
73
 
 * support for non blocking BIOs and a few
74
 
 * other refinements.
 
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
OCSP_REQ_CTX *OCSP_sendreq_new(BIO *io, char *path, OCSP_REQUEST *req,
 
122
                                                                int maxline)
 
123
        {
 
124
        static char post_hdr[] = "POST %s HTTP/1.0\r\n"
 
125
        "Content-Type: application/ocsp-request\r\n"
 
126
        "Content-Length: %d\r\n\r\n";
 
127
 
 
128
        OCSP_REQ_CTX *rctx;
 
129
        rctx = OPENSSL_malloc(sizeof(OCSP_REQ_CTX));
 
130
        rctx->state = OHS_FIRSTLINE;
 
131
        rctx->mem = BIO_new(BIO_s_mem());
 
132
        rctx->io = io;
 
133
        if (maxline > 0)
 
134
                rctx->iobuflen = maxline;
 
135
        else
 
136
                rctx->iobuflen = OCSP_MAX_LINE_LEN;
 
137
        rctx->iobuf = OPENSSL_malloc(rctx->iobuflen);
 
138
        if (!path)
 
139
                path = "/";
 
140
 
 
141
        if (BIO_printf(rctx->mem, post_hdr, path,
 
142
                                i2d_OCSP_REQUEST(req, NULL)) <= 0)
 
143
                {
 
144
                rctx->state = OHS_ERROR;
 
145
                return 0;
 
146
                }
 
147
        if (i2d_OCSP_REQUEST_bio(rctx->mem, req) <= 0)
 
148
                {
 
149
                rctx->state = OHS_ERROR;
 
150
                return 0;
 
151
                }
 
152
        rctx->state = OHS_ASN1_WRITE;
 
153
        rctx->asn1_len = BIO_get_mem_data(rctx->mem, NULL);
 
154
 
 
155
        return rctx;
 
156
        }
 
157
 
 
158
/* Parse the HTTP response. This will look like this:
 
159
 * "HTTP/1.0 200 OK". We need to obtain the numeric code and
 
160
 * (optional) informational message.
75
161
 */
76
162
 
77
 
OCSP_RESPONSE *OCSP_sendreq_bio(BIO *b, char *path, OCSP_REQUEST *req)
78
 
{
79
 
        BIO *mem = NULL;
80
 
        char tmpbuf[1024];
81
 
        OCSP_RESPONSE *resp = NULL;
 
163
static int parse_http_line1(char *line)
 
164
        {
 
165
        int retcode;
82
166
        char *p, *q, *r;
83
 
        int len, retcode;
84
 
        static char req_txt[] =
85
 
"POST %s HTTP/1.0\r\n\
86
 
Content-Type: application/ocsp-request\r\n\
87
 
Content-Length: %d\r\n\r\n";
88
 
 
89
 
        len = i2d_OCSP_REQUEST(req, NULL);
90
 
        if(BIO_printf(b, req_txt, path, len) < 0) {
91
 
                OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_WRITE_ERROR);
92
 
                goto err;
93
 
        }
94
 
        if(i2d_OCSP_REQUEST_bio(b, req) <= 0) {
95
 
                OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_WRITE_ERROR);
96
 
                goto err;
97
 
        }
98
 
        if(!(mem = BIO_new(BIO_s_mem()))) goto err;
99
 
        /* Copy response to a memory BIO: socket bios can't do gets! */
100
 
        while ((len = BIO_read(b, tmpbuf, sizeof tmpbuf))) {
101
 
                if(len < 0) {
102
 
                        OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_READ_ERROR);
103
 
                        goto err;
104
 
                }
105
 
                BIO_write(mem, tmpbuf, len);
106
 
        }
107
 
        if(BIO_gets(mem, tmpbuf, 512) <= 0) {
108
 
                OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
109
 
                goto err;
110
 
        }
111
 
        /* Parse the HTTP response. This will look like this:
112
 
         * "HTTP/1.0 200 OK". We need to obtain the numeric code and
113
 
         * (optional) informational message.
114
 
         */
115
 
 
116
167
        /* Skip to first white space (passed protocol info) */
117
 
        for(p = tmpbuf; *p && !isspace((unsigned char)*p); p++) continue;
118
 
        if(!*p) {
119
 
                OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
120
 
                goto err;
121
 
        }
 
168
 
 
169
        for(p = line; *p && !isspace((unsigned char)*p); p++)
 
170
                continue;
 
171
        if(!*p)
 
172
                {
 
173
                OCSPerr(OCSP_F_PARSE_HTTP_LINE1,
 
174
                                        OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
 
175
                return 0;
 
176
                }
 
177
 
122
178
        /* Skip past white space to start of response code */
123
 
        while(*p && isspace((unsigned char)*p)) p++;
124
 
        if(!*p) {
125
 
                OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
126
 
                goto err;
127
 
        }
 
179
        while(*p && isspace((unsigned char)*p))
 
180
                p++;
 
181
 
 
182
        if(!*p)
 
183
                {
 
184
                OCSPerr(OCSP_F_PARSE_HTTP_LINE1,
 
185
                                        OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
 
186
                return 0;
 
187
                }
 
188
 
128
189
        /* Find end of response code: first whitespace after start of code */
129
 
        for(q = p; *q && !isspace((unsigned char)*q); q++) continue;
130
 
        if(!*q) {
131
 
                OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
132
 
                goto err;
133
 
        }
 
190
        for(q = p; *q && !isspace((unsigned char)*q); q++)
 
191
                continue;
 
192
 
 
193
        if(!*q)
 
194
                {
 
195
                OCSPerr(OCSP_F_PARSE_HTTP_LINE1,
 
196
                                        OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
 
197
                return 0;
 
198
                }
 
199
 
134
200
        /* Set end of response code and start of message */ 
135
201
        *q++ = 0;
 
202
 
136
203
        /* Attempt to parse numeric code */
137
204
        retcode = strtoul(p, &r, 10);
138
 
        if(*r) goto err;
 
205
 
 
206
        if(*r)
 
207
                return 0;
 
208
 
139
209
        /* Skip over any leading white space in message */
140
 
        while(*q && isspace((unsigned char)*q))  q++;
141
 
        if(*q) {
142
 
        /* Finally zap any trailing white space in message (include CRLF) */
143
 
        /* We know q has a non white space character so this is OK */
144
 
                for(r = q + strlen(q) - 1; isspace((unsigned char)*r); r--) *r = 0;
145
 
        }
146
 
        if(retcode != 200) {
147
 
                OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_RESPONSE_ERROR);
148
 
                if(!*q) { 
 
210
        while(*q && isspace((unsigned char)*q))
 
211
                q++;
 
212
 
 
213
        if(*q)
 
214
                {
 
215
                /* Finally zap any trailing white space in message (include
 
216
                 * CRLF) */
 
217
 
 
218
                /* We know q has a non white space character so this is OK */
 
219
                for(r = q + strlen(q) - 1; isspace((unsigned char)*r); r--)
 
220
                        *r = 0;
 
221
                }
 
222
        if(retcode != 200)
 
223
                {
 
224
                OCSPerr(OCSP_F_PARSE_HTTP_LINE1, OCSP_R_SERVER_RESPONSE_ERROR);
 
225
                if(!*q)
149
226
                        ERR_add_error_data(2, "Code=", p);
150
 
                }
151
 
                else {
 
227
                else
152
228
                        ERR_add_error_data(4, "Code=", p, ",Reason=", q);
153
 
                }
154
 
                goto err;
155
 
        }
156
 
        /* Find blank line marking beginning of content */      
157
 
        while(BIO_gets(mem, tmpbuf, 512) > 0)
158
 
        {
159
 
                for(p = tmpbuf; *p && isspace((unsigned char)*p); p++) continue;
160
 
                if(!*p) break;
161
 
        }
162
 
        if(*p) {
163
 
                OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_NO_CONTENT);
164
 
                goto err;
165
 
        }
166
 
        if(!(resp = d2i_OCSP_RESPONSE_bio(mem, NULL))) {
167
 
                OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,ERR_R_NESTED_ASN1_ERROR);
168
 
                goto err;
169
 
        }
170
 
        err:
171
 
        BIO_free(mem);
172
 
        return resp;
173
 
}
 
229
                return 0;
 
230
                }
 
231
 
 
232
 
 
233
        return 1;
 
234
 
 
235
        }
 
236
 
 
237
int OCSP_sendreq_nbio(OCSP_RESPONSE **presp, OCSP_REQ_CTX *rctx)
 
238
        {
 
239
        int i, n;
 
240
        const unsigned char *p;
 
241
        next_io:
 
242
        if (!(rctx->state & OHS_NOREAD))
 
243
                {
 
244
                n = BIO_read(rctx->io, rctx->iobuf, rctx->iobuflen);
 
245
 
 
246
                if (n <= 0)
 
247
                        {
 
248
                        if (BIO_should_retry(rctx->io))
 
249
                                return -1;
 
250
                        return 0;
 
251
                        }
 
252
 
 
253
                /* Write data to memory BIO */
 
254
 
 
255
                if (BIO_write(rctx->mem, rctx->iobuf, n) != n)
 
256
                        return 0;
 
257
                }
 
258
 
 
259
        switch(rctx->state)
 
260
                {
 
261
 
 
262
                case OHS_ASN1_WRITE:
 
263
                n = BIO_get_mem_data(rctx->mem, &p);
 
264
 
 
265
                i = BIO_write(rctx->io,
 
266
                        p + (n - rctx->asn1_len), rctx->asn1_len);
 
267
 
 
268
                if (i <= 0)
 
269
                        {
 
270
                        if (BIO_should_retry(rctx->io))
 
271
                                return -1;
 
272
                        rctx->state = OHS_ERROR;
 
273
                        return 0;
 
274
                        }
 
275
 
 
276
                rctx->asn1_len -= i;
 
277
 
 
278
                if (rctx->asn1_len > 0)
 
279
                        goto next_io;
 
280
 
 
281
                rctx->state = OHS_ASN1_FLUSH;
 
282
 
 
283
                (void)BIO_reset(rctx->mem);
 
284
 
 
285
                case OHS_ASN1_FLUSH:
 
286
 
 
287
                i = BIO_flush(rctx->io);
 
288
 
 
289
                if (i > 0)
 
290
                        {
 
291
                        rctx->state = OHS_FIRSTLINE;
 
292
                        goto next_io;
 
293
                        }
 
294
 
 
295
                if (BIO_should_retry(rctx->io))
 
296
                        return -1;
 
297
 
 
298
                rctx->state = OHS_ERROR;
 
299
                return 0;
 
300
 
 
301
                case OHS_ERROR:
 
302
                return 0;
 
303
 
 
304
                case OHS_FIRSTLINE:
 
305
                case OHS_HEADERS:
 
306
 
 
307
                /* Attempt to read a line in */
 
308
 
 
309
                next_line:
 
310
                /* Due to &%^*$" memory BIO behaviour with BIO_gets we
 
311
                 * have to check there's a complete line in there before
 
312
                 * calling BIO_gets or we'll just get a partial read.
 
313
                 */
 
314
                n = BIO_get_mem_data(rctx->mem, &p);
 
315
                if ((n <= 0) || !memchr(p, '\n', n))
 
316
                        {
 
317
                        if (n >= rctx->iobuflen)
 
318
                                {
 
319
                                rctx->state = OHS_ERROR;
 
320
                                return 0;
 
321
                                }
 
322
                        goto next_io;
 
323
                        }
 
324
                n = BIO_gets(rctx->mem, (char *)rctx->iobuf, rctx->iobuflen);
 
325
 
 
326
                if (n <= 0)
 
327
                        {
 
328
                        if (BIO_should_retry(rctx->mem))
 
329
                                goto next_io;
 
330
                        rctx->state = OHS_ERROR;
 
331
                        return 0;
 
332
                        }
 
333
 
 
334
                /* Don't allow excessive lines */
 
335
                if (n == rctx->iobuflen)
 
336
                        {
 
337
                        rctx->state = OHS_ERROR;
 
338
                        return 0;
 
339
                        }
 
340
 
 
341
                /* First line */
 
342
                if (rctx->state == OHS_FIRSTLINE)
 
343
                        {
 
344
                        if (parse_http_line1((char *)rctx->iobuf))
 
345
                                {
 
346
                                rctx->state = OHS_HEADERS;
 
347
                                goto next_line;
 
348
                                }
 
349
                        else
 
350
                                {
 
351
                                rctx->state = OHS_ERROR;
 
352
                                return 0;
 
353
                                }
 
354
                        }
 
355
                else
 
356
                        {
 
357
                        /* Look for blank line: end of headers */
 
358
                        for (p = rctx->iobuf; *p; p++)
 
359
                                {
 
360
                                if ((*p != '\r') && (*p != '\n'))
 
361
                                        break;
 
362
                                }
 
363
                        if (*p)
 
364
                                goto next_line;
 
365
 
 
366
                        rctx->state = OHS_ASN1_HEADER;
 
367
 
 
368
                        }
 
369
 
 
370
                /* Fall thru */
 
371
 
 
372
 
 
373
                case OHS_ASN1_HEADER:
 
374
                /* Now reading ASN1 header: can read at least 6 bytes which
 
375
                 * is more than enough for any valid ASN1 SEQUENCE header
 
376
                 */
 
377
                n = BIO_get_mem_data(rctx->mem, &p);
 
378
                if (n < 6)
 
379
                        goto next_io;
 
380
 
 
381
                /* Check it is an ASN1 SEQUENCE */
 
382
                if (*p++ != (V_ASN1_SEQUENCE|V_ASN1_CONSTRUCTED))
 
383
                        {
 
384
                        rctx->state = OHS_ERROR;
 
385
                        return 0;
 
386
                        }
 
387
 
 
388
                /* Check out length field */
 
389
                if (*p & 0x80)
 
390
                        {
 
391
                        n = *p & 0x7F;
 
392
                        /* Not NDEF or excessive length */
 
393
                        if (!n || (n > 4))
 
394
                                {
 
395
                                rctx->state = OHS_ERROR;
 
396
                                return 0;
 
397
                                }
 
398
                        p++;
 
399
                        rctx->asn1_len = 0;
 
400
                        for (i = 0; i < n; i++)
 
401
                                {
 
402
                                rctx->asn1_len <<= 8;
 
403
                                rctx->asn1_len |= *p++;
 
404
                                }
 
405
 
 
406
                        if (rctx->asn1_len > OCSP_MAX_REQUEST_LENGTH)
 
407
                                {
 
408
                                rctx->state = OHS_ERROR;
 
409
                                return 0;
 
410
                                }
 
411
 
 
412
                        rctx->asn1_len += n + 2;
 
413
                        }
 
414
                else
 
415
                        rctx->asn1_len = *p + 2;
 
416
 
 
417
                rctx->state = OHS_ASN1_CONTENT;
 
418
 
 
419
                /* Fall thru */
 
420
                
 
421
                case OHS_ASN1_CONTENT:
 
422
                n = BIO_get_mem_data(rctx->mem, &p);
 
423
                if (n < (int)rctx->asn1_len)
 
424
                        goto next_io;
 
425
 
 
426
 
 
427
                *presp = d2i_OCSP_RESPONSE(NULL, &p, rctx->asn1_len);
 
428
                if (*presp)
 
429
                        {
 
430
                        rctx->state = OHS_DONE;
 
431
                        return 1;
 
432
                        }
 
433
 
 
434
                rctx->state = OHS_ERROR;
 
435
                return 0;
 
436
 
 
437
                break;
 
438
 
 
439
                case OHS_DONE:
 
440
                return 1;
 
441
 
 
442
                }
 
443
 
 
444
 
 
445
 
 
446
        return 0;
 
447
 
 
448
 
 
449
        }
 
450
 
 
451
/* Blocking OCSP request handler: now a special case of non-blocking I/O */
 
452
 
 
453
OCSP_RESPONSE *OCSP_sendreq_bio(BIO *b, char *path, OCSP_REQUEST *req)
 
454
        {
 
455
        OCSP_RESPONSE *resp = NULL;
 
456
        OCSP_REQ_CTX *ctx;
 
457
        int rv;
 
458
 
 
459
        ctx = OCSP_sendreq_new(b, path, req, -1);
 
460
 
 
461
        do
 
462
                {
 
463
                rv = OCSP_sendreq_nbio(&resp, ctx);
 
464
                } while ((rv == -1) && BIO_should_retry(b));
 
465
 
 
466
        OCSP_REQ_CTX_free(ctx);
 
467
 
 
468
        if (rv)
 
469
                return resp;
 
470
 
 
471
        return NULL;
 
472
        }