]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/CyaSSL/src/ocsp.c
Add FreeRTOS-Plus directory.
[freertos] / FreeRTOS-Plus / CyaSSL / src / ocsp.c
1 /* ocsp.c
2  *
3  * Copyright (C) 2006-2012 Sawtooth Consulting Ltd.
4  *
5  * This file is part of CyaSSL.
6  *
7  * CyaSSL is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * CyaSSL is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20  */
21
22 #ifdef HAVE_CONFIG_H
23     #include <config.h>
24 #endif
25
26 #include <cyassl/error.h>
27 #include <cyassl/ocsp.h>
28 #include <cyassl/internal.h>
29 #include <ctype.h>
30
31 #include <string.h>
32 #include <unistd.h>
33 #include <netdb.h>
34 #include <netinet/in.h>
35 #include <netinet/tcp.h>
36 #include <arpa/inet.h>
37 #include <sys/ioctl.h>
38 #include <sys/time.h>
39 #include <sys/types.h>
40 #include <sys/socket.h>
41
42
43 #ifdef HAVE_OCSP
44 CYASSL_API int ocsp_test(unsigned char* buf, int sz);
45 #define CYASSL_OCSP_ENABLE       0x0001 /* Enable OCSP lookups */
46 #define CYASSL_OCSP_URL_OVERRIDE 0x0002 /* Use the override URL instead of URL
47                                          * in certificate */
48
49 typedef struct sockaddr_in  SOCKADDR_IN_T;
50 #define AF_INET_V    AF_INET
51 #define SOCKET_T unsigned int
52    
53
54 int ocsp_test(unsigned char* buf, int sz)
55 {
56     CYASSL_OCSP ocsp;
57     OcspResponse resp;
58     int result;
59     
60     CyaSSL_OCSP_Init(&ocsp);
61     InitOcspResponse(&resp, buf, sz, NULL);
62
63     ocsp.enabled = 1;
64     ocsp.useOverrideUrl = 1;
65     CyaSSL_OCSP_set_override_url(&ocsp, "http://ocsp.example.com:8080/bob");
66     CyaSSL_OCSP_Lookup_Cert(&ocsp, NULL);
67
68     result = OcspResponseDecode(&resp);
69     
70     FreeOcspResponse(&resp);
71     CyaSSL_OCSP_Cleanup(&ocsp);
72
73     return result;
74 }
75
76
77 int CyaSSL_OCSP_Init(CYASSL_OCSP* ocsp)
78 {
79     if (ocsp != NULL) {
80         XMEMSET(ocsp, 0, sizeof(*ocsp));
81         return 0;
82     }
83
84     return -1;
85 }
86
87
88 void CyaSSL_OCSP_Cleanup(CYASSL_OCSP* ocsp)
89 {
90     ocsp->enabled = 0;
91 }
92
93
94 int CyaSSL_OCSP_set_override_url(CYASSL_OCSP* ocsp, const char* url)
95 {
96     if (ocsp != NULL && url != NULL) {
97         int i, cur, hostname;
98
99         /* need to break the url down into scheme, address, and port */
100         /* "http://example.com:8080/" */
101         if (XSTRNCMP(url, "http://", 7) == 0) {
102             cur = 7;
103         } else cur = 0;
104
105         i = 0;
106         while (url[cur] != 0 && url[cur] != ':' && url[cur] != '/') {
107             ocsp->overrideName[i++] = url[cur++];
108         }
109         ocsp->overrideName[i] = 0;
110         /* Need to pick out the path after the domain name */
111
112         if (url[cur] == ':') {
113             char port[6];
114             int j;
115             i = 0;
116             cur++;
117             while (url[cur] != 0 && url[cur] != '/' && i < 6) {
118                 port[i++] = url[cur++];
119             }
120
121             ocsp->overridePort = 0;
122             for (j = 0; j < i; j++) {
123                 if (port[j] < '0' || port[j] > '9') return -1;
124                 ocsp->overridePort = 
125                             (ocsp->overridePort * 10) + (port[j] - '0');
126             }
127         }
128         else
129             ocsp->overridePort = 80;
130
131         if (url[cur] == '/') {
132             i = 0;
133             while (url[cur] != 0 && i < 80) {
134                 ocsp->overridePath[i++] = url[cur++];
135             }
136             ocsp->overridePath[i] = 0;
137         }
138         else {
139             ocsp->overridePath[0] = '/';
140             ocsp->overridePath[1] = 0;
141         }
142             
143
144         return 1;
145     }
146
147     return 0;
148 }
149
150
151 static INLINE void tcp_socket(SOCKET_T* sockfd, SOCKADDR_IN_T* addr,
152                               const char* peer, word16 port)
153 {
154     const char* host = peer;
155
156     /* peer could be in human readable form */
157     if (peer != INADDR_ANY && isalpha(peer[0])) {
158         struct hostent* entry = gethostbyname(peer);
159
160         if (entry) {
161             struct sockaddr_in tmp;
162             memset(&tmp, 0, sizeof(struct sockaddr_in));
163             memcpy(&tmp.sin_addr.s_addr, entry->h_addr_list[0],
164                    entry->h_length);
165             host = inet_ntoa(tmp.sin_addr);
166         }
167         else
168             CYASSL_MSG("no entry for host");
169     }
170
171     *sockfd = socket(AF_INET_V, SOCK_STREAM, 0);
172     memset(addr, 0, sizeof(SOCKADDR_IN_T));
173
174     addr->sin_family = AF_INET_V;
175     addr->sin_port = htons(port);
176     if (host == INADDR_ANY)
177         addr->sin_addr.s_addr = INADDR_ANY;
178     else
179         addr->sin_addr.s_addr = inet_addr(host);
180 }
181
182
183 static INLINE void tcp_connect(SOCKET_T* sockfd, const char* ip, word16 port)
184 {
185     SOCKADDR_IN_T addr;
186     tcp_socket(sockfd, &addr, ip, port);
187
188     if (connect(*sockfd, (const struct sockaddr*)&addr, sizeof(addr)) != 0)
189         CYASSL_MSG("tcp connect failed");
190 }
191
192
193 static int build_http_request(CYASSL_OCSP* ocsp, int ocspReqSz,
194                                                         byte* buf, int bufSize)
195 {
196     return snprintf((char*)buf, bufSize,
197         "POST %s HTTP/1.1\r\n"
198         "Host: %s\r\n"
199         "Content-Length: %d\r\n"
200         "Content-Type: application/ocsp-request\r\n"
201         "\r\n", 
202         ocsp->overridePath, ocsp->overrideName, ocspReqSz);
203 }
204
205 #if 0
206 static const char foo[] = \
207         "\x30\x81\xB7\x30\x81\xB4\x30\x81\x8C\x30\x44\x30\x42\x30\x09\x06\x05\x2B\x0E\x03" \
208         "\x02\x1A\x05\x00\x04\x14\x49\x2D\x52\x83\x4B\x40\x37\xF5\xA9\x9E\x26\xA2\x3E\x48" \
209         "\x2F\x2E\x37\x34\xC9\x54\x04\x14\x21\xA2\x25\xEE\x57\x38\x34\x5A\x24\x9D\xF3\x7C" \
210         "\x18\x60\x59\x7A\x04\x3D\xF5\x69\x02\x09\x00\x89\x5A\xA2\xBD\xFE\x26\x8B\xEE\x30" \
211         "\x44\x30\x42\x30\x09\x06\x05\x2B\x0E\x03\x02\x1A\x05\x00\x04\x14\x49\x2D\x52\x83" \
212         "\x4B\x40\x37\xF5\xA9\x9E\x26\xA2\x3E\x48\x2F\x2E\x37\x34\xC9\x54\x04\x14\x21\xA2" \
213         "\x25\xEE\x57\x38\x34\x5A\x24\x9D\xF3\x7C\x18\x60\x59\x7A\x04\x3D\xF5\x69\x02\x09" \
214         "\x00\x89\x5A\xA2\xBD\xFE\x26\x8B\xEF\xA2\x23\x30\x21\x30\x1F\x06\x09\x2B\x06\x01" \
215         "\x05\x05\x07\x30\x01\x02\x04\x12\x04\x10\x20\x56\x47\x19\x65\x33\xB6\xB5\xAD\x39" \
216         "\x1F\x21\x65\xE0\x44\x1E";
217
218
219 static int build_ocsp_request(CYASSL_OCSP* ocsp, byte* buf, int bufSz)
220 {
221     memcpy(buf, foo, sizeof(foo));
222     return sizeof(foo) - 1;
223 }
224 #endif
225
226 static byte* decode_http_response(byte* httpBuf, int httpBufSz, int* ocspRespSz)
227 {
228     int idx = 0;
229     int stop = 0;
230     byte* contentType = NULL;
231     byte* contentLength = NULL;
232     byte* content = NULL;
233     char* buf = (char*)httpBuf; /* kludge so I'm not constantly casting */
234
235     if (strncasecmp(buf, "HTTP/1", 6) != 0)
236         return NULL;
237     
238     idx = 9; /* sets to the first byte after "HTTP/1.X ", which should be the
239               * HTTP result code */
240
241      if (strncasecmp(&buf[idx], "200 OK", 6) != 0)
242         return NULL;
243     
244     idx += 8;
245
246     while (idx < httpBufSz && !stop) {
247         if (buf[idx] == '\r' && buf[idx+1] == '\n') {
248             stop = 1;
249             idx += 2;
250         }
251         else {
252             if (contentType == NULL &&
253                 strncasecmp(&buf[idx], "Content-Type:", 13) == 0) {
254                 idx += 13;
255                 if (buf[idx] == ' ') idx++;
256                 if (strncasecmp(&buf[idx], "application/ocsp-response", 25) != 0)
257                     return NULL;
258                 idx += 27;
259             } else if (contentLength == NULL &&
260                 strncasecmp(&buf[idx], "Content-Length:", 15) == 0) {
261                 int len = 0;
262                 idx += 15;
263                 if (buf[idx] == ' ') idx++;
264                 while (buf[idx] > '0' && buf[idx] < '9' && idx < httpBufSz) {
265                     len = (len * 10) + (buf[idx] - '0');
266                     idx++;
267                 }
268                 *ocspRespSz = len;
269                 idx += 2; /* skip the crlf */
270             } else {
271                 /* Advance idx past the next \r\n */
272                 char* end = strstr(&buf[idx], "\r\n");
273                 idx = end - buf + 2;
274                 stop = 1;
275             }
276         }
277     }
278     return &httpBuf[idx];
279 }
280
281
282 #define SCRATCH_BUFFER_SIZE 2048
283
284 int CyaSSL_OCSP_Lookup_Cert(CYASSL_OCSP* ocsp, DecodedCert* cert)
285 {
286     SOCKET_T sfd = -1;
287     byte buf[SCRATCH_BUFFER_SIZE];
288     byte* httpBuf = &buf[0];
289     int httpBufSz = SCRATCH_BUFFER_SIZE/4;
290     byte* ocspReqBuf = &buf[httpBufSz];
291     int ocspReqSz = SCRATCH_BUFFER_SIZE - httpBufSz;
292     OcspResponse ocspResponse;
293     int result = CERT_UNKNOWN;
294
295     /* If OCSP lookups are disabled, return success. */
296     if (!ocsp->enabled) {
297         CYASSL_MSG("OCSP lookup disabled, assuming CERT_GOOD");
298         return CERT_GOOD;
299     }
300
301     /* If OCSP lookups are enabled, but URL Override is disabled, return 
302     ** a failure. Need to have an override URL for right now. */
303     if (!ocsp->useOverrideUrl || cert == NULL) {
304         CYASSL_MSG("OCSP lookup enabled, but URL Override disabled");
305         return CERT_UNKNOWN;
306     }
307
308     XMEMCPY(ocsp->status[0].issuerHash, cert->issuerHash, SHA_SIZE);
309     XMEMCPY(ocsp->status[0].issuerKeyHash, cert->issuerKeyHash, SHA_SIZE);
310     XMEMCPY(ocsp->status[0].serial, cert->serial, cert->serialSz);
311     ocsp->status[0].serialSz = cert->serialSz;
312     ocsp->statusLen = 1;
313
314     /*ocspReqSz = build_ocsp_request(ocsp, ocspReqBuf, ocspReqSz);*/
315     ocspReqSz = EncodeOcspRequest(cert, ocspReqBuf, ocspReqSz);
316     httpBufSz = build_http_request(ocsp, ocspReqSz, httpBuf, httpBufSz);
317
318     tcp_connect(&sfd, ocsp->overrideName, ocsp->overridePort);
319     if (sfd > 0) {
320         int written;
321         written = write(sfd, httpBuf, httpBufSz);
322         if (written == httpBufSz) {
323             written = write(sfd, ocspReqBuf, ocspReqSz);
324             if (written == ocspReqSz) {
325                 httpBufSz = read(sfd, buf, SCRATCH_BUFFER_SIZE);
326                 if (httpBufSz > 0) {
327                     ocspReqBuf = decode_http_response(buf, httpBufSz,
328                         &ocspReqSz);
329                 }
330             }
331         }
332         close(sfd);
333         if (ocspReqBuf == NULL) {
334             CYASSL_MSG("HTTP response was not OK, no OCSP response");
335             return CERT_UNKNOWN;
336         }
337     } else {
338         CYASSL_MSG("OCSP Responder connection failed");
339         return CERT_UNKNOWN;
340     }
341
342     InitOcspResponse(&ocspResponse, ocspReqBuf, ocspReqSz, NULL);
343     OcspResponseDecode(&ocspResponse);
344     if (ocspResponse.responseStatus != OCSP_SUCCESSFUL) {
345         CYASSL_MSG("OCSP Responder failure");
346     } else {
347         result = ocspResponse.certStatus[0];
348     }
349     FreeOcspResponse(&ocspResponse);
350
351     return result;
352 }
353
354
355 #endif /* HAVE_OCSP */
356