aboutsummaryrefslogtreecommitdiff
path: root/lib/curl_darwinssl.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/curl_darwinssl.c')
-rw-r--r--lib/curl_darwinssl.c79
1 files changed, 62 insertions, 17 deletions
diff --git a/lib/curl_darwinssl.c b/lib/curl_darwinssl.c
index d18e28ef2..5340c6142 100644
--- a/lib/curl_darwinssl.c
+++ b/lib/curl_darwinssl.c
@@ -59,6 +59,7 @@
/* From MacTypes.h (which we can't include because it isn't present in iOS: */
#define ioErr -36
+#define paramErr -50
/* 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
@@ -628,40 +629,36 @@ CF_INLINE const char *TLSCipherNameForNumber(SSLCipherSuite cipher) {
return "TLS_NULL_WITH_NULL_NULL";
}
-CF_INLINE bool IsRunningMountainLionOrLater(void)
-{
#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
+CF_INLINE void GetDarwinVersionNumber(int *major, int *minor)
+{
int mib[2];
char *os_version;
size_t os_version_len;
- char *os_version_major/*, *os_version_minor, *os_version_point*/;
- int os_version_major_int;
+ char *os_version_major, *os_version_minor/*, *os_version_point*/;
/* Get the Darwin kernel version from the kernel using sysctl(): */
mib[0] = CTL_KERN;
mib[1] = KERN_OSRELEASE;
if(sysctl(mib, 2, NULL, &os_version_len, NULL, 0) == -1)
- return false;
+ return;
os_version = malloc(os_version_len*sizeof(char));
if(!os_version)
- return false;
+ return;
if(sysctl(mib, 2, os_version, &os_version_len, NULL, 0) == -1) {
free(os_version);
- return false;
+ return;
}
- /* Parse the version. If it's version 12.0.0 or later, then this user is
- using Mountain Lion. */
+ /* Parse the version: */
os_version_major = strtok(os_version, ".");
- /*os_version_minor = strtok(NULL, ".");
- os_version_point = strtok(NULL, ".");*/
- os_version_major_int = atoi(os_version_major);
+ os_version_minor = strtok(NULL, ".");
+ /*os_version_point = strtok(NULL, ".");*/
+ *major = atoi(os_version_major);
+ *minor = atoi(os_version_minor);
free(os_version);
- return os_version_major_int >= 12;
-#else
- return true; /* iOS users: this doesn't concern you */
-#endif
}
+#endif
/* Apple provides a myriad of ways of getting information about a certificate
into a string. Some aren't available under iOS or newer cats. So here's
@@ -707,6 +704,13 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
#endif
/*SSLConnectionRef ssl_connection;*/
OSStatus err = noErr;
+#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
+ size_t all_ciphers_count = 0UL, allowed_ciphers_count = 0UL, i;
+ SSLCipherSuite *all_ciphers = NULL, *allowed_ciphers = NULL;
+ int darwinver_maj = 0, darwinver_min = 0;
+
+ GetDarwinVersionNumber(&darwinver_maj, &darwinver_min);
+#endif
#if defined(__MAC_10_8) || defined(__IPHONE_5_0)
if(SSLCreateContext != NULL) { /* use the newer API if avaialble */
@@ -851,7 +855,12 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
to disable certificate validation if the user turned that off.
(SecureTransport will always validate the certificate chain by
default.) */
- if(SSLSetSessionOption != NULL && IsRunningMountainLionOrLater()) {
+ /* (Note: Darwin 12.x.x is Mountain Lion.) */
+#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
+ if(SSLSetSessionOption != NULL && darwinver_maj >= 12) {
+#else
+ if(SSLSetSessionOption != NULL) {
+#endif /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */
err = SSLSetSessionOption(connssl->ssl_ctx,
kSSLSessionOptionBreakOnServerAuth,
data->set.ssl.verifypeer?false:true);
@@ -895,6 +904,31 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
}
}
+ /* There's a known bug in early versions of Mountain Lion where ST's ECC
+ ciphers (cipher suite 0xC001 through 0xC032) simply do not work.
+ Work around the problem here by disabling those ciphers if we are running
+ in an affected version of OS X. */
+#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
+ if(darwinver_maj == 12 && darwinver_min <= 3) {
+ (void)SSLGetNumberSupportedCiphers(connssl->ssl_ctx, &all_ciphers_count);
+ all_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite));
+ allowed_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite));
+ if(all_ciphers && allowed_ciphers &&
+ SSLGetSupportedCiphers(connssl->ssl_ctx, all_ciphers,
+ &all_ciphers_count) == noErr) {
+ for(i = 0UL ; i < all_ciphers_count ; i++) {
+ if(all_ciphers[i] < 0xC001 || all_ciphers[i] > 0xC032) {
+ allowed_ciphers[allowed_ciphers_count++] = all_ciphers[i];
+ }
+ }
+ (void)SSLSetEnabledCiphers(connssl->ssl_ctx, allowed_ciphers,
+ allowed_ciphers_count);
+ }
+ Curl_safefree(all_ciphers);
+ Curl_safefree(allowed_ciphers);
+ }
+#endif /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */
+
err = SSLSetIOFuncs(connssl->ssl_ctx, SocketRead, SocketWrite);
if(err != noErr) {
failf(data, "SSL: SSLSetIOFuncs() failed: OSStatus %d", err);
@@ -947,6 +981,7 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex)
/* the documentation says we need to call SSLHandshake() again */
return darwinssl_connect_step2(conn, sockindex);
+ /* These are all certificate problems with the server: */
case errSSLXCertChainInvalid:
failf(data, "SSL certificate problem: Invalid certificate chain");
return CURLE_SSL_CACERT;
@@ -961,14 +996,24 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex)
"expired certificate");
return CURLE_SSL_CACERT;
+ /* This error is raised if the server's cert didn't match the server's
+ host name: */
case errSSLHostNameMismatch:
failf(data, "SSL certificate peer verification failed, the "
"certificate did not match \"%s\"\n", conn->host.dispname);
return CURLE_PEER_FAILED_VERIFICATION;
+ /* Generic handshake errors: */
case errSSLConnectionRefused:
failf(data, "Server dropped the connection during the SSL handshake");
return CURLE_SSL_CONNECT_ERROR;
+ case errSSLClosedAbort:
+ failf(data, "Server aborted the SSL handshake");
+ return CURLE_SSL_CONNECT_ERROR;
+ case paramErr: /* if you're getting this, it could be a cipher problem */
+ failf(data, "Internal SSL engine error encountered during the "
+ "SSL handshake");
+ return CURLE_SSL_CONNECT_ERROR;
default:
failf(data, "Unknown SSL protocol error in connection to %s:%d",
conn->host.name, err);