xref: /openbsd-src/lib/libcrypto/ocsp/ocsp_ht.c (revision beb6838fd0672171f4e3433e59ead856aa4a59c9)
1*beb6838fSjsg /* $OpenBSD: ocsp_ht.c,v 1.27 2023/11/28 09:29:20 jsg Exp $ */
2e6841c1dSdjm /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
34fcf65c5Sdjm  * project 2006.
4da347917Sbeck  */
5da347917Sbeck /* ====================================================================
64fcf65c5Sdjm  * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
7da347917Sbeck  *
8da347917Sbeck  * Redistribution and use in source and binary forms, with or without
9da347917Sbeck  * modification, are permitted provided that the following conditions
10da347917Sbeck  * are met:
11da347917Sbeck  *
12da347917Sbeck  * 1. Redistributions of source code must retain the above copyright
13da347917Sbeck  *    notice, this list of conditions and the following disclaimer.
14da347917Sbeck  *
15da347917Sbeck  * 2. Redistributions in binary form must reproduce the above copyright
16da347917Sbeck  *    notice, this list of conditions and the following disclaimer in
17da347917Sbeck  *    the documentation and/or other materials provided with the
18da347917Sbeck  *    distribution.
19da347917Sbeck  *
20da347917Sbeck  * 3. All advertising materials mentioning features or use of this
21da347917Sbeck  *    software must display the following acknowledgment:
22da347917Sbeck  *    "This product includes software developed by the OpenSSL Project
23da347917Sbeck  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24da347917Sbeck  *
25da347917Sbeck  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26da347917Sbeck  *    endorse or promote products derived from this software without
27da347917Sbeck  *    prior written permission. For written permission, please contact
28da347917Sbeck  *    licensing@OpenSSL.org.
29da347917Sbeck  *
30da347917Sbeck  * 5. Products derived from this software may not be called "OpenSSL"
31da347917Sbeck  *    nor may "OpenSSL" appear in their names without prior written
32da347917Sbeck  *    permission of the OpenSSL Project.
33da347917Sbeck  *
34da347917Sbeck  * 6. Redistributions of any form whatsoever must retain the following
35da347917Sbeck  *    acknowledgment:
36da347917Sbeck  *    "This product includes software developed by the OpenSSL Project
37da347917Sbeck  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38da347917Sbeck  *
39da347917Sbeck  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40da347917Sbeck  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41da347917Sbeck  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42da347917Sbeck  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43da347917Sbeck  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44da347917Sbeck  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45da347917Sbeck  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46da347917Sbeck  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47da347917Sbeck  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48da347917Sbeck  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49da347917Sbeck  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50da347917Sbeck  * OF THE POSSIBILITY OF SUCH DAMAGE.
51da347917Sbeck  * ====================================================================
52da347917Sbeck  *
53da347917Sbeck  * This product includes cryptographic software written by Eric Young
54da347917Sbeck  * (eay@cryptsoft.com).  This product includes software written by Tim
55da347917Sbeck  * Hudson (tjh@cryptsoft.com).
56da347917Sbeck  *
57da347917Sbeck  */
58da347917Sbeck 
59da347917Sbeck #include <stdio.h>
60da347917Sbeck #include <stdlib.h>
61da347917Sbeck #include <ctype.h>
62da347917Sbeck #include <string.h>
63e6841c1dSdjm #include <openssl/asn1.h>
64da347917Sbeck #include <openssl/ocsp.h>
65da347917Sbeck #include <openssl/err.h>
66da347917Sbeck #include <openssl/buffer.h>
67da347917Sbeck 
684fcf65c5Sdjm /* Stateful OCSP request code, supporting non-blocking I/O */
69da347917Sbeck 
704fcf65c5Sdjm /* Opaque OCSP request status structure */
714fcf65c5Sdjm 
724fcf65c5Sdjm struct ocsp_req_ctx_st {
734fcf65c5Sdjm 	int state;		/* Current I/O state */
744fcf65c5Sdjm 	unsigned char *iobuf;	/* Line buffer */
754fcf65c5Sdjm 	int iobuflen;		/* Line buffer length */
764fcf65c5Sdjm 	BIO *io;		/* BIO to perform I/O with */
774fcf65c5Sdjm 	BIO *mem;		/* Memory BIO response is built into */
784fcf65c5Sdjm 	unsigned long asn1_len;	/* ASN1 length of response */
794fcf65c5Sdjm };
804fcf65c5Sdjm 
814fcf65c5Sdjm #define OCSP_MAX_REQUEST_LENGTH	(100 * 1024)
824fcf65c5Sdjm #define OCSP_MAX_LINE_LEN	4096;
834fcf65c5Sdjm 
844fcf65c5Sdjm /* OCSP states */
854fcf65c5Sdjm 
864fcf65c5Sdjm /* If set no reading should be performed */
874fcf65c5Sdjm #define OHS_NOREAD		0x1000
884fcf65c5Sdjm /* Error condition */
894fcf65c5Sdjm #define OHS_ERROR		(0 | OHS_NOREAD)
904fcf65c5Sdjm /* First line being read */
914fcf65c5Sdjm #define OHS_FIRSTLINE		1
924fcf65c5Sdjm /* MIME headers being read */
934fcf65c5Sdjm #define OHS_HEADERS		2
944fcf65c5Sdjm /* OCSP initial header (tag + length) being read */
954fcf65c5Sdjm #define OHS_ASN1_HEADER		3
964fcf65c5Sdjm /* OCSP content octets being read */
974fcf65c5Sdjm #define OHS_ASN1_CONTENT	4
984fcf65c5Sdjm /* Request being sent */
994fcf65c5Sdjm #define OHS_ASN1_WRITE		(6 | OHS_NOREAD)
1004fcf65c5Sdjm /* Request being flushed */
1014fcf65c5Sdjm #define OHS_ASN1_FLUSH		(7 | OHS_NOREAD)
1024fcf65c5Sdjm /* Completed */
1034fcf65c5Sdjm #define OHS_DONE		(8 | OHS_NOREAD)
1044fcf65c5Sdjm 
1054fcf65c5Sdjm 
1064fcf65c5Sdjm static int parse_http_line1(char *line);
1074fcf65c5Sdjm 
1082d2941d0Smiod void
OCSP_REQ_CTX_free(OCSP_REQ_CTX * rctx)1092d2941d0Smiod OCSP_REQ_CTX_free(OCSP_REQ_CTX *rctx)
110da347917Sbeck {
11168a272ffSmiod 	if (rctx == NULL)
11268a272ffSmiod 		return;
11368a272ffSmiod 
1144fcf65c5Sdjm 	BIO_free(rctx->mem);
1156f3a6cb1Sbeck 	free(rctx->iobuf);
1166f3a6cb1Sbeck 	free(rctx);
1174fcf65c5Sdjm }
118a1e92f6bSbeck LCRYPTO_ALIAS(OCSP_REQ_CTX_free);
119da347917Sbeck 
1202d2941d0Smiod int
OCSP_REQ_CTX_set1_req(OCSP_REQ_CTX * rctx,OCSP_REQUEST * req)1212d2941d0Smiod OCSP_REQ_CTX_set1_req(OCSP_REQ_CTX *rctx, OCSP_REQUEST *req)
1220a5d6edeSdjm {
123dda2f39bSdoug 	if (BIO_printf(rctx->mem, "Content-Type: application/ocsp-request\r\n"
124dda2f39bSdoug 	    "Content-Length: %d\r\n\r\n", i2d_OCSP_REQUEST(req, NULL)) <= 0)
1250a5d6edeSdjm 		return 0;
1260a5d6edeSdjm 	if (i2d_OCSP_REQUEST_bio(rctx->mem, req) <= 0)
1270a5d6edeSdjm 		return 0;
1280a5d6edeSdjm 	rctx->state = OHS_ASN1_WRITE;
1290a5d6edeSdjm 	rctx->asn1_len = BIO_get_mem_data(rctx->mem, NULL);
1300a5d6edeSdjm 	return 1;
1310a5d6edeSdjm }
132a1e92f6bSbeck LCRYPTO_ALIAS(OCSP_REQ_CTX_set1_req);
1330a5d6edeSdjm 
1342d2941d0Smiod int
OCSP_REQ_CTX_add1_header(OCSP_REQ_CTX * rctx,const char * name,const char * value)1352d2941d0Smiod OCSP_REQ_CTX_add1_header(OCSP_REQ_CTX *rctx, const char *name,
1362d2941d0Smiod     const char *value)
1370a5d6edeSdjm {
1380a5d6edeSdjm 	if (!name)
1390a5d6edeSdjm 		return 0;
1400a5d6edeSdjm 	if (BIO_puts(rctx->mem, name) <= 0)
1410a5d6edeSdjm 		return 0;
1422d2941d0Smiod 	if (value) {
1430a5d6edeSdjm 		if (BIO_write(rctx->mem, ": ", 2) != 2)
1440a5d6edeSdjm 			return 0;
1450a5d6edeSdjm 		if (BIO_puts(rctx->mem, value) <= 0)
1460a5d6edeSdjm 			return 0;
1470a5d6edeSdjm 	}
1480a5d6edeSdjm 	if (BIO_write(rctx->mem, "\r\n", 2) != 2)
1490a5d6edeSdjm 		return 0;
1500a5d6edeSdjm 	return 1;
1510a5d6edeSdjm }
152a1e92f6bSbeck LCRYPTO_ALIAS(OCSP_REQ_CTX_add1_header);
1530a5d6edeSdjm 
1542d2941d0Smiod OCSP_REQ_CTX *
OCSP_sendreq_new(BIO * io,const char * path,OCSP_REQUEST * req,int maxline)15514edca61Stb OCSP_sendreq_new(BIO *io, const char *path, OCSP_REQUEST *req, int maxline)
1564fcf65c5Sdjm {
1574fcf65c5Sdjm 	OCSP_REQ_CTX *rctx;
1582d2941d0Smiod 
1596f3a6cb1Sbeck 	rctx = malloc(sizeof(OCSP_REQ_CTX));
160c9004369Smiod 	if (rctx == NULL)
161a0f54154Smiod 		return NULL;
1620a5d6edeSdjm 	rctx->state = OHS_ERROR;
1637f3aaf75Smiod 	if ((rctx->mem = BIO_new(BIO_s_mem())) == NULL) {
1647f3aaf75Smiod 		free(rctx);
1657f3aaf75Smiod 		return NULL;
1667f3aaf75Smiod 	}
1674fcf65c5Sdjm 	rctx->io = io;
1680a5d6edeSdjm 	rctx->asn1_len = 0;
1694fcf65c5Sdjm 	if (maxline > 0)
1704fcf65c5Sdjm 		rctx->iobuflen = maxline;
1714fcf65c5Sdjm 	else
1724fcf65c5Sdjm 		rctx->iobuflen = OCSP_MAX_LINE_LEN;
1736f3a6cb1Sbeck 	rctx->iobuf = malloc(rctx->iobuflen);
17464b5e5f5Sjsg 	if (!rctx->iobuf) {
175603b910fSjsg 		BIO_free(rctx->mem);
17664b5e5f5Sjsg 		free(rctx);
177a0f54154Smiod 		return NULL;
17864b5e5f5Sjsg 	}
1794fcf65c5Sdjm 	if (!path)
1804fcf65c5Sdjm 		path = "/";
1814fcf65c5Sdjm 
182dda2f39bSdoug 	if (BIO_printf(rctx->mem, "POST %s HTTP/1.0\r\n", path) <= 0) {
18364b5e5f5Sjsg 		free(rctx->iobuf);
184603b910fSjsg 		BIO_free(rctx->mem);
18564b5e5f5Sjsg 		free(rctx);
186a0f54154Smiod 		return NULL;
18764b5e5f5Sjsg 	}
1880a5d6edeSdjm 
18964b5e5f5Sjsg 	if (req && !OCSP_REQ_CTX_set1_req(rctx, req)) {
19064b5e5f5Sjsg 		free(rctx->iobuf);
191603b910fSjsg 		BIO_free(rctx->mem);
19264b5e5f5Sjsg 		free(rctx);
193a0f54154Smiod 		return NULL;
19464b5e5f5Sjsg 	}
1954fcf65c5Sdjm 
1964fcf65c5Sdjm 	return rctx;
197da347917Sbeck }
198a1e92f6bSbeck LCRYPTO_ALIAS(OCSP_sendreq_new);
1994fcf65c5Sdjm 
200da347917Sbeck /* Parse the HTTP response. This will look like this:
201da347917Sbeck  * "HTTP/1.0 200 OK". We need to obtain the numeric code and
2023a5f3d0eSmarkus  * (optional) informational message.
203da347917Sbeck  */
2042d2941d0Smiod static int
parse_http_line1(char * line)2052d2941d0Smiod parse_http_line1(char *line)
2064fcf65c5Sdjm {
2074fcf65c5Sdjm 	int retcode;
2084fcf65c5Sdjm 	char *p, *q, *r;
2094fcf65c5Sdjm 
2102d2941d0Smiod 	/* Skip to first white space (passed protocol info) */
2114fcf65c5Sdjm 	for (p = line; *p && !isspace((unsigned char)*p); p++)
2124fcf65c5Sdjm 		continue;
2132d2941d0Smiod 	if (!*p) {
2145067ae9fSbeck 		OCSPerror(OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
2154fcf65c5Sdjm 		return 0;
216da347917Sbeck 	}
2174fcf65c5Sdjm 
218da347917Sbeck 	/* Skip past white space to start of response code */
2194fcf65c5Sdjm 	while (*p && isspace((unsigned char)*p))
2204fcf65c5Sdjm 		p++;
2212d2941d0Smiod 	if (!*p) {
2225067ae9fSbeck 		OCSPerror(OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
2234fcf65c5Sdjm 		return 0;
224da347917Sbeck 	}
2254fcf65c5Sdjm 
226da347917Sbeck 	/* Find end of response code: first whitespace after start of code */
2274fcf65c5Sdjm 	for (q = p; *q && !isspace((unsigned char)*q); q++)
2284fcf65c5Sdjm 		continue;
2292d2941d0Smiod 	if (!*q) {
2305067ae9fSbeck 		OCSPerror(OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
2314fcf65c5Sdjm 		return 0;
232da347917Sbeck 	}
2334fcf65c5Sdjm 
234da347917Sbeck 	/* Set end of response code and start of message */
235da347917Sbeck 	*q++ = 0;
2364fcf65c5Sdjm 
237da347917Sbeck 	/* Attempt to parse numeric code */
238da347917Sbeck 	retcode = strtoul(p, &r, 10);
2394fcf65c5Sdjm 
2404fcf65c5Sdjm 	if (*r)
2414fcf65c5Sdjm 		return 0;
2424fcf65c5Sdjm 
243da347917Sbeck 	/* Skip over any leading white space in message */
2444fcf65c5Sdjm 	while (*q && isspace((unsigned char)*q))
2454fcf65c5Sdjm 		q++;
2462d2941d0Smiod 	if (*q) {
2474fcf65c5Sdjm 		/* Finally zap any trailing white space in message (include
2484fcf65c5Sdjm 		 * CRLF) */
2494fcf65c5Sdjm 
2504fcf65c5Sdjm 		/* We know q has a non white space character so this is OK */
2514fcf65c5Sdjm 		for (r = q + strlen(q) - 1; isspace((unsigned char)*r); r--)
2524fcf65c5Sdjm 			*r = 0;
253da347917Sbeck 	}
2542d2941d0Smiod 	if (retcode != 200) {
2555067ae9fSbeck 		OCSPerror(OCSP_R_SERVER_RESPONSE_ERROR);
2564fcf65c5Sdjm 		if (!*q)
2570f637b92Sbeck 			ERR_asprintf_error_data("Code=%s", p);
2584fcf65c5Sdjm 		else
2590f637b92Sbeck 			ERR_asprintf_error_data("Code=%s,Reason=%s", p, q);
2604fcf65c5Sdjm 		return 0;
261da347917Sbeck 	}
2624fcf65c5Sdjm 
2634fcf65c5Sdjm 	return 1;
264da347917Sbeck }
2654fcf65c5Sdjm 
2662d2941d0Smiod int
OCSP_sendreq_nbio(OCSP_RESPONSE ** presp,OCSP_REQ_CTX * rctx)2672d2941d0Smiod OCSP_sendreq_nbio(OCSP_RESPONSE **presp, OCSP_REQ_CTX *rctx)
2684fcf65c5Sdjm {
2694fcf65c5Sdjm 	int i, n;
2704fcf65c5Sdjm 	const unsigned char *p;
2712d2941d0Smiod 
2724fcf65c5Sdjm next_io:
2732d2941d0Smiod 	if (!(rctx->state & OHS_NOREAD)) {
2744fcf65c5Sdjm 		n = BIO_read(rctx->io, rctx->iobuf, rctx->iobuflen);
2754fcf65c5Sdjm 
2762d2941d0Smiod 		if (n <= 0) {
2774fcf65c5Sdjm 			if (BIO_should_retry(rctx->io))
2784fcf65c5Sdjm 				return -1;
2794fcf65c5Sdjm 			return 0;
2804fcf65c5Sdjm 		}
2814fcf65c5Sdjm 
2824fcf65c5Sdjm 		/* Write data to memory BIO */
2834fcf65c5Sdjm 		if (BIO_write(rctx->mem, rctx->iobuf, n) != n)
2844fcf65c5Sdjm 			return 0;
2854fcf65c5Sdjm 	}
2864fcf65c5Sdjm 
2872d2941d0Smiod 	switch (rctx->state) {
2884fcf65c5Sdjm 	case OHS_ASN1_WRITE:
2894fcf65c5Sdjm 		n = BIO_get_mem_data(rctx->mem, &p);
2904fcf65c5Sdjm 		i = BIO_write(rctx->io,
2914fcf65c5Sdjm 		    p + (n - rctx->asn1_len), rctx->asn1_len);
2922d2941d0Smiod 		if (i <= 0) {
2934fcf65c5Sdjm 			if (BIO_should_retry(rctx->io))
2944fcf65c5Sdjm 				return -1;
2954fcf65c5Sdjm 			rctx->state = OHS_ERROR;
2964fcf65c5Sdjm 			return 0;
2974fcf65c5Sdjm 		}
2984fcf65c5Sdjm 
2994fcf65c5Sdjm 		rctx->asn1_len -= i;
3004fcf65c5Sdjm 		if (rctx->asn1_len > 0)
3014fcf65c5Sdjm 			goto next_io;
3024fcf65c5Sdjm 
3034fcf65c5Sdjm 		rctx->state = OHS_ASN1_FLUSH;
3044fcf65c5Sdjm 
3054fcf65c5Sdjm 		(void)BIO_reset(rctx->mem);
3062d2941d0Smiod 		/* FALLTHROUGH */
3074fcf65c5Sdjm 
3084fcf65c5Sdjm 	case OHS_ASN1_FLUSH:
3094fcf65c5Sdjm 		i = BIO_flush(rctx->io);
3102d2941d0Smiod 		if (i > 0) {
3114fcf65c5Sdjm 			rctx->state = OHS_FIRSTLINE;
3124fcf65c5Sdjm 			goto next_io;
3134fcf65c5Sdjm 		}
3144fcf65c5Sdjm 
3154fcf65c5Sdjm 		if (BIO_should_retry(rctx->io))
3164fcf65c5Sdjm 			return -1;
3174fcf65c5Sdjm 
3184fcf65c5Sdjm 		rctx->state = OHS_ERROR;
3194fcf65c5Sdjm 		return 0;
3204fcf65c5Sdjm 
3214fcf65c5Sdjm 	case OHS_ERROR:
3224fcf65c5Sdjm 		return 0;
3234fcf65c5Sdjm 
3244fcf65c5Sdjm 	case OHS_FIRSTLINE:
3254fcf65c5Sdjm 	case OHS_HEADERS:
3264fcf65c5Sdjm 		/* Attempt to read a line in */
3274fcf65c5Sdjm next_line:
3284fcf65c5Sdjm 		/* Due to &%^*$" memory BIO behaviour with BIO_gets we
3294fcf65c5Sdjm 		 * have to check there's a complete line in there before
3304fcf65c5Sdjm 		 * calling BIO_gets or we'll just get a partial read.
3314fcf65c5Sdjm 		 */
3324fcf65c5Sdjm 		n = BIO_get_mem_data(rctx->mem, &p);
3332d2941d0Smiod 		if ((n <= 0) || !memchr(p, '\n', n)) {
3342d2941d0Smiod 			if (n >= rctx->iobuflen) {
3354fcf65c5Sdjm 				rctx->state = OHS_ERROR;
3364fcf65c5Sdjm 				return 0;
3374fcf65c5Sdjm 			}
3384fcf65c5Sdjm 			goto next_io;
3394fcf65c5Sdjm 		}
3404fcf65c5Sdjm 		n = BIO_gets(rctx->mem, (char *)rctx->iobuf, rctx->iobuflen);
3412d2941d0Smiod 		if (n <= 0) {
3424fcf65c5Sdjm 			if (BIO_should_retry(rctx->mem))
3434fcf65c5Sdjm 				goto next_io;
3444fcf65c5Sdjm 			rctx->state = OHS_ERROR;
3454fcf65c5Sdjm 			return 0;
3464fcf65c5Sdjm 		}
3474fcf65c5Sdjm 
3484fcf65c5Sdjm 		/* Don't allow excessive lines */
3492d2941d0Smiod 		if (n == rctx->iobuflen) {
3504fcf65c5Sdjm 			rctx->state = OHS_ERROR;
3514fcf65c5Sdjm 			return 0;
3524fcf65c5Sdjm 		}
3534fcf65c5Sdjm 
3544fcf65c5Sdjm 		/* First line */
3552d2941d0Smiod 		if (rctx->state == OHS_FIRSTLINE) {
3562d2941d0Smiod 			if (parse_http_line1((char *)rctx->iobuf)) {
3574fcf65c5Sdjm 				rctx->state = OHS_HEADERS;
3584fcf65c5Sdjm 				goto next_line;
3592d2941d0Smiod 			} else {
3604fcf65c5Sdjm 				rctx->state = OHS_ERROR;
3614fcf65c5Sdjm 				return 0;
3624fcf65c5Sdjm 			}
3632d2941d0Smiod 		} else {
3644fcf65c5Sdjm 			/* Look for blank line: end of headers */
3652d2941d0Smiod 			for (p = rctx->iobuf; *p; p++) {
3664fcf65c5Sdjm 				if ((*p != '\r') && (*p != '\n'))
3674fcf65c5Sdjm 					break;
3684fcf65c5Sdjm 			}
3694fcf65c5Sdjm 			if (*p)
3704fcf65c5Sdjm 				goto next_line;
3714fcf65c5Sdjm 
3724fcf65c5Sdjm 			rctx->state = OHS_ASN1_HEADER;
3734fcf65c5Sdjm 		}
374*beb6838fSjsg 		/* FALLTHROUGH */
3754fcf65c5Sdjm 
3764fcf65c5Sdjm 	case OHS_ASN1_HEADER:
377c32db552Sdjm 		/* Now reading ASN1 header: can read at least 2 bytes which
378c32db552Sdjm 		 * is enough for ASN1 SEQUENCE header and either length field
379c32db552Sdjm 		 * or at least the length of the length field.
3804fcf65c5Sdjm 		 */
3814fcf65c5Sdjm 		n = BIO_get_mem_data(rctx->mem, &p);
382c32db552Sdjm 		if (n < 2)
3834fcf65c5Sdjm 			goto next_io;
3844fcf65c5Sdjm 
3854fcf65c5Sdjm 		/* Check it is an ASN1 SEQUENCE */
3862d2941d0Smiod 		if (*p++ != (V_ASN1_SEQUENCE|V_ASN1_CONSTRUCTED)) {
3874fcf65c5Sdjm 			rctx->state = OHS_ERROR;
3884fcf65c5Sdjm 			return 0;
3894fcf65c5Sdjm 		}
3904fcf65c5Sdjm 
3914fcf65c5Sdjm 		/* Check out length field */
3922d2941d0Smiod 		if (*p & 0x80) {
393c32db552Sdjm 			/* If MSB set on initial length octet we can now
394c32db552Sdjm 			 * always read 6 octets: make sure we have them.
395c32db552Sdjm 			 */
396c32db552Sdjm 			if (n < 6)
397c32db552Sdjm 				goto next_io;
3984fcf65c5Sdjm 			n = *p & 0x7F;
3994fcf65c5Sdjm 			/* Not NDEF or excessive length */
4002d2941d0Smiod 			if (!n || (n > 4)) {
4014fcf65c5Sdjm 				rctx->state = OHS_ERROR;
4024fcf65c5Sdjm 				return 0;
4034fcf65c5Sdjm 			}
4044fcf65c5Sdjm 			p++;
4054fcf65c5Sdjm 			rctx->asn1_len = 0;
4062d2941d0Smiod 			for (i = 0; i < n; i++) {
4074fcf65c5Sdjm 				rctx->asn1_len <<= 8;
4084fcf65c5Sdjm 				rctx->asn1_len |= *p++;
4094fcf65c5Sdjm 			}
4104fcf65c5Sdjm 
4112d2941d0Smiod 			if (rctx->asn1_len > OCSP_MAX_REQUEST_LENGTH) {
4124fcf65c5Sdjm 				rctx->state = OHS_ERROR;
4134fcf65c5Sdjm 				return 0;
4144fcf65c5Sdjm 			}
4154fcf65c5Sdjm 
4164fcf65c5Sdjm 			rctx->asn1_len += n + 2;
4172d2941d0Smiod 		} else
4184fcf65c5Sdjm 			rctx->asn1_len = *p + 2;
4194fcf65c5Sdjm 
4204fcf65c5Sdjm 		rctx->state = OHS_ASN1_CONTENT;
4214fcf65c5Sdjm 
4222d2941d0Smiod 		/* FALLTHROUGH */
4234fcf65c5Sdjm 
4244fcf65c5Sdjm 	case OHS_ASN1_CONTENT:
4254fcf65c5Sdjm 		n = BIO_get_mem_data(rctx->mem, &p);
4264fcf65c5Sdjm 		if (n < (int)rctx->asn1_len)
4274fcf65c5Sdjm 			goto next_io;
4284fcf65c5Sdjm 
4294fcf65c5Sdjm 		*presp = d2i_OCSP_RESPONSE(NULL, &p, rctx->asn1_len);
4302d2941d0Smiod 		if (*presp) {
4314fcf65c5Sdjm 			rctx->state = OHS_DONE;
4324fcf65c5Sdjm 			return 1;
4334fcf65c5Sdjm 		}
4344fcf65c5Sdjm 
4354fcf65c5Sdjm 		rctx->state = OHS_ERROR;
4364fcf65c5Sdjm 		return 0;
4374fcf65c5Sdjm 
4384fcf65c5Sdjm 	case OHS_DONE:
4394fcf65c5Sdjm 		return 1;
4404fcf65c5Sdjm 	}
4414fcf65c5Sdjm 
4424fcf65c5Sdjm 	return 0;
4434fcf65c5Sdjm }
444a1e92f6bSbeck LCRYPTO_ALIAS(OCSP_sendreq_nbio);
4454fcf65c5Sdjm 
4464fcf65c5Sdjm /* Blocking OCSP request handler: now a special case of non-blocking I/O */
4472d2941d0Smiod OCSP_RESPONSE *
OCSP_sendreq_bio(BIO * b,const char * path,OCSP_REQUEST * req)44814edca61Stb OCSP_sendreq_bio(BIO *b, const char *path, OCSP_REQUEST *req)
4494fcf65c5Sdjm {
4504fcf65c5Sdjm 	OCSP_RESPONSE *resp = NULL;
4514fcf65c5Sdjm 	OCSP_REQ_CTX *ctx;
4524fcf65c5Sdjm 	int rv;
4534fcf65c5Sdjm 
4544fcf65c5Sdjm 	ctx = OCSP_sendreq_new(b, path, req, -1);
455a0f54154Smiod 	if (ctx == NULL)
456a0f54154Smiod 		return NULL;
4574fcf65c5Sdjm 
4582d2941d0Smiod 	do {
4594fcf65c5Sdjm 		rv = OCSP_sendreq_nbio(&resp, ctx);
4604fcf65c5Sdjm 	} while ((rv == -1) && BIO_should_retry(b));
4614fcf65c5Sdjm 
4624fcf65c5Sdjm 	OCSP_REQ_CTX_free(ctx);
4634fcf65c5Sdjm 
4644fcf65c5Sdjm 	if (rv)
465da347917Sbeck 		return resp;
4664fcf65c5Sdjm 
4674fcf65c5Sdjm 	return NULL;
468da347917Sbeck }
469a1e92f6bSbeck LCRYPTO_ALIAS(OCSP_sendreq_bio);
470