ocsp_ht.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. /* ocsp_ht.c */
  2. /*
  3. * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project
  4. * 2006.
  5. */
  6. /* ====================================================================
  7. * Copyright (c) 2006 The OpenSSL Project. All rights reserved.
  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
  14. * notice, this list of conditions and the following disclaimer.
  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. #include <stdio.h>
  60. #include <stdlib.h>
  61. #include <ctype.h>
  62. #include <string.h>
  63. #include "e_os.h"
  64. #include <openssl/asn1.h>
  65. #include <openssl/ocsp.h>
  66. #include <openssl/err.h>
  67. #include <openssl/buffer.h>
  68. #ifdef OPENSSL_SYS_SUNOS
  69. # define strtoul (unsigned long)strtol
  70. #endif /* OPENSSL_SYS_SUNOS */
  71. /* Stateful OCSP request code, supporting non-blocking I/O */
  72. /* Opaque OCSP request status structure */
  73. struct ocsp_req_ctx_st {
  74. int state; /* Current I/O state */
  75. unsigned char *iobuf; /* Line buffer */
  76. int iobuflen; /* Line buffer length */
  77. BIO *io; /* BIO to perform I/O with */
  78. BIO *mem; /* Memory BIO response is built into */
  79. unsigned long asn1_len; /* ASN1 length of response */
  80. };
  81. #define OCSP_MAX_REQUEST_LENGTH (100 * 1024)
  82. #define OCSP_MAX_LINE_LEN 4096;
  83. /* OCSP states */
  84. /* If set no reading should be performed */
  85. #define OHS_NOREAD 0x1000
  86. /* Error condition */
  87. #define OHS_ERROR (0 | OHS_NOREAD)
  88. /* First line being read */
  89. #define OHS_FIRSTLINE 1
  90. /* MIME headers being read */
  91. #define OHS_HEADERS 2
  92. /* OCSP initial header (tag + length) being read */
  93. #define OHS_ASN1_HEADER 3
  94. /* OCSP content octets being read */
  95. #define OHS_ASN1_CONTENT 4
  96. /* Request being sent */
  97. #define OHS_ASN1_WRITE (6 | OHS_NOREAD)
  98. /* Request being flushed */
  99. #define OHS_ASN1_FLUSH (7 | OHS_NOREAD)
  100. /* Completed */
  101. #define OHS_DONE (8 | OHS_NOREAD)
  102. static int parse_http_line1(char *line);
  103. void OCSP_REQ_CTX_free(OCSP_REQ_CTX *rctx)
  104. {
  105. if (rctx->mem)
  106. BIO_free(rctx->mem);
  107. if (rctx->iobuf)
  108. OPENSSL_free(rctx->iobuf);
  109. OPENSSL_free(rctx);
  110. }
  111. OCSP_REQ_CTX *OCSP_sendreq_new(BIO *io, char *path, OCSP_REQUEST *req,
  112. int maxline)
  113. {
  114. static char post_hdr[] = "POST %s HTTP/1.0\r\n"
  115. "Content-Type: application/ocsp-request\r\n"
  116. "Content-Length: %d\r\n\r\n";
  117. OCSP_REQ_CTX *rctx;
  118. rctx = OPENSSL_malloc(sizeof(OCSP_REQ_CTX));
  119. rctx->state = OHS_FIRSTLINE;
  120. rctx->mem = BIO_new(BIO_s_mem());
  121. rctx->io = io;
  122. if (maxline > 0)
  123. rctx->iobuflen = maxline;
  124. else
  125. rctx->iobuflen = OCSP_MAX_LINE_LEN;
  126. rctx->iobuf = OPENSSL_malloc(rctx->iobuflen);
  127. if (!path)
  128. path = "/";
  129. if (BIO_printf(rctx->mem, post_hdr, path,
  130. i2d_OCSP_REQUEST(req, NULL)) <= 0) {
  131. rctx->state = OHS_ERROR;
  132. return 0;
  133. }
  134. if (i2d_OCSP_REQUEST_bio(rctx->mem, req) <= 0) {
  135. rctx->state = OHS_ERROR;
  136. return 0;
  137. }
  138. rctx->state = OHS_ASN1_WRITE;
  139. rctx->asn1_len = BIO_get_mem_data(rctx->mem, NULL);
  140. return rctx;
  141. }
  142. /*
  143. * Parse the HTTP response. This will look like this: "HTTP/1.0 200 OK". We
  144. * need to obtain the numeric code and (optional) informational message.
  145. */
  146. static int parse_http_line1(char *line)
  147. {
  148. int retcode;
  149. char *p, *q, *r;
  150. /* Skip to first white space (passed protocol info) */
  151. for (p = line; *p && !isspace((unsigned char)*p); p++)
  152. continue;
  153. if (!*p) {
  154. OCSPerr(OCSP_F_PARSE_HTTP_LINE1, OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
  155. return 0;
  156. }
  157. /* Skip past white space to start of response code */
  158. while (*p && isspace((unsigned char)*p))
  159. p++;
  160. if (!*p) {
  161. OCSPerr(OCSP_F_PARSE_HTTP_LINE1, OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
  162. return 0;
  163. }
  164. /* Find end of response code: first whitespace after start of code */
  165. for (q = p; *q && !isspace((unsigned char)*q); q++)
  166. continue;
  167. if (!*q) {
  168. OCSPerr(OCSP_F_PARSE_HTTP_LINE1, OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
  169. return 0;
  170. }
  171. /* Set end of response code and start of message */
  172. *q++ = 0;
  173. /* Attempt to parse numeric code */
  174. retcode = strtoul(p, &r, 10);
  175. if (*r)
  176. return 0;
  177. /* Skip over any leading white space in message */
  178. while (*q && isspace((unsigned char)*q))
  179. q++;
  180. if (*q) {
  181. /*
  182. * Finally zap any trailing white space in message (include CRLF)
  183. */
  184. /* We know q has a non white space character so this is OK */
  185. for (r = q + strlen(q) - 1; isspace((unsigned char)*r); r--)
  186. *r = 0;
  187. }
  188. if (retcode != 200) {
  189. OCSPerr(OCSP_F_PARSE_HTTP_LINE1, OCSP_R_SERVER_RESPONSE_ERROR);
  190. if (!*q)
  191. ERR_add_error_data(2, "Code=", p);
  192. else
  193. ERR_add_error_data(4, "Code=", p, ",Reason=", q);
  194. return 0;
  195. }
  196. return 1;
  197. }
  198. int OCSP_sendreq_nbio(OCSP_RESPONSE **presp, OCSP_REQ_CTX *rctx)
  199. {
  200. int i, n;
  201. const unsigned char *p;
  202. next_io:
  203. if (!(rctx->state & OHS_NOREAD)) {
  204. n = BIO_read(rctx->io, rctx->iobuf, rctx->iobuflen);
  205. if (n <= 0) {
  206. if (BIO_should_retry(rctx->io))
  207. return -1;
  208. return 0;
  209. }
  210. /* Write data to memory BIO */
  211. if (BIO_write(rctx->mem, rctx->iobuf, n) != n)
  212. return 0;
  213. }
  214. switch (rctx->state) {
  215. case OHS_ASN1_WRITE:
  216. n = BIO_get_mem_data(rctx->mem, &p);
  217. i = BIO_write(rctx->io, p + (n - rctx->asn1_len), rctx->asn1_len);
  218. if (i <= 0) {
  219. if (BIO_should_retry(rctx->io))
  220. return -1;
  221. rctx->state = OHS_ERROR;
  222. return 0;
  223. }
  224. rctx->asn1_len -= i;
  225. if (rctx->asn1_len > 0)
  226. goto next_io;
  227. rctx->state = OHS_ASN1_FLUSH;
  228. (void)BIO_reset(rctx->mem);
  229. case OHS_ASN1_FLUSH:
  230. i = BIO_flush(rctx->io);
  231. if (i > 0) {
  232. rctx->state = OHS_FIRSTLINE;
  233. goto next_io;
  234. }
  235. if (BIO_should_retry(rctx->io))
  236. return -1;
  237. rctx->state = OHS_ERROR;
  238. return 0;
  239. case OHS_ERROR:
  240. return 0;
  241. case OHS_FIRSTLINE:
  242. case OHS_HEADERS:
  243. /* Attempt to read a line in */
  244. next_line:
  245. /*
  246. * Due to &%^*$" memory BIO behaviour with BIO_gets we have to check
  247. * there's a complete line in there before calling BIO_gets or we'll
  248. * just get a partial read.
  249. */
  250. n = BIO_get_mem_data(rctx->mem, &p);
  251. if ((n <= 0) || !memchr(p, '\n', n)) {
  252. if (n >= rctx->iobuflen) {
  253. rctx->state = OHS_ERROR;
  254. return 0;
  255. }
  256. goto next_io;
  257. }
  258. n = BIO_gets(rctx->mem, (char *)rctx->iobuf, rctx->iobuflen);
  259. if (n <= 0) {
  260. if (BIO_should_retry(rctx->mem))
  261. goto next_io;
  262. rctx->state = OHS_ERROR;
  263. return 0;
  264. }
  265. /* Don't allow excessive lines */
  266. if (n == rctx->iobuflen) {
  267. rctx->state = OHS_ERROR;
  268. return 0;
  269. }
  270. /* First line */
  271. if (rctx->state == OHS_FIRSTLINE) {
  272. if (parse_http_line1((char *)rctx->iobuf)) {
  273. rctx->state = OHS_HEADERS;
  274. goto next_line;
  275. } else {
  276. rctx->state = OHS_ERROR;
  277. return 0;
  278. }
  279. } else {
  280. /* Look for blank line: end of headers */
  281. for (p = rctx->iobuf; *p; p++) {
  282. if ((*p != '\r') && (*p != '\n'))
  283. break;
  284. }
  285. if (*p)
  286. goto next_line;
  287. rctx->state = OHS_ASN1_HEADER;
  288. }
  289. /* Fall thru */
  290. case OHS_ASN1_HEADER:
  291. /*
  292. * Now reading ASN1 header: can read at least 2 bytes which is enough
  293. * for ASN1 SEQUENCE header and either length field or at least the
  294. * length of the length field.
  295. */
  296. n = BIO_get_mem_data(rctx->mem, &p);
  297. if (n < 2)
  298. goto next_io;
  299. /* Check it is an ASN1 SEQUENCE */
  300. if (*p++ != (V_ASN1_SEQUENCE | V_ASN1_CONSTRUCTED)) {
  301. rctx->state = OHS_ERROR;
  302. return 0;
  303. }
  304. /* Check out length field */
  305. if (*p & 0x80) {
  306. /*
  307. * If MSB set on initial length octet we can now always read 6
  308. * octets: make sure we have them.
  309. */
  310. if (n < 6)
  311. goto next_io;
  312. n = *p & 0x7F;
  313. /* Not NDEF or excessive length */
  314. if (!n || (n > 4)) {
  315. rctx->state = OHS_ERROR;
  316. return 0;
  317. }
  318. p++;
  319. rctx->asn1_len = 0;
  320. for (i = 0; i < n; i++) {
  321. rctx->asn1_len <<= 8;
  322. rctx->asn1_len |= *p++;
  323. }
  324. if (rctx->asn1_len > OCSP_MAX_REQUEST_LENGTH) {
  325. rctx->state = OHS_ERROR;
  326. return 0;
  327. }
  328. rctx->asn1_len += n + 2;
  329. } else
  330. rctx->asn1_len = *p + 2;
  331. rctx->state = OHS_ASN1_CONTENT;
  332. /* Fall thru */
  333. case OHS_ASN1_CONTENT:
  334. n = BIO_get_mem_data(rctx->mem, &p);
  335. if (n < (int)rctx->asn1_len)
  336. goto next_io;
  337. *presp = d2i_OCSP_RESPONSE(NULL, &p, rctx->asn1_len);
  338. if (*presp) {
  339. rctx->state = OHS_DONE;
  340. return 1;
  341. }
  342. rctx->state = OHS_ERROR;
  343. return 0;
  344. break;
  345. case OHS_DONE:
  346. return 1;
  347. }
  348. return 0;
  349. }
  350. /* Blocking OCSP request handler: now a special case of non-blocking I/O */
  351. OCSP_RESPONSE *OCSP_sendreq_bio(BIO *b, char *path, OCSP_REQUEST *req)
  352. {
  353. OCSP_RESPONSE *resp = NULL;
  354. OCSP_REQ_CTX *ctx;
  355. int rv;
  356. ctx = OCSP_sendreq_new(b, path, req, -1);
  357. if (!ctx)
  358. return NULL;
  359. do {
  360. rv = OCSP_sendreq_nbio(&resp, ctx);
  361. } while ((rv == -1) && BIO_should_retry(b));
  362. OCSP_REQ_CTX_free(ctx);
  363. if (rv)
  364. return resp;
  365. return NULL;
  366. }