wolf SSL / CyaSSL-2.9.4

Dependents:  

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers io.c Source File

io.c

00001 /* io.c
00002  *
00003  * Copyright (C) 2006-2013 wolfSSL Inc.
00004  *
00005  * This file is part of CyaSSL.
00006  *
00007  * CyaSSL is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 2 of the License, or
00010  * (at your option) any later version.
00011  *
00012  * CyaSSL is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
00020  */
00021 
00022 #ifdef HAVE_CONFIG_H
00023     #include <config.h>
00024 #endif
00025 
00026 #include <cyassl/ctaocrypt/settings.h>
00027 
00028 #ifdef _WIN32_WCE
00029     /* On WinCE winsock2.h must be included before windows.h for socket stuff */
00030     #include <winsock2.h>
00031 #endif
00032 
00033 #include <cyassl/internal.h>
00034 #include <cyassl/error-ssl.h>
00035 
00036 /* if user writes own I/O callbacks they can define CYASSL_USER_IO to remove
00037    automatic setting of default I/O functions EmbedSend() and EmbedReceive()
00038    but they'll still need SetCallback xxx() at end of file 
00039 */
00040 #ifndef CYASSL_USER_IO
00041 
00042 #ifdef HAVE_LIBZ
00043     #include "zlib.h"
00044 #endif
00045 
00046 #ifndef USE_WINDOWS_API
00047     #ifdef CYASSL_LWIP
00048         /* lwIP needs to be configured to use sockets API in this mode */
00049         /* LWIP_SOCKET 1 in lwip/opt.h or in build */
00050         #include "lwip/sockets.h"
00051         #include <errno.h>
00052         #ifndef LWIP_PROVIDE_ERRNO
00053             #define LWIP_PROVIDE_ERRNO 1
00054         #endif
00055     #elif defined(FREESCALE_MQX)
00056         #include <posix.h>
00057         #include <rtcs.h>
00058     #elif defined(CYASSL_MDK_ARM)
00059         #if defined(CYASSL_MDK5)
00060             #include "cmsis_os.h"
00061             #include "rl_fs.h" 
00062             #include "rl_net.h" 
00063         #else
00064             #include <rtl.h>
00065         #endif
00066         #undef RNG
00067         #include "CYASSL_MDK_ARM.h"
00068         #undef RNG
00069         #define RNG CyaSSL_RNG 
00070         /* for avoiding name conflict in "stm32f2xx.h" */
00071         static int errno;
00072     #else
00073         #include <sys/types.h>
00074         #include <errno.h>
00075         #ifndef EBSNET
00076             #include <unistd.h>
00077         #endif
00078         #include <fcntl.h>
00079         #if !(defined(DEVKITPRO) || defined(HAVE_RTP_SYS) || defined(EBSNET))
00080             #include <sys/socket.h>
00081             #include <arpa/inet.h>
00082             #include <netinet/in.h>
00083             #include <netdb.h>
00084             #ifdef __PPU
00085                 #include <netex/errno.h>
00086             #else
00087                 #include <sys/ioctl.h>
00088             #endif
00089         #endif
00090         #ifdef HAVE_RTP_SYS
00091             #include <socket.h>
00092         #endif
00093         #ifdef EBSNET
00094             #include "rtipapi.h"  /* errno */
00095             #include "socket.h"
00096         #endif
00097     #endif
00098 #endif /* USE_WINDOWS_API */
00099 
00100 #ifdef __sun
00101     #include <sys/filio.h>
00102 #endif
00103 
00104 #ifdef USE_WINDOWS_API 
00105     /* no epipe yet */
00106     #ifndef WSAEPIPE
00107         #define WSAEPIPE       -12345
00108     #endif
00109     #define SOCKET_EWOULDBLOCK WSAEWOULDBLOCK
00110     #define SOCKET_EAGAIN      WSAETIMEDOUT
00111     #define SOCKET_ECONNRESET  WSAECONNRESET
00112     #define SOCKET_EINTR       WSAEINTR
00113     #define SOCKET_EPIPE       WSAEPIPE
00114     #define SOCKET_ECONNREFUSED WSAENOTCONN
00115     #define SOCKET_ECONNABORTED WSAECONNABORTED
00116     #define close(s) closesocket(s)
00117 #elif defined(__PPU)
00118     #define SOCKET_EWOULDBLOCK SYS_NET_EWOULDBLOCK
00119     #define SOCKET_EAGAIN      SYS_NET_EAGAIN
00120     #define SOCKET_ECONNRESET  SYS_NET_ECONNRESET
00121     #define SOCKET_EINTR       SYS_NET_EINTR
00122     #define SOCKET_EPIPE       SYS_NET_EPIPE
00123     #define SOCKET_ECONNREFUSED SYS_NET_ECONNREFUSED
00124     #define SOCKET_ECONNABORTED SYS_NET_ECONNABORTED
00125 #elif defined(FREESCALE_MQX)
00126     /* RTCS doesn't have an EWOULDBLOCK error */
00127     #define SOCKET_EWOULDBLOCK EAGAIN
00128     #define SOCKET_EAGAIN      EAGAIN
00129     #define SOCKET_ECONNRESET  RTCSERR_TCP_CONN_RESET
00130     #define SOCKET_EINTR       EINTR
00131     #define SOCKET_EPIPE       EPIPE
00132     #define SOCKET_ECONNREFUSED RTCSERR_TCP_CONN_REFUSED
00133     #define SOCKET_ECONNABORTED RTCSERR_TCP_CONN_ABORTED
00134 #elif defined(CYASSL_MDK_ARM)
00135     #if defined(CYASSL_MDK5)
00136         #define SOCKET_EWOULDBLOCK BSD_ERROR_WOULDBLOCK
00137         #define SOCKET_EAGAIN      BSD_ERROR_LOCKED
00138         #define SOCKET_ECONNRESET  BSD_ERROR_CLOSED
00139         #define SOCKET_EINTR       BSD_ERROR
00140         #define SOCKET_EPIPE       BSD_ERROR
00141         #define SOCKET_ECONNREFUSED BSD_ERROR
00142         #define SOCKET_ECONNABORTED BSD_ERROR
00143     #else
00144         #define SOCKET_EWOULDBLOCK SCK_EWOULDBLOCK
00145         #define SOCKET_EAGAIN      SCK_ELOCKED
00146         #define SOCKET_ECONNRESET  SCK_ECLOSED
00147         #define SOCKET_EINTR       SCK_ERROR
00148         #define SOCKET_EPIPE       SCK_ERROR
00149         #define SOCKET_ECONNREFUSED SCK_ERROR
00150         #define SOCKET_ECONNABORTED SCK_ERROR
00151     #endif
00152 #else
00153     #define SOCKET_EWOULDBLOCK EWOULDBLOCK
00154     #define SOCKET_EAGAIN      EAGAIN
00155     #define SOCKET_ECONNRESET  ECONNRESET
00156     #define SOCKET_EINTR       EINTR
00157     #define SOCKET_EPIPE       EPIPE
00158     #define SOCKET_ECONNREFUSED ECONNREFUSED
00159     #define SOCKET_ECONNABORTED ECONNABORTED
00160 #endif /* USE_WINDOWS_API */
00161 
00162 
00163 #ifdef DEVKITPRO
00164     /* from network.h */
00165     int net_send(int, const void*, int, unsigned int);
00166     int net_recv(int, void*, int, unsigned int);
00167     #define SEND_FUNCTION net_send
00168     #define RECV_FUNCTION net_recv
00169 #elif defined(CYASSL_LWIP)
00170     #define SEND_FUNCTION lwip_send
00171     #define RECV_FUNCTION lwip_recv
00172 #else
00173     #define SEND_FUNCTION send
00174     #define RECV_FUNCTION recv
00175 #endif
00176 
00177 
00178 /* Translates return codes returned from 
00179  * send() and recv() if need be. 
00180  */
00181 static INLINE int TranslateReturnCode(int old, int sd)
00182 {
00183     (void)sd;
00184 
00185 #ifdef FREESCALE_MQX
00186     if (old == 0) {
00187         errno = SOCKET_EWOULDBLOCK;
00188         return -1;  /* convert to BSD style wouldblock as error */
00189     }
00190 
00191     if (old < 0) {
00192         errno = RTCS_geterror(sd);
00193         if (errno == RTCSERR_TCP_CONN_CLOSING)
00194             return 0;   /* convert to BSD style closing */
00195     }
00196 #endif
00197 
00198     return old;
00199 }
00200 
00201 static INLINE int LastError(void)
00202 {
00203 #ifdef USE_WINDOWS_API 
00204     return WSAGetLastError();
00205 #elif defined(EBSNET)
00206     return xn_getlasterror();
00207 #else
00208     return errno;
00209 #endif
00210 }
00211 
00212 /* The receive embedded callback
00213  *  return : nb bytes read, or error
00214  */
00215 int EmbedReceive(CYASSL *ssl, char *buf, int sz, void *ctx)
00216 {
00217     int recvd;
00218     int err;
00219     int sd = *(int*)ctx;
00220 
00221 #ifdef CYASSL_DTLS
00222     {
00223         int dtls_timeout = CyaSSL_dtls_get_current_timeout(ssl);
00224         if (CyaSSL_dtls(ssl)
00225                      && !CyaSSL_get_using_nonblock(ssl)
00226                      && dtls_timeout != 0) {
00227             #ifdef USE_WINDOWS_API
00228                 DWORD timeout = dtls_timeout * 1000;
00229             #else
00230                 struct timeval timeout;
00231                 XMEMSET(&timeout, 0, sizeof(timeout));
00232                 timeout.tv_sec = dtls_timeout;
00233             #endif
00234             if (setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout,
00235                            sizeof(timeout)) != 0) {
00236                 CYASSL_MSG("setsockopt rcvtimeo failed");
00237             }
00238         }
00239     }
00240 #endif
00241 
00242     recvd = (int)RECV_FUNCTION(sd, buf, sz, ssl->rflags);
00243 
00244     recvd = TranslateReturnCode(recvd, sd);
00245 
00246     if (recvd < 0) {
00247         err = LastError();
00248         CYASSL_MSG("Embed Receive error");
00249 
00250         if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) {
00251             if (!CyaSSL_dtls(ssl) || CyaSSL_get_using_nonblock(ssl)) {
00252                 CYASSL_MSG("    Would block");
00253                 return CYASSL_CBIO_ERR_WANT_READ;
00254             }
00255             else {
00256                 CYASSL_MSG("    Socket timeout");
00257                 return CYASSL_CBIO_ERR_TIMEOUT;
00258             }
00259         }
00260         else if (err == SOCKET_ECONNRESET) {
00261             CYASSL_MSG("    Connection reset");
00262             return CYASSL_CBIO_ERR_CONN_RST;
00263         }
00264         else if (err == SOCKET_EINTR) {
00265             CYASSL_MSG("    Socket interrupted");
00266             return CYASSL_CBIO_ERR_ISR;
00267         }
00268         else if (err == SOCKET_ECONNREFUSED) {
00269             CYASSL_MSG("    Connection refused");
00270             return CYASSL_CBIO_ERR_WANT_READ;
00271         }
00272         else if (err == SOCKET_ECONNABORTED) {
00273             CYASSL_MSG("    Connection aborted");
00274             return CYASSL_CBIO_ERR_CONN_CLOSE;
00275         }
00276         else {
00277             CYASSL_MSG("    General error");
00278             return CYASSL_CBIO_ERR_GENERAL;
00279         }
00280     }
00281     else if (recvd == 0) {
00282         CYASSL_MSG("Embed receive connection closed");
00283         return CYASSL_CBIO_ERR_CONN_CLOSE;
00284     }
00285 
00286     return recvd;
00287 }
00288 
00289 /* The send embedded callback
00290  *  return : nb bytes sent, or error
00291  */
00292 int EmbedSend(CYASSL* ssl, char *buf, int sz, void *ctx)
00293 {
00294     int sd = *(int*)ctx;
00295     int sent;
00296     int len = sz;
00297     int err;
00298 
00299     sent = (int)SEND_FUNCTION(sd, &buf[sz - len], len, ssl->wflags);
00300 
00301     if (sent < 0) {
00302         err = LastError();
00303         CYASSL_MSG("Embed Send error");
00304 
00305         if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) {
00306             CYASSL_MSG("    Would Block");
00307             return CYASSL_CBIO_ERR_WANT_WRITE;
00308         }
00309         else if (err == SOCKET_ECONNRESET) {
00310             CYASSL_MSG("    Connection reset");
00311             return CYASSL_CBIO_ERR_CONN_RST;
00312         }
00313         else if (err == SOCKET_EINTR) {
00314             CYASSL_MSG("    Socket interrupted");
00315             return CYASSL_CBIO_ERR_ISR;
00316         }
00317         else if (err == SOCKET_EPIPE) {
00318             CYASSL_MSG("    Socket EPIPE");
00319             return CYASSL_CBIO_ERR_CONN_CLOSE;
00320         }
00321         else {
00322             CYASSL_MSG("    General error");
00323             return CYASSL_CBIO_ERR_GENERAL;
00324         }
00325     }
00326  
00327     return sent;
00328 }
00329 
00330 
00331 #ifdef CYASSL_DTLS
00332 
00333 #include <cyassl/ctaocrypt/sha.h>
00334 
00335 #ifdef USE_WINDOWS_API
00336    #define XSOCKLENT int
00337 #else
00338    #define XSOCKLENT socklen_t
00339 #endif
00340 
00341 #define SENDTO_FUNCTION sendto
00342 #define RECVFROM_FUNCTION recvfrom
00343 
00344 
00345 /* The receive embedded callback
00346  *  return : nb bytes read, or error
00347  */
00348 int EmbedReceiveFrom(CYASSL *ssl, char *buf, int sz, void *ctx)
00349 {
00350     CYASSL_DTLS_CTX* dtlsCtx = (CYASSL_DTLS_CTX*)ctx;
00351     int recvd;
00352     int err;
00353     int sd = dtlsCtx->fd;
00354     int dtls_timeout = CyaSSL_dtls_get_current_timeout(ssl);
00355     struct sockaddr_storage peer;
00356     XSOCKLENT peerSz = sizeof(peer);
00357 
00358     CYASSL_ENTER("EmbedReceiveFrom()");
00359 
00360     if (!CyaSSL_get_using_nonblock(ssl) && dtls_timeout != 0) {
00361         #ifdef USE_WINDOWS_API
00362             DWORD timeout = dtls_timeout * 1000;
00363         #else
00364             struct timeval timeout;
00365             XMEMSET(&timeout, 0, sizeof(timeout));
00366             timeout.tv_sec = dtls_timeout;
00367         #endif
00368         if (setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout,
00369                        sizeof(timeout)) != 0) {
00370                 CYASSL_MSG("setsockopt rcvtimeo failed");
00371         }
00372     }
00373 
00374     recvd = (int)RECVFROM_FUNCTION(sd, buf, sz, ssl->rflags,
00375                                   (struct sockaddr*)&peer, &peerSz);
00376 
00377     recvd = TranslateReturnCode(recvd, sd);
00378 
00379     if (recvd < 0) {
00380         err = LastError();
00381         CYASSL_MSG("Embed Receive From error");
00382 
00383         if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) {
00384             if (CyaSSL_get_using_nonblock(ssl)) {
00385                 CYASSL_MSG("    Would block");
00386                 return CYASSL_CBIO_ERR_WANT_READ;
00387             }
00388             else {
00389                 CYASSL_MSG("    Socket timeout");
00390                 return CYASSL_CBIO_ERR_TIMEOUT;
00391             }
00392         }
00393         else if (err == SOCKET_ECONNRESET) {
00394             CYASSL_MSG("    Connection reset");
00395             return CYASSL_CBIO_ERR_CONN_RST;
00396         }
00397         else if (err == SOCKET_EINTR) {
00398             CYASSL_MSG("    Socket interrupted");
00399             return CYASSL_CBIO_ERR_ISR;
00400         }
00401         else if (err == SOCKET_ECONNREFUSED) {
00402             CYASSL_MSG("    Connection refused");
00403             return CYASSL_CBIO_ERR_WANT_READ;
00404         }
00405         else {
00406             CYASSL_MSG("    General error");
00407             return CYASSL_CBIO_ERR_GENERAL;
00408         }
00409     }
00410     else {
00411         if (dtlsCtx->peer.sz > 0
00412                 && peerSz != (XSOCKLENT)dtlsCtx->peer.sz
00413                 && memcmp(&peer, dtlsCtx->peer.sa, peerSz) != 0) {
00414             CYASSL_MSG("    Ignored packet from invalid peer");
00415             return CYASSL_CBIO_ERR_WANT_READ;
00416         }
00417     }
00418 
00419     return recvd;
00420 }
00421 
00422 
00423 /* The send embedded callback
00424  *  return : nb bytes sent, or error
00425  */
00426 int EmbedSendTo(CYASSL* ssl, char *buf, int sz, void *ctx)
00427 {
00428     CYASSL_DTLS_CTX* dtlsCtx = (CYASSL_DTLS_CTX*)ctx;
00429     int sd = dtlsCtx->fd;
00430     int sent;
00431     int len = sz;
00432     int err;
00433 
00434     CYASSL_ENTER("EmbedSendTo()");
00435 
00436     sent = (int)SENDTO_FUNCTION(sd, &buf[sz - len], len, ssl->wflags,
00437                                 dtlsCtx->peer.sa, dtlsCtx->peer.sz);
00438     if (sent < 0) {
00439         err = LastError();
00440         CYASSL_MSG("Embed Send To error");
00441 
00442         if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) {
00443             CYASSL_MSG("    Would Block");
00444             return CYASSL_CBIO_ERR_WANT_WRITE;
00445         }
00446         else if (err == SOCKET_ECONNRESET) {
00447             CYASSL_MSG("    Connection reset");
00448             return CYASSL_CBIO_ERR_CONN_RST;
00449         }
00450         else if (err == SOCKET_EINTR) {
00451             CYASSL_MSG("    Socket interrupted");
00452             return CYASSL_CBIO_ERR_ISR;
00453         }
00454         else if (err == SOCKET_EPIPE) {
00455             CYASSL_MSG("    Socket EPIPE");
00456             return CYASSL_CBIO_ERR_CONN_CLOSE;
00457         }
00458         else {
00459             CYASSL_MSG("    General error");
00460             return CYASSL_CBIO_ERR_GENERAL;
00461         }
00462     }
00463  
00464     return sent;
00465 }
00466 
00467 
00468 /* The DTLS Generate Cookie callback
00469  *  return : number of bytes copied into buf, or error
00470  */
00471 int EmbedGenerateCookie(CYASSL* ssl, byte *buf, int sz, void *ctx)
00472 {
00473     int sd = ssl->wfd;
00474     struct sockaddr_storage peer;
00475     XSOCKLENT peerSz = sizeof(peer);
00476     Sha sha;
00477     byte digest[SHA_DIGEST_SIZE];
00478     int  ret = 0;
00479 
00480     (void)ctx;
00481 
00482     XMEMSET(&peer, 0, sizeof(peer));
00483     if (getpeername(sd, (struct sockaddr*)&peer, &peerSz) != 0) {
00484         CYASSL_MSG("getpeername failed in EmbedGenerateCookie");
00485         return GEN_COOKIE_E;
00486     }
00487     
00488     ret = InitSha(&sha);
00489     if (ret != 0)
00490         return ret;
00491     ShaUpdate(&sha, (byte*)&peer, peerSz);
00492     ShaFinal(&sha, digest);
00493 
00494     if (sz > SHA_DIGEST_SIZE)
00495         sz = SHA_DIGEST_SIZE;
00496     XMEMCPY(buf, digest, sz);
00497 
00498     return sz;
00499 }
00500 
00501 #endif /* CYASSL_DTLS */
00502 
00503 #ifdef HAVE_OCSP
00504 
00505 
00506 static int tcp_connect(SOCKET_T* sockfd, const char* ip, word16 port)
00507 {
00508     struct sockaddr_storage addr;
00509     int sockaddr_len = sizeof(struct sockaddr_in);
00510     XMEMSET(&addr, 0, sizeof(addr));
00511 
00512     #ifdef HAVE_GETADDRINFO
00513     {
00514         struct addrinfo hints;
00515         struct addrinfo* answer = NULL;
00516         char strPort[8];
00517 
00518         XMEMSET(&hints, 0, sizeof(hints));
00519         hints.ai_family = AF_UNSPEC;
00520         hints.ai_socktype = SOCK_STREAM;
00521         hints.ai_protocol = IPPROTO_TCP;
00522 
00523         XSNPRINTF(strPort, sizeof(strPort), "%d", port);
00524         strPort[7] = '\0';
00525 
00526         if (getaddrinfo(ip, strPort, &hints, &answer) < 0 || answer == NULL) {
00527             CYASSL_MSG("no addr info for OCSP responder");
00528             return -1;
00529         }
00530 
00531         sockaddr_len = answer->ai_addrlen;
00532         XMEMCPY(&addr, answer->ai_addr, sockaddr_len);
00533         freeaddrinfo(answer);
00534 
00535     }
00536     #else /* HAVE_GETADDRINFO */
00537     {
00538         struct hostent* entry = gethostbyname(ip);
00539         struct sockaddr_in *sin = (struct sockaddr_in *)&addr;
00540 
00541         if (entry) {
00542             sin->sin_family = AF_INET;
00543             sin->sin_port = htons(port);
00544             XMEMCPY(&sin->sin_addr.s_addr, entry->h_addr_list[0],
00545                                                                entry->h_length);
00546         }
00547         else {
00548             CYASSL_MSG("no addr info for OCSP responder");
00549             return -1;
00550         }
00551     }
00552     #endif /* HAVE_GETADDRINFO */
00553 
00554     *sockfd = socket(addr.ss_family, SOCK_STREAM, 0);
00555     if (*sockfd < 0) {
00556         CYASSL_MSG("bad socket fd, out of fds?");
00557         return -1;
00558     }
00559 
00560     if (connect(*sockfd, (struct sockaddr *)&addr, sockaddr_len) != 0) {
00561         CYASSL_MSG("OCSP responder tcp connect failed");
00562         return -1;
00563     }
00564 
00565     return 0;
00566 }
00567 
00568 
00569 static int build_http_request(const char* domainName, const char* path,
00570                                     int ocspReqSz, byte* buf, int bufSize)
00571 {
00572     return XSNPRINTF((char*)buf, bufSize,
00573         "POST %s HTTP/1.1\r\n"
00574         "Host: %s\r\n"
00575         "Content-Length: %d\r\n"
00576         "Content-Type: application/ocsp-request\r\n"
00577         "\r\n", 
00578         path, domainName, ocspReqSz);
00579 }
00580 
00581 
00582 static int decode_url(const char* url, int urlSz,
00583     char* outName, char* outPath, word16* outPort)
00584 {
00585     int result = -1;
00586 
00587     if (outName != NULL && outPath != NULL && outPort != NULL)
00588     {
00589         if (url == NULL || urlSz == 0)
00590         {
00591             *outName = 0;
00592             *outPath = 0;
00593             *outPort = 0;
00594         }
00595         else
00596         {
00597             int i, cur;
00598     
00599             /* need to break the url down into scheme, address, and port */
00600             /*     "http://example.com:8080/" */
00601             /*     "http://[::1]:443/"        */
00602             if (XSTRNCMP(url, "http://", 7) == 0) {
00603                 cur = 7;
00604             } else cur = 0;
00605     
00606             i = 0;
00607             if (url[cur] == '[') {
00608                 cur++;
00609                 /* copy until ']' */
00610                 while (url[cur] != 0 && url[cur] != ']' && cur < urlSz) {
00611                     outName[i++] = url[cur++];
00612                 }
00613                 cur++; /* skip ']' */
00614             }
00615             else {
00616                 while (url[cur] != 0 && url[cur] != ':' &&
00617                                                url[cur] != '/' && cur < urlSz) {
00618                     outName[i++] = url[cur++];
00619                 }
00620             }
00621             outName[i] = 0;
00622             /* Need to pick out the path after the domain name */
00623     
00624             if (cur < urlSz && url[cur] == ':') {
00625                 char port[6];
00626                 int j;
00627                 word32 bigPort = 0;
00628                 i = 0;
00629                 cur++;
00630                 while (cur < urlSz && url[cur] != 0 && url[cur] != '/' &&
00631                         i < 6) {
00632                     port[i++] = url[cur++];
00633                 }
00634     
00635                 for (j = 0; j < i; j++) {
00636                     if (port[j] < '0' || port[j] > '9') return -1;
00637                     bigPort = (bigPort * 10) + (port[j] - '0');
00638                 }
00639                 *outPort = (word16)bigPort;
00640             }
00641             else
00642                 *outPort = 80;
00643     
00644             if (cur < urlSz && url[cur] == '/') {
00645                 i = 0;
00646                 while (cur < urlSz && url[cur] != 0 && i < 80) {
00647                     outPath[i++] = url[cur++];
00648                 }
00649                 outPath[i] = 0;
00650             }
00651             else {
00652                 outPath[0] = '/';
00653                 outPath[1] = 0;
00654             }
00655             result = 0;
00656         }
00657     }
00658 
00659     return result;
00660 }
00661 
00662 
00663 /* return: >0 OCSP Response Size
00664  *         -1 error */
00665 static int process_http_response(int sfd, byte** respBuf,
00666                                                   byte* httpBuf, int httpBufSz)
00667 {
00668     int result;
00669     int len = 0;
00670     char *start, *end;
00671     byte *recvBuf = NULL;
00672     int recvBufSz = 0;
00673     enum phr_state { phr_init, phr_http_start, phr_have_length,
00674                      phr_have_type, phr_wait_end, phr_http_end
00675     } state = phr_init;
00676 
00677     start = end = NULL;
00678     do {
00679         if (end == NULL) {
00680             result = (int)recv(sfd, (char*)httpBuf+len, httpBufSz-len-1, 0);
00681             if (result > 0) {
00682                 len += result;
00683                 start = (char*)httpBuf;
00684                 start[len] = 0;
00685             }
00686             else {
00687                 CYASSL_MSG("process_http_response recv http from peer failed");
00688                 return -1;
00689             }
00690         }
00691         end = XSTRSTR(start, "\r\n");
00692 
00693         if (end == NULL) {
00694             if (len != 0)
00695                 XMEMMOVE(httpBuf, start, len);
00696             start = end = NULL;
00697         }
00698         else if (end == start) {
00699             if (state == phr_wait_end) {
00700                 state = phr_http_end;
00701                 len -= 2;
00702                 start += 2;
00703              }
00704              else {
00705                 CYASSL_MSG("process_http_response header ended early");
00706                 return -1;
00707              }
00708         }
00709         else {
00710             *end = 0;
00711             len -= (int)(end - start) + 2;
00712                 /* adjust len to remove the first line including the /r/n */
00713 
00714             if (XSTRNCASECMP(start, "HTTP/1", 6) == 0) {
00715                 start += 9;
00716                 if (XSTRNCASECMP(start, "200 OK", 6) != 0 ||
00717                                                            state != phr_init) {
00718                     CYASSL_MSG("process_http_response not OK");
00719                     return -1;
00720                 }
00721                 state = phr_http_start;
00722             }
00723             else if (XSTRNCASECMP(start, "Content-Type:", 13) == 0) {
00724                 start += 13;
00725                 while (*start == ' ' && *start != '\0') start++;
00726                 if (XSTRNCASECMP(start, "application/ocsp-response", 25) != 0) {
00727                     CYASSL_MSG("process_http_response not ocsp-response");
00728                     return -1;
00729                 }
00730                 
00731                 if (state == phr_http_start) state = phr_have_type;
00732                 else if (state == phr_have_length) state = phr_wait_end;
00733                 else {
00734                     CYASSL_MSG("process_http_response type invalid state");
00735                     return -1;
00736                 }
00737             }
00738             else if (XSTRNCASECMP(start, "Content-Length:", 15) == 0) {
00739                 start += 15;
00740                 while (*start == ' ' && *start != '\0') start++;
00741                 recvBufSz = atoi(start);
00742 
00743                 if (state == phr_http_start) state = phr_have_length;
00744                 else if (state == phr_have_type) state = phr_wait_end;
00745                 else {
00746                     CYASSL_MSG("process_http_response length invalid state");
00747                     return -1;
00748                 }
00749             }
00750             
00751             start = end + 2;
00752         }
00753     } while (state != phr_http_end);
00754 
00755     recvBuf = XMALLOC(recvBufSz, NULL, DYNAMIC_TYPE_IN_BUFFER);
00756     if (recvBuf == NULL) {
00757         CYASSL_MSG("process_http_response couldn't create response buffer");
00758         return -1;
00759     }
00760 
00761     /* copy the remainder of the httpBuf into the respBuf */
00762     if (len != 0)
00763         XMEMCPY(recvBuf, start, len);
00764 
00765     /* receive the OCSP response data */
00766     do {
00767         result = (int)recv(sfd, (char*)recvBuf+len, recvBufSz-len, 0);
00768         if (result > 0)
00769             len += result;
00770         else {
00771             CYASSL_MSG("process_http_response recv ocsp from peer failed");
00772             return -1;
00773         }
00774     } while (len != recvBufSz);
00775 
00776     *respBuf = recvBuf;
00777     return recvBufSz;
00778 }
00779 
00780 
00781 #define SCRATCH_BUFFER_SIZE 512
00782 
00783 int EmbedOcspLookup(void* ctx, const char* url, int urlSz,
00784                         byte* ocspReqBuf, int ocspReqSz, byte** ocspRespBuf)
00785 {
00786     char domainName[80], path[80];
00787     int httpBufSz;
00788     SOCKET_T sfd = 0;
00789     word16 port;
00790     int ocspRespSz = 0;
00791     byte* httpBuf = NULL;
00792 
00793     (void)ctx;
00794 
00795     if (ocspReqBuf == NULL || ocspReqSz == 0) {
00796         CYASSL_MSG("OCSP request is required for lookup");
00797         return -1;
00798     }
00799 
00800     if (ocspRespBuf == NULL) {
00801         CYASSL_MSG("Cannot save OCSP response");
00802         return -1;
00803     }
00804 
00805     if (decode_url(url, urlSz, domainName, path, &port) < 0) {
00806         CYASSL_MSG("Unable to decode OCSP URL");
00807         return -1;
00808     }
00809     
00810     /* Note, the library uses the EmbedOcspRespFree() callback to
00811      * free this buffer. */
00812     httpBufSz = SCRATCH_BUFFER_SIZE;
00813     httpBuf = (byte*)XMALLOC(httpBufSz, NULL, DYNAMIC_TYPE_IN_BUFFER);
00814 
00815     if (httpBuf == NULL) {
00816         CYASSL_MSG("Unable to create OCSP response buffer");
00817         return -1;
00818     }
00819 
00820     httpBufSz = build_http_request(domainName, path, ocspReqSz,
00821                                                         httpBuf, httpBufSz);
00822 
00823     if ((tcp_connect(&sfd, domainName, port) == 0) && (sfd > 0)) {
00824         int written;
00825         written = (int)send(sfd, (char*)httpBuf, httpBufSz, 0);
00826         if (written == httpBufSz) {
00827             written = (int)send(sfd, (char*)ocspReqBuf, ocspReqSz, 0);
00828             if (written == ocspReqSz) {
00829                 ocspRespSz = process_http_response(sfd, ocspRespBuf,
00830                                                  httpBuf, SCRATCH_BUFFER_SIZE);
00831             }
00832         }
00833         close(sfd);
00834         if (ocspRespSz == 0) {
00835             CYASSL_MSG("OCSP response was not OK, no OCSP response");
00836             XFREE(httpBuf, NULL, DYNAMIC_TYPE_IN_BUFFER);
00837             return -1;
00838         }
00839     } else {
00840         CYASSL_MSG("OCSP Responder connection failed");
00841         close(sfd);
00842         XFREE(httpBuf, NULL, DYNAMIC_TYPE_IN_BUFFER);
00843         return -1;
00844     }
00845 
00846     XFREE(httpBuf, NULL, DYNAMIC_TYPE_IN_BUFFER);
00847     return ocspRespSz;
00848 }
00849 
00850 
00851 void EmbedOcspRespFree(void* ctx, byte *resp)
00852 {
00853     (void)ctx;
00854 
00855     if (resp)
00856         XFREE(resp, NULL, DYNAMIC_TYPE_IN_BUFFER);
00857 }
00858 
00859 
00860 #endif
00861 
00862 #endif /* CYASSL_USER_IO */
00863 
00864 CYASSL_API void CyaSSL_SetIORecv(CYASSL_CTX *ctx, CallbackIORecv CBIORecv)
00865 {
00866     ctx->CBIORecv = CBIORecv;
00867 }
00868 
00869 
00870 CYASSL_API void CyaSSL_SetIOSend(CYASSL_CTX *ctx, CallbackIOSend CBIOSend)
00871 {
00872     ctx->CBIOSend = CBIOSend;
00873 }
00874 
00875 
00876 CYASSL_API void CyaSSL_SetIOReadCtx(CYASSL* ssl, void *rctx)
00877 {
00878     ssl->IOCB_ReadCtx = rctx;
00879 }
00880 
00881 
00882 CYASSL_API void CyaSSL_SetIOWriteCtx(CYASSL* ssl, void *wctx)
00883 {
00884     ssl->IOCB_WriteCtx = wctx;
00885 }
00886 
00887 
00888 CYASSL_API void* CyaSSL_GetIOReadCtx(CYASSL* ssl)
00889 {
00890     if (ssl)
00891         return ssl->IOCB_ReadCtx;
00892 
00893     return NULL;
00894 }
00895 
00896 
00897 CYASSL_API void* CyaSSL_GetIOWriteCtx(CYASSL* ssl)
00898 {
00899     if (ssl)
00900         return ssl->IOCB_WriteCtx;
00901 
00902     return NULL;
00903 }
00904 
00905 
00906 CYASSL_API void CyaSSL_SetIOReadFlags(CYASSL* ssl, int flags)
00907 {
00908     ssl->rflags = flags; 
00909 }
00910 
00911 
00912 CYASSL_API void CyaSSL_SetIOWriteFlags(CYASSL* ssl, int flags)
00913 {
00914     ssl->wflags = flags;
00915 }
00916 
00917 
00918 #ifdef CYASSL_DTLS
00919 
00920 CYASSL_API void CyaSSL_CTX_SetGenCookie(CYASSL_CTX* ctx, CallbackGenCookie cb)
00921 {
00922     ctx->CBIOCookie = cb;
00923 }
00924 
00925 
00926 CYASSL_API void CyaSSL_SetCookieCtx(CYASSL* ssl, void *ctx)
00927 {
00928     ssl->IOCB_CookieCtx = ctx;
00929 }
00930 
00931 
00932 CYASSL_API void* CyaSSL_GetCookieCtx(CYASSL* ssl)
00933 {
00934     if (ssl)
00935         return ssl->IOCB_CookieCtx;
00936 
00937     return NULL;
00938 }
00939 
00940 #endif /* CYASSL_DTLS */
00941 
00942 
00943 #ifdef HAVE_NETX
00944 
00945 /* The NetX receive callback
00946  *  return :  bytes read, or error
00947  */
00948 int NetX_Receive(CYASSL *ssl, char *buf, int sz, void *ctx)
00949 {
00950     NetX_Ctx* nxCtx = (NetX_Ctx*)ctx;
00951     ULONG left;
00952     ULONG total;
00953     ULONG copied = 0;
00954     UINT  status;
00955 
00956     if (nxCtx == NULL || nxCtx->nxSocket == NULL) {
00957         CYASSL_MSG("NetX Recv NULL parameters");
00958         return CYASSL_CBIO_ERR_GENERAL;
00959     }
00960 
00961     if (nxCtx->nxPacket == NULL) {
00962         status = nx_tcp_socket_receive(nxCtx->nxSocket, &nxCtx->nxPacket,
00963                                        nxCtx->nxWait);
00964         if (status != NX_SUCCESS) {
00965             CYASSL_MSG("NetX Recv receive error");
00966             return CYASSL_CBIO_ERR_GENERAL;
00967         }
00968     }
00969 
00970     if (nxCtx->nxPacket) {
00971         status = nx_packet_length_get(nxCtx->nxPacket, &total);
00972         if (status != NX_SUCCESS) {
00973             CYASSL_MSG("NetX Recv length get error");
00974             return CYASSL_CBIO_ERR_GENERAL;
00975         }
00976 
00977         left = total - nxCtx->nxOffset;
00978         status = nx_packet_data_extract_offset(nxCtx->nxPacket, nxCtx->nxOffset,
00979                                                buf, sz, &copied);
00980         if (status != NX_SUCCESS) {
00981             CYASSL_MSG("NetX Recv data extract offset error");
00982             return CYASSL_CBIO_ERR_GENERAL;
00983         }
00984 
00985         nxCtx->nxOffset += copied;
00986 
00987         if (copied == left) {
00988             CYASSL_MSG("NetX Recv Drained packet");
00989             nx_packet_release(nxCtx->nxPacket);
00990             nxCtx->nxPacket = NULL;
00991             nxCtx->nxOffset = 0;
00992         }
00993     }
00994 
00995     return copied;
00996 }
00997 
00998 
00999 /* The NetX send callback
01000  *  return : bytes sent, or error
01001  */
01002 int NetX_Send(CYASSL* ssl, char *buf, int sz, void *ctx)
01003 {
01004     NetX_Ctx*       nxCtx = (NetX_Ctx*)ctx;
01005     NX_PACKET*      packet;
01006     NX_PACKET_POOL* pool;   /* shorthand */
01007     UINT            status;
01008 
01009     if (nxCtx == NULL || nxCtx->nxSocket == NULL) {
01010         CYASSL_MSG("NetX Send NULL parameters");
01011         return CYASSL_CBIO_ERR_GENERAL;
01012     }
01013 
01014     pool = nxCtx->nxSocket->nx_tcp_socket_ip_ptr->nx_ip_default_packet_pool;
01015     status = nx_packet_allocate(pool, &packet, NX_TCP_PACKET,
01016                                 nxCtx->nxWait);
01017     if (status != NX_SUCCESS) {
01018         CYASSL_MSG("NetX Send packet alloc error");
01019         return CYASSL_CBIO_ERR_GENERAL;
01020     }
01021 
01022     status = nx_packet_data_append(packet, buf, sz, pool, nxCtx->nxWait);
01023     if (status != NX_SUCCESS) {
01024         nx_packet_release(packet);
01025         CYASSL_MSG("NetX Send data append error");
01026         return CYASSL_CBIO_ERR_GENERAL;
01027     }
01028 
01029     status = nx_tcp_socket_send(nxCtx->nxSocket, packet, nxCtx->nxWait);
01030     if (status != NX_SUCCESS) {
01031         nx_packet_release(packet);
01032         CYASSL_MSG("NetX Send socket send error");
01033         return CYASSL_CBIO_ERR_GENERAL;
01034     }
01035 
01036     return sz;
01037 }
01038 
01039 
01040 /* like set_fd, but for default NetX context */
01041 void CyaSSL_SetIO_NetX(CYASSL* ssl, NX_TCP_SOCKET* nxSocket, ULONG waitOption)
01042 {
01043     if (ssl) {
01044         ssl->nxCtx.nxSocket = nxSocket;
01045         ssl->nxCtx.nxWait   = waitOption;
01046     }
01047 }
01048 
01049 #endif /* HAVE_NETX */
01050