From 6d1ea388cbd9de7f2a944a0c64f5feaec1b1904a Mon Sep 17 00:00:00 2001 From: Nick Zitzmann Date: Tue, 26 Jun 2012 14:01:51 +0200 Subject: darwinssl: add support for native Mac OS X/iOS SSL --- lib/curl_darwinssl.c | 661 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 661 insertions(+) create mode 100644 lib/curl_darwinssl.c (limited to 'lib/curl_darwinssl.c') 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, . + * + * 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 +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#ifdef USE_DARWINSSL +#include +#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 */ -- cgit v1.2.1 From 3a4b28d473e7c02fe8d2e30c25861eea2d8d0d22 Mon Sep 17 00:00:00 2001 From: Nick Zitzmann Date: Tue, 26 Jun 2012 21:39:48 +0200 Subject: DarwinSSL: several adjustments - Renamed st_ function prefix to darwinssl_ - Renamed Curl_st_ function prefix to Curl_darwinssl_ - Moved the duplicated ssl_connect_done out of the #ifdef in lib/urldata.h - Fixed a teensy little bug that made non-blocking connection attempts block - Made it so that it builds cleanly against the iOS 5.1 SDK --- lib/curl_darwinssl.c | 88 +++++++++++++++++++++++++++------------------------- 1 file changed, 46 insertions(+), 42 deletions(-) (limited to 'lib/curl_darwinssl.c') diff --git a/lib/curl_darwinssl.c b/lib/curl_darwinssl.c index b21cc468b..627117d1d 100644 --- a/lib/curl_darwinssl.c +++ b/lib/curl_darwinssl.c @@ -36,6 +36,8 @@ #ifdef USE_DARWINSSL #include +#include +#include #include "urldata.h" #include "sendf.h" #include "inet_pton.h" @@ -147,8 +149,8 @@ static OSStatus SocketWrite(SSLConnectionRef connection, return ortn; } -static CURLcode st_connect_step1(struct connectdata *conn, - int sockindex) +static CURLcode darwinssl_connect_step1(struct connectdata *conn, + int sockindex) { struct SessionHandle *data = conn->data; curl_socket_t sockfd = conn->sock[sockindex]; @@ -252,7 +254,7 @@ static CURLcode st_connect_step1(struct connectdata *conn, } static CURLcode -st_connect_step2(struct connectdata *conn, int sockindex) +darwinssl_connect_step2(struct connectdata *conn, int sockindex) { struct SessionHandle *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; @@ -276,7 +278,7 @@ st_connect_step2(struct connectdata *conn, int sockindex) case errSSLServerAuthCompleted: /* the documentation says we need to call SSLHandshake() again */ - return st_connect_step2(conn, sockindex); + return darwinssl_connect_step2(conn, sockindex); case errSSLXCertChainInvalid: case errSSLUnknownRootCert: @@ -306,8 +308,8 @@ st_connect_step2(struct connectdata *conn, int sockindex) } static CURLcode -st_connect_step3(struct connectdata *conn, - int sockindex) +darwinssl_connect_step3(struct connectdata *conn, + int sockindex) { struct SessionHandle *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; @@ -344,14 +346,14 @@ st_connect_step3(struct connectdata *conn, return CURLE_OK; } -static Curl_recv st_recv; -static Curl_send st_send; +static Curl_recv darwinssl_recv; +static Curl_send darwinssl_send; static CURLcode -st_connect_common(struct connectdata *conn, - int sockindex, - bool nonblocking, - bool *done) +darwinssl_connect_common(struct connectdata *conn, + int sockindex, + bool nonblocking, + bool *done) { CURLcode retcode; struct SessionHandle *data = conn->data; @@ -375,7 +377,7 @@ st_connect_common(struct connectdata *conn, failf(data, "SSL connection timeout"); return CURLE_OPERATION_TIMEDOUT; } - retcode = st_connect_step1(conn, sockindex); + retcode = darwinssl_connect_step1(conn, sockindex); if(retcode) return retcode; } @@ -432,26 +434,27 @@ st_connect_common(struct connectdata *conn, * 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); + retcode = darwinssl_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))) + ssl_connect_2_writing == connssl->connecting_state || + ssl_connect_2_wouldblock == 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); + retcode = darwinssl_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; + conn->recv[sockindex] = darwinssl_recv; + conn->send[sockindex] = darwinssl_send; *done = TRUE; } else @@ -464,21 +467,21 @@ st_connect_common(struct connectdata *conn, } CURLcode -Curl_st_connect_nonblocking(struct connectdata *conn, - int sockindex, - bool *done) +Curl_darwinssl_connect_nonblocking(struct connectdata *conn, + int sockindex, + bool *done) { - return st_connect_common(conn, sockindex, TRUE, done); + return darwinssl_connect_common(conn, sockindex, TRUE, done); } CURLcode -Curl_st_connect(struct connectdata *conn, - int sockindex) +Curl_darwinssl_connect(struct connectdata *conn, + int sockindex) { CURLcode retcode; bool done = FALSE; - retcode = st_connect_common(conn, sockindex, FALSE, &done); + retcode = darwinssl_connect_common(conn, sockindex, FALSE, &done); if(retcode) return retcode; @@ -488,7 +491,7 @@ Curl_st_connect(struct connectdata *conn, return CURLE_OK; } -void Curl_st_close(struct connectdata *conn, int sockindex) +void Curl_darwinssl_close(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; @@ -498,13 +501,13 @@ void Curl_st_close(struct connectdata *conn, int sockindex) connssl->ssl_sockfd = 0; } -void Curl_st_close_all(struct SessionHandle *data) +void Curl_darwinssl_close_all(struct SessionHandle *data) { /* SecureTransport doesn't separate sessions from contexts, so... */ (void)data; } -int Curl_st_shutdown(struct connectdata *conn, int sockindex) +int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct SessionHandle *data = conn->data; @@ -519,7 +522,7 @@ int Curl_st_shutdown(struct connectdata *conn, int sockindex) if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE) return 0; - Curl_st_close(conn, sockindex); + Curl_darwinssl_close(conn, sockindex); rc = 0; @@ -558,7 +561,7 @@ int Curl_st_shutdown(struct connectdata *conn, int sockindex) return rc; } -size_t Curl_st_version(char *buffer, size_t size) +size_t Curl_darwinssl_version(char *buffer, size_t size) { return snprintf(buffer, size, "SecureTransport"); } @@ -571,7 +574,7 @@ size_t Curl_st_version(char *buffer, size_t size) * 0 means the connection has been closed * -1 means the connection status is unknown */ -int Curl_st_check_cxn(struct connectdata *conn) +int Curl_darwinssl_check_cxn(struct connectdata *conn) { struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET]; OSStatus err; @@ -586,7 +589,8 @@ int Curl_st_check_cxn(struct connectdata *conn) return 0; } -bool Curl_st_data_pending(const struct connectdata *conn, int connindex) +bool Curl_darwinssl_data_pending(const struct connectdata *conn, + int connindex) { const struct ssl_connect_data *connssl = &conn->ssl[connindex]; OSStatus err; @@ -602,11 +606,11 @@ bool Curl_st_data_pending(const struct connectdata *conn, int connindex) return false; } -static ssize_t st_send(struct connectdata *conn, - int sockindex, - const void *mem, - size_t len, - CURLcode *curlcode) +static ssize_t darwinssl_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]; @@ -630,11 +634,11 @@ static ssize_t st_send(struct connectdata *conn, 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) +static ssize_t darwinssl_recv(struct connectdata *conn, + int num, + char *buf, + size_t buffersize, + CURLcode *curlcode) { /*struct SessionHandle *data = conn->data;*/ struct ssl_connect_data *connssl = &conn->ssl[num]; -- cgit v1.2.1 From 7aa95afadd39867dd95fd4f3df316f7e7decac7a Mon Sep 17 00:00:00 2001 From: Nick Zitzmann Date: Wed, 27 Jun 2012 11:57:31 +0200 Subject: DarwinSSL: allow using NTLM authentication Allow NTLM authentication when building using SecureTransport (Darwin) for SSL. This uses CommonCrypto, a cryptography library that ships with all versions of iOS and Mac OS X. It's like OpenSSL's libcrypto, except that it's missing a few less-common cyphers and doesn't have a big number data structure. --- lib/curl_darwinssl.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'lib/curl_darwinssl.c') diff --git a/lib/curl_darwinssl.c b/lib/curl_darwinssl.c index 627117d1d..b98e06868 100644 --- a/lib/curl_darwinssl.c +++ b/lib/curl_darwinssl.c @@ -21,8 +21,8 @@ ***************************************************************************/ /* - * Source file for all SecureTransport-specific code for the TLS/SSL layer. - * No code but sslgen.c should ever call or use these functions. + * Source file for all iOS and Mac OS X SecureTransport-specific code for the + * TLS/SSL layer. No code but sslgen.c should ever call or use these functions. */ #include "setup.h" @@ -38,6 +38,7 @@ #include #include #include +#include #include "urldata.h" #include "sendf.h" #include "inet_pton.h" @@ -606,6 +607,23 @@ bool Curl_darwinssl_data_pending(const struct connectdata *conn, return false; } +void Curl_darwinssl_random(struct SessionHandle *data, + unsigned char *entropy, + size_t length) +{ + (void)data; + arc4random_buf(entropy, length); +} + +void Curl_darwinssl_md5sum(unsigned char *tmp, /* input */ + size_t tmplen, + unsigned char *md5sum, /* output */ + size_t md5len) +{ + (void)md5len; + (void)CC_MD5(tmp, tmplen, md5sum); +} + static ssize_t darwinssl_send(struct connectdata *conn, int sockindex, const void *mem, -- cgit v1.2.1 From 57d2732ccb97943f2ac026513f2bc1b2b78548f6 Mon Sep 17 00:00:00 2001 From: Yang Tse Date: Wed, 27 Jun 2012 17:13:16 +0200 Subject: build: add our standard includes to curl_darwinssl.c and curl_multibyte.c --- lib/curl_darwinssl.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'lib/curl_darwinssl.c') diff --git a/lib/curl_darwinssl.c b/lib/curl_darwinssl.c index b98e06868..b9989143e 100644 --- a/lib/curl_darwinssl.c +++ b/lib/curl_darwinssl.c @@ -6,6 +6,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2012, Nick Zitzmann, . + * Copyright (C) 2012, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -27,6 +28,8 @@ #include "setup.h" +#ifdef USE_DARWINSSL + #ifdef HAVE_LIMITS_H #include #endif @@ -34,11 +37,11 @@ #include #endif -#ifdef USE_DARWINSSL #include #include #include #include + #include "urldata.h" #include "sendf.h" #include "inet_pton.h" @@ -47,6 +50,13 @@ #include "sslgen.h" #include "curl_darwinssl.h" +#define _MPRINTF_REPLACE /* use our functions only */ +#include + +#include "curl_memory.h" +/* The last #include file should be: */ +#include "memdebug.h" + /* From MacTypes.h (which we can't include because it isn't present in iOS: */ #define ioErr -36 -- cgit v1.2.1 From 825fff880e4ac3f5ed1e8d089baa33fee227a792 Mon Sep 17 00:00:00 2001 From: Nick Zitzmann Date: Sat, 7 Jul 2012 22:37:52 +0200 Subject: darwinssl: output cipher with text, remove SNI warning The code was printing a warning when SNI was set up successfully. Oops. Printing the cipher number in verbose mode was something only TLS/SSL programmers might understand, so I had it print the name of the cipher, just like in the OpenSSL code. That'll be at least a little bit easier to understand. The SecureTransport API doesn't have a method of getting a string from a cipher like OpenSSL does, so I had to generate the strings manually. --- lib/curl_darwinssl.c | 222 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 218 insertions(+), 4 deletions(-) (limited to 'lib/curl_darwinssl.c') diff --git a/lib/curl_darwinssl.c b/lib/curl_darwinssl.c index b9989143e..5a2bcf5ff 100644 --- a/lib/curl_darwinssl.c +++ b/lib/curl_darwinssl.c @@ -160,6 +160,222 @@ static OSStatus SocketWrite(SSLConnectionRef connection, return ortn; } +CF_INLINE const char *CipherNameForNumber(SSLCipherSuite cipher) { + switch (cipher) { + case SSL_RSA_WITH_NULL_MD5: + return "SSL_RSA_WITH_NULL_MD5"; + break; + case SSL_RSA_WITH_NULL_SHA: + return "SSL_RSA_WITH_NULL_SHA"; + break; + case SSL_RSA_EXPORT_WITH_RC4_40_MD5: + return "SSL_RSA_EXPORT_WITH_RC4_40_MD5"; + break; + case SSL_RSA_WITH_RC4_128_MD5: + return "SSL_RSA_WITH_RC4_128_MD5"; + break; + case SSL_RSA_WITH_RC4_128_SHA: + return "SSL_RSA_WITH_RC4_128_SHA"; + break; + case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5: + return "SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5"; + break; + case SSL_RSA_WITH_IDEA_CBC_SHA: + return "SSL_RSA_WITH_IDEA_CBC_SHA"; + break; + case SSL_RSA_EXPORT_WITH_DES40_CBC_SHA: + return "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA"; + break; + case SSL_RSA_WITH_DES_CBC_SHA: + return "SSL_RSA_WITH_DES_CBC_SHA"; + break; + case SSL_RSA_WITH_3DES_EDE_CBC_SHA: + return "SSL_RSA_WITH_3DES_EDE_CBC_SHA"; + break; + case SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA: + return "SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA"; + break; + case SSL_DH_DSS_WITH_DES_CBC_SHA: + return "SSL_DH_DSS_WITH_DES_CBC_SHA"; + break; + case SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA: + return "SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA"; + break; + case SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA: + return "SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA"; + break; + case SSL_DH_RSA_WITH_DES_CBC_SHA: + return "SSL_DH_RSA_WITH_DES_CBC_SHA"; + break; + case SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA: + return "SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA"; + break; + case SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA: + return "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"; + break; + case SSL_DHE_DSS_WITH_DES_CBC_SHA: + return "SSL_DHE_DSS_WITH_DES_CBC_SHA"; + break; + case SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA: + return "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA"; + break; + case SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA: + return "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA"; + break; + case SSL_DHE_RSA_WITH_DES_CBC_SHA: + return "SSL_DHE_RSA_WITH_DES_CBC_SHA"; + break; + case SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA: + return "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA"; + break; + case SSL_DH_anon_EXPORT_WITH_RC4_40_MD5: + return "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5"; + break; + case SSL_DH_anon_WITH_RC4_128_MD5: + return "SSL_DH_anon_WITH_RC4_128_MD5"; + break; + case SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA: + return "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA"; + break; + case SSL_DH_anon_WITH_DES_CBC_SHA: + return "SSL_DH_anon_WITH_DES_CBC_SHA"; + break; + case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA: + return "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA"; + break; + case SSL_FORTEZZA_DMS_WITH_NULL_SHA: + return "SSL_FORTEZZA_DMS_WITH_NULL_SHA"; + break; + case SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA: + return "SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA"; + break; + case TLS_RSA_WITH_AES_128_CBC_SHA: + return "TLS_RSA_WITH_AES_128_CBC_SHA"; + break; + case TLS_DH_DSS_WITH_AES_128_CBC_SHA: + return "TLS_DH_DSS_WITH_AES_128_CBC_SHA"; + break; + case TLS_DH_RSA_WITH_AES_128_CBC_SHA: + return "TLS_DH_RSA_WITH_AES_128_CBC_SHA"; + break; + case TLS_DHE_DSS_WITH_AES_128_CBC_SHA: + return "TLS_DHE_DSS_WITH_AES_128_CBC_SHA"; + break; + case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: + return "TLS_DHE_RSA_WITH_AES_128_CBC_SHA"; + break; + case TLS_DH_anon_WITH_AES_128_CBC_SHA: + return "TLS_DH_anon_WITH_AES_128_CBC_SHA"; + break; + case TLS_RSA_WITH_AES_256_CBC_SHA: + return "TLS_RSA_WITH_AES_256_CBC_SHA"; + break; + case TLS_DH_DSS_WITH_AES_256_CBC_SHA: + return "TLS_DH_DSS_WITH_AES_256_CBC_SHA"; + break; + case TLS_DH_RSA_WITH_AES_256_CBC_SHA: + return "TLS_DH_RSA_WITH_AES_256_CBC_SHA"; + break; + case TLS_DHE_DSS_WITH_AES_256_CBC_SHA: + return "TLS_DHE_DSS_WITH_AES_256_CBC_SHA"; + break; + case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: + return "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"; + break; + case TLS_DH_anon_WITH_AES_256_CBC_SHA: + return "TLS_DH_anon_WITH_AES_256_CBC_SHA"; + break; + case TLS_ECDH_ECDSA_WITH_NULL_SHA: + return "TLS_ECDH_ECDSA_WITH_NULL_SHA"; + break; + case TLS_ECDH_ECDSA_WITH_RC4_128_SHA: + return "TLS_ECDH_ECDSA_WITH_RC4_128_SHA"; + break; + case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA: + return "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA"; + break; + case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA: + return "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA"; + break; + case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA: + return "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA"; + break; + case TLS_ECDHE_ECDSA_WITH_NULL_SHA: + return "TLS_ECDHE_ECDSA_WITH_NULL_SHA"; + break; + case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: + return "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA"; + break; + case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA: + return "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA"; + break; + case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: + return "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA"; + break; + case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: + return "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA"; + break; + case TLS_ECDH_RSA_WITH_NULL_SHA: + return "TLS_ECDH_RSA_WITH_NULL_SHA"; + break; + case TLS_ECDH_RSA_WITH_RC4_128_SHA: + return "TLS_ECDH_RSA_WITH_RC4_128_SHA"; + break; + case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA: + return "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA"; + break; + case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA: + return "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA"; + break; + case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA: + return "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA"; + break; + case TLS_ECDHE_RSA_WITH_NULL_SHA: + return "TLS_ECDHE_RSA_WITH_NULL_SHA"; + break; + case TLS_ECDHE_RSA_WITH_RC4_128_SHA: + return "TLS_ECDHE_RSA_WITH_RC4_128_SHA"; + break; + case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: + return "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA"; + break; + case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: + return "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"; + break; + case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: + return "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"; + break; + case TLS_ECDH_anon_WITH_NULL_SHA: + return "TLS_ECDH_anon_WITH_NULL_SHA"; + break; + case TLS_ECDH_anon_WITH_RC4_128_SHA: + return "TLS_ECDH_anon_WITH_RC4_128_SHA"; + break; + case TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA: + return "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA"; + break; + case TLS_ECDH_anon_WITH_AES_128_CBC_SHA: + return "TLS_ECDH_anon_WITH_AES_128_CBC_SHA"; + break; + case TLS_ECDH_anon_WITH_AES_256_CBC_SHA: + return "TLS_ECDH_anon_WITH_AES_256_CBC_SHA"; + break; + case SSL_RSA_WITH_RC2_CBC_MD5: + return "SSL_RSA_WITH_RC2_CBC_MD5"; + break; + case SSL_RSA_WITH_IDEA_CBC_MD5: + return "SSL_RSA_WITH_IDEA_CBC_MD5"; + break; + case SSL_RSA_WITH_DES_CBC_MD5: + return "SSL_RSA_WITH_DES_CBC_MD5"; + break; + case SSL_RSA_WITH_3DES_EDE_CBC_MD5: + return "SSL_RSA_WITH_3DES_EDE_CBC_MD5"; + break; + } + return "(NONE)"; +} + static CURLcode darwinssl_connect_step1(struct connectdata *conn, int sockindex) { @@ -226,6 +442,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, return CURLE_SSL_CONNECT_ERROR; } + /* If this is a domain name and not an IP address, then configure SNI: */ if((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) && #ifdef ENABLE_IPV6 (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr)) && @@ -237,9 +454,6 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, 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); @@ -312,7 +526,7 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex) /* Informational message */ (void)SSLGetNegotiatedCipher(connssl->ssl_ctx, &cipher); - infof (data, "SSL connection using cipher %u\n", cipher); + infof (data, "SSL connection using %s\n", CipherNameForNumber(cipher)); return CURLE_OK; } -- cgit v1.2.1 From 59c88da74d6d35f3529bdf5aa8b2fbdd8b9f39af Mon Sep 17 00:00:00 2001 From: Nick Zitzmann Date: Sat, 7 Jul 2012 16:03:16 -0600 Subject: darwinssl: don't use arc4random_buf Re-wrote Curl_darwinssl_random() to not use arc4random_buf() because the function is not available prior to iOS 4.3 and OS X 10.7. --- lib/curl_darwinssl.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'lib/curl_darwinssl.c') diff --git a/lib/curl_darwinssl.c b/lib/curl_darwinssl.c index 5a2bcf5ff..893a6fc2a 100644 --- a/lib/curl_darwinssl.c +++ b/lib/curl_darwinssl.c @@ -835,8 +835,19 @@ void Curl_darwinssl_random(struct SessionHandle *data, unsigned char *entropy, size_t length) { + /* arc4random_buf() isn't available on cats older than Lion, so let's + do this manually for the benefit of the older cats. */ + size_t i; + u_int32_t random = 0; + + for(i = 0 ; i < length ; i++) { + if(i % sizeof(u_int32_t) == 0) + random = arc4random(); + entropy[i] = random & 0xFF; + random >>= 8; + } + i = random = 0; (void)data; - arc4random_buf(entropy, length); } void Curl_darwinssl_md5sum(unsigned char *tmp, /* input */ -- cgit v1.2.1 From f92779198d07abb18e8a5c4dd3a2e1b7c4c8726a Mon Sep 17 00:00:00 2001 From: Nick Zitzmann Date: Mon, 16 Jul 2012 20:20:57 -0600 Subject: darwinssl: fixed freeze involving the multi interface Previously the curl_multi interface would freeze if darwinssl was enabled and at least one of the handles tried to connect to a Web site using HTTPS. Removed the "wouldblock" state darwinssl was using because I figured out a solution for our "would block but in which direction?" dilemma. --- lib/curl_darwinssl.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) (limited to 'lib/curl_darwinssl.c') diff --git a/lib/curl_darwinssl.c b/lib/curl_darwinssl.c index 893a6fc2a..c848be746 100644 --- a/lib/curl_darwinssl.c +++ b/lib/curl_darwinssl.c @@ -71,7 +71,9 @@ static OSStatus SocketRead(SSLConnectionRef connection, UInt32 bytesToGo = *dataLength; UInt32 initLen = bytesToGo; UInt8 *currData = (UInt8 *)data; - int sock = *(int *)connection; + /*int sock = *(int *)connection;*/ + struct ssl_connect_data *connssl = (struct ssl_connect_data *)connection; + int sock = connssl->ssl_sockfd; OSStatus rtn = noErr; UInt32 bytesRead; int rrtn; @@ -100,6 +102,7 @@ static OSStatus SocketRead(SSLConnectionRef connection, break; case EAGAIN: rtn = errSSLWouldBlock; + connssl->ssl_direction = false; break; default: rtn = ioErr; @@ -128,7 +131,9 @@ static OSStatus SocketWrite(SSLConnectionRef connection, size_t *dataLength) /* IN/OUT */ { UInt32 bytesSent = 0; - int sock = *(int *)connection; + /*int sock = *(int *)connection;*/ + struct ssl_connect_data *connssl = (struct ssl_connect_data *)connection; + int sock = connssl->ssl_sockfd; int length; UInt32 dataLen = *dataLength; const UInt8 *dataPtr = (UInt8 *)data; @@ -148,6 +153,7 @@ static OSStatus SocketWrite(SSLConnectionRef connection, theErr = errno; if(theErr == EAGAIN) { ortn = errSSLWouldBlock; + connssl->ssl_direction = true; } else { ortn = ioErr; @@ -388,7 +394,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, #else struct in_addr addr; #endif - SSLConnectionRef ssl_connection; + /*SSLConnectionRef ssl_connection;*/ OSStatus err = noErr; if(connssl->ssl_ctx) @@ -467,8 +473,9 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, * 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); + /*ssl_connection = &(connssl->ssl_sockfd); + err = SSLSetConnection(connssl->ssl_ctx, ssl_connection);*/ + err = SSLSetConnection(connssl->ssl_ctx, connssl); if(err != noErr) { failf(data, "SSL: SSLSetConnection() failed: %d", err); return CURLE_SSL_CONNECT_ERROR; @@ -488,8 +495,7 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex) 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); + || ssl_connect_2_writing == connssl->connecting_state); /* Here goes nothing: */ err = SSLHandshake(connssl->ssl_ctx); @@ -497,7 +503,8 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex) if(err != noErr) { switch (err) { case errSSLWouldBlock: /* they're not done with us yet */ - connssl->connecting_state = ssl_connect_2_wouldblock; + connssl->connecting_state = connssl->ssl_direction ? + ssl_connect_2_writing : ssl_connect_2_reading; return CURLE_OK; break; @@ -609,8 +616,7 @@ darwinssl_connect_common(struct connectdata *conn, 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) { + ssl_connect_2_writing == connssl->connecting_state) { /* check allowed time left */ timeout_ms = Curl_timeleft(data, NULL, TRUE); @@ -623,14 +629,11 @@ darwinssl_connect_common(struct connectdata *conn, /* 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) { + || connssl->connecting_state == ssl_connect_2_writing) { - curl_socket_t writefd = ssl_connect_2_writing - || ssl_connect_2_wouldblock == + curl_socket_t writefd = ssl_connect_2_writing == connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - curl_socket_t readfd = ssl_connect_2_reading - || ssl_connect_2_wouldblock == + curl_socket_t readfd = ssl_connect_2_reading == connssl->connecting_state?sockfd:CURL_SOCKET_BAD; what = Curl_socket_ready(readfd, writefd, nonblocking?0:timeout_ms); @@ -663,8 +666,7 @@ darwinssl_connect_common(struct connectdata *conn, if(retcode || (nonblocking && (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))) + ssl_connect_2_writing == connssl->connecting_state))) return retcode; } /* repeat step2 until all transactions are done. */ -- cgit v1.2.1 From d792e75f2c14757cfac9bba6690b5917873201a6 Mon Sep 17 00:00:00 2001 From: Nick Zitzmann Date: Thu, 16 Aug 2012 22:31:41 -0600 Subject: darwinssl: add TLS 1.1 and 1.2 support, replace deprecated functions In Mountain Lion, Apple added TLS 1.1 and 1.2, and deprecated a number of SecureTransport functions, some of which we were using. We now check to see if the replacement functions are present, and if so, we use them instead. The old functions are still present for users of older cats. Also fixed a build warning that started to appear under Mountain Lion --- lib/curl_darwinssl.c | 388 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 369 insertions(+), 19 deletions(-) (limited to 'lib/curl_darwinssl.c') diff --git a/lib/curl_darwinssl.c b/lib/curl_darwinssl.c index c848be746..1626b57e2 100644 --- a/lib/curl_darwinssl.c +++ b/lib/curl_darwinssl.c @@ -60,6 +60,16 @@ /* From MacTypes.h (which we can't include because it isn't present in iOS: */ #define ioErr -36 +/* In Mountain Lion and iOS 5, Apple made some changes to the API. They + added TLS 1.1 and 1.2 support, and deprecated and replaced some + functions. You need to build against the Mountain Lion or iOS 5 SDK + or later to get TLS 1.1 or 1.2 support working in cURL. We'll weak-link + to the newer functions and use them if present in the user's OS. + + Builders: If you want TLS 1.1 and 1.2 but still want to retain support + for older cats, don't forget to set the MACOSX_DEPLOYMENT_TARGET + environmental variable prior to building cURL. */ + /* The following two functions were ripped from Apple sample code, * with some modifications: */ static OSStatus SocketRead(SSLConnectionRef connection, @@ -166,8 +176,9 @@ static OSStatus SocketWrite(SSLConnectionRef connection, return ortn; } -CF_INLINE const char *CipherNameForNumber(SSLCipherSuite cipher) { +CF_INLINE const char *SSLCipherNameForNumber(SSLCipherSuite cipher) { switch (cipher) { + /* SSL version 3.0 */ case SSL_RSA_WITH_NULL_MD5: return "SSL_RSA_WITH_NULL_MD5"; break; @@ -255,6 +266,26 @@ CF_INLINE const char *CipherNameForNumber(SSLCipherSuite cipher) { case SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA: return "SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA"; break; + /* SSL version 2.0 */ + case SSL_RSA_WITH_RC2_CBC_MD5: + return "SSL_RSA_WITH_RC2_CBC_MD5"; + break; + case SSL_RSA_WITH_IDEA_CBC_MD5: + return "SSL_RSA_WITH_IDEA_CBC_MD5"; + break; + case SSL_RSA_WITH_DES_CBC_MD5: + return "SSL_RSA_WITH_DES_CBC_MD5"; + break; + case SSL_RSA_WITH_3DES_EDE_CBC_MD5: + return "SSL_RSA_WITH_3DES_EDE_CBC_MD5"; + break; + } + return "SSL_NULL_WITH_NULL_NULL"; +} + +CF_INLINE const char *TLSCipherNameForNumber(SSLCipherSuite cipher) { + switch(cipher) { + /* TLS 1.0 with AES (RFC 3268) */ case TLS_RSA_WITH_AES_128_CBC_SHA: return "TLS_RSA_WITH_AES_128_CBC_SHA"; break; @@ -291,6 +322,7 @@ CF_INLINE const char *CipherNameForNumber(SSLCipherSuite cipher) { case TLS_DH_anon_WITH_AES_256_CBC_SHA: return "TLS_DH_anon_WITH_AES_256_CBC_SHA"; break; + /* TLS 1.0 with ECDSA (RFC 4492) */ case TLS_ECDH_ECDSA_WITH_NULL_SHA: return "TLS_ECDH_ECDSA_WITH_NULL_SHA"; break; @@ -366,20 +398,172 @@ CF_INLINE const char *CipherNameForNumber(SSLCipherSuite cipher) { case TLS_ECDH_anon_WITH_AES_256_CBC_SHA: return "TLS_ECDH_anon_WITH_AES_256_CBC_SHA"; break; - case SSL_RSA_WITH_RC2_CBC_MD5: - return "SSL_RSA_WITH_RC2_CBC_MD5"; +#if defined(__MAC_10_8) || defined(__IPHONE_5_0) + /* TLS 1.2 (RFC 5246) */ + case TLS_RSA_WITH_NULL_MD5: + return "TLS_RSA_WITH_NULL_MD5"; break; - case SSL_RSA_WITH_IDEA_CBC_MD5: - return "SSL_RSA_WITH_IDEA_CBC_MD5"; + case TLS_RSA_WITH_NULL_SHA: + return "TLS_RSA_WITH_NULL_SHA"; break; - case SSL_RSA_WITH_DES_CBC_MD5: - return "SSL_RSA_WITH_DES_CBC_MD5"; + case TLS_RSA_WITH_RC4_128_MD5: + return "TLS_RSA_WITH_RC4_128_MD5"; break; - case SSL_RSA_WITH_3DES_EDE_CBC_MD5: - return "SSL_RSA_WITH_3DES_EDE_CBC_MD5"; + case TLS_RSA_WITH_RC4_128_SHA: + return "TLS_RSA_WITH_RC4_128_SHA"; + break; + case TLS_RSA_WITH_3DES_EDE_CBC_SHA: + return "TLS_RSA_WITH_3DES_EDE_CBC_SHA"; + break; + case TLS_RSA_WITH_NULL_SHA256: + return "TLS_RSA_WITH_NULL_SHA256"; + break; + case TLS_RSA_WITH_AES_128_CBC_SHA256: + return "TLS_RSA_WITH_AES_128_CBC_SHA256"; + break; + case TLS_RSA_WITH_AES_256_CBC_SHA256: + return "TLS_RSA_WITH_AES_256_CBC_SHA256"; + break; + case TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA: + return "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA"; + break; + case TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA: + return "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA"; + break; + case TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA: + return "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA"; + break; + case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: + return "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA"; + break; + case TLS_DH_DSS_WITH_AES_128_CBC_SHA256: + return "TLS_DH_DSS_WITH_AES_128_CBC_SHA256"; + break; + case TLS_DH_RSA_WITH_AES_128_CBC_SHA256: + return "TLS_DH_RSA_WITH_AES_128_CBC_SHA256"; + break; + case TLS_DHE_DSS_WITH_AES_128_CBC_SHA256: + return "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256"; + break; + case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256: + return "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256"; + break; + case TLS_DH_DSS_WITH_AES_256_CBC_SHA256: + return "TLS_DH_DSS_WITH_AES_256_CBC_SHA256"; + break; + case TLS_DH_RSA_WITH_AES_256_CBC_SHA256: + return "TLS_DH_RSA_WITH_AES_256_CBC_SHA256"; + break; + case TLS_DHE_DSS_WITH_AES_256_CBC_SHA256: + return "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256"; + break; + case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256: + return "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256"; + break; + case TLS_DH_anon_WITH_RC4_128_MD5: + return "TLS_DH_anon_WITH_RC4_128_MD5"; + break; + case TLS_DH_anon_WITH_3DES_EDE_CBC_SHA: + return "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA"; + break; + case TLS_DH_anon_WITH_AES_128_CBC_SHA256: + return "TLS_DH_anon_WITH_AES_128_CBC_SHA256"; + break; + case TLS_DH_anon_WITH_AES_256_CBC_SHA256: + return "TLS_DH_anon_WITH_AES_256_CBC_SHA256"; + break; + /* TLS 1.2 with AES GCM (RFC 5288) */ + case TLS_RSA_WITH_AES_128_GCM_SHA256: + return "TLS_RSA_WITH_AES_128_GCM_SHA256"; + break; + case TLS_RSA_WITH_AES_256_GCM_SHA384: + return "TLS_RSA_WITH_AES_256_GCM_SHA384"; + break; + case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256: + return "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"; + break; + case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384: + return "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384"; + break; + case TLS_DH_RSA_WITH_AES_128_GCM_SHA256: + return "TLS_DH_RSA_WITH_AES_128_GCM_SHA256"; + break; + case TLS_DH_RSA_WITH_AES_256_GCM_SHA384: + return "TLS_DH_RSA_WITH_AES_256_GCM_SHA384"; + break; + case TLS_DHE_DSS_WITH_AES_128_GCM_SHA256: + return "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256"; + break; + case TLS_DHE_DSS_WITH_AES_256_GCM_SHA384: + return "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384"; + break; + case TLS_DH_DSS_WITH_AES_128_GCM_SHA256: + return "TLS_DH_DSS_WITH_AES_128_GCM_SHA256"; + break; + case TLS_DH_DSS_WITH_AES_256_GCM_SHA384: + return "TLS_DH_DSS_WITH_AES_256_GCM_SHA384"; + break; + case TLS_DH_anon_WITH_AES_128_GCM_SHA256: + return "TLS_DH_anon_WITH_AES_128_GCM_SHA256"; + break; + case TLS_DH_anon_WITH_AES_256_GCM_SHA384: + return "TLS_DH_anon_WITH_AES_256_GCM_SHA384"; + break; + /* TLS 1.2 with elliptic curve ciphers (RFC 5289) */ + case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: + return "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"; break; + case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384: + return "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384"; + break; + case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256: + return "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256"; + break; + case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384: + return "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384"; + break; + case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: + return "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"; + break; + case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384: + return "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384"; + break; + case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256: + return "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256"; + break; + case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384: + return "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384"; + break; + case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: + return "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"; + break; + case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: + return "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"; + break; + case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256: + return "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256"; + break; + case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384: + return "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384"; + break; + case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: + return "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"; + break; + case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: + return "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"; + break; + case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256: + return "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256"; + break; + case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384: + return "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384"; + break; + case TLS_EMPTY_RENEGOTIATION_INFO_SCSV: + return "TLS_EMPTY_RENEGOTIATION_INFO_SCSV"; + break; +#endif /* defined(__MAC_10_8) || defined(__IPHONE_5_0) */ } - return "(NONE)"; + return "TLS_NULL_WITH_NULL_NULL"; } static CURLcode darwinssl_connect_step1(struct connectdata *conn, @@ -397,6 +581,18 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, /*SSLConnectionRef ssl_connection;*/ OSStatus err = noErr; +#if defined(__MAC_10_8) || defined(__IPHONE_5_0) + if(SSLCreateContext != NULL) { /* use the newer API if avaialble */ + if(connssl->ssl_ctx) + CFRelease(connssl->ssl_ctx); + connssl->ssl_ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType); + if(!connssl->ssl_ctx) { + failf(data, "SSL: couldn't create a context!"); + return CURLE_OUT_OF_MEMORY; + } + } + else { +#elif !defined(TARGET_OS_EMBEDDED) if(connssl->ssl_ctx) (void)SSLDisposeContext(connssl->ssl_ctx); err = SSLNewContext(false, &(connssl->ssl_ctx)); @@ -404,8 +600,77 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, failf(data, "SSL: couldn't create a context: OSStatus %d", err); return CURLE_OUT_OF_MEMORY; } +#endif /* defined(__MAC_10_8) || defined(__IPHONE_5_0) */ +#if defined(__MAC_10_8) || defined(__IPHONE_5_0) + } +#endif /* defined(__MAC_10_8) || defined(__IPHONE_5_0) */ /* check to see if we've been told to use an explicit SSL/TLS version */ +#if defined(__MAC_10_8) || defined(__IPHONE_5_0) + if(SSLSetProtocolVersionMax != NULL) { + switch(data->set.ssl.version) { + case CURL_SSLVERSION_DEFAULT: default: + (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kSSLProtocol3); + (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol12); + break; + case CURL_SSLVERSION_TLSv1: + (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol1); + (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol12); + break; + case CURL_SSLVERSION_SSLv3: + (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kSSLProtocol3); + (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kSSLProtocol3); + break; + case CURL_SSLVERSION_SSLv2: + (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kSSLProtocol2); + (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kSSLProtocol2); + } + } + else { +#if !defined(TARGET_OS_EMBEDDED) + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kSSLProtocolAll, + false); + switch (data->set.ssl.version) { + case CURL_SSLVERSION_DEFAULT: default: + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kSSLProtocol3, + true); + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kTLSProtocol1, + true); + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kTLSProtocol11, + true); + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kTLSProtocol12, + true); + break; + case CURL_SSLVERSION_TLSv1: + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kTLSProtocol1, + true); + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kTLSProtocol11, + true); + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kTLSProtocol12, + true); + break; + case CURL_SSLVERSION_SSLv3: + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kSSLProtocol3, + true); + break; + case CURL_SSLVERSION_SSLv2: + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kSSLProtocol2, + true); + break; + } +#endif /* TARGET_OS_EMBEDDED */ + } +#else (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, kSSLProtocolAll, false); switch(data->set.ssl.version) { default: @@ -433,6 +698,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, true); break; } +#endif /* defined(__MAC_10_8) || defined(__IPHONE_5_0) */ /* No need to load certificates here. SecureTransport uses the Keychain * (which is also part of the Security framework) to evaluate trust. */ @@ -441,12 +707,28 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, * 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. */ +#if defined(__MAC_10_6) || defined(__IPHONE_5_0) + if(SSLSetSessionOption != NULL) { + err = SSLSetSessionOption(connssl->ssl_ctx, + kSSLSessionOptionBreakOnServerAuth, + data->set.ssl.verifypeer?false:true); + if(err != noErr) { + failf(data, "SSL: SSLSetSessionOption() failed: OSStatus %d", err); + return CURLE_SSL_CONNECT_ERROR; + } + } + else { +#elif !defined(TARGET_OS_EMBEDDED) 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; } +#endif /* defined(__MAC_10_6) || defined(__IPHONE_5_0) */ +#if defined(__MAC_10_6) || defined(__IPHONE_5_0) + } +#endif /* defined(__MAC_10_6) || defined(__IPHONE_5_0) */ /* If this is a domain name and not an IP address, then configure SNI: */ if((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) && @@ -492,6 +774,7 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex) struct ssl_connect_data *connssl = &conn->ssl[sockindex]; OSStatus err; SSLCipherSuite cipher; + SSLProtocol protocol = 0; DEBUGASSERT(ssl_connect_2 == connssl->connecting_state || ssl_connect_2_reading == connssl->connecting_state @@ -533,7 +816,34 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex) /* Informational message */ (void)SSLGetNegotiatedCipher(connssl->ssl_ctx, &cipher); - infof (data, "SSL connection using %s\n", CipherNameForNumber(cipher)); + (void)SSLGetNegotiatedProtocolVersion(connssl->ssl_ctx, &protocol); + switch (protocol) { + case kSSLProtocol2: + infof(data, "SSL 2.0 connection using %s\n", + SSLCipherNameForNumber(cipher)); + break; + case kSSLProtocol3: + infof(data, "SSL 3.0 connection using %s\n", + SSLCipherNameForNumber(cipher)); + break; + case kTLSProtocol1: + infof(data, "TLS 1.0 connection using %s\n", + TLSCipherNameForNumber(cipher)); + break; +#if defined(__MAC_10_8) || defined(__IPHONE_5_0) + case kTLSProtocol11: + infof(data, "TLS 1.1 connection using %s\n", + TLSCipherNameForNumber(cipher)); + break; + case kTLSProtocol12: + infof(data, "TLS 1.2 connection using %s\n", + TLSCipherNameForNumber(cipher)); + break; +#endif + default: + infof(data, "Unknown protocol connection\n"); + break; + } return CURLE_OK; } @@ -551,10 +861,35 @@ darwinssl_connect_step3(struct connectdata *conn, SecCertificateRef server_cert; OSStatus err; CFIndex i, count; + SecTrustRef trust; /* There is no step 3! * Well, okay, if verbose mode is on, let's print the details of the * server certificates. */ +#if defined(__MAC_10_7) || defined(__IPHONE_5_0) + if(SecTrustGetCertificateCount != NULL) { +#pragma unused(server_certs) + err = SSLCopyPeerTrust(connssl->ssl_ctx, &trust); + if(err == noErr) { + count = SecTrustGetCertificateCount(trust); + for(i = 0L ; i < count ; i++) { + server_cert = SecTrustGetCertificateAtIndex(trust, 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(trust); + } + } + else { +#elif !defined(TARGET_OS_EMBEDDED) +#pragma unused(trust) err = SSLCopyPeerCertificates(connssl->ssl_ctx, &server_certs); if(err == noErr) { count = CFArrayGetCount(server_certs); @@ -573,6 +908,10 @@ darwinssl_connect_step3(struct connectdata *conn, } CFRelease(server_certs); } +#endif /* defined(__MAC_10_7) || defined(__IPHONE_5_0) */ +#if defined(__MAC_10_7) || defined(__IPHONE_5_0) + } +#endif /* defined(__MAC_10_7) || defined(__IPHONE_5_0) */ connssl->connecting_state = ssl_connect_done; return CURLE_OK; @@ -722,9 +1061,20 @@ void Curl_darwinssl_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; + if(connssl->ssl_ctx) { + (void)SSLClose(connssl->ssl_ctx); +#if defined(__MAC_10_8) || defined(__IPHONE_5_0) + if(SSLCreateContext != NULL) + CFRelease(connssl->ssl_ctx); +#if !defined(TARGET_OS_EMBEDDED) + else + (void)SSLDisposeContext(connssl->ssl_ctx); +#endif /* !defined(TARGET_OS_EMBEDDED */ +#else + (void)SSLDisposeContext(connssl->ssl_ctx); +#endif /* defined(__MAC_10_8) || defined(__IPHONE_5_0) */ + connssl->ssl_ctx = NULL; + } connssl->ssl_sockfd = 0; } @@ -840,15 +1190,15 @@ void Curl_darwinssl_random(struct SessionHandle *data, /* arc4random_buf() isn't available on cats older than Lion, so let's do this manually for the benefit of the older cats. */ size_t i; - u_int32_t random = 0; + u_int32_t random_number = 0; for(i = 0 ; i < length ; i++) { if(i % sizeof(u_int32_t) == 0) - random = arc4random(); - entropy[i] = random & 0xFF; - random >>= 8; + random_number = arc4random(); + entropy[i] = random_number & 0xFF; + random_number >>= 8; } - i = random = 0; + i = random_number = 0; (void)data; } -- cgit v1.2.1 From 2f6e1a8cc3f4573b29d48b7bd8177dbbc4c337fd Mon Sep 17 00:00:00 2001 From: Nick Zitzmann Date: Mon, 20 Aug 2012 20:22:51 -0600 Subject: darwinssl: Bugfix for previous commit for older cats I accidentally broke functionality for versions of OS X prior to Mountain Lion in the previous commit. This commit fixes the problems. --- lib/curl_darwinssl.c | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) (limited to 'lib/curl_darwinssl.c') diff --git a/lib/curl_darwinssl.c b/lib/curl_darwinssl.c index 1626b57e2..78f31029e 100644 --- a/lib/curl_darwinssl.c +++ b/lib/curl_darwinssl.c @@ -561,6 +561,28 @@ CF_INLINE const char *TLSCipherNameForNumber(SSLCipherSuite cipher) { case TLS_EMPTY_RENEGOTIATION_INFO_SCSV: return "TLS_EMPTY_RENEGOTIATION_INFO_SCSV"; break; +#else + case SSL_RSA_WITH_NULL_MD5: + return "TLS_RSA_WITH_NULL_MD5"; + break; + case SSL_RSA_WITH_NULL_SHA: + return "TLS_RSA_WITH_NULL_SHA"; + break; + case SSL_RSA_WITH_RC4_128_MD5: + return "TLS_RSA_WITH_RC4_128_MD5"; + break; + case SSL_RSA_WITH_RC4_128_SHA: + return "TLS_RSA_WITH_RC4_128_SHA"; + break; + case SSL_RSA_WITH_3DES_EDE_CBC_SHA: + return "TLS_RSA_WITH_3DES_EDE_CBC_SHA"; + break; + case SSL_DH_anon_WITH_RC4_128_MD5: + return "TLS_DH_anon_WITH_RC4_128_MD5"; + break; + case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA: + return "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA"; + break; #endif /* defined(__MAC_10_8) || defined(__IPHONE_5_0) */ } return "TLS_NULL_WITH_NULL_NULL"; @@ -592,7 +614,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, } } else { -#elif !defined(TARGET_OS_EMBEDDED) +#elif TARGET_OS_EMBEDDED == 0 if(connssl->ssl_ctx) (void)SSLDisposeContext(connssl->ssl_ctx); err = SSLNewContext(false, &(connssl->ssl_ctx)); @@ -627,7 +649,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, } } else { -#if !defined(TARGET_OS_EMBEDDED) +#if TARGET_OS_EMBEDDED == 0 (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, kSSLProtocolAll, false); @@ -668,7 +690,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, true); break; } -#endif /* TARGET_OS_EMBEDDED */ +#endif /* TARGET_OS_EMBEDDED == 0 */ } #else (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, kSSLProtocolAll, false); @@ -718,7 +740,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, } } else { -#elif !defined(TARGET_OS_EMBEDDED) +#elif TARGET_OS_EMBEDDED == 0 err = SSLSetEnableCertVerify(connssl->ssl_ctx, data->set.ssl.verifypeer?true:false); if(err != noErr) { @@ -888,7 +910,7 @@ darwinssl_connect_step3(struct connectdata *conn, } } else { -#elif !defined(TARGET_OS_EMBEDDED) +#elif TARGET_OS_EMBEDDED == 0 #pragma unused(trust) err = SSLCopyPeerCertificates(connssl->ssl_ctx, &server_certs); if(err == noErr) { @@ -1066,10 +1088,10 @@ void Curl_darwinssl_close(struct connectdata *conn, int sockindex) #if defined(__MAC_10_8) || defined(__IPHONE_5_0) if(SSLCreateContext != NULL) CFRelease(connssl->ssl_ctx); -#if !defined(TARGET_OS_EMBEDDED) +#if TARGET_OS_EMBEDDED == 0 else (void)SSLDisposeContext(connssl->ssl_ctx); -#endif /* !defined(TARGET_OS_EMBEDDED */ +#endif /* TARGET_OS_EMBEDDED == 0 */ #else (void)SSLDisposeContext(connssl->ssl_ctx); #endif /* defined(__MAC_10_8) || defined(__IPHONE_5_0) */ -- cgit v1.2.1 From badb81769a32c263e4a1d4d161688bb67fbf940d Mon Sep 17 00:00:00 2001 From: Nick Zitzmann Date: Fri, 7 Sep 2012 20:01:08 -0600 Subject: darwinssl: fixed for older Mac OS X versions SSL didn't work on older cats if built on a newer cat with weak-linking turned on to support the older cat --- lib/curl_darwinssl.c | 58 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 13 deletions(-) (limited to 'lib/curl_darwinssl.c') diff --git a/lib/curl_darwinssl.c b/lib/curl_darwinssl.c index 78f31029e..d5685bede 100644 --- a/lib/curl_darwinssl.c +++ b/lib/curl_darwinssl.c @@ -614,7 +614,17 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, } } else { -#elif TARGET_OS_EMBEDDED == 0 +#if TARGET_OS_EMBEDDED == 0 /* the older API does not exist on iOS */ + 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; + } +#endif /* TARGET_OS_EMBEDDED == 0 */ + } +#else if(connssl->ssl_ctx) (void)SSLDisposeContext(connssl->ssl_ctx); err = SSLNewContext(false, &(connssl->ssl_ctx)); @@ -623,9 +633,6 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, return CURLE_OUT_OF_MEMORY; } #endif /* defined(__MAC_10_8) || defined(__IPHONE_5_0) */ -#if defined(__MAC_10_8) || defined(__IPHONE_5_0) - } -#endif /* defined(__MAC_10_8) || defined(__IPHONE_5_0) */ /* check to see if we've been told to use an explicit SSL/TLS version */ #if defined(__MAC_10_8) || defined(__IPHONE_5_0) @@ -740,7 +747,16 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, } } else { -#elif TARGET_OS_EMBEDDED == 0 +#if TARGET_OS_EMBEDDED == 0 + 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; + } +#endif /* TARGET_OS_EMBEDDED == 0 */ + } +#else err = SSLSetEnableCertVerify(connssl->ssl_ctx, data->set.ssl.verifypeer?true:false); if(err != noErr) { @@ -748,9 +764,6 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, return CURLE_SSL_CONNECT_ERROR; } #endif /* defined(__MAC_10_6) || defined(__IPHONE_5_0) */ -#if defined(__MAC_10_6) || defined(__IPHONE_5_0) - } -#endif /* defined(__MAC_10_6) || defined(__IPHONE_5_0) */ /* If this is a domain name and not an IP address, then configure SNI: */ if((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) && @@ -889,7 +902,7 @@ darwinssl_connect_step3(struct connectdata *conn, * Well, okay, if verbose mode is on, let's print the details of the * server certificates. */ #if defined(__MAC_10_7) || defined(__IPHONE_5_0) - if(SecTrustGetCertificateCount != NULL) { + if(SecTrustEvaluateAsync != NULL) { #pragma unused(server_certs) err = SSLCopyPeerTrust(connssl->ssl_ctx, &trust); if(err == noErr) { @@ -910,7 +923,29 @@ darwinssl_connect_step3(struct connectdata *conn, } } else { -#elif TARGET_OS_EMBEDDED == 0 +#if TARGET_OS_EMBEDDED == 0 + 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); + } +#endif /* TARGET_OS_EMBEDDED == 0 */ + } +#else #pragma unused(trust) err = SSLCopyPeerCertificates(connssl->ssl_ctx, &server_certs); if(err == noErr) { @@ -931,9 +966,6 @@ darwinssl_connect_step3(struct connectdata *conn, CFRelease(server_certs); } #endif /* defined(__MAC_10_7) || defined(__IPHONE_5_0) */ -#if defined(__MAC_10_7) || defined(__IPHONE_5_0) - } -#endif /* defined(__MAC_10_7) || defined(__IPHONE_5_0) */ connssl->connecting_state = ssl_connect_done; return CURLE_OK; -- cgit v1.2.1 From f1d2e1850819f54d1c950989614da7445bdd457f Mon Sep 17 00:00:00 2001 From: Nick Zitzmann Date: Tue, 16 Oct 2012 10:33:13 -0600 Subject: darwinssl: un-broke iOS build, fix error on server disconnect The iOS build was broken by a reference to a function that only existed under OS X; fixed. Also fixed a hard-to-reproduce problem where, if the server disconnected before libcurl got the chance to hang up first and SecureTransport was in use, then we'd raise an error instead of failing gracefully. --- lib/curl_darwinssl.c | 92 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 81 insertions(+), 11 deletions(-) (limited to 'lib/curl_darwinssl.c') diff --git a/lib/curl_darwinssl.c b/lib/curl_darwinssl.c index d5685bede..31531dbcc 100644 --- a/lib/curl_darwinssl.c +++ b/lib/curl_darwinssl.c @@ -266,6 +266,44 @@ CF_INLINE const char *SSLCipherNameForNumber(SSLCipherSuite cipher) { case SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA: return "SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA"; break; + /* TLS 1.0 with AES (RFC 3268) + (Apparently these are used in SSLv3 implementations as well.) */ + case TLS_RSA_WITH_AES_128_CBC_SHA: + return "TLS_RSA_WITH_AES_128_CBC_SHA"; + break; + case TLS_DH_DSS_WITH_AES_128_CBC_SHA: + return "TLS_DH_DSS_WITH_AES_128_CBC_SHA"; + break; + case TLS_DH_RSA_WITH_AES_128_CBC_SHA: + return "TLS_DH_RSA_WITH_AES_128_CBC_SHA"; + break; + case TLS_DHE_DSS_WITH_AES_128_CBC_SHA: + return "TLS_DHE_DSS_WITH_AES_128_CBC_SHA"; + break; + case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: + return "TLS_DHE_RSA_WITH_AES_128_CBC_SHA"; + break; + case TLS_DH_anon_WITH_AES_128_CBC_SHA: + return "TLS_DH_anon_WITH_AES_128_CBC_SHA"; + break; + case TLS_RSA_WITH_AES_256_CBC_SHA: + return "TLS_RSA_WITH_AES_256_CBC_SHA"; + break; + case TLS_DH_DSS_WITH_AES_256_CBC_SHA: + return "TLS_DH_DSS_WITH_AES_256_CBC_SHA"; + break; + case TLS_DH_RSA_WITH_AES_256_CBC_SHA: + return "TLS_DH_RSA_WITH_AES_256_CBC_SHA"; + break; + case TLS_DHE_DSS_WITH_AES_256_CBC_SHA: + return "TLS_DHE_DSS_WITH_AES_256_CBC_SHA"; + break; + case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: + return "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"; + break; + case TLS_DH_anon_WITH_AES_256_CBC_SHA: + return "TLS_DH_anon_WITH_AES_256_CBC_SHA"; + break; /* SSL version 2.0 */ case SSL_RSA_WITH_RC2_CBC_MD5: return "SSL_RSA_WITH_RC2_CBC_MD5"; @@ -614,7 +652,8 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, } } else { -#if TARGET_OS_EMBEDDED == 0 /* the older API does not exist on iOS */ + /* The old ST API does not exist under iOS, so don't compile it: */ +#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) if(connssl->ssl_ctx) (void)SSLDisposeContext(connssl->ssl_ctx); err = SSLNewContext(false, &(connssl->ssl_ctx)); @@ -622,7 +661,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, failf(data, "SSL: couldn't create a context: OSStatus %d", err); return CURLE_OUT_OF_MEMORY; } -#endif /* TARGET_OS_EMBEDDED == 0 */ +#endif /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */ } #else if(connssl->ssl_ctx) @@ -656,7 +695,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, } } else { -#if TARGET_OS_EMBEDDED == 0 +#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, kSSLProtocolAll, false); @@ -697,7 +736,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, true); break; } -#endif /* TARGET_OS_EMBEDDED == 0 */ +#endif /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */ } #else (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, kSSLProtocolAll, false); @@ -747,14 +786,14 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, } } else { -#if TARGET_OS_EMBEDDED == 0 +#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) 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; } -#endif /* TARGET_OS_EMBEDDED == 0 */ +#endif /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */ } #else err = SSLSetEnableCertVerify(connssl->ssl_ctx, @@ -902,6 +941,32 @@ darwinssl_connect_step3(struct connectdata *conn, * Well, okay, if verbose mode is on, let's print the details of the * server certificates. */ #if defined(__MAC_10_7) || defined(__IPHONE_5_0) +#if (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE) +#pragma unused(server_certs) + err = SSLCopyPeerTrust(connssl->ssl_ctx, &trust); + if(err == noErr) { + count = SecTrustGetCertificateCount(trust); + for(i = 0L ; i < count ; i++) { + server_cert = SecTrustGetCertificateAtIndex(trust, 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(trust); + } +#else + /* SSLCopyPeerCertificates() is deprecated as of Mountain Lion. + The function SecTrustGetCertificateAtIndex() is officially present + in Lion, but it is unfortunately also present in Snow Leopard as + private API and doesn't work as expected. So we have to look for + a different symbol to make sure this code is only executed under + Lion or later. */ if(SecTrustEvaluateAsync != NULL) { #pragma unused(server_certs) err = SSLCopyPeerTrust(connssl->ssl_ctx, &trust); @@ -909,7 +974,8 @@ darwinssl_connect_step3(struct connectdata *conn, count = SecTrustGetCertificateCount(trust); for(i = 0L ; i < count ; i++) { server_cert = SecTrustGetCertificateAtIndex(trust, i); - server_cert_summary = SecCertificateCopySubjectSummary(server_cert); + server_cert_summary = + SecCertificateCopyLongDescription(NULL, server_cert, NULL); memset(server_cert_summary_c, 0, 128); if(CFStringGetCString(server_cert_summary, server_cert_summary_c, @@ -923,7 +989,6 @@ darwinssl_connect_step3(struct connectdata *conn, } } else { -#if TARGET_OS_EMBEDDED == 0 err = SSLCopyPeerCertificates(connssl->ssl_ctx, &server_certs); if(err == noErr) { count = CFArrayGetCount(server_certs); @@ -943,8 +1008,8 @@ darwinssl_connect_step3(struct connectdata *conn, } CFRelease(server_certs); } -#endif /* TARGET_OS_EMBEDDED == 0 */ } +#endif /* (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE) */ #else #pragma unused(trust) err = SSLCopyPeerCertificates(connssl->ssl_ctx, &server_certs); @@ -1120,10 +1185,10 @@ void Curl_darwinssl_close(struct connectdata *conn, int sockindex) #if defined(__MAC_10_8) || defined(__IPHONE_5_0) if(SSLCreateContext != NULL) CFRelease(connssl->ssl_ctx); -#if TARGET_OS_EMBEDDED == 0 +#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) else (void)SSLDisposeContext(connssl->ssl_ctx); -#endif /* TARGET_OS_EMBEDDED == 0 */ +#endif /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */ #else (void)SSLDisposeContext(connssl->ssl_ctx); #endif /* defined(__MAC_10_8) || defined(__IPHONE_5_0) */ @@ -1311,6 +1376,11 @@ static ssize_t darwinssl_recv(struct connectdata *conn, return -1; break; + case errSSLClosedGraceful: /* they're done; fail gracefully */ + *curlcode = CURLE_OK; + return -1; + break; + default: failf(conn->data, "SSLRead() return error %d", err); *curlcode = CURLE_RECV_ERROR; -- cgit v1.2.1 From da82f59b697310229ccdf66104d5d65a44dfab98 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 27 Oct 2012 12:31:39 +0200 Subject: CURLOPT_SSL_VERIFYHOST: stop supporting the 1 value After a research team wrote a document[1] that found several live source codes out there in the wild that misused the CURLOPT_SSL_VERIFYHOST option thinking it was a boolean, this change now bans 1 as a value and will make libcurl return error for it. 1 was never a sensible value to use in production but was introduced back in the days to help debugging. It was always documented clearly this way. 1 was never supported by all SSL backends in libcurl, so this cleanup makes the treatment of it unified. The report's list of mistakes for this option were all PHP code and while there's a binding layer between libcurl and PHP, the PHP team has decided that they have an as thin layer as possible on top of libcurl so they will not alter or specifically filter a 'TRUE' value for this particular option. I sympathize with that position. [1] = http://daniel.haxx.se/blog/2012/10/25/libcurl-claimed-to-be-dangerous/ --- lib/curl_darwinssl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'lib/curl_darwinssl.c') diff --git a/lib/curl_darwinssl.c b/lib/curl_darwinssl.c index 31531dbcc..334944f09 100644 --- a/lib/curl_darwinssl.c +++ b/lib/curl_darwinssl.c @@ -632,7 +632,6 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, 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 @@ -809,7 +808,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, #ifdef ENABLE_IPV6 (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr)) && #endif - sni) { + data->set.ssl.verifyhost) { err = SSLSetPeerDomainName(connssl->ssl_ctx, conn->host.name, strlen(conn->host.name)); if(err != noErr) { -- cgit v1.2.1 From 1394cad30fcac7eb21adb9158dfcfab10e9f53d4 Mon Sep 17 00:00:00 2001 From: Oscar Koeroo Date: Sat, 3 Nov 2012 02:06:51 +0100 Subject: SSL: Several SSL-backend related fixes axTLS: This will make the axTLS backend perform the RFC2818 checks, honoring the VERIFYHOST setting similar to the OpenSSL backend. Generic for OpenSSL and axTLS: Move the hostcheck and cert_hostcheck functions from the lib/ssluse.c files to make them genericly available for both the OpenSSL, axTLS and other SSL backends. They are now in the new lib/hostcheck.c file. CyaSSL: CyaSSL now also has the RFC2818 checks enabled by default. There is a limitation that the verifyhost can not be enabled exclusively on the Subject CN field comparison. This SSL backend will thus behave like the NSS and the GnuTLS (meaning: RFC2818 ok, or bust). In other words: setting verifyhost to 0 or 1 will disable the Subject Alt Names checks too. Schannel: Updated the schannel information messages: Split the IP address usage message from the verifyhost setting and changed the message about disabling SNI (Server Name Indication, used in HTTP virtual hosting) into a message stating that the Subject Alternative Names checks are being disabled when verifyhost is set to 0 or 1. As a side effect of switching off the RFC2818 related servername checks with SCH_CRED_NO_SERVERNAME_CHECK (http://msdn.microsoft.com/en-us/library/aa923430.aspx) the SNI feature is being disabled. This effect is not documented in MSDN, but Wireshark output clearly shows the effect (details on the libcurl maillist). PolarSSL: Fix the prototype change in PolarSSL of ssl_set_session() and the move of the peer_cert from the ssl_context to the ssl_session. Found this change in the PolarSSL SVN between r1316 and r1317 where the POLARSSL_VERSION_NUMBER was at 0x01010100. But to accommodate the Ubuntu PolarSSL version 1.1.4 the check is to discriminate between lower then PolarSSL version 1.2.0 and 1.2.0 and higher. Note: The PolarSSL SVN trunk jumped from version 1.1.1 to 1.2.0. Generic: All the SSL backends are fixed and checked to work with the ssl.verifyhost as a boolean, which is an internal API change. --- lib/curl_darwinssl.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'lib/curl_darwinssl.c') diff --git a/lib/curl_darwinssl.c b/lib/curl_darwinssl.c index 334944f09..3cc278a1f 100644 --- a/lib/curl_darwinssl.c +++ b/lib/curl_darwinssl.c @@ -803,6 +803,8 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, } #endif /* defined(__MAC_10_6) || defined(__IPHONE_5_0) */ + /* If this is a domain name and not an IP address, then configure SNI. + * Also: the verifyhost setting influences SNI usage */ /* If this is a domain name and not an IP address, then configure SNI: */ if((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) && #ifdef ENABLE_IPV6 @@ -862,7 +864,6 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex) connssl->connecting_state = connssl->ssl_direction ? ssl_connect_2_writing : ssl_connect_2_reading; return CURLE_OK; - break; case errSSLServerAuthCompleted: /* the documentation says we need to call SSLHandshake() again */ @@ -874,13 +875,16 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex) case errSSLCertExpired: failf(data, "SSL certificate problem: OSStatus %d", err); return CURLE_SSL_CACERT; - break; + + case errSSLHostNameMismatch: + failf(data, "SSL certificate peer verification failed, the " + "certificate did not match \"%s\"\n", conn->host.dispname); + return CURLE_PEER_FAILED_VERIFICATION; default: failf(data, "Unknown SSL protocol error in connection to %s:%d", conn->host.name, err); return CURLE_SSL_CONNECT_ERROR; - break; } } else { -- cgit v1.2.1