aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Zitzmann <nick@chronosnet.com>2012-06-26 14:01:51 +0200
committerDaniel Stenberg <daniel@haxx.se>2012-06-26 14:04:15 +0200
commit6d1ea388cbd9de7f2a944a0c64f5feaec1b1904a (patch)
treef038997efab45284df2161121772dec49008d6cb
parent07e3ea7f261bdbaddd7d8d7f4d6374c5d01acb51 (diff)
darwinssl: add support for native Mac OS X/iOS SSL
-rw-r--r--configure.ac27
-rw-r--r--lib/Makefile.inc4
-rw-r--r--lib/curl_darwinssl.c661
-rw-r--r--lib/curl_darwinssl.h62
-rw-r--r--lib/setup.h3
-rw-r--r--lib/sslgen.c2
-rw-r--r--lib/urldata.h14
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 {