1109998Smarkm/* ocsp_ht.c */
2194206Ssimon/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3194206Ssimon * project 2006.
4109998Smarkm */
5109998Smarkm/* ====================================================================
6194206Ssimon * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
7109998Smarkm *
8109998Smarkm * Redistribution and use in source and binary forms, with or without
9109998Smarkm * modification, are permitted provided that the following conditions
10109998Smarkm * are met:
11109998Smarkm *
12109998Smarkm * 1. Redistributions of source code must retain the above copyright
13109998Smarkm *    notice, this list of conditions and the following disclaimer.
14109998Smarkm *
15109998Smarkm * 2. Redistributions in binary form must reproduce the above copyright
16109998Smarkm *    notice, this list of conditions and the following disclaimer in
17109998Smarkm *    the documentation and/or other materials provided with the
18109998Smarkm *    distribution.
19109998Smarkm *
20109998Smarkm * 3. All advertising materials mentioning features or use of this
21109998Smarkm *    software must display the following acknowledgment:
22109998Smarkm *    "This product includes software developed by the OpenSSL Project
23109998Smarkm *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24109998Smarkm *
25109998Smarkm * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26109998Smarkm *    endorse or promote products derived from this software without
27109998Smarkm *    prior written permission. For written permission, please contact
28109998Smarkm *    licensing@OpenSSL.org.
29109998Smarkm *
30109998Smarkm * 5. Products derived from this software may not be called "OpenSSL"
31109998Smarkm *    nor may "OpenSSL" appear in their names without prior written
32109998Smarkm *    permission of the OpenSSL Project.
33109998Smarkm *
34109998Smarkm * 6. Redistributions of any form whatsoever must retain the following
35109998Smarkm *    acknowledgment:
36109998Smarkm *    "This product includes software developed by the OpenSSL Project
37109998Smarkm *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38109998Smarkm *
39109998Smarkm * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40109998Smarkm * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41109998Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42109998Smarkm * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43109998Smarkm * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44109998Smarkm * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45109998Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46109998Smarkm * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47109998Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48109998Smarkm * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49109998Smarkm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50109998Smarkm * OF THE POSSIBILITY OF SUCH DAMAGE.
51109998Smarkm * ====================================================================
52109998Smarkm *
53109998Smarkm * This product includes cryptographic software written by Eric Young
54109998Smarkm * (eay@cryptsoft.com).  This product includes software written by Tim
55109998Smarkm * Hudson (tjh@cryptsoft.com).
56109998Smarkm *
57109998Smarkm */
58109998Smarkm
59109998Smarkm#include <stdio.h>
60109998Smarkm#include <stdlib.h>
61109998Smarkm#include <ctype.h>
62109998Smarkm#include <string.h>
63194206Ssimon#include "e_os.h"
64194206Ssimon#include <openssl/asn1.h>
65109998Smarkm#include <openssl/ocsp.h>
66109998Smarkm#include <openssl/err.h>
67109998Smarkm#include <openssl/buffer.h>
68109998Smarkm#ifdef OPENSSL_SYS_SUNOS
69109998Smarkm#define strtoul (unsigned long)strtol
70109998Smarkm#endif /* OPENSSL_SYS_SUNOS */
71109998Smarkm
72194206Ssimon/* Stateful OCSP request code, supporting non-blocking I/O */
73109998Smarkm
74194206Ssimon/* Opaque OCSP request status structure */
75109998Smarkm
76194206Ssimonstruct ocsp_req_ctx_st {
77194206Ssimon	int state;		/* Current I/O state */
78194206Ssimon	unsigned char *iobuf;	/* Line buffer */
79194206Ssimon	int iobuflen;		/* Line buffer length */
80194206Ssimon	BIO *io;		/* BIO to perform I/O with */
81194206Ssimon	BIO *mem;		/* Memory BIO response is built into */
82194206Ssimon	unsigned long asn1_len;	/* ASN1 length of response */
83194206Ssimon	};
84194206Ssimon
85194206Ssimon#define OCSP_MAX_REQUEST_LENGTH	(100 * 1024)
86194206Ssimon#define OCSP_MAX_LINE_LEN	4096;
87194206Ssimon
88194206Ssimon/* OCSP states */
89194206Ssimon
90194206Ssimon/* If set no reading should be performed */
91194206Ssimon#define OHS_NOREAD		0x1000
92194206Ssimon/* Error condition */
93194206Ssimon#define OHS_ERROR		(0 | OHS_NOREAD)
94194206Ssimon/* First line being read */
95194206Ssimon#define OHS_FIRSTLINE		1
96194206Ssimon/* MIME headers being read */
97194206Ssimon#define OHS_HEADERS		2
98194206Ssimon/* OCSP initial header (tag + length) being read */
99194206Ssimon#define OHS_ASN1_HEADER		3
100194206Ssimon/* OCSP content octets being read */
101194206Ssimon#define OHS_ASN1_CONTENT	4
102194206Ssimon/* Request being sent */
103194206Ssimon#define OHS_ASN1_WRITE		(6 | OHS_NOREAD)
104194206Ssimon/* Request being flushed */
105194206Ssimon#define OHS_ASN1_FLUSH		(7 | OHS_NOREAD)
106194206Ssimon/* Completed */
107194206Ssimon#define OHS_DONE		(8 | OHS_NOREAD)
108194206Ssimon
109194206Ssimon
110194206Ssimonstatic int parse_http_line1(char *line);
111194206Ssimon
112194206Ssimonvoid OCSP_REQ_CTX_free(OCSP_REQ_CTX *rctx)
113194206Ssimon	{
114194206Ssimon	if (rctx->mem)
115194206Ssimon		BIO_free(rctx->mem);
116194206Ssimon	if (rctx->iobuf)
117194206Ssimon		OPENSSL_free(rctx->iobuf);
118194206Ssimon	OPENSSL_free(rctx);
119109998Smarkm	}
120194206Ssimon
121238405Sjkimint OCSP_REQ_CTX_set1_req(OCSP_REQ_CTX *rctx, OCSP_REQUEST *req)
122194206Ssimon	{
123238405Sjkim	static const char req_hdr[] =
124194206Ssimon	"Content-Type: application/ocsp-request\r\n"
125194206Ssimon	"Content-Length: %d\r\n\r\n";
126238405Sjkim        if (BIO_printf(rctx->mem, req_hdr, i2d_OCSP_REQUEST(req, NULL)) <= 0)
127238405Sjkim		return 0;
128238405Sjkim        if (i2d_OCSP_REQUEST_bio(rctx->mem, req) <= 0)
129238405Sjkim		return 0;
130238405Sjkim	rctx->state = OHS_ASN1_WRITE;
131238405Sjkim	rctx->asn1_len = BIO_get_mem_data(rctx->mem, NULL);
132238405Sjkim	return 1;
133238405Sjkim	}
134194206Ssimon
135238405Sjkimint OCSP_REQ_CTX_add1_header(OCSP_REQ_CTX *rctx,
136238405Sjkim		const char *name, const char *value)
137238405Sjkim	{
138238405Sjkim	if (!name)
139238405Sjkim		return 0;
140238405Sjkim	if (BIO_puts(rctx->mem, name) <= 0)
141238405Sjkim		return 0;
142238405Sjkim	if (value)
143238405Sjkim		{
144238405Sjkim		if (BIO_write(rctx->mem, ": ", 2) != 2)
145238405Sjkim			return 0;
146238405Sjkim		if (BIO_puts(rctx->mem, value) <= 0)
147238405Sjkim			return 0;
148238405Sjkim		}
149238405Sjkim	if (BIO_write(rctx->mem, "\r\n", 2) != 2)
150238405Sjkim		return 0;
151238405Sjkim	return 1;
152238405Sjkim	}
153238405Sjkim
154238405SjkimOCSP_REQ_CTX *OCSP_sendreq_new(BIO *io, char *path, OCSP_REQUEST *req,
155238405Sjkim								int maxline)
156238405Sjkim	{
157238405Sjkim	static const char post_hdr[] = "POST %s HTTP/1.0\r\n";
158238405Sjkim
159194206Ssimon	OCSP_REQ_CTX *rctx;
160194206Ssimon	rctx = OPENSSL_malloc(sizeof(OCSP_REQ_CTX));
161279264Sdelphij	if (!rctx)
162279264Sdelphij		return NULL;
163238405Sjkim	rctx->state = OHS_ERROR;
164194206Ssimon	rctx->mem = BIO_new(BIO_s_mem());
165194206Ssimon	rctx->io = io;
166238405Sjkim	rctx->asn1_len = 0;
167194206Ssimon	if (maxline > 0)
168194206Ssimon		rctx->iobuflen = maxline;
169194206Ssimon	else
170194206Ssimon		rctx->iobuflen = OCSP_MAX_LINE_LEN;
171194206Ssimon	rctx->iobuf = OPENSSL_malloc(rctx->iobuflen);
172279264Sdelphij	if (!rctx->mem || !rctx->iobuf)
173279264Sdelphij		goto err;
174194206Ssimon	if (!path)
175194206Ssimon		path = "/";
176194206Ssimon
177238405Sjkim        if (BIO_printf(rctx->mem, post_hdr, path) <= 0)
178279264Sdelphij		goto err;
179238405Sjkim
180238405Sjkim	if (req && !OCSP_REQ_CTX_set1_req(rctx, req))
181279264Sdelphij		goto err;
182194206Ssimon
183194206Ssimon	return rctx;
184279264Sdelphij	err:
185279264Sdelphij	OCSP_REQ_CTX_free(rctx);
186279264Sdelphij	return NULL;
187109998Smarkm	}
188109998Smarkm
189194206Ssimon/* Parse the HTTP response. This will look like this:
190194206Ssimon * "HTTP/1.0 200 OK". We need to obtain the numeric code and
191194206Ssimon * (optional) informational message.
192194206Ssimon */
193194206Ssimon
194194206Ssimonstatic int parse_http_line1(char *line)
195194206Ssimon	{
196194206Ssimon	int retcode;
197194206Ssimon	char *p, *q, *r;
198109998Smarkm	/* Skip to first white space (passed protocol info) */
199194206Ssimon
200194206Ssimon	for(p = line; *p && !isspace((unsigned char)*p); p++)
201194206Ssimon		continue;
202194206Ssimon	if(!*p)
203194206Ssimon		{
204194206Ssimon		OCSPerr(OCSP_F_PARSE_HTTP_LINE1,
205194206Ssimon					OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
206194206Ssimon		return 0;
207194206Ssimon		}
208194206Ssimon
209109998Smarkm	/* Skip past white space to start of response code */
210194206Ssimon	while(*p && isspace((unsigned char)*p))
211194206Ssimon		p++;
212194206Ssimon
213194206Ssimon	if(!*p)
214194206Ssimon		{
215194206Ssimon		OCSPerr(OCSP_F_PARSE_HTTP_LINE1,
216194206Ssimon					OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
217194206Ssimon		return 0;
218194206Ssimon		}
219194206Ssimon
220109998Smarkm	/* Find end of response code: first whitespace after start of code */
221194206Ssimon	for(q = p; *q && !isspace((unsigned char)*q); q++)
222194206Ssimon		continue;
223194206Ssimon
224194206Ssimon	if(!*q)
225194206Ssimon		{
226194206Ssimon		OCSPerr(OCSP_F_PARSE_HTTP_LINE1,
227194206Ssimon					OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
228194206Ssimon		return 0;
229194206Ssimon		}
230194206Ssimon
231109998Smarkm	/* Set end of response code and start of message */
232109998Smarkm	*q++ = 0;
233194206Ssimon
234109998Smarkm	/* Attempt to parse numeric code */
235109998Smarkm	retcode = strtoul(p, &r, 10);
236194206Ssimon
237194206Ssimon	if(*r)
238194206Ssimon		return 0;
239194206Ssimon
240109998Smarkm	/* Skip over any leading white space in message */
241194206Ssimon	while(*q && isspace((unsigned char)*q))
242194206Ssimon		q++;
243194206Ssimon
244194206Ssimon	if(*q)
245194206Ssimon		{
246194206Ssimon		/* Finally zap any trailing white space in message (include
247194206Ssimon		 * CRLF) */
248194206Ssimon
249194206Ssimon		/* We know q has a non white space character so this is OK */
250194206Ssimon		for(r = q + strlen(q) - 1; isspace((unsigned char)*r); r--)
251194206Ssimon			*r = 0;
252194206Ssimon		}
253194206Ssimon	if(retcode != 200)
254194206Ssimon		{
255194206Ssimon		OCSPerr(OCSP_F_PARSE_HTTP_LINE1, OCSP_R_SERVER_RESPONSE_ERROR);
256194206Ssimon		if(!*q)
257120631Snectar			ERR_add_error_data(2, "Code=", p);
258194206Ssimon		else
259120631Snectar			ERR_add_error_data(4, "Code=", p, ",Reason=", q);
260194206Ssimon		return 0;
261120631Snectar		}
262194206Ssimon
263194206Ssimon
264194206Ssimon	return 1;
265194206Ssimon
266109998Smarkm	}
267194206Ssimon
268194206Ssimonint OCSP_sendreq_nbio(OCSP_RESPONSE **presp, OCSP_REQ_CTX *rctx)
269109998Smarkm	{
270194206Ssimon	int i, n;
271194206Ssimon	const unsigned char *p;
272194206Ssimon	next_io:
273194206Ssimon	if (!(rctx->state & OHS_NOREAD))
274194206Ssimon		{
275194206Ssimon		n = BIO_read(rctx->io, rctx->iobuf, rctx->iobuflen);
276194206Ssimon
277194206Ssimon		if (n <= 0)
278194206Ssimon			{
279194206Ssimon			if (BIO_should_retry(rctx->io))
280194206Ssimon				return -1;
281194206Ssimon			return 0;
282194206Ssimon			}
283194206Ssimon
284194206Ssimon		/* Write data to memory BIO */
285194206Ssimon
286194206Ssimon		if (BIO_write(rctx->mem, rctx->iobuf, n) != n)
287194206Ssimon			return 0;
288194206Ssimon		}
289194206Ssimon
290194206Ssimon	switch(rctx->state)
291194206Ssimon		{
292194206Ssimon
293194206Ssimon		case OHS_ASN1_WRITE:
294194206Ssimon		n = BIO_get_mem_data(rctx->mem, &p);
295194206Ssimon
296194206Ssimon		i = BIO_write(rctx->io,
297194206Ssimon			p + (n - rctx->asn1_len), rctx->asn1_len);
298194206Ssimon
299194206Ssimon		if (i <= 0)
300194206Ssimon			{
301194206Ssimon			if (BIO_should_retry(rctx->io))
302194206Ssimon				return -1;
303194206Ssimon			rctx->state = OHS_ERROR;
304194206Ssimon			return 0;
305194206Ssimon			}
306194206Ssimon
307194206Ssimon		rctx->asn1_len -= i;
308194206Ssimon
309194206Ssimon		if (rctx->asn1_len > 0)
310194206Ssimon			goto next_io;
311194206Ssimon
312194206Ssimon		rctx->state = OHS_ASN1_FLUSH;
313194206Ssimon
314194206Ssimon		(void)BIO_reset(rctx->mem);
315194206Ssimon
316194206Ssimon		case OHS_ASN1_FLUSH:
317194206Ssimon
318194206Ssimon		i = BIO_flush(rctx->io);
319194206Ssimon
320194206Ssimon		if (i > 0)
321194206Ssimon			{
322194206Ssimon			rctx->state = OHS_FIRSTLINE;
323194206Ssimon			goto next_io;
324194206Ssimon			}
325194206Ssimon
326194206Ssimon		if (BIO_should_retry(rctx->io))
327194206Ssimon			return -1;
328194206Ssimon
329194206Ssimon		rctx->state = OHS_ERROR;
330194206Ssimon		return 0;
331194206Ssimon
332194206Ssimon		case OHS_ERROR:
333194206Ssimon		return 0;
334194206Ssimon
335194206Ssimon		case OHS_FIRSTLINE:
336194206Ssimon		case OHS_HEADERS:
337194206Ssimon
338194206Ssimon		/* Attempt to read a line in */
339194206Ssimon
340194206Ssimon		next_line:
341194206Ssimon		/* Due to &%^*$" memory BIO behaviour with BIO_gets we
342194206Ssimon		 * have to check there's a complete line in there before
343194206Ssimon		 * calling BIO_gets or we'll just get a partial read.
344194206Ssimon		 */
345194206Ssimon		n = BIO_get_mem_data(rctx->mem, &p);
346194206Ssimon		if ((n <= 0) || !memchr(p, '\n', n))
347194206Ssimon			{
348194206Ssimon			if (n >= rctx->iobuflen)
349194206Ssimon				{
350194206Ssimon				rctx->state = OHS_ERROR;
351194206Ssimon				return 0;
352194206Ssimon				}
353194206Ssimon			goto next_io;
354194206Ssimon			}
355194206Ssimon		n = BIO_gets(rctx->mem, (char *)rctx->iobuf, rctx->iobuflen);
356194206Ssimon
357194206Ssimon		if (n <= 0)
358194206Ssimon			{
359194206Ssimon			if (BIO_should_retry(rctx->mem))
360194206Ssimon				goto next_io;
361194206Ssimon			rctx->state = OHS_ERROR;
362194206Ssimon			return 0;
363194206Ssimon			}
364194206Ssimon
365194206Ssimon		/* Don't allow excessive lines */
366194206Ssimon		if (n == rctx->iobuflen)
367194206Ssimon			{
368194206Ssimon			rctx->state = OHS_ERROR;
369194206Ssimon			return 0;
370194206Ssimon			}
371194206Ssimon
372194206Ssimon		/* First line */
373194206Ssimon		if (rctx->state == OHS_FIRSTLINE)
374194206Ssimon			{
375194206Ssimon			if (parse_http_line1((char *)rctx->iobuf))
376194206Ssimon				{
377194206Ssimon				rctx->state = OHS_HEADERS;
378194206Ssimon				goto next_line;
379194206Ssimon				}
380194206Ssimon			else
381194206Ssimon				{
382194206Ssimon				rctx->state = OHS_ERROR;
383194206Ssimon				return 0;
384194206Ssimon				}
385194206Ssimon			}
386194206Ssimon		else
387194206Ssimon			{
388194206Ssimon			/* Look for blank line: end of headers */
389194206Ssimon			for (p = rctx->iobuf; *p; p++)
390194206Ssimon				{
391194206Ssimon				if ((*p != '\r') && (*p != '\n'))
392194206Ssimon					break;
393194206Ssimon				}
394194206Ssimon			if (*p)
395194206Ssimon				goto next_line;
396194206Ssimon
397194206Ssimon			rctx->state = OHS_ASN1_HEADER;
398194206Ssimon
399194206Ssimon			}
400194206Ssimon
401194206Ssimon		/* Fall thru */
402194206Ssimon
403194206Ssimon
404194206Ssimon		case OHS_ASN1_HEADER:
405215697Ssimon		/* Now reading ASN1 header: can read at least 2 bytes which
406215697Ssimon		 * is enough for ASN1 SEQUENCE header and either length field
407215697Ssimon		 * or at least the length of the length field.
408194206Ssimon		 */
409194206Ssimon		n = BIO_get_mem_data(rctx->mem, &p);
410215697Ssimon		if (n < 2)
411194206Ssimon			goto next_io;
412194206Ssimon
413194206Ssimon		/* Check it is an ASN1 SEQUENCE */
414194206Ssimon		if (*p++ != (V_ASN1_SEQUENCE|V_ASN1_CONSTRUCTED))
415194206Ssimon			{
416194206Ssimon			rctx->state = OHS_ERROR;
417194206Ssimon			return 0;
418194206Ssimon			}
419194206Ssimon
420194206Ssimon		/* Check out length field */
421194206Ssimon		if (*p & 0x80)
422194206Ssimon			{
423215697Ssimon			/* If MSB set on initial length octet we can now
424215697Ssimon			 * always read 6 octets: make sure we have them.
425215697Ssimon			 */
426215697Ssimon			if (n < 6)
427215697Ssimon				goto next_io;
428194206Ssimon			n = *p & 0x7F;
429194206Ssimon			/* Not NDEF or excessive length */
430194206Ssimon			if (!n || (n > 4))
431194206Ssimon				{
432194206Ssimon				rctx->state = OHS_ERROR;
433194206Ssimon				return 0;
434194206Ssimon				}
435194206Ssimon			p++;
436194206Ssimon			rctx->asn1_len = 0;
437194206Ssimon			for (i = 0; i < n; i++)
438194206Ssimon				{
439194206Ssimon				rctx->asn1_len <<= 8;
440194206Ssimon				rctx->asn1_len |= *p++;
441194206Ssimon				}
442194206Ssimon
443194206Ssimon			if (rctx->asn1_len > OCSP_MAX_REQUEST_LENGTH)
444194206Ssimon				{
445194206Ssimon				rctx->state = OHS_ERROR;
446194206Ssimon				return 0;
447194206Ssimon				}
448194206Ssimon
449194206Ssimon			rctx->asn1_len += n + 2;
450194206Ssimon			}
451194206Ssimon		else
452194206Ssimon			rctx->asn1_len = *p + 2;
453194206Ssimon
454194206Ssimon		rctx->state = OHS_ASN1_CONTENT;
455194206Ssimon
456194206Ssimon		/* Fall thru */
457194206Ssimon
458194206Ssimon		case OHS_ASN1_CONTENT:
459194206Ssimon		n = BIO_get_mem_data(rctx->mem, &p);
460194206Ssimon		if (n < (int)rctx->asn1_len)
461194206Ssimon			goto next_io;
462194206Ssimon
463194206Ssimon
464194206Ssimon		*presp = d2i_OCSP_RESPONSE(NULL, &p, rctx->asn1_len);
465194206Ssimon		if (*presp)
466194206Ssimon			{
467194206Ssimon			rctx->state = OHS_DONE;
468194206Ssimon			return 1;
469194206Ssimon			}
470194206Ssimon
471194206Ssimon		rctx->state = OHS_ERROR;
472194206Ssimon		return 0;
473194206Ssimon
474194206Ssimon		break;
475194206Ssimon
476194206Ssimon		case OHS_DONE:
477194206Ssimon		return 1;
478194206Ssimon
479194206Ssimon		}
480194206Ssimon
481194206Ssimon
482194206Ssimon
483194206Ssimon	return 0;
484194206Ssimon
485194206Ssimon
486109998Smarkm	}
487194206Ssimon
488194206Ssimon/* Blocking OCSP request handler: now a special case of non-blocking I/O */
489194206Ssimon
490194206SsimonOCSP_RESPONSE *OCSP_sendreq_bio(BIO *b, char *path, OCSP_REQUEST *req)
491194206Ssimon	{
492194206Ssimon	OCSP_RESPONSE *resp = NULL;
493194206Ssimon	OCSP_REQ_CTX *ctx;
494194206Ssimon	int rv;
495194206Ssimon
496194206Ssimon	ctx = OCSP_sendreq_new(b, path, req, -1);
497194206Ssimon
498279264Sdelphij	if (!ctx)
499279264Sdelphij		return NULL;
500279264Sdelphij
501194206Ssimon	do
502194206Ssimon		{
503194206Ssimon		rv = OCSP_sendreq_nbio(&resp, ctx);
504194206Ssimon		} while ((rv == -1) && BIO_should_retry(b));
505194206Ssimon
506194206Ssimon	OCSP_REQ_CTX_free(ctx);
507194206Ssimon
508194206Ssimon	if (rv)
509194206Ssimon		return resp;
510194206Ssimon
511194206Ssimon	return NULL;
512109998Smarkm	}
513