]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/WolfSSL/src/io.c
ac24bd17cc6db0f53db52a494abfdb0705c49c4e
[freertos] / FreeRTOS-Plus / Source / WolfSSL / src / io.c
1 /* io.c
2  *
3  * Copyright (C) 2006-2014 wolfSSL Inc.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #ifdef HAVE_CONFIG_H
23     #include <config.h>
24 #endif
25
26 #include <cyassl/ctaocrypt/settings.h>
27
28 #ifdef _WIN32_WCE
29     /* On WinCE winsock2.h must be included before windows.h for socket stuff */
30     #include <winsock2.h>
31 #endif
32
33 #include <cyassl/internal.h>
34 #include <cyassl/error-ssl.h>
35
36 /* if user writes own I/O callbacks they can define CYASSL_USER_IO to remove
37    automatic setting of default I/O functions EmbedSend() and EmbedReceive()
38    but they'll still need SetCallback xxx() at end of file 
39 */
40 #ifndef CYASSL_USER_IO
41
42 #ifdef HAVE_LIBZ
43     #include "zlib.h"
44 #endif
45
46 #ifndef USE_WINDOWS_API
47     #ifdef CYASSL_LWIP
48         /* lwIP needs to be configured to use sockets API in this mode */
49         /* LWIP_SOCKET 1 in lwip/opt.h or in build */
50         #include "lwip/sockets.h"
51         #include <errno.h>
52         #ifndef LWIP_PROVIDE_ERRNO
53             #define LWIP_PROVIDE_ERRNO 1
54         #endif
55     #elif defined(FREESCALE_MQX)
56         #include <posix.h>
57         #include <rtcs.h>
58     #elif defined(CYASSL_MDK_ARM)
59         #if defined(CYASSL_MDK5)
60             #include "cmsis_os.h"
61             #include "rl_fs.h" 
62             #include "rl_net.h" 
63         #else
64             #include <rtl.h>
65         #endif
66         #undef RNG
67         #include "CYASSL_MDK_ARM.h"
68         #undef RNG
69         #define RNG CyaSSL_RNG 
70         /* for avoiding name conflict in "stm32f2xx.h" */
71         static int errno;
72     #elif defined(CYASSL_IAR_ARM)
73         /* nothing */
74     #else
75         #include <sys/types.h>
76         #include <errno.h>
77         #ifndef EBSNET
78             #include <unistd.h>
79         #endif
80         #include <fcntl.h>
81         #if !(defined(DEVKITPRO) || defined(HAVE_RTP_SYS) || defined(EBSNET))
82             #include <sys/socket.h>
83             #include <arpa/inet.h>
84             #include <netinet/in.h>
85             #include <netdb.h>
86             #ifdef __PPU
87                 #include <netex/errno.h>
88             #else
89                 #include <sys/ioctl.h>
90             #endif
91         #endif
92         #ifdef HAVE_RTP_SYS
93             #include <socket.h>
94         #endif
95         #ifdef EBSNET
96             #include "rtipapi.h"  /* errno */
97             #include "socket.h"
98         #endif
99     #endif
100 #endif /* USE_WINDOWS_API */
101
102 #ifdef __sun
103     #include <sys/filio.h>
104 #endif
105
106 #ifdef USE_WINDOWS_API 
107     /* no epipe yet */
108     #ifndef WSAEPIPE
109         #define WSAEPIPE       -12345
110     #endif
111     #define SOCKET_EWOULDBLOCK WSAEWOULDBLOCK
112     #define SOCKET_EAGAIN      WSAETIMEDOUT
113     #define SOCKET_ECONNRESET  WSAECONNRESET
114     #define SOCKET_EINTR       WSAEINTR
115     #define SOCKET_EPIPE       WSAEPIPE
116     #define SOCKET_ECONNREFUSED WSAENOTCONN
117     #define SOCKET_ECONNABORTED WSAECONNABORTED
118     #define close(s) closesocket(s)
119 #elif defined(__PPU)
120     #define SOCKET_EWOULDBLOCK SYS_NET_EWOULDBLOCK
121     #define SOCKET_EAGAIN      SYS_NET_EAGAIN
122     #define SOCKET_ECONNRESET  SYS_NET_ECONNRESET
123     #define SOCKET_EINTR       SYS_NET_EINTR
124     #define SOCKET_EPIPE       SYS_NET_EPIPE
125     #define SOCKET_ECONNREFUSED SYS_NET_ECONNREFUSED
126     #define SOCKET_ECONNABORTED SYS_NET_ECONNABORTED
127 #elif defined(FREESCALE_MQX)
128     /* RTCS doesn't have an EWOULDBLOCK error */
129     #define SOCKET_EWOULDBLOCK EAGAIN
130     #define SOCKET_EAGAIN      EAGAIN
131     #define SOCKET_ECONNRESET  RTCSERR_TCP_CONN_RESET
132     #define SOCKET_EINTR       EINTR
133     #define SOCKET_EPIPE       EPIPE
134     #define SOCKET_ECONNREFUSED RTCSERR_TCP_CONN_REFUSED
135     #define SOCKET_ECONNABORTED RTCSERR_TCP_CONN_ABORTED
136 #elif defined(CYASSL_MDK_ARM)
137     #if defined(CYASSL_MDK5)
138         #define SOCKET_EWOULDBLOCK BSD_ERROR_WOULDBLOCK
139         #define SOCKET_EAGAIN      BSD_ERROR_LOCKED
140         #define SOCKET_ECONNRESET  BSD_ERROR_CLOSED
141         #define SOCKET_EINTR       BSD_ERROR
142         #define SOCKET_EPIPE       BSD_ERROR
143         #define SOCKET_ECONNREFUSED BSD_ERROR
144         #define SOCKET_ECONNABORTED BSD_ERROR
145     #else
146         #define SOCKET_EWOULDBLOCK SCK_EWOULDBLOCK
147         #define SOCKET_EAGAIN      SCK_ELOCKED
148         #define SOCKET_ECONNRESET  SCK_ECLOSED
149         #define SOCKET_EINTR       SCK_ERROR
150         #define SOCKET_EPIPE       SCK_ERROR
151         #define SOCKET_ECONNREFUSED SCK_ERROR
152         #define SOCKET_ECONNABORTED SCK_ERROR
153     #endif
154 #else
155     #define SOCKET_EWOULDBLOCK EWOULDBLOCK
156     #define SOCKET_EAGAIN      EAGAIN
157     #define SOCKET_ECONNRESET  ECONNRESET
158     #define SOCKET_EINTR       EINTR
159     #define SOCKET_EPIPE       EPIPE
160     #define SOCKET_ECONNREFUSED ECONNREFUSED
161     #define SOCKET_ECONNABORTED ECONNABORTED
162 #endif /* USE_WINDOWS_API */
163
164
165 #ifdef DEVKITPRO
166     /* from network.h */
167     int net_send(int, const void*, int, unsigned int);
168     int net_recv(int, void*, int, unsigned int);
169     #define SEND_FUNCTION net_send
170     #define RECV_FUNCTION net_recv
171 #elif defined(CYASSL_LWIP)
172     #define SEND_FUNCTION lwip_send
173     #define RECV_FUNCTION lwip_recv
174 #else
175     #define SEND_FUNCTION send
176     #define RECV_FUNCTION recv
177 #endif
178
179
180 /* Translates return codes returned from 
181  * send() and recv() if need be. 
182  */
183 static INLINE int TranslateReturnCode(int old, int sd)
184 {
185     (void)sd;
186
187 #ifdef FREESCALE_MQX
188     if (old == 0) {
189         errno = SOCKET_EWOULDBLOCK;
190         return -1;  /* convert to BSD style wouldblock as error */
191     }
192
193     if (old < 0) {
194         errno = RTCS_geterror(sd);
195         if (errno == RTCSERR_TCP_CONN_CLOSING)
196             return 0;   /* convert to BSD style closing */
197     }
198 #endif
199
200     return old;
201 }
202
203 static INLINE int LastError(void)
204 {
205 #ifdef USE_WINDOWS_API 
206     return WSAGetLastError();
207 #elif defined(EBSNET)
208     return xn_getlasterror();
209 #else
210     return errno;
211 #endif
212 }
213
214 /* The receive embedded callback
215  *  return : nb bytes read, or error
216  */
217 int EmbedReceive(CYASSL *ssl, char *buf, int sz, void *ctx)
218 {
219     int recvd;
220     int err;
221     int sd = *(int*)ctx;
222
223 #ifdef CYASSL_DTLS
224     {
225         int dtls_timeout = CyaSSL_dtls_get_current_timeout(ssl);
226         if (CyaSSL_dtls(ssl)
227                      && !CyaSSL_get_using_nonblock(ssl)
228                      && dtls_timeout != 0) {
229             #ifdef USE_WINDOWS_API
230                 DWORD timeout = dtls_timeout * 1000;
231             #else
232                 struct timeval timeout;
233                 XMEMSET(&timeout, 0, sizeof(timeout));
234                 timeout.tv_sec = dtls_timeout;
235             #endif
236             if (setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout,
237                            sizeof(timeout)) != 0) {
238                 CYASSL_MSG("setsockopt rcvtimeo failed");
239             }
240         }
241     }
242 #endif
243
244     recvd = (int)RECV_FUNCTION(sd, buf, sz, ssl->rflags);
245
246     recvd = TranslateReturnCode(recvd, sd);
247
248     if (recvd < 0) {
249         err = LastError();
250         CYASSL_MSG("Embed Receive error");
251
252         if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) {
253             if (!CyaSSL_dtls(ssl) || CyaSSL_get_using_nonblock(ssl)) {
254                 CYASSL_MSG("    Would block");
255                 return CYASSL_CBIO_ERR_WANT_READ;
256             }
257             else {
258                 CYASSL_MSG("    Socket timeout");
259                 return CYASSL_CBIO_ERR_TIMEOUT;
260             }
261         }
262         else if (err == SOCKET_ECONNRESET) {
263             CYASSL_MSG("    Connection reset");
264             return CYASSL_CBIO_ERR_CONN_RST;
265         }
266         else if (err == SOCKET_EINTR) {
267             CYASSL_MSG("    Socket interrupted");
268             return CYASSL_CBIO_ERR_ISR;
269         }
270         else if (err == SOCKET_ECONNREFUSED) {
271             CYASSL_MSG("    Connection refused");
272             return CYASSL_CBIO_ERR_WANT_READ;
273         }
274         else if (err == SOCKET_ECONNABORTED) {
275             CYASSL_MSG("    Connection aborted");
276             return CYASSL_CBIO_ERR_CONN_CLOSE;
277         }
278         else {
279             CYASSL_MSG("    General error");
280             return CYASSL_CBIO_ERR_GENERAL;
281         }
282     }
283     else if (recvd == 0) {
284         CYASSL_MSG("Embed receive connection closed");
285         return CYASSL_CBIO_ERR_CONN_CLOSE;
286     }
287
288     return recvd;
289 }
290
291 /* The send embedded callback
292  *  return : nb bytes sent, or error
293  */
294 int EmbedSend(CYASSL* ssl, char *buf, int sz, void *ctx)
295 {
296     int sd = *(int*)ctx;
297     int sent;
298     int len = sz;
299     int err;
300
301     sent = (int)SEND_FUNCTION(sd, &buf[sz - len], len, ssl->wflags);
302
303     if (sent < 0) {
304         err = LastError();
305         CYASSL_MSG("Embed Send error");
306
307         if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) {
308             CYASSL_MSG("    Would Block");
309             return CYASSL_CBIO_ERR_WANT_WRITE;
310         }
311         else if (err == SOCKET_ECONNRESET) {
312             CYASSL_MSG("    Connection reset");
313             return CYASSL_CBIO_ERR_CONN_RST;
314         }
315         else if (err == SOCKET_EINTR) {
316             CYASSL_MSG("    Socket interrupted");
317             return CYASSL_CBIO_ERR_ISR;
318         }
319         else if (err == SOCKET_EPIPE) {
320             CYASSL_MSG("    Socket EPIPE");
321             return CYASSL_CBIO_ERR_CONN_CLOSE;
322         }
323         else {
324             CYASSL_MSG("    General error");
325             return CYASSL_CBIO_ERR_GENERAL;
326         }
327     }
328  
329     return sent;
330 }
331
332
333 #ifdef CYASSL_DTLS
334
335 #include <cyassl/ctaocrypt/sha.h>
336
337 #ifdef USE_WINDOWS_API
338    #define XSOCKLENT int
339 #else
340    #define XSOCKLENT socklen_t
341 #endif
342
343 #define SENDTO_FUNCTION sendto
344 #define RECVFROM_FUNCTION recvfrom
345
346
347 /* The receive embedded callback
348  *  return : nb bytes read, or error
349  */
350 int EmbedReceiveFrom(CYASSL *ssl, char *buf, int sz, void *ctx)
351 {
352     CYASSL_DTLS_CTX* dtlsCtx = (CYASSL_DTLS_CTX*)ctx;
353     int recvd;
354     int err;
355     int sd = dtlsCtx->fd;
356     int dtls_timeout = CyaSSL_dtls_get_current_timeout(ssl);
357     struct sockaddr_storage peer;
358     XSOCKLENT peerSz = sizeof(peer);
359
360     CYASSL_ENTER("EmbedReceiveFrom()");
361
362     if (!CyaSSL_get_using_nonblock(ssl) && dtls_timeout != 0) {
363         #ifdef USE_WINDOWS_API
364             DWORD timeout = dtls_timeout * 1000;
365         #else
366             struct timeval timeout;
367             XMEMSET(&timeout, 0, sizeof(timeout));
368             timeout.tv_sec = dtls_timeout;
369         #endif
370         if (setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout,
371                        sizeof(timeout)) != 0) {
372                 CYASSL_MSG("setsockopt rcvtimeo failed");
373         }
374     }
375
376     recvd = (int)RECVFROM_FUNCTION(sd, buf, sz, ssl->rflags,
377                                   (struct sockaddr*)&peer, &peerSz);
378
379     recvd = TranslateReturnCode(recvd, sd);
380
381     if (recvd < 0) {
382         err = LastError();
383         CYASSL_MSG("Embed Receive From error");
384
385         if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) {
386             if (CyaSSL_get_using_nonblock(ssl)) {
387                 CYASSL_MSG("    Would block");
388                 return CYASSL_CBIO_ERR_WANT_READ;
389             }
390             else {
391                 CYASSL_MSG("    Socket timeout");
392                 return CYASSL_CBIO_ERR_TIMEOUT;
393             }
394         }
395         else if (err == SOCKET_ECONNRESET) {
396             CYASSL_MSG("    Connection reset");
397             return CYASSL_CBIO_ERR_CONN_RST;
398         }
399         else if (err == SOCKET_EINTR) {
400             CYASSL_MSG("    Socket interrupted");
401             return CYASSL_CBIO_ERR_ISR;
402         }
403         else if (err == SOCKET_ECONNREFUSED) {
404             CYASSL_MSG("    Connection refused");
405             return CYASSL_CBIO_ERR_WANT_READ;
406         }
407         else {
408             CYASSL_MSG("    General error");
409             return CYASSL_CBIO_ERR_GENERAL;
410         }
411     }
412     else {
413         if (dtlsCtx->peer.sz > 0
414                 && peerSz != (XSOCKLENT)dtlsCtx->peer.sz
415                 && memcmp(&peer, dtlsCtx->peer.sa, peerSz) != 0) {
416             CYASSL_MSG("    Ignored packet from invalid peer");
417             return CYASSL_CBIO_ERR_WANT_READ;
418         }
419     }
420
421     return recvd;
422 }
423
424
425 /* The send embedded callback
426  *  return : nb bytes sent, or error
427  */
428 int EmbedSendTo(CYASSL* ssl, char *buf, int sz, void *ctx)
429 {
430     CYASSL_DTLS_CTX* dtlsCtx = (CYASSL_DTLS_CTX*)ctx;
431     int sd = dtlsCtx->fd;
432     int sent;
433     int len = sz;
434     int err;
435
436     CYASSL_ENTER("EmbedSendTo()");
437
438     sent = (int)SENDTO_FUNCTION(sd, &buf[sz - len], len, ssl->wflags,
439                                 dtlsCtx->peer.sa, dtlsCtx->peer.sz);
440     if (sent < 0) {
441         err = LastError();
442         CYASSL_MSG("Embed Send To error");
443
444         if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) {
445             CYASSL_MSG("    Would Block");
446             return CYASSL_CBIO_ERR_WANT_WRITE;
447         }
448         else if (err == SOCKET_ECONNRESET) {
449             CYASSL_MSG("    Connection reset");
450             return CYASSL_CBIO_ERR_CONN_RST;
451         }
452         else if (err == SOCKET_EINTR) {
453             CYASSL_MSG("    Socket interrupted");
454             return CYASSL_CBIO_ERR_ISR;
455         }
456         else if (err == SOCKET_EPIPE) {
457             CYASSL_MSG("    Socket EPIPE");
458             return CYASSL_CBIO_ERR_CONN_CLOSE;
459         }
460         else {
461             CYASSL_MSG("    General error");
462             return CYASSL_CBIO_ERR_GENERAL;
463         }
464     }
465  
466     return sent;
467 }
468
469
470 /* The DTLS Generate Cookie callback
471  *  return : number of bytes copied into buf, or error
472  */
473 int EmbedGenerateCookie(CYASSL* ssl, byte *buf, int sz, void *ctx)
474 {
475     int sd = ssl->wfd;
476     struct sockaddr_storage peer;
477     XSOCKLENT peerSz = sizeof(peer);
478     Sha sha;
479     byte digest[SHA_DIGEST_SIZE];
480     int  ret = 0;
481
482     (void)ctx;
483
484     XMEMSET(&peer, 0, sizeof(peer));
485     if (getpeername(sd, (struct sockaddr*)&peer, &peerSz) != 0) {
486         CYASSL_MSG("getpeername failed in EmbedGenerateCookie");
487         return GEN_COOKIE_E;
488     }
489     
490     ret = InitSha(&sha);
491     if (ret != 0)
492         return ret;
493     ShaUpdate(&sha, (byte*)&peer, peerSz);
494     ShaFinal(&sha, digest);
495
496     if (sz > SHA_DIGEST_SIZE)
497         sz = SHA_DIGEST_SIZE;
498     XMEMCPY(buf, digest, sz);
499
500     return sz;
501 }
502
503 #endif /* CYASSL_DTLS */
504
505 #ifdef HAVE_OCSP
506
507
508 static int Word16ToString(char* d, word16 number)
509 {
510     int i = 0;
511
512     if (d != NULL) {
513         word16 order = 10000;
514         word16 digit;
515
516         if (number == 0) {
517             d[i++] = '0';
518         }
519         else {
520             while (order) {
521                 digit = number / order;
522                 if (i > 0 || digit != 0) {
523                     d[i++] = digit + '0';
524                 }
525                 if (digit != 0)
526                     number %= digit * order;
527                 if (order > 1)
528                     order /= 10;
529                 else
530                     order = 0;
531             }
532         }
533         d[i] = 0;
534     }
535
536     return i;
537 }
538
539
540 static int tcp_connect(SOCKET_T* sockfd, const char* ip, word16 port)
541 {
542     struct sockaddr_storage addr;
543     int sockaddr_len = sizeof(struct sockaddr_in);
544     XMEMSET(&addr, 0, sizeof(addr));
545
546     #ifdef HAVE_GETADDRINFO
547     {
548         struct addrinfo hints;
549         struct addrinfo* answer = NULL;
550         char strPort[6];
551
552         XMEMSET(&hints, 0, sizeof(hints));
553         hints.ai_family = AF_UNSPEC;
554         hints.ai_socktype = SOCK_STREAM;
555         hints.ai_protocol = IPPROTO_TCP;
556
557         if (Word16ToString(strPort, port) == 0) {
558             CYASSL_MSG("invalid port number for OCSP responder");
559             return -1;
560         }
561
562         if (getaddrinfo(ip, strPort, &hints, &answer) < 0 || answer == NULL) {
563             CYASSL_MSG("no addr info for OCSP responder");
564             return -1;
565         }
566
567         sockaddr_len = answer->ai_addrlen;
568         XMEMCPY(&addr, answer->ai_addr, sockaddr_len);
569         freeaddrinfo(answer);
570
571     }
572     #else /* HAVE_GETADDRINFO */
573     {
574         struct hostent* entry = gethostbyname(ip);
575         struct sockaddr_in *sin = (struct sockaddr_in *)&addr;
576
577         if (entry) {
578             sin->sin_family = AF_INET;
579             sin->sin_port = htons(port);
580             XMEMCPY(&sin->sin_addr.s_addr, entry->h_addr_list[0],
581                                                                entry->h_length);
582         }
583         else {
584             CYASSL_MSG("no addr info for OCSP responder");
585             return -1;
586         }
587     }
588     #endif /* HAVE_GETADDRINFO */
589
590     *sockfd = socket(addr.ss_family, SOCK_STREAM, 0);
591     if (*sockfd < 0) {
592         CYASSL_MSG("bad socket fd, out of fds?");
593         return -1;
594     }
595
596     if (connect(*sockfd, (struct sockaddr *)&addr, sockaddr_len) != 0) {
597         CYASSL_MSG("OCSP responder tcp connect failed");
598         return -1;
599     }
600
601     return 0;
602 }
603
604
605 static int build_http_request(const char* domainName, const char* path,
606                                     int ocspReqSz, byte* buf, int bufSize)
607 {
608     word32 domainNameLen, pathLen, ocspReqSzStrLen, completeLen;
609     char ocspReqSzStr[6];
610
611     domainNameLen = (word32)XSTRLEN(domainName);
612     pathLen = (word32)XSTRLEN(path);
613     ocspReqSzStrLen = Word16ToString(ocspReqSzStr, ocspReqSz);
614
615     completeLen = domainNameLen + pathLen + ocspReqSzStrLen + 84;
616     if (completeLen > (word32)bufSize)
617         return 0;
618
619     XSTRNCPY((char*)buf, "POST ", 5);
620     buf += 5;
621     XSTRNCPY((char*)buf, path, pathLen);
622     buf += pathLen;
623     XSTRNCPY((char*)buf, " HTTP/1.1\r\nHost: ", 17);
624     buf += 17;
625     XSTRNCPY((char*)buf, domainName, domainNameLen);
626     buf += domainNameLen;
627     XSTRNCPY((char*)buf, "\r\nContent-Length: ", 18);
628     buf += 18;
629     XSTRNCPY((char*)buf, ocspReqSzStr, ocspReqSzStrLen);
630     buf += ocspReqSzStrLen;
631     XSTRNCPY((char*)buf,
632                       "\r\nContent-Type: application/ocsp-request\r\n\r\n", 44);
633
634     return completeLen;
635 }
636
637
638 static int decode_url(const char* url, int urlSz,
639     char* outName, char* outPath, word16* outPort)
640 {
641     int result = -1;
642
643     if (outName != NULL && outPath != NULL && outPort != NULL)
644     {
645         if (url == NULL || urlSz == 0)
646         {
647             *outName = 0;
648             *outPath = 0;
649             *outPort = 0;
650         }
651         else
652         {
653             int i, cur;
654     
655             /* need to break the url down into scheme, address, and port */
656             /*     "http://example.com:8080/" */
657             /*     "http://[::1]:443/"        */
658             if (XSTRNCMP(url, "http://", 7) == 0) {
659                 cur = 7;
660             } else cur = 0;
661     
662             i = 0;
663             if (url[cur] == '[') {
664                 cur++;
665                 /* copy until ']' */
666                 while (url[cur] != 0 && url[cur] != ']' && cur < urlSz) {
667                     outName[i++] = url[cur++];
668                 }
669                 cur++; /* skip ']' */
670             }
671             else {
672                 while (url[cur] != 0 && url[cur] != ':' &&
673                                                url[cur] != '/' && cur < urlSz) {
674                     outName[i++] = url[cur++];
675                 }
676             }
677             outName[i] = 0;
678             /* Need to pick out the path after the domain name */
679     
680             if (cur < urlSz && url[cur] == ':') {
681                 char port[6];
682                 int j;
683                 word32 bigPort = 0;
684                 i = 0;
685                 cur++;
686                 while (cur < urlSz && url[cur] != 0 && url[cur] != '/' &&
687                         i < 6) {
688                     port[i++] = url[cur++];
689                 }
690     
691                 for (j = 0; j < i; j++) {
692                     if (port[j] < '0' || port[j] > '9') return -1;
693                     bigPort = (bigPort * 10) + (port[j] - '0');
694                 }
695                 *outPort = (word16)bigPort;
696             }
697             else
698                 *outPort = 80;
699     
700             if (cur < urlSz && url[cur] == '/') {
701                 i = 0;
702                 while (cur < urlSz && url[cur] != 0 && i < 80) {
703                     outPath[i++] = url[cur++];
704                 }
705                 outPath[i] = 0;
706             }
707             else {
708                 outPath[0] = '/';
709                 outPath[1] = 0;
710             }
711             result = 0;
712         }
713     }
714
715     return result;
716 }
717
718
719 /* return: >0 OCSP Response Size
720  *         -1 error */
721 static int process_http_response(int sfd, byte** respBuf,
722                                                   byte* httpBuf, int httpBufSz)
723 {
724     int result;
725     int len = 0;
726     char *start, *end;
727     byte *recvBuf = NULL;
728     int recvBufSz = 0;
729     enum phr_state { phr_init, phr_http_start, phr_have_length,
730                      phr_have_type, phr_wait_end, phr_http_end
731     } state = phr_init;
732
733     start = end = NULL;
734     do {
735         if (end == NULL) {
736             result = (int)recv(sfd, (char*)httpBuf+len, httpBufSz-len-1, 0);
737             if (result > 0) {
738                 len += result;
739                 start = (char*)httpBuf;
740                 start[len] = 0;
741             }
742             else {
743                 CYASSL_MSG("process_http_response recv http from peer failed");
744                 return -1;
745             }
746         }
747         end = XSTRSTR(start, "\r\n");
748
749         if (end == NULL) {
750             if (len != 0)
751                 XMEMMOVE(httpBuf, start, len);
752             start = end = NULL;
753         }
754         else if (end == start) {
755             if (state == phr_wait_end) {
756                 state = phr_http_end;
757                 len -= 2;
758                 start += 2;
759              }
760              else {
761                 CYASSL_MSG("process_http_response header ended early");
762                 return -1;
763              }
764         }
765         else {
766             *end = 0;
767             len -= (int)(end - start) + 2;
768                 /* adjust len to remove the first line including the /r/n */
769
770             if (XSTRNCASECMP(start, "HTTP/1", 6) == 0) {
771                 start += 9;
772                 if (XSTRNCASECMP(start, "200 OK", 6) != 0 ||
773                                                            state != phr_init) {
774                     CYASSL_MSG("process_http_response not OK");
775                     return -1;
776                 }
777                 state = phr_http_start;
778             }
779             else if (XSTRNCASECMP(start, "Content-Type:", 13) == 0) {
780                 start += 13;
781                 while (*start == ' ' && *start != '\0') start++;
782                 if (XSTRNCASECMP(start, "application/ocsp-response", 25) != 0) {
783                     CYASSL_MSG("process_http_response not ocsp-response");
784                     return -1;
785                 }
786                 
787                 if (state == phr_http_start) state = phr_have_type;
788                 else if (state == phr_have_length) state = phr_wait_end;
789                 else {
790                     CYASSL_MSG("process_http_response type invalid state");
791                     return -1;
792                 }
793             }
794             else if (XSTRNCASECMP(start, "Content-Length:", 15) == 0) {
795                 start += 15;
796                 while (*start == ' ' && *start != '\0') start++;
797                 recvBufSz = atoi(start);
798
799                 if (state == phr_http_start) state = phr_have_length;
800                 else if (state == phr_have_type) state = phr_wait_end;
801                 else {
802                     CYASSL_MSG("process_http_response length invalid state");
803                     return -1;
804                 }
805             }
806             
807             start = end + 2;
808         }
809     } while (state != phr_http_end);
810
811     recvBuf = XMALLOC(recvBufSz, NULL, DYNAMIC_TYPE_IN_BUFFER);
812     if (recvBuf == NULL) {
813         CYASSL_MSG("process_http_response couldn't create response buffer");
814         return -1;
815     }
816
817     /* copy the remainder of the httpBuf into the respBuf */
818     if (len != 0)
819         XMEMCPY(recvBuf, start, len);
820
821     /* receive the OCSP response data */
822     do {
823         result = (int)recv(sfd, (char*)recvBuf+len, recvBufSz-len, 0);
824         if (result > 0)
825             len += result;
826         else {
827             CYASSL_MSG("process_http_response recv ocsp from peer failed");
828             return -1;
829         }
830     } while (len != recvBufSz);
831
832     *respBuf = recvBuf;
833     return recvBufSz;
834 }
835
836
837 #define SCRATCH_BUFFER_SIZE 512
838
839 int EmbedOcspLookup(void* ctx, const char* url, int urlSz,
840                         byte* ocspReqBuf, int ocspReqSz, byte** ocspRespBuf)
841 {
842     char domainName[80], path[80];
843     int httpBufSz;
844     SOCKET_T sfd = 0;
845     word16 port;
846     int ocspRespSz = 0;
847     byte* httpBuf = NULL;
848
849     (void)ctx;
850
851     if (ocspReqBuf == NULL || ocspReqSz == 0) {
852         CYASSL_MSG("OCSP request is required for lookup");
853         return -1;
854     }
855
856     if (ocspRespBuf == NULL) {
857         CYASSL_MSG("Cannot save OCSP response");
858         return -1;
859     }
860
861     if (decode_url(url, urlSz, domainName, path, &port) < 0) {
862         CYASSL_MSG("Unable to decode OCSP URL");
863         return -1;
864     }
865     
866     /* Note, the library uses the EmbedOcspRespFree() callback to
867      * free this buffer. */
868     httpBufSz = SCRATCH_BUFFER_SIZE;
869     httpBuf = (byte*)XMALLOC(httpBufSz, NULL, DYNAMIC_TYPE_IN_BUFFER);
870
871     if (httpBuf == NULL) {
872         CYASSL_MSG("Unable to create OCSP response buffer");
873         return -1;
874     }
875
876     httpBufSz = build_http_request(domainName, path, ocspReqSz,
877                                                         httpBuf, httpBufSz);
878
879     if ((tcp_connect(&sfd, domainName, port) == 0) && (sfd > 0)) {
880         int written;
881         written = (int)send(sfd, (char*)httpBuf, httpBufSz, 0);
882         if (written == httpBufSz) {
883             written = (int)send(sfd, (char*)ocspReqBuf, ocspReqSz, 0);
884             if (written == ocspReqSz) {
885                 ocspRespSz = process_http_response(sfd, ocspRespBuf,
886                                                  httpBuf, SCRATCH_BUFFER_SIZE);
887             }
888         }
889         close(sfd);
890         if (ocspRespSz == 0) {
891             CYASSL_MSG("OCSP response was not OK, no OCSP response");
892             XFREE(httpBuf, NULL, DYNAMIC_TYPE_IN_BUFFER);
893             return -1;
894         }
895     } else {
896         CYASSL_MSG("OCSP Responder connection failed");
897         close(sfd);
898         XFREE(httpBuf, NULL, DYNAMIC_TYPE_IN_BUFFER);
899         return -1;
900     }
901
902     XFREE(httpBuf, NULL, DYNAMIC_TYPE_IN_BUFFER);
903     return ocspRespSz;
904 }
905
906
907 void EmbedOcspRespFree(void* ctx, byte *resp)
908 {
909     (void)ctx;
910
911     if (resp)
912         XFREE(resp, NULL, DYNAMIC_TYPE_IN_BUFFER);
913 }
914
915
916 #endif
917
918 #endif /* CYASSL_USER_IO */
919
920 CYASSL_API void CyaSSL_SetIORecv(CYASSL_CTX *ctx, CallbackIORecv CBIORecv)
921 {
922     ctx->CBIORecv = CBIORecv;
923 }
924
925
926 CYASSL_API void CyaSSL_SetIOSend(CYASSL_CTX *ctx, CallbackIOSend CBIOSend)
927 {
928     ctx->CBIOSend = CBIOSend;
929 }
930
931
932 CYASSL_API void CyaSSL_SetIOReadCtx(CYASSL* ssl, void *rctx)
933 {
934         ssl->IOCB_ReadCtx = rctx;
935 }
936
937
938 CYASSL_API void CyaSSL_SetIOWriteCtx(CYASSL* ssl, void *wctx)
939 {
940         ssl->IOCB_WriteCtx = wctx;
941 }
942
943
944 CYASSL_API void* CyaSSL_GetIOReadCtx(CYASSL* ssl)
945 {
946     if (ssl)
947         return ssl->IOCB_ReadCtx;
948
949     return NULL;
950 }
951
952
953 CYASSL_API void* CyaSSL_GetIOWriteCtx(CYASSL* ssl)
954 {
955     if (ssl)
956         return ssl->IOCB_WriteCtx;
957
958     return NULL;
959 }
960
961
962 CYASSL_API void CyaSSL_SetIOReadFlags(CYASSL* ssl, int flags)
963 {
964     ssl->rflags = flags; 
965 }
966
967
968 CYASSL_API void CyaSSL_SetIOWriteFlags(CYASSL* ssl, int flags)
969 {
970     ssl->wflags = flags;
971 }
972
973
974 #ifdef CYASSL_DTLS
975
976 CYASSL_API void CyaSSL_CTX_SetGenCookie(CYASSL_CTX* ctx, CallbackGenCookie cb)
977 {
978     ctx->CBIOCookie = cb;
979 }
980
981
982 CYASSL_API void CyaSSL_SetCookieCtx(CYASSL* ssl, void *ctx)
983 {
984         ssl->IOCB_CookieCtx = ctx;
985 }
986
987
988 CYASSL_API void* CyaSSL_GetCookieCtx(CYASSL* ssl)
989 {
990     if (ssl)
991             return ssl->IOCB_CookieCtx;
992
993     return NULL;
994 }
995
996 #endif /* CYASSL_DTLS */
997
998
999 #ifdef HAVE_NETX
1000
1001 /* The NetX receive callback
1002  *  return :  bytes read, or error
1003  */
1004 int NetX_Receive(CYASSL *ssl, char *buf, int sz, void *ctx)
1005 {
1006     NetX_Ctx* nxCtx = (NetX_Ctx*)ctx;
1007     ULONG left;
1008     ULONG total;
1009     ULONG copied = 0;
1010     UINT  status;
1011
1012     if (nxCtx == NULL || nxCtx->nxSocket == NULL) {
1013         CYASSL_MSG("NetX Recv NULL parameters");
1014         return CYASSL_CBIO_ERR_GENERAL;
1015     }
1016
1017     if (nxCtx->nxPacket == NULL) {
1018         status = nx_tcp_socket_receive(nxCtx->nxSocket, &nxCtx->nxPacket,
1019                                        nxCtx->nxWait);
1020         if (status != NX_SUCCESS) {
1021             CYASSL_MSG("NetX Recv receive error");
1022             return CYASSL_CBIO_ERR_GENERAL;
1023         }
1024     }
1025
1026     if (nxCtx->nxPacket) {
1027         status = nx_packet_length_get(nxCtx->nxPacket, &total);
1028         if (status != NX_SUCCESS) {
1029             CYASSL_MSG("NetX Recv length get error");
1030             return CYASSL_CBIO_ERR_GENERAL;
1031         }
1032
1033         left = total - nxCtx->nxOffset;
1034         status = nx_packet_data_extract_offset(nxCtx->nxPacket, nxCtx->nxOffset,
1035                                                buf, sz, &copied);
1036         if (status != NX_SUCCESS) {
1037             CYASSL_MSG("NetX Recv data extract offset error");
1038             return CYASSL_CBIO_ERR_GENERAL;
1039         }
1040
1041         nxCtx->nxOffset += copied;
1042
1043         if (copied == left) {
1044             CYASSL_MSG("NetX Recv Drained packet");
1045             nx_packet_release(nxCtx->nxPacket);
1046             nxCtx->nxPacket = NULL;
1047             nxCtx->nxOffset = 0;
1048         }
1049     }
1050
1051     return copied;
1052 }
1053
1054
1055 /* The NetX send callback
1056  *  return : bytes sent, or error
1057  */
1058 int NetX_Send(CYASSL* ssl, char *buf, int sz, void *ctx)
1059 {
1060     NetX_Ctx*       nxCtx = (NetX_Ctx*)ctx;
1061     NX_PACKET*      packet;
1062     NX_PACKET_POOL* pool;   /* shorthand */
1063     UINT            status;
1064
1065     if (nxCtx == NULL || nxCtx->nxSocket == NULL) {
1066         CYASSL_MSG("NetX Send NULL parameters");
1067         return CYASSL_CBIO_ERR_GENERAL;
1068     }
1069
1070     pool = nxCtx->nxSocket->nx_tcp_socket_ip_ptr->nx_ip_default_packet_pool;
1071     status = nx_packet_allocate(pool, &packet, NX_TCP_PACKET,
1072                                 nxCtx->nxWait);
1073     if (status != NX_SUCCESS) {
1074         CYASSL_MSG("NetX Send packet alloc error");
1075         return CYASSL_CBIO_ERR_GENERAL;
1076     }
1077
1078     status = nx_packet_data_append(packet, buf, sz, pool, nxCtx->nxWait);
1079     if (status != NX_SUCCESS) {
1080         nx_packet_release(packet);
1081         CYASSL_MSG("NetX Send data append error");
1082         return CYASSL_CBIO_ERR_GENERAL;
1083     }
1084
1085     status = nx_tcp_socket_send(nxCtx->nxSocket, packet, nxCtx->nxWait);
1086     if (status != NX_SUCCESS) {
1087         nx_packet_release(packet);
1088         CYASSL_MSG("NetX Send socket send error");
1089         return CYASSL_CBIO_ERR_GENERAL;
1090     }
1091
1092     return sz;
1093 }
1094
1095
1096 /* like set_fd, but for default NetX context */
1097 void CyaSSL_SetIO_NetX(CYASSL* ssl, NX_TCP_SOCKET* nxSocket, ULONG waitOption)
1098 {
1099     if (ssl) {
1100         ssl->nxCtx.nxSocket = nxSocket;
1101         ssl->nxCtx.nxWait   = waitOption;
1102     }
1103 }
1104
1105 #endif /* HAVE_NETX */
1106