Permalink
Browse files

darwinssl: disable ECC ciphers under Mountain Lion by default

I found out that ECC doesn't work as of OS X 10.8.3, so those ciphers are
turned off until the next point release of OS X.
  • Loading branch information...
nickzman committed Mar 19, 2013
1 parent 91ab249 commit 6f1f7e5de8c774e51957afd988d8d316b5a6d92f
Showing with 63 additions and 17 deletions.
  1. +1 −0 RELEASE-NOTES
  2. +62 −17 lib/curl_darwinssl.c
View
@@ -55,6 +55,7 @@ This release includes the following bugfixes:
o curlbuild.h.dist: enhance non-configure GCC ABI detection logic
o sasl: Fixed null pointer reference when decoding empty digest challenge [8]
o easy: do not ignore poll() failures other than EINTR
+ o darwinssl: disable ECC ciphers under Mountain Lion by default
This release includes the following known bugs:
View
@@ -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);

0 comments on commit 6f1f7e5

Please sign in to comment.