diff options
author | Nick Zitzmann <nick@chronosnet.com> | 2012-06-26 14:01:51 +0200 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2012-06-26 14:04:15 +0200 |
commit | 6d1ea388cbd9de7f2a944a0c64f5feaec1b1904a (patch) | |
tree | f038997efab45284df2161121772dec49008d6cb | |
parent | 07e3ea7f261bdbaddd7d8d7f4d6374c5d01acb51 (diff) |
darwinssl: add support for native Mac OS X/iOS SSL
-rw-r--r-- | configure.ac | 27 | ||||
-rw-r--r-- | lib/Makefile.inc | 4 | ||||
-rw-r--r-- | lib/curl_darwinssl.c | 661 | ||||
-rw-r--r-- | lib/curl_darwinssl.h | 62 | ||||
-rw-r--r-- | lib/setup.h | 3 | ||||
-rw-r--r-- | lib/sslgen.c | 2 | ||||
-rw-r--r-- | lib/urldata.h | 14 |
7 files changed, 769 insertions, 4 deletions
diff --git a/configure.ac b/configure.ac index 1774b3a19..3c792cd27 100644 --- a/configure.ac +++ b/configure.ac @@ -1371,6 +1371,29 @@ else AC_MSG_RESULT(no) fi +OPT_DARWINSSL=no +AC_ARG_WITH(darwinssl,dnl +AC_HELP_STRING([--with-darwinssl],[enable iOS/Mac OS X native SSL/TLS]) +AC_HELP_STRING([--without-darwinssl], [disable iOS/Mac OS X native SSL/TLS]), + OPT_DARWINSSL=$withval) + +AC_MSG_CHECKING([whether to enable iOS/Mac OS X native SSL/TLS]) +if test "$curl_ssl_msg" = "$init_ssl_msg"; then + if test "x$OPT_DARWINSSL" != "xno" && + test -d "/System/Library/Frameworks/Security.framework"; then + AC_MSG_RESULT(yes) + AC_DEFINE(USE_DARWINSSL, 1, [to enable iOS/Mac OS X native SSL/TLS support]) + AC_SUBST(USE_DARWINSSL, [1]) + curl_ssl_msg="enabled (iOS/Mac OS X-native)" + DARWINSSL_ENABLED=1 + LDFLAGS="$LDFLAGS -framework CoreFoundation -framework Security" + else + AC_MSG_RESULT(no) + fi +else + AC_MSG_RESULT(no) +fi + dnl ********************************************************************** dnl Check for the presence of SSL libraries and headers dnl ********************************************************************** @@ -2233,7 +2256,7 @@ if test "$curl_ssl_msg" = "$init_ssl_msg"; then fi fi -if test "x$OPENSSL_ENABLED$GNUTLS_ENABLED$NSS_ENABLED$POLARSSL_ENABLED$AXTLS_ENABLED$CYASSL_ENABLED$WINSSL_ENABLED" = "x"; then +if test "x$OPENSSL_ENABLED$GNUTLS_ENABLED$NSS_ENABLED$POLARSSL_ENABLED$AXTLS_ENABLED$CYASSL_ENABLED$WINSSL_ENABLED$DARWINSSL_ENABLED" = "x"; then AC_MSG_WARN([SSL disabled, you will not be able to use HTTPS, FTPS, NTLM and more.]) AC_MSG_WARN([Use --with-ssl, --with-gnutls, --with-polarssl, --with-cyassl, --with-nss, --with-axtls or --with-winssl to address this.]) else @@ -2510,6 +2533,8 @@ AC_HELP_STRING([--disable-versioned-symbols], [Disable versioned symbols in shar versioned_symbols_flavour="AXTLS_" elif test "x$WINSSL_ENABLED" == "x1"; then versioned_symbols_flavour="WINSSL_" + elif test "x$DARWINSSL_ENABLED" == "x1"; then + versioned_symbols_flavour="DARWINSSL_" else versioned_symbols_flavour="" fi diff --git a/lib/Makefile.inc b/lib/Makefile.inc index 4e36dc69c..e0044ec65 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -24,7 +24,7 @@ CSOURCES = file.c timeval.c base64.c hostip.c progress.c formdata.c \ idn_win32.c http_negotiate_sspi.c cyassl.c http_proxy.c non-ascii.c \ asyn-ares.c asyn-thread.c curl_gssapi.c curl_ntlm.c curl_ntlm_wb.c \ curl_ntlm_core.c curl_ntlm_msgs.c curl_sasl.c curl_schannel.c \ - curl_multibyte.c + curl_multibyte.c curl_darwinssl.c HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h \ progress.h formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h \ @@ -41,4 +41,4 @@ HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h \ warnless.h curl_hmac.h polarssl.h curl_rtmp.h curl_gethostname.h \ gopher.h axtls.h cyassl.h http_proxy.h non-ascii.h asyn.h curl_ntlm.h \ curl_gssapi.h curl_ntlm_wb.h curl_ntlm_core.h curl_ntlm_msgs.h \ - curl_sasl.h curl_schannel.h curl_multibyte.h + curl_sasl.h curl_schannel.h curl_multibyte.h curl_darwinssl.h diff --git a/lib/curl_darwinssl.c b/lib/curl_darwinssl.c new file mode 100644 index 000000000..b21cc468b --- /dev/null +++ b/lib/curl_darwinssl.c @@ -0,0 +1,661 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2012, Nick Zitzmann, <nickzman@gmail.com>. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* + * Source file for all SecureTransport-specific code for the TLS/SSL layer. + * No code but sslgen.c should ever call or use these functions. + */ + +#include "setup.h" + +#ifdef HAVE_LIMITS_H +#include <limits.h> +#endif +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif + +#ifdef USE_DARWINSSL +#include <Security/Security.h> +#include "urldata.h" +#include "sendf.h" +#include "inet_pton.h" +#include "connect.h" +#include "select.h" +#include "sslgen.h" +#include "curl_darwinssl.h" + +/* From MacTypes.h (which we can't include because it isn't present in iOS: */ +#define ioErr -36 + +/* The following two functions were ripped from Apple sample code, + * with some modifications: */ +static OSStatus SocketRead(SSLConnectionRef connection, + void *data, /* owned by + * caller, data + * RETURNED */ + size_t *dataLength) /* IN/OUT */ +{ + UInt32 bytesToGo = *dataLength; + UInt32 initLen = bytesToGo; + UInt8 *currData = (UInt8 *)data; + int sock = *(int *)connection; + OSStatus rtn = noErr; + UInt32 bytesRead; + int rrtn; + int theErr; + + *dataLength = 0; + + for(;;) { + bytesRead = 0; + rrtn = read(sock, currData, bytesToGo); + if(rrtn <= 0) { + /* this is guesswork... */ + theErr = errno; + if((rrtn == 0) && (theErr == 0)) { + /* try fix for iSync */ + rtn = errSSLClosedGraceful; + } + else /* do the switch */ + switch(theErr) { + case ENOENT: + /* connection closed */ + rtn = errSSLClosedGraceful; + break; + case ECONNRESET: + rtn = errSSLClosedAbort; + break; + case EAGAIN: + rtn = errSSLWouldBlock; + break; + default: + rtn = ioErr; + break; + } + break; + } + else { + bytesRead = rrtn; + } + bytesToGo -= bytesRead; + currData += bytesRead; + + if(bytesToGo == 0) { + /* filled buffer with incoming data, done */ + break; + } + } + *dataLength = initLen - bytesToGo; + + return rtn; +} + +static OSStatus SocketWrite(SSLConnectionRef connection, + const void *data, + size_t *dataLength) /* IN/OUT */ +{ + UInt32 bytesSent = 0; + int sock = *(int *)connection; + int length; + UInt32 dataLen = *dataLength; + const UInt8 *dataPtr = (UInt8 *)data; + OSStatus ortn; + int theErr; + + *dataLength = 0; + + do { + length = write(sock, + (char*)dataPtr + bytesSent, + dataLen - bytesSent); + } while((length > 0) && + ( (bytesSent += length) < dataLen) ); + + if(length <= 0) { + theErr = errno; + if(theErr == EAGAIN) { + ortn = errSSLWouldBlock; + } + else { + ortn = ioErr; + } + } + else { + ortn = noErr; + } + *dataLength = bytesSent; + return ortn; +} + +static CURLcode st_connect_step1(struct connectdata *conn, + int sockindex) +{ + struct SessionHandle *data = conn->data; + curl_socket_t sockfd = conn->sock[sockindex]; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + bool sni = true; +#ifdef ENABLE_IPV6 + struct in6_addr addr; +#else + struct in_addr addr; +#endif + SSLConnectionRef ssl_connection; + OSStatus err = noErr; + + if(connssl->ssl_ctx) + (void)SSLDisposeContext(connssl->ssl_ctx); + err = SSLNewContext(false, &(connssl->ssl_ctx)); + if(err != noErr) { + failf(data, "SSL: couldn't create a context: OSStatus %d", err); + return CURLE_OUT_OF_MEMORY; + } + + /* check to see if we've been told to use an explicit SSL/TLS version */ + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, kSSLProtocolAll, false); + switch(data->set.ssl.version) { + default: + case CURL_SSLVERSION_DEFAULT: + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kSSLProtocol3, + true); + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kTLSProtocol1, + true); + break; + case CURL_SSLVERSION_TLSv1: + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kTLSProtocol1, + true); + break; + case CURL_SSLVERSION_SSLv2: + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kSSLProtocol2, + true); + break; + case CURL_SSLVERSION_SSLv3: + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kSSLProtocol3, + true); + break; + } + + /* No need to load certificates here. SecureTransport uses the Keychain + * (which is also part of the Security framework) to evaluate trust. */ + + /* SSL always tries to verify the peer, this only says whether it should + * fail to connect if the verification fails, or if it should continue + * anyway. In the latter case the result of the verification is checked with + * SSL_get_verify_result() below. */ + err = SSLSetEnableCertVerify(connssl->ssl_ctx, + data->set.ssl.verifypeer?true:false); + if(err != noErr) { + failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err); + return CURLE_SSL_CONNECT_ERROR; + } + + if((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) && +#ifdef ENABLE_IPV6 + (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr)) && +#endif + sni) { + err = SSLSetPeerDomainName(connssl->ssl_ctx, conn->host.name, + strlen(conn->host.name)); + if(err != noErr) { + infof(data, "WARNING: SSL: SSLSetPeerDomainName() failed: OSStatus %d", + err); + } + else + infof(data, "WARNING: failed to configure " + "server name indication (SNI) TLS extension\n"); + } + + err = SSLSetIOFuncs(connssl->ssl_ctx, SocketRead, SocketWrite); + if(err != noErr) { + failf(data, "SSL: SSLSetIOFuncs() failed: OSStatus %d", err); + return CURLE_SSL_CONNECT_ERROR; + } + + /* pass the raw socket into the SSL layers */ + /* We need to store the FD in a constant memory address, because + * SSLSetConnection() will not copy that address. I've found that + * conn->sock[sockindex] may change on its own. */ + connssl->ssl_sockfd = sockfd; + ssl_connection = &(connssl->ssl_sockfd); + err = SSLSetConnection(connssl->ssl_ctx, ssl_connection); + if(err != noErr) { + failf(data, "SSL: SSLSetConnection() failed: %d", err); + return CURLE_SSL_CONNECT_ERROR; + } + + connssl->connecting_state = ssl_connect_2; + return CURLE_OK; +} + +static CURLcode +st_connect_step2(struct connectdata *conn, int sockindex) +{ + struct SessionHandle *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + OSStatus err; + SSLCipherSuite cipher; + + DEBUGASSERT(ssl_connect_2 == connssl->connecting_state + || ssl_connect_2_reading == connssl->connecting_state + || ssl_connect_2_writing == connssl->connecting_state + || ssl_connect_2_wouldblock == connssl->connecting_state); + + /* Here goes nothing: */ + err = SSLHandshake(connssl->ssl_ctx); + + if(err != noErr) { + switch (err) { + case errSSLWouldBlock: /* they're not done with us yet */ + connssl->connecting_state = ssl_connect_2_wouldblock; + return CURLE_OK; + break; + + case errSSLServerAuthCompleted: + /* the documentation says we need to call SSLHandshake() again */ + return st_connect_step2(conn, sockindex); + + case errSSLXCertChainInvalid: + case errSSLUnknownRootCert: + case errSSLNoRootCert: + case errSSLCertExpired: + failf(data, "SSL certificate problem: OSStatus %d", err); + return CURLE_SSL_CACERT; + break; + + default: + failf(data, "Unknown SSL protocol error in connection to %s:%d", + conn->host.name, err); + return CURLE_SSL_CONNECT_ERROR; + break; + } + } + else { + /* we have been connected fine, we're not waiting for anything else. */ + connssl->connecting_state = ssl_connect_3; + + /* Informational message */ + (void)SSLGetNegotiatedCipher(connssl->ssl_ctx, &cipher); + infof (data, "SSL connection using cipher %u\n", cipher); + + return CURLE_OK; + } +} + +static CURLcode +st_connect_step3(struct connectdata *conn, + int sockindex) +{ + struct SessionHandle *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + CFStringRef server_cert_summary; + char server_cert_summary_c[128]; + CFArrayRef server_certs; + SecCertificateRef server_cert; + OSStatus err; + CFIndex i, count; + + /* There is no step 3! + * Well, okay, if verbose mode is on, let's print the details of the + * server certificates. */ + err = SSLCopyPeerCertificates(connssl->ssl_ctx, &server_certs); + if(err == noErr) { + count = CFArrayGetCount(server_certs); + for(i = 0L ; i < count ; i++) { + server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs, i); + + server_cert_summary = SecCertificateCopySubjectSummary(server_cert); + memset(server_cert_summary_c, 0, 128); + if(CFStringGetCString(server_cert_summary, + server_cert_summary_c, + 128, + kCFStringEncodingUTF8)) { + infof(data, "Server certificate: %s\n", server_cert_summary_c); + } + CFRelease(server_cert_summary); + } + CFRelease(server_certs); + } + + connssl->connecting_state = ssl_connect_done; + return CURLE_OK; +} + +static Curl_recv st_recv; +static Curl_send st_send; + +static CURLcode +st_connect_common(struct connectdata *conn, + int sockindex, + bool nonblocking, + bool *done) +{ + CURLcode retcode; + struct SessionHandle *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + curl_socket_t sockfd = conn->sock[sockindex]; + long timeout_ms; + int what; + + /* check if the connection has already been established */ + if(ssl_connection_complete == connssl->state) { + *done = TRUE; + return CURLE_OK; + } + + if(ssl_connect_1==connssl->connecting_state) { + /* Find out how much more time we're allowed */ + timeout_ms = Curl_timeleft(data, NULL, TRUE); + + if(timeout_ms < 0) { + /* no need to continue if time already is up */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + retcode = st_connect_step1(conn, sockindex); + if(retcode) + return retcode; + } + + while(ssl_connect_2 == connssl->connecting_state || + ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state || + ssl_connect_2_wouldblock == connssl->connecting_state) { + + /* check allowed time left */ + timeout_ms = Curl_timeleft(data, NULL, TRUE); + + if(timeout_ms < 0) { + /* no need to continue if time already is up */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + + /* if ssl is expecting something, check if it's available. */ + if(connssl->connecting_state == ssl_connect_2_reading + || connssl->connecting_state == ssl_connect_2_writing + || connssl->connecting_state == ssl_connect_2_wouldblock) { + + curl_socket_t writefd = ssl_connect_2_writing + || ssl_connect_2_wouldblock == + connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + curl_socket_t readfd = ssl_connect_2_reading + || ssl_connect_2_wouldblock == + connssl->connecting_state?sockfd:CURL_SOCKET_BAD; + + what = Curl_socket_ready(readfd, writefd, nonblocking?0:timeout_ms); + if(what < 0) { + /* fatal error */ + failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); + return CURLE_SSL_CONNECT_ERROR; + } + else if(0 == what) { + if(nonblocking) { + *done = FALSE; + return CURLE_OK; + } + else { + /* timeout */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; + } + } + /* socket is readable or writable */ + } + + /* Run transaction, and return to the caller if it failed or if this + * connection is done nonblocking and this loop would execute again. This + * permits the owner of a multi handle to abort a connection attempt + * before step2 has completed while ensuring that a client using select() + * or epoll() will always have a valid fdset to wait on. + */ + retcode = st_connect_step2(conn, sockindex); + if(retcode || (nonblocking && + (ssl_connect_2 == connssl->connecting_state || + ssl_connect_2_reading == connssl->connecting_state || + ssl_connect_2_writing == connssl->connecting_state))) + return retcode; + + } /* repeat step2 until all transactions are done. */ + + + if(ssl_connect_3==connssl->connecting_state) { + retcode = st_connect_step3(conn, sockindex); + if(retcode) + return retcode; + } + + if(ssl_connect_done==connssl->connecting_state) { + connssl->state = ssl_connection_complete; + conn->recv[sockindex] = st_recv; + conn->send[sockindex] = st_send; + *done = TRUE; + } + else + *done = FALSE; + + /* Reset our connect state machine */ + connssl->connecting_state = ssl_connect_1; + + return CURLE_OK; +} + +CURLcode +Curl_st_connect_nonblocking(struct connectdata *conn, + int sockindex, + bool *done) +{ + return st_connect_common(conn, sockindex, TRUE, done); +} + +CURLcode +Curl_st_connect(struct connectdata *conn, + int sockindex) +{ + CURLcode retcode; + bool done = FALSE; + + retcode = st_connect_common(conn, sockindex, FALSE, &done); + + if(retcode) + return retcode; + + DEBUGASSERT(done); + + return CURLE_OK; +} + +void Curl_st_close(struct connectdata *conn, int sockindex) +{ + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + + (void)SSLClose(connssl->ssl_ctx); + (void)SSLDisposeContext(connssl->ssl_ctx); + connssl->ssl_ctx = NULL; + connssl->ssl_sockfd = 0; +} + +void Curl_st_close_all(struct SessionHandle *data) +{ + /* SecureTransport doesn't separate sessions from contexts, so... */ + (void)data; +} + +int Curl_st_shutdown(struct connectdata *conn, int sockindex) +{ + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct SessionHandle *data = conn->data; + ssize_t nread; + int what; + int rc; + char buf[120]; + + if(!connssl->ssl_ctx) + return 0; + + if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE) + return 0; + + Curl_st_close(conn, sockindex); + + rc = 0; + + what = Curl_socket_ready(conn->sock[sockindex], + CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); + + for(;;) { + if(what < 0) { + /* anything that gets here is fatally bad */ + failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); + rc = -1; + break; + } + + if(!what) { /* timeout */ + failf(data, "SSL shutdown timeout"); + break; + } + + /* Something to read, let's do it and hope that it is the close + notify alert from the server. No way to SSL_Read now, so use read(). */ + + nread = read(conn->sock[sockindex], buf, sizeof(buf)); + + if(nread < 0) { + failf(data, "read: %s", strerror(errno)); + rc = -1; + } + + if(nread <= 0) + break; + + what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, 0); + } + + return rc; +} + +size_t Curl_st_version(char *buffer, size_t size) +{ + return snprintf(buffer, size, "SecureTransport"); +} + +/* + * This function uses SSLGetSessionState to determine connection status. + * + * Return codes: + * 1 means the connection is still in place + * 0 means the connection has been closed + * -1 means the connection status is unknown + */ +int Curl_st_check_cxn(struct connectdata *conn) +{ + struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET]; + OSStatus err; + SSLSessionState state; + + if(connssl->ssl_ctx) { + err = SSLGetSessionState(connssl->ssl_ctx, &state); + if(err == noErr) + return state == kSSLConnected || state == kSSLHandshake; + return -1; + } + return 0; +} + +bool Curl_st_data_pending(const struct connectdata *conn, int connindex) +{ + const struct ssl_connect_data *connssl = &conn->ssl[connindex]; + OSStatus err; + size_t buffer; + + if(connssl->ssl_ctx) { /* SSL is in use */ + err = SSLGetBufferedReadSize(connssl->ssl_ctx, &buffer); + if(err == noErr) + return buffer > 0UL; + return false; + } + else + return false; +} + +static ssize_t st_send(struct connectdata *conn, + int sockindex, + const void *mem, + size_t len, + CURLcode *curlcode) +{ + /*struct SessionHandle *data = conn->data;*/ + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + size_t processed; + OSStatus err = SSLWrite(connssl->ssl_ctx, mem, len, &processed); + + if(err != noErr) { + switch (err) { + case errSSLWouldBlock: /* we're not done yet; keep sending */ + *curlcode = CURLE_AGAIN; + return -1; + break; + + default: + failf(conn->data, "SSLWrite() return error %d", err); + *curlcode = CURLE_SEND_ERROR; + return -1; + break; + } + } + return (ssize_t)processed; +} + +static ssize_t st_recv(struct connectdata *conn, /* connection data */ + int num, /* socketindex */ + char *buf, /* store read data here */ + size_t buffersize, /* max amount to read */ + CURLcode *curlcode) +{ + /*struct SessionHandle *data = conn->data;*/ + struct ssl_connect_data *connssl = &conn->ssl[num]; + size_t processed; + OSStatus err = SSLRead(connssl->ssl_ctx, buf, buffersize, &processed); + + if(err != noErr) { + switch (err) { + case errSSLWouldBlock: /* we're not done yet; keep reading */ + *curlcode = CURLE_AGAIN; + return -1; + break; + + default: + failf(conn->data, "SSLRead() return error %d", err); + *curlcode = CURLE_RECV_ERROR; + return -1; + break; + } + } + return (ssize_t)processed; +} + +#endif /* USE_DARWINSSL */ diff --git a/lib/curl_darwinssl.h b/lib/curl_darwinssl.h new file mode 100644 index 000000000..6eb20cc0f --- /dev/null +++ b/lib/curl_darwinssl.h @@ -0,0 +1,62 @@ +#ifndef HEADER_CURL_DARWINSSL_H +#define HEADER_CURL_DARWINSSL_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2012, Nick Zitzmann, <nickzman@gmail.com>. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#include "setup.h" + +#ifdef USE_DARWINSSL + +CURLcode Curl_st_connect(struct connectdata *conn, int sockindex); + +CURLcode Curl_st_connect_nonblocking(struct connectdata *conn, + int sockindex, + bool *done); + +/* this function doesn't actually do anything */ +void Curl_st_close_all(struct SessionHandle *data); + +/* close a SSL connection */ +void Curl_st_close(struct connectdata *conn, int sockindex); + +size_t Curl_st_version(char *buffer, size_t size); +int Curl_st_shutdown(struct connectdata *conn, int sockindex); +int Curl_st_check_cxn(struct connectdata *conn); +bool Curl_st_data_pending(const struct connectdata *conn, int connindex); + +/* API setup for SecureTransport */ +#define curlssl_init() (1) +#define curlssl_cleanup() Curl_nop_stmt +#define curlssl_connect Curl_st_connect +#define curlssl_connect_nonblocking Curl_st_connect_nonblocking +#define curlssl_session_free(x) Curl_nop_stmt +#define curlssl_close_all Curl_st_close_all +#define curlssl_close Curl_st_close +#define curlssl_shutdown(x,y) 0 +#define curlssl_set_engine(x,y) (x=x, y=y, CURLE_NOT_BUILT_IN) +#define curlssl_set_engine_default(x) (x=x, CURLE_NOT_BUILT_IN) +#define curlssl_engines_list(x) (x=x, (struct curl_slist *)NULL) +#define curlssl_version Curl_st_version +#define curlssl_check_cxn Curl_st_check_cxn +#define curlssl_data_pending(x,y) Curl_st_data_pending(x, y) + +#endif /* USE_DARWINSSL */ +#endif /* HEADER_CURL_DARWINSSL_H */
\ No newline at end of file diff --git a/lib/setup.h b/lib/setup.h index 4b4876131..a2d0b2845 100644 --- a/lib/setup.h +++ b/lib/setup.h @@ -581,7 +581,8 @@ int netware_init(void); #if defined(USE_GNUTLS) || defined(USE_SSLEAY) || defined(USE_NSS) || \ defined(USE_QSOSSL) || defined(USE_POLARSSL) || defined(USE_AXTLS) || \ - defined(USE_CYASSL) || defined(USE_SCHANNEL) + defined(USE_CYASSL) || defined(USE_SCHANNEL) || \ + defined(USE_DARWINSSL) #define USE_SSL /* SSL support has been enabled */ #endif diff --git a/lib/sslgen.c b/lib/sslgen.c index 28326ddb1..8cf91f001 100644 --- a/lib/sslgen.c +++ b/lib/sslgen.c @@ -34,6 +34,7 @@ Curl_polarssl_ - prefix for PolarSSL ones Curl_cyassl_ - prefix for CyaSSL ones Curl_schannel_ - prefix for Schannel SSPI ones + Curl_st_ - prefix for SecureTransport (Darwin) ones Note that this source code uses curlssl_* functions, and they are all defines/macros #defined by the lib-specific header files. @@ -59,6 +60,7 @@ #include "axtls.h" /* axTLS versions */ #include "cyassl.h" /* CyaSSL versions */ #include "curl_schannel.h" /* Schannel SSPI version */ +#include "curl_darwinssl.h" /* SecureTransport (Darwin) version */ #include "sendf.h" #include "rawstr.h" #include "url.h" diff --git a/lib/urldata.h b/lib/urldata.h index ae6326a4e..dfb4fab9f 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -139,6 +139,10 @@ #include <schannel.h> #endif +#ifdef USE_DARWINSSL +#include <Security/Security.h> +#endif + #ifdef HAVE_NETINET_IN_H #include <netinet/in.h> #endif @@ -242,7 +246,12 @@ typedef enum { ssl_connect_2_reading, ssl_connect_2_writing, ssl_connect_3, +#ifdef USE_DARWINSSL + ssl_connect_done, + ssl_connect_2_wouldblock +#else ssl_connect_done +#endif /* USE_DARWINSSL */ } ssl_connect_state; typedef enum { @@ -313,6 +322,11 @@ struct ssl_connect_data { unsigned char *encdata_buffer, *decdata_buffer; unsigned long req_flags, ret_flags; #endif /* USE_SCHANNEL */ +#ifdef USE_DARWINSSL + SSLContextRef ssl_ctx; + curl_socket_t ssl_sockfd; + ssl_connect_state connecting_state; +#endif /* USE_DARWINSSL */ }; struct ssl_config_data { |