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