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