mirror of
https://github.com/moparisthebest/curl
synced 2024-11-12 04:25:08 -05:00
darwinssl: add support for native Mac OS X/iOS SSL
This commit is contained in:
parent
07e3ea7f26
commit
6d1ea388cb
27
configure.ac
27
configure.ac
@ -1371,6 +1371,29 @@ else
|
|||||||
AC_MSG_RESULT(no)
|
AC_MSG_RESULT(no)
|
||||||
fi
|
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 **********************************************************************
|
||||||
dnl Check for the presence of SSL libraries and headers
|
dnl Check for the presence of SSL libraries and headers
|
||||||
dnl **********************************************************************
|
dnl **********************************************************************
|
||||||
@ -2233,7 +2256,7 @@ if test "$curl_ssl_msg" = "$init_ssl_msg"; then
|
|||||||
fi
|
fi
|
||||||
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([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.])
|
AC_MSG_WARN([Use --with-ssl, --with-gnutls, --with-polarssl, --with-cyassl, --with-nss, --with-axtls or --with-winssl to address this.])
|
||||||
else
|
else
|
||||||
@ -2510,6 +2533,8 @@ AC_HELP_STRING([--disable-versioned-symbols], [Disable versioned symbols in shar
|
|||||||
versioned_symbols_flavour="AXTLS_"
|
versioned_symbols_flavour="AXTLS_"
|
||||||
elif test "x$WINSSL_ENABLED" == "x1"; then
|
elif test "x$WINSSL_ENABLED" == "x1"; then
|
||||||
versioned_symbols_flavour="WINSSL_"
|
versioned_symbols_flavour="WINSSL_"
|
||||||
|
elif test "x$DARWINSSL_ENABLED" == "x1"; then
|
||||||
|
versioned_symbols_flavour="DARWINSSL_"
|
||||||
else
|
else
|
||||||
versioned_symbols_flavour=""
|
versioned_symbols_flavour=""
|
||||||
fi
|
fi
|
||||||
|
@ -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 \
|
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 \
|
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_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 \
|
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 \
|
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 \
|
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 \
|
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_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
|
||||||
|
661
lib/curl_darwinssl.c
Normal file
661
lib/curl_darwinssl.c
Normal file
@ -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 */
|
62
lib/curl_darwinssl.h
Normal file
62
lib/curl_darwinssl.h
Normal file
@ -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 */
|
@ -581,7 +581,8 @@ int netware_init(void);
|
|||||||
|
|
||||||
#if defined(USE_GNUTLS) || defined(USE_SSLEAY) || defined(USE_NSS) || \
|
#if defined(USE_GNUTLS) || defined(USE_SSLEAY) || defined(USE_NSS) || \
|
||||||
defined(USE_QSOSSL) || defined(USE_POLARSSL) || defined(USE_AXTLS) || \
|
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 */
|
#define USE_SSL /* SSL support has been enabled */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
Curl_polarssl_ - prefix for PolarSSL ones
|
Curl_polarssl_ - prefix for PolarSSL ones
|
||||||
Curl_cyassl_ - prefix for CyaSSL ones
|
Curl_cyassl_ - prefix for CyaSSL ones
|
||||||
Curl_schannel_ - prefix for Schannel SSPI 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
|
Note that this source code uses curlssl_* functions, and they are all
|
||||||
defines/macros #defined by the lib-specific header files.
|
defines/macros #defined by the lib-specific header files.
|
||||||
@ -59,6 +60,7 @@
|
|||||||
#include "axtls.h" /* axTLS versions */
|
#include "axtls.h" /* axTLS versions */
|
||||||
#include "cyassl.h" /* CyaSSL versions */
|
#include "cyassl.h" /* CyaSSL versions */
|
||||||
#include "curl_schannel.h" /* Schannel SSPI version */
|
#include "curl_schannel.h" /* Schannel SSPI version */
|
||||||
|
#include "curl_darwinssl.h" /* SecureTransport (Darwin) version */
|
||||||
#include "sendf.h"
|
#include "sendf.h"
|
||||||
#include "rawstr.h"
|
#include "rawstr.h"
|
||||||
#include "url.h"
|
#include "url.h"
|
||||||
|
@ -139,6 +139,10 @@
|
|||||||
#include <schannel.h>
|
#include <schannel.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_DARWINSSL
|
||||||
|
#include <Security/Security.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_NETINET_IN_H
|
#ifdef HAVE_NETINET_IN_H
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#endif
|
#endif
|
||||||
@ -242,7 +246,12 @@ typedef enum {
|
|||||||
ssl_connect_2_reading,
|
ssl_connect_2_reading,
|
||||||
ssl_connect_2_writing,
|
ssl_connect_2_writing,
|
||||||
ssl_connect_3,
|
ssl_connect_3,
|
||||||
|
#ifdef USE_DARWINSSL
|
||||||
|
ssl_connect_done,
|
||||||
|
ssl_connect_2_wouldblock
|
||||||
|
#else
|
||||||
ssl_connect_done
|
ssl_connect_done
|
||||||
|
#endif /* USE_DARWINSSL */
|
||||||
} ssl_connect_state;
|
} ssl_connect_state;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -313,6 +322,11 @@ struct ssl_connect_data {
|
|||||||
unsigned char *encdata_buffer, *decdata_buffer;
|
unsigned char *encdata_buffer, *decdata_buffer;
|
||||||
unsigned long req_flags, ret_flags;
|
unsigned long req_flags, ret_flags;
|
||||||
#endif /* USE_SCHANNEL */
|
#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 {
|
struct ssl_config_data {
|
||||||
|
Loading…
Reference in New Issue
Block a user