This is a port of cyaSSL 2.7.0.

Dependents:   CyaSSL_DTLS_Cellular CyaSSL_DTLS_Ethernet

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 "bsd_socket.h"
00027 
00028 #include <cyassl/ctaocrypt/settings.h>
00029 
00030 #ifdef _WIN32_WCE
00031     /* On WinCE winsock2.h must be included before windows.h for socket stuff */
00032     #include <winsock2.h>
00033 #endif
00034 
00035 #include <cyassl/internal.h>
00036 #include <cyassl/ctaoerror.h>
00037 
00038 /* if user writes own I/O callbacks they can define CYASSL_USER_IO to remove
00039    automatic setting of default I/O functions EmbedSend() and EmbedReceive()
00040    but they'll still need SetCallback xxx() at end of file 
00041 */
00042 #ifndef CYASSL_USER_IO
00043 
00044 #ifdef HAVE_LIBZ
00045     #include "zlib.h"
00046 #endif
00047 
00048 #ifndef USE_WINDOWS_API
00049     #ifdef CYASSL_LWIP
00050         /* lwIP needs to be configured to use sockets API in this mode */
00051         /* LWIP_SOCKET 1 in lwip/opt.h or in build */
00052         #include "lwip/sockets.h"
00053         #include <errno.h>
00054         #ifndef LWIP_PROVIDE_ERRNO
00055             #define LWIP_PROVIDE_ERRNO 1
00056         #endif
00057     #elif defined(FREESCALE_MQX)
00058         #include <posix.h>
00059         #include <rtcs.h>
00060     #elif defined(CYASSL_MDK_ARM)
00061         #include <rtl.h>
00062         #undef RNG
00063         #include "CYASSL_MDK_ARM.h"
00064         #undef RNG
00065         #define RNG CyaSSL_RNG 
00066         /* for avoiding name conflict in "stm32f2xx.h" */
00067         static int errno;
00068     #else
00069  //       #include <sys/types.h>
00070         #include <errno.h>
00071         #ifndef EBSNET
00072  //           #include <unistd.h>
00073         #endif
00074         #include <fcntl.h>
00075         #if !(defined(DEVKITPRO) || defined(HAVE_RTP_SYS) || defined(EBSNET))
00076             #include <sys/socket.h>
00077             #include <arpa/inet.h>
00078             #include <netinet/in.h>
00079             #include <netdb.h>
00080             #ifdef __PPU
00081                 #include <netex/errno.h>
00082             #else
00083                 #include <sys/ioctl.h>
00084             #endif
00085         #endif
00086         #ifdef HAVE_RTP_SYS
00087             #include <socket.h>
00088         #endif
00089         #ifdef EBSNET
00090             #include "rtipapi.h"  /* errno */
00091             #include "socket.h"
00092         #endif
00093     #endif
00094 #endif /* USE_WINDOWS_API */
00095 
00096 #ifdef __sun
00097     #include <sys/filio.h>
00098 #endif
00099 
00100 #ifdef USE_WINDOWS_API 
00101     /* no epipe yet */
00102     #ifndef WSAEPIPE
00103         #define WSAEPIPE       -12345
00104     #endif
00105     #define SOCKET_EWOULDBLOCK WSAEWOULDBLOCK
00106     #define SOCKET_EAGAIN      WSAETIMEDOUT
00107     #define SOCKET_ECONNRESET  WSAECONNRESET
00108     #define SOCKET_EINTR       WSAEINTR
00109     #define SOCKET_EPIPE       WSAEPIPE
00110     #define SOCKET_ECONNREFUSED WSAENOTCONN
00111     #define SOCKET_ECONNABORTED WSAECONNABORTED
00112 #elif defined(__PPU)
00113     #define SOCKET_EWOULDBLOCK SYS_NET_EWOULDBLOCK
00114     #define SOCKET_EAGAIN      SYS_NET_EAGAIN
00115     #define SOCKET_ECONNRESET  SYS_NET_ECONNRESET
00116     #define SOCKET_EINTR       SYS_NET_EINTR
00117     #define SOCKET_EPIPE       SYS_NET_EPIPE
00118     #define SOCKET_ECONNREFUSED SYS_NET_ECONNREFUSED
00119     #define SOCKET_ECONNABORTED SYS_NET_ECONNABORTED
00120 #elif defined(FREESCALE_MQX)
00121     /* RTCS doesn't have an EWOULDBLOCK error */
00122     #define SOCKET_EWOULDBLOCK EAGAIN
00123     #define SOCKET_EAGAIN      EAGAIN
00124     #define SOCKET_ECONNRESET  RTCSERR_TCP_CONN_RESET
00125     #define SOCKET_EINTR       EINTR
00126     #define SOCKET_EPIPE       EPIPE
00127     #define SOCKET_ECONNREFUSED RTCSERR_TCP_CONN_REFUSED
00128     #define SOCKET_ECONNABORTED RTCSERR_TCP_CONN_ABORTED
00129 #elif defined(CYASSL_MDK_ARM)
00130     #define SOCKET_EWOULDBLOCK SCK_EWOULDBLOCK
00131     #define SOCKET_EAGAIN      SCK_ELOCKED
00132     #define SOCKET_ECONNRESET  SCK_ECLOSED
00133     #define SOCKET_EINTR       SCK_ERROR
00134     #define SOCKET_EPIPE       SCK_ERROR
00135     #define SOCKET_ECONNREFUSED SCK_ERROR
00136     #define SOCKET_ECONNABORTED SCK_ERROR
00137 #else
00138     #define SOCKET_EWOULDBLOCK EWOULDBLOCK
00139     #define SOCKET_EAGAIN      EAGAIN
00140     #define SOCKET_ECONNRESET  ECONNRESET
00141     #define SOCKET_EINTR       EINTR
00142     #define SOCKET_EPIPE       EPIPE
00143     #define SOCKET_ECONNREFUSED ECONNREFUSED
00144     #define SOCKET_ECONNABORTED ECONNABORTED
00145 #endif /* USE_WINDOWS_API */
00146 
00147 
00148 #ifdef DEVKITPRO
00149     /* from network.h */
00150     int net_send(int, const void*, int, unsigned int);
00151     int net_recv(int, void*, int, unsigned int);
00152     #define SEND_FUNCTION net_send
00153     #define RECV_FUNCTION net_recv
00154 #elif defined(CYASSL_LWIP)
00155     #define SEND_FUNCTION lwip_send
00156     #define RECV_FUNCTION lwip_recv
00157 #else
00158     #define SEND_FUNCTION send
00159     #define RECV_FUNCTION recv
00160 #endif
00161 
00162 
00163 /* Translates return codes returned from 
00164  * send() and recv() if need be. 
00165  */
00166 static INLINE int TranslateReturnCode(int old, int sd)
00167 {
00168     (void)sd;
00169 
00170 #ifdef FREESCALE_MQX
00171     if (old == 0) {
00172         errno = SOCKET_EWOULDBLOCK;
00173         return -1;  /* convert to BSD style wouldblock as error */
00174     }
00175 
00176     if (old < 0) {
00177         errno = RTCS_geterror(sd);
00178         if (errno == RTCSERR_TCP_CONN_CLOSING)
00179             return 0;   /* convert to BSD style closing */
00180     }
00181 #endif
00182 
00183     return old;
00184 }
00185 
00186 static INLINE int LastError(void)
00187 {
00188 #ifdef USE_WINDOWS_API 
00189     return WSAGetLastError();
00190 #elif defined(EBSNET)
00191     return xn_getlasterror();
00192 #else
00193     return errno;
00194 #endif
00195 }
00196 
00197 /* The receive embedded callback
00198  *  return : nb bytes read, or error
00199  */
00200 int EmbedReceive(CYASSL *ssl, char *buf, int sz, void *ctx)
00201 {
00202     int recvd;
00203     int err;
00204     int sd = *(int*)ctx;
00205 
00206 #ifdef CYASSL_DTLS
00207     {
00208         int dtls_timeout = CyaSSL_dtls_get_current_timeout(ssl);
00209         if (CyaSSL_dtls(ssl)
00210                      && !CyaSSL_get_using_nonblock(ssl)
00211                      && dtls_timeout != 0) {
00212             #ifdef USE_WINDOWS_API
00213                 DWORD timeout = dtls_timeout * 1000;
00214             #else
00215                 struct timeval timeout;
00216                 XMEMSET(&timeout, 0, sizeof(timeout));
00217                 timeout.tv_sec = dtls_timeout;
00218             #endif
00219             if (setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout,
00220                            sizeof(timeout)) != 0) {
00221                 CYASSL_MSG("setsockopt rcvtimeo failed");
00222             }
00223         }
00224     }
00225 #endif
00226 
00227     recvd = (int)RECV_FUNCTION(sd, buf, sz, ssl->rflags);
00228 
00229     recvd = TranslateReturnCode(recvd, sd);
00230 
00231     if (recvd < 0) {
00232         err = LastError();
00233         CYASSL_MSG("Embed Receive error");
00234 
00235         if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) {
00236             if (!CyaSSL_dtls(ssl) || CyaSSL_get_using_nonblock(ssl)) {
00237                 CYASSL_MSG("    Would block");
00238                 return CYASSL_CBIO_ERR_WANT_READ;
00239             }
00240             else {
00241                 CYASSL_MSG("    Socket timeout");
00242                 return CYASSL_CBIO_ERR_TIMEOUT;
00243             }
00244         }
00245         else if (err == SOCKET_ECONNRESET) {
00246             CYASSL_MSG("    Connection reset");
00247             return CYASSL_CBIO_ERR_CONN_RST;
00248         }
00249         else if (err == SOCKET_EINTR) {
00250             CYASSL_MSG("    Socket interrupted");
00251             return CYASSL_CBIO_ERR_ISR;
00252         }
00253         else if (err == SOCKET_ECONNREFUSED) {
00254             CYASSL_MSG("    Connection refused");
00255             return CYASSL_CBIO_ERR_WANT_READ;
00256         }
00257         else if (err == SOCKET_ECONNABORTED) {
00258             CYASSL_MSG("    Connection aborted");
00259             return CYASSL_CBIO_ERR_CONN_CLOSE;
00260         }
00261         else {
00262             CYASSL_MSG("    General error");
00263             return CYASSL_CBIO_ERR_GENERAL;
00264         }
00265     }
00266     else if (recvd == 0) {
00267         CYASSL_MSG("Embed receive connection closed");
00268         return CYASSL_CBIO_ERR_CONN_CLOSE;
00269     }
00270 
00271     return recvd;
00272 }
00273 
00274 /* The send embedded callback
00275  *  return : nb bytes sent, or error
00276  */
00277 int EmbedSend(CYASSL* ssl, char *buf, int sz, void *ctx)
00278 {
00279     int sd = *(int*)ctx;
00280     int sent;
00281     int len = sz;
00282     int err;
00283 
00284     sent = (int)SEND_FUNCTION(sd, &buf[sz - len], len, ssl->wflags);
00285 
00286     if (sent < 0) {
00287         err = LastError();
00288         CYASSL_MSG("Embed Send error");
00289 
00290         if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) {
00291             CYASSL_MSG("    Would Block");
00292             return CYASSL_CBIO_ERR_WANT_WRITE;
00293         }
00294         else if (err == SOCKET_ECONNRESET) {
00295             CYASSL_MSG("    Connection reset");
00296             return CYASSL_CBIO_ERR_CONN_RST;
00297         }
00298         else if (err == SOCKET_EINTR) {
00299             CYASSL_MSG("    Socket interrupted");
00300             return CYASSL_CBIO_ERR_ISR;
00301         }
00302         else if (err == SOCKET_EPIPE) {
00303             CYASSL_MSG("    Socket EPIPE");
00304             return CYASSL_CBIO_ERR_CONN_CLOSE;
00305         }
00306         else {
00307             CYASSL_MSG("    General error");
00308             return CYASSL_CBIO_ERR_GENERAL;
00309         }
00310     }
00311  
00312     return sent;
00313 }
00314 
00315 
00316 #ifdef CYASSL_DTLS
00317 
00318 #include <cyassl/ctaocrypt/sha.h>
00319 
00320 #ifdef USE_WINDOWS_API
00321    #define XSOCKLENT int
00322 #else
00323    #define XSOCKLENT socklen_t
00324 #endif
00325 
00326 #define SENDTO_FUNCTION sendto
00327 #define RECVFROM_FUNCTION recvfrom
00328 
00329 
00330 /* The receive embedded callback
00331  *  return : nb bytes read, or error
00332  */
00333 int EmbedReceiveFrom(CYASSL *ssl, char *buf, int sz, void *ctx)
00334 {
00335     CYASSL_DTLS_CTX* dtlsCtx = (CYASSL_DTLS_CTX*)ctx;
00336     int recvd;
00337     int err;
00338     int sd = dtlsCtx->fd;
00339     int dtls_timeout = CyaSSL_dtls_get_current_timeout(ssl);
00340     struct sockaddr_in peer;
00341     XSOCKLENT peerSz = sizeof(peer);
00342 
00343     CYASSL_ENTER("EmbedReceiveFrom()");
00344 
00345     if (!CyaSSL_get_using_nonblock(ssl) && dtls_timeout != 0) {
00346         #ifdef USE_WINDOWS_API
00347             DWORD timeout = dtls_timeout * 1000;
00348         #else
00349             struct timeval timeout;
00350             XMEMSET(&timeout, 0, sizeof(timeout));
00351             timeout.tv_sec = dtls_timeout;
00352         #endif
00353         if (setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout,
00354                        sizeof(timeout)) != 0) {
00355                 CYASSL_MSG("setsockopt rcvtimeo failed");
00356         }
00357     }
00358 
00359     recvd = (int)RECVFROM_FUNCTION(sd, buf, sz, ssl->rflags,
00360                                   (struct sockaddr*)&peer, &peerSz);
00361     recvd = TranslateReturnCode(recvd, sd);
00362 
00363     if (recvd < 0) {
00364         err = LastError();
00365         CYASSL_MSG("Embed Receive From error");
00366 
00367         if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) {
00368             if (CyaSSL_get_using_nonblock(ssl)) {
00369                 CYASSL_MSG("    Would block");
00370                 return CYASSL_CBIO_ERR_WANT_READ;
00371             }
00372             else {
00373                 CYASSL_MSG("    Socket timeout");
00374                 return CYASSL_CBIO_ERR_TIMEOUT;
00375             }
00376         }
00377         else if (err == SOCKET_ECONNRESET) {
00378             CYASSL_MSG("    Connection reset");
00379             return CYASSL_CBIO_ERR_CONN_RST;
00380         }
00381         else if (err == SOCKET_EINTR) {
00382             CYASSL_MSG("    Socket interrupted");
00383             return CYASSL_CBIO_ERR_ISR;
00384         }
00385         else if (err == SOCKET_ECONNREFUSED) {
00386             CYASSL_MSG("    Connection refused");
00387             return CYASSL_CBIO_ERR_WANT_READ;
00388         }
00389         else {
00390             CYASSL_MSG("    General error");
00391             return CYASSL_CBIO_ERR_GENERAL;
00392         }
00393     }
00394     else {
00395         if (dtlsCtx->peer.sz > 0
00396                 && peerSz != (XSOCKLENT)dtlsCtx->peer.sz
00397                 && memcmp(&peer, dtlsCtx->peer.sa, peerSz) != 0) {
00398             CYASSL_MSG("    Ignored packet from invalid peer");
00399             return CYASSL_CBIO_ERR_WANT_READ;
00400         }
00401     }
00402 
00403     return recvd;
00404 }
00405 
00406 
00407 /* The send embedded callback
00408  *  return : nb bytes sent, or error
00409  */
00410 int EmbedSendTo(CYASSL* ssl, char *buf, int sz, void *ctx)
00411 {
00412     CYASSL_DTLS_CTX* dtlsCtx = (CYASSL_DTLS_CTX*)ctx;
00413     int sd = dtlsCtx->fd;
00414     int sent;
00415     int len = sz;
00416     int err;
00417 
00418     CYASSL_ENTER("EmbedSendTo()");
00419 
00420     sent = (int)SENDTO_FUNCTION(sd, &buf[sz - len], len, ssl->wflags,
00421                                 dtlsCtx->peer.sa, dtlsCtx->peer.sz);
00422     if (sent < 0) {
00423         err = LastError();
00424         CYASSL_MSG("Embed Send To error");
00425 
00426         if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) {
00427             CYASSL_MSG("    Would Block");
00428             return CYASSL_CBIO_ERR_WANT_WRITE;
00429         }
00430         else if (err == SOCKET_ECONNRESET) {
00431             CYASSL_MSG("    Connection reset");
00432             return CYASSL_CBIO_ERR_CONN_RST;
00433         }
00434         else if (err == SOCKET_EINTR) {
00435             CYASSL_MSG("    Socket interrupted");
00436             return CYASSL_CBIO_ERR_ISR;
00437         }
00438         else if (err == SOCKET_EPIPE) {
00439             CYASSL_MSG("    Socket EPIPE");
00440             return CYASSL_CBIO_ERR_CONN_CLOSE;
00441         }
00442         else {
00443             CYASSL_MSG("    General error");
00444             return CYASSL_CBIO_ERR_GENERAL;
00445         }
00446     }
00447  
00448     return sent;
00449 }
00450 
00451 
00452 /* The DTLS Generate Cookie callback
00453  *  return : number of bytes copied into buf, or error
00454  */
00455 int EmbedGenerateCookie(CYASSL* ssl, byte *buf, int sz, void *ctx)
00456 {
00457     int sd = ssl->wfd;
00458     struct sockaddr_in peer;
00459     XSOCKLENT peerSz = sizeof(peer);
00460     byte cookieSrc[sizeof(struct in_addr) + sizeof(int)];
00461     int cookieSrcSz = 0;
00462     Sha sha;
00463 
00464     (void)ctx;
00465 
00466     if (getpeername(sd, (struct sockaddr*)&peer, &peerSz) != 0) {
00467         CYASSL_MSG("getpeername failed in EmbedGenerateCookie");
00468         return GEN_COOKIE_E;
00469     }
00470     
00471     if (peer.sin_family == AF_INET) {
00472         struct sockaddr_in *s = (struct sockaddr_in*)&peer;
00473 
00474         cookieSrcSz = sizeof(struct in_addr) + sizeof(s->sin_port);
00475         XMEMCPY(cookieSrc, &s->sin_port, sizeof(s->sin_port));
00476         XMEMCPY(cookieSrc + sizeof(s->sin_port),
00477                                      &s->sin_addr, sizeof(struct in_addr));
00478     }
00479 
00480     InitSha(&sha);
00481     ShaUpdate(&sha, cookieSrc, cookieSrcSz);
00482 
00483     if (sz < SHA_DIGEST_SIZE) {
00484         byte digest[SHA_DIGEST_SIZE];
00485         ShaFinal(&sha, digest);
00486         XMEMCPY(buf, digest, sz);
00487         return sz;
00488     }
00489 
00490     ShaFinal(&sha, buf);
00491 
00492     return SHA_DIGEST_SIZE;
00493 }
00494 
00495 #endif /* CYASSL_DTLS */
00496 
00497 #ifdef HAVE_OCSP
00498 
00499 #ifdef TEST_IPV6
00500     typedef struct sockaddr_in6 SOCKADDR_IN_T;
00501     #define AF_INET_V    AF_INET6
00502 #else
00503     typedef struct sockaddr_in  SOCKADDR_IN_T;
00504     #define AF_INET_V    AF_INET
00505 #endif
00506 
00507 
00508 static INLINE int tcp_connect(SOCKET_T* sockfd, const char* ip, word16 port)
00509 {
00510     SOCKADDR_IN_T addr;
00511     const char* host = ip;
00512 
00513     /* peer could be in human readable form */
00514     if (ip != INADDR_ANY && isalpha(ip[0])) {
00515         struct hostent* entry = gethostbyname(ip);
00516 
00517         if (entry) {
00518             struct sockaddr_in tmp;
00519             XMEMSET(&tmp, 0, sizeof(struct sockaddr_in));
00520             XMEMCPY(&tmp.sin_addr.s_addr, entry->h_addr_list[0],
00521                    entry->h_length);
00522             host = inet_ntoa(tmp.sin_addr);
00523         }
00524         else {
00525             CYASSL_MSG("no addr entry for OCSP responder");
00526             return -1;
00527         }
00528     }
00529 
00530     *sockfd = socket(AF_INET_V, SOCK_STREAM, 0);
00531     if (*sockfd < 0) {
00532         CYASSL_MSG("bad socket fd, out of fds?");
00533         return -1;
00534     }
00535     XMEMSET(&addr, 0, sizeof(SOCKADDR_IN_T));
00536 
00537     addr.sin_family = AF_INET_V;
00538     addr.sin_port = htons(port);
00539     if (host == INADDR_ANY)
00540         addr.sin_addr.s_addr = INADDR_ANY;
00541     else
00542         addr.sin_addr.s_addr = inet_addr(host);
00543 
00544     if (connect(*sockfd, (const struct sockaddr*)&addr, sizeof(addr)) != 0) {
00545         CYASSL_MSG("OCSP responder tcp connect failed");
00546         return -1;
00547     }
00548 
00549     return 0;
00550 }
00551 
00552 
00553 static int build_http_request(const char* domainName, const char* path,
00554                                     int ocspReqSz, byte* buf, int bufSize)
00555 {
00556     return snprintf((char*)buf, bufSize,
00557         "POST %s HTTP/1.1\r\n"
00558         "Host: %s\r\n"
00559         "Content-Length: %d\r\n"
00560         "Content-Type: application/ocsp-request\r\n"
00561         "\r\n", 
00562         path, domainName, ocspReqSz);
00563 }
00564 
00565 
00566 static int decode_http_response(byte* httpBuf, int httpBufSz, byte** dst)
00567 {
00568     int idx = 0;
00569     int stop = 0;
00570     int len = 0;
00571     byte* contentType = NULL;
00572     byte* contentLength = NULL;
00573     char* buf = (char*)httpBuf; /* kludge so I'm not constantly casting */
00574 
00575     if (XSTRNCASECMP(buf, "HTTP/1", 6) != 0)
00576         return 0;
00577     
00578     idx = 9; /* sets to the first byte after "HTTP/1.X ", which should be the
00579               * HTTP result code */
00580 
00581      if (XSTRNCASECMP(&buf[idx], "200 OK", 6) != 0)
00582         return 0;
00583     
00584     idx += 8;
00585 
00586     while (idx < httpBufSz && !stop) {
00587         if (buf[idx] == '\r' && buf[idx+1] == '\n') {
00588             stop = 1;
00589             idx += 2;
00590         }
00591         else {
00592             if (contentType == NULL &&
00593                            XSTRNCASECMP(&buf[idx], "Content-Type:", 13) == 0) {
00594                 idx += 13;
00595                 if (buf[idx] == ' ') idx++;
00596                 if (XSTRNCASECMP(&buf[idx],
00597                                        "application/ocsp-response", 25) != 0) {
00598                     return 0;
00599                 }
00600                 idx += 27;
00601             }
00602             else if (contentLength == NULL &&
00603                          XSTRNCASECMP(&buf[idx], "Content-Length:", 15) == 0) {
00604                 idx += 15;
00605                 if (buf[idx] == ' ') idx++;
00606                 while (buf[idx] >= '0' && buf[idx] <= '9' && idx < httpBufSz) {
00607                     len = (len * 10) + (buf[idx] - '0');
00608                     idx++;
00609                 }
00610                 idx += 2; /* skip the crlf */
00611             }
00612             else {
00613                 /* Advance idx past the next \r\n */
00614                 char* end = XSTRSTR(&buf[idx], "\r\n");
00615                 idx = (int)(end - buf + 2);
00616             }
00617         }
00618     }
00619     
00620     if (len > 0) {
00621         *dst = (byte*)XMALLOC(len, NULL, DYNAMIC_TYPE_IN_BUFFER);
00622         XMEMCPY(*dst, httpBuf + idx, len);
00623     }
00624 
00625     return len;
00626 }
00627 
00628 
00629 static int decode_url(const char* url, int urlSz,
00630     char* outName, char* outPath, int* outPort)
00631 {
00632     int result = -1;
00633 
00634     if (outName != NULL && outPath != NULL && outPort != NULL)
00635     {
00636         if (url == NULL || urlSz == 0)
00637         {
00638             *outName = 0;
00639             *outPath = 0;
00640             *outPort = 0;
00641         }
00642         else
00643         {
00644             int i, cur;
00645     
00646             /* need to break the url down into scheme, address, and port */
00647             /* "http://example.com:8080/" */
00648             if (XSTRNCMP(url, "http://", 7) == 0) {
00649                 cur = 7;
00650             } else cur = 0;
00651     
00652             i = 0;
00653             while (url[cur] != 0 && url[cur] != ':' &&
00654                                                url[cur] != '/' && cur < urlSz) {
00655                 outName[i++] = url[cur++];
00656             }
00657             outName[i] = 0;
00658             /* Need to pick out the path after the domain name */
00659     
00660             if (cur < urlSz && url[cur] == ':') {
00661                 char port[6];
00662                 int j;
00663                 i = 0;
00664                 cur++;
00665                 while (cur < urlSz && url[cur] != 0 && url[cur] != '/' &&
00666                         i < 6) {
00667                     port[i++] = url[cur++];
00668                 }
00669     
00670                 *outPort = 0;
00671                 for (j = 0; j < i; j++) {
00672                     if (port[j] < '0' || port[j] > '9') return -1;
00673                     *outPort = (*outPort * 10) + (port[j] - '0');
00674                 }
00675             }
00676             else
00677                 *outPort = 80;
00678     
00679             if (cur < urlSz && url[cur] == '/') {
00680                 i = 0;
00681                 while (cur < urlSz && url[cur] != 0 && i < 80) {
00682                     outPath[i++] = url[cur++];
00683                 }
00684                 outPath[i] = 0;
00685             }
00686             else {
00687                 outPath[0] = '/';
00688                 outPath[1] = 0;
00689             }
00690             result = 0;
00691         }
00692     }
00693 
00694     return result;
00695 }
00696 
00697 
00698 #define SCRATCH_BUFFER_SIZE 2048
00699 
00700 int EmbedOcspLookup(void* ctx, const char* url, int urlSz,
00701                         byte* ocspReqBuf, int ocspReqSz, byte** ocspRespBuf)
00702 {
00703     char domainName[80], path[80];
00704     int port, httpBufSz, sfd = -1;
00705     int ocspRespSz = 0;
00706     byte* httpBuf = NULL;
00707 
00708     (void)ctx;
00709 
00710     if (ocspReqBuf == NULL || ocspReqSz == 0) {
00711         CYASSL_MSG("OCSP request is required for lookup");
00712         return -1;
00713     }
00714 
00715     if (ocspRespBuf == NULL) {
00716         CYASSL_MSG("Cannot save OCSP response");
00717         return -1;
00718     }
00719 
00720     if (decode_url(url, urlSz, domainName, path, &port) < 0) {
00721         CYASSL_MSG("Unable to decode OCSP URL");
00722         return -1;
00723     }
00724     
00725     httpBufSz = SCRATCH_BUFFER_SIZE;
00726     httpBuf = (byte*)XMALLOC(httpBufSz, NULL, DYNAMIC_TYPE_IN_BUFFER);
00727 
00728     if (httpBuf == NULL) {
00729         CYASSL_MSG("Unable to create OCSP response buffer");
00730         return -1;
00731     }
00732     *ocspRespBuf = httpBuf;
00733 
00734     httpBufSz = build_http_request(domainName, path, ocspReqSz,
00735                                                         httpBuf, httpBufSz);
00736 
00737     if ((tcp_connect(&sfd, domainName, port) == 0) && (sfd > 0)) {
00738         int written;
00739         written = (int)send(sfd, httpBuf, httpBufSz, 0);
00740         if (written == httpBufSz) {
00741             written = (int)send(sfd, ocspReqBuf, ocspReqSz, 0);
00742             if (written == ocspReqSz) {
00743                 httpBufSz = (int)recv(sfd, httpBuf, SCRATCH_BUFFER_SIZE, 0);
00744                 if (httpBufSz > 0) {
00745                     ocspRespSz = decode_http_response(httpBuf, httpBufSz,
00746                         ocspRespBuf);
00747                 }
00748             }
00749         }
00750         close(sfd);
00751         if (ocspRespSz == 0) {
00752             CYASSL_MSG("OCSP response was not OK, no OCSP response");
00753             return -1;
00754         }
00755     } else {
00756         CYASSL_MSG("OCSP Responder connection failed");
00757         close(sfd);
00758         return -1;
00759     }
00760 
00761     return ocspRespSz;
00762 }
00763 
00764 
00765 void EmbedOcspRespFree(void* ctx, byte *resp)
00766 {
00767     (void)ctx;
00768 
00769     if (resp)
00770         XFREE(resp, NULL, DYNAMIC_TYPE_IN_BUFFER);
00771 }
00772 
00773 
00774 #endif
00775 
00776 #endif /* CYASSL_USER_IO */
00777 
00778 CYASSL_API void CyaSSL_SetIORecv(CYASSL_CTX *ctx, CallbackIORecv CBIORecv)
00779 {
00780     ctx->CBIORecv = CBIORecv;
00781 }
00782 
00783 
00784 CYASSL_API void CyaSSL_SetIOSend(CYASSL_CTX *ctx, CallbackIOSend CBIOSend)
00785 {
00786     ctx->CBIOSend = CBIOSend;
00787 }
00788 
00789 
00790 CYASSL_API void CyaSSL_SetIOReadCtx(CYASSL* ssl, void *rctx)
00791 {
00792     ssl->IOCB_ReadCtx = rctx;
00793 }
00794 
00795 
00796 CYASSL_API void CyaSSL_SetIOWriteCtx(CYASSL* ssl, void *wctx)
00797 {
00798     ssl->IOCB_WriteCtx = wctx;
00799 }
00800 
00801 
00802 CYASSL_API void CyaSSL_SetIOReadFlags(CYASSL* ssl, int flags)
00803 {
00804     ssl->rflags = flags; 
00805 }
00806 
00807 
00808 CYASSL_API void CyaSSL_SetIOWriteFlags(CYASSL* ssl, int flags)
00809 {
00810     ssl->wflags = flags;
00811 }
00812 
00813 
00814 #ifdef CYASSL_DTLS
00815 
00816 CYASSL_API void CyaSSL_CTX_SetGenCookie(CYASSL_CTX* ctx, CallbackGenCookie cb)
00817 {
00818     ctx->CBIOCookie = cb;
00819 }
00820 
00821 
00822 CYASSL_API void CyaSSL_SetCookieCtx(CYASSL* ssl, void *ctx)
00823 {
00824     ssl->IOCB_CookieCtx = ctx;
00825 }
00826 
00827 #endif /* CYASSL_DTLS */
00828 
00829 
00830 #ifdef HAVE_OCSP
00831 
00832 CYASSL_API void CyaSSL_SetIOOcsp(CYASSL_CTX* ctx, CallbackIOOcsp cb)
00833 {
00834     ctx->ocsp.CBIOOcsp = cb;
00835 }
00836 
00837 CYASSL_API void CyaSSL_SetIOOcspRespFree(CYASSL_CTX* ctx,
00838                                                      CallbackIOOcspRespFree cb)
00839 {
00840     ctx->ocsp.CBIOOcspRespFree = cb;
00841 }
00842 
00843 CYASSL_API void CyaSSL_SetIOOcspCtx(CYASSL_CTX* ctx, void *octx)
00844 {
00845     ctx->ocsp.IOCB_OcspCtx = octx;
00846 }
00847 
00848 #endif