]> git.saurik.com Git - apple/security.git/blobdiff - OSX/libsecurity_ssl/lib/sslContext.c
Security-59306.61.1.tar.gz
[apple/security.git] / OSX / libsecurity_ssl / lib / sslContext.c
index 653cbe32bfd1db930c531c8987269c7bf19f9ca7..fc1826feb498ef885f4980884d2c4e133d3f3cb4 100644 (file)
@@ -29,7 +29,6 @@
 
 #include "SSLRecordInternal.h"
 #include "SecureTransportPriv.h"
 
 #include "SSLRecordInternal.h"
 #include "SecureTransportPriv.h"
-#include "appleSession.h"
 #include "ssl.h"
 #include "sslCipherSpecs.h"
 #include "sslContext.h"
 #include "ssl.h"
 #include "sslCipherSpecs.h"
 #include "sslContext.h"
@@ -37,7 +36,6 @@
 #include "sslDebug.h"
 #include "sslKeychain.h"
 #include "sslMemory.h"
 #include "sslDebug.h"
 #include "sslKeychain.h"
 #include "sslMemory.h"
-#include "sslUtils.h"
 
 #include "tlsCallbacks.h"
 
 
 #include "tlsCallbacks.h"
 
@@ -78,26 +76,6 @@ static void sslFreeDnList(SSLContext *ctx)
     ctx->acceptableDNList = NULL;
 }
 
     ctx->acceptableDNList = NULL;
 }
 
-/*
-  This frees ctx->localCert, which is allocated in parseIncomingCert.
-  This is structured as a list, but all the SSLCertificates structs are
-  allocated as a single array, so there is only on sslFree(localCert).
- */
-static void sslFreeLocalCert(SSLContext *ctx)
-{
-    SSLCertificate  *cert;
-
-    cert = ctx->localCert;
-    while (cert)
-    {
-        SSLFreeBuffer(&cert->derCert);
-        cert = cert->next;
-    }
-    sslFree(ctx->localCert);
-    ctx->localCert = NULL;
-}
-
-
 Boolean sslIsSessionActive(const SSLContext *ctx)
 {
        assert(ctx != NULL);
 Boolean sslIsSessionActive(const SSLContext *ctx)
 {
        assert(ctx != NULL);
@@ -107,6 +85,7 @@ Boolean sslIsSessionActive(const SSLContext *ctx)
                case SSL_HdskStateUninit:
                case SSL_HdskStateGracefulClose:
                case SSL_HdskStateErrorClose:
                case SSL_HdskStateUninit:
                case SSL_HdskStateGracefulClose:
                case SSL_HdskStateErrorClose:
+        case SSL_HdskStateOutOfBandError:
                        return false;
                default:
                        return true;
                        return false;
                default:
                        return true;
@@ -134,15 +113,20 @@ Boolean sslIsSessionActive(const SSLContext *ctx)
 #define MIN_ALLOWED_DTLS_MTU    64      /* this ensure than there will be no integer
                                             underflow when calculating max write size */
 
 #define MIN_ALLOWED_DTLS_MTU    64      /* this ensure than there will be no integer
                                             underflow when calculating max write size */
 
-int kSplitDefaultValue;
+/* Preferences values */
 CFIndex kMinDhGroupSizeDefaultValue;
 CFIndex kMinDhGroupSizeDefaultValue;
+CFIndex kMinProtocolVersionDefaultValue;
+CFStringRef kSSLSessionConfigDefaultValue;
+Boolean kSSLDisableRecordSplittingDefaultValue;
+
+static tls_cache_t g_session_cache = NULL;
 
 #if TARGET_OS_IPHONE
 /*
  * Instead of using CFPropertyListReadFromFile we use a
  * CFPropertyListCreateWithStream directly
  * here. CFPropertyListReadFromFile() uses
 
 #if TARGET_OS_IPHONE
 /*
  * Instead of using CFPropertyListReadFromFile we use a
  * CFPropertyListCreateWithStream directly
  * here. CFPropertyListReadFromFile() uses
- * CFURLCopyResourcePropertyForKey() andCF pulls in CoreServices for
+ * CFURLCopyResourcePropertyForKey() and CF pulls in CoreServices for
  * CFURLCopyResourcePropertyForKey() and that doesn't work in install
  * enviroment.
  */
  * CFURLCopyResourcePropertyForKey() and that doesn't work in install
  * enviroment.
  */
@@ -161,55 +145,93 @@ CopyPlistFromFile(CFURLRef url)
 #endif
 
 
 #endif
 
 
-static void _SSLContextReadDefault()
+static
+CFTypeRef SSLPreferencesCopyValue(CFStringRef key, CFPropertyListRef managed_prefs)
 {
 {
-       /* 0 = disabled, 1 = split every write, 2 = split second and subsequent writes */
-    /* Enabled by default, this may cause some interop issues, see <rdar://problem/12307662> and <rdar://problem/12323307> */
-    const int defaultSplitDefaultValue = 2;
-
-       CFTypeRef value = (CFTypeRef)CFPreferencesCopyValue(CFSTR("SSLWriteSplit"),
-                                                       CFSTR("com.apple.security"),
-                                                       kCFPreferencesAnyUser,
-                                                       kCFPreferencesCurrentHost);
-       if (value) {
-               if (CFGetTypeID(value) == CFBooleanGetTypeID())
-                       kSplitDefaultValue = CFBooleanGetValue((CFBooleanRef)value) ? 1 : 0;
-               else if (CFGetTypeID(value) == CFNumberGetTypeID()) {
-                       if (!CFNumberGetValue((CFNumberRef)value, kCFNumberIntType, &kSplitDefaultValue))
-                               kSplitDefaultValue = defaultSplitDefaultValue;
-               }
-               if (kSplitDefaultValue < 0 || kSplitDefaultValue > 2) {
-                       kSplitDefaultValue = defaultSplitDefaultValue;
-               }
-               CFRelease(value);
-       }
-       else {
-               kSplitDefaultValue = defaultSplitDefaultValue;
-       }
+    CFTypeRef value = (CFTypeRef) CFPreferencesCopyAppValue(CFSTR("SSLSessionConfig"), kCFPreferencesCurrentApplication);
 
 
-    /* Min DH Group Size */
-    kMinDhGroupSizeDefaultValue = CFPreferencesGetAppIntegerValue(CFSTR("SSLMinDhGroupSize"), kCFPreferencesCurrentApplication, NULL);
+    if(!value && managed_prefs) {
+        value =  CFDictionaryGetValue(managed_prefs, key);
+        if (value)
+            CFRetain(value);
+    }
+
+    return value;
+}
+
+static
+CFIndex SSLPreferencesGetInteger(CFStringRef key, CFPropertyListRef managed_prefs)
+{
+    CFTypeRef value = SSLPreferencesCopyValue(key, managed_prefs);
+    CFIndex int_value = 0;
+    if (isNumber(value)) {
+        CFNumberGetValue(value, kCFNumberCFIndexType, &int_value);
+    }
+    CFReleaseSafe(value);
+    return int_value;
+}
+
+static
+Boolean SSLPreferencesGetBoolean(CFStringRef key, CFPropertyListRef managed_prefs)
+{
+    CFTypeRef value = SSLPreferencesCopyValue(key, managed_prefs);
+    Boolean bool_value = FALSE;
+    if (isBoolean(value)) {
+        bool_value = CFBooleanGetValue(value);
+    }
+
+    CFReleaseSafe(value);
+    return bool_value;
+}
+
+static
+CFStringRef SSLPreferencesCopyString(CFStringRef key, CFPropertyListRef managed_prefs)
+{
+    CFTypeRef value = SSLPreferencesCopyValue(key, managed_prefs);
+    if (isString(value)) {
+        return value;
+    } else {
+        CFReleaseSafe(value);
+        return NULL;
+    }
+}
+
+static void _SSLContextReadDefault()
+{
+    CFPropertyListRef managed_prefs = NULL;
 
 #if TARGET_OS_IPHONE
 
 #if TARGET_OS_IPHONE
-    /* on iOS, if the above returned nothing, we manually look into mobile's Managed Preferences */
+    /* on iOS, we also look for preferences from mobile's Managed Preferences */
     /* Note that if the process is running as mobile, the above call will already have read the Managed Preference plist.
     /* Note that if the process is running as mobile, the above call will already have read the Managed Preference plist.
-       As a result, if you have some preferences set manually with defaults, which preference applies may be different for mobile vs not-mobile. */
-    if(kMinDhGroupSizeDefaultValue == 0) {
-        CFURLRef prefURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, CFSTR("/Library/Managed Preferences/mobile/.GlobalPreferences.plist"), kCFURLPOSIXPathStyle, false);
-        if(prefURL) {
-            CFPropertyListRef plist = CopyPlistFromFile(prefURL);
-            if (plist) {
-                value =  CFDictionaryGetValue(plist, CFSTR("SSLMinDhGroupSize"));
-                if (isNumber(value)) {
-                    CFNumberGetValue(value, kCFNumberCFIndexType, &kMinDhGroupSizeDefaultValue);
-                }
-            }
-            CFReleaseSafe(plist);
-        }
-        CFReleaseSafe(prefURL);
+     As a result, if you have some preferences set manually with defaults, which preference applies may be different for mobile vs not-mobile. */
+    CFURLRef prefURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, CFSTR("/Library/Managed Preferences/mobile/.GlobalPreferences.plist"), kCFURLPOSIXPathStyle, false);
+    if(prefURL) {
+        managed_prefs = CopyPlistFromFile(prefURL);
     }
     }
+    CFReleaseSafe(prefURL);
 #endif
 
 #endif
 
+    /* Disable record splitting */
+    /* Enabled by default, this may cause some interop issues, see <rdar://problem/12307662> and <rdar://problem/12323307> */
+    kSSLDisableRecordSplittingDefaultValue = SSLPreferencesGetBoolean(CFSTR("SSLDisableRecordSplitting"), managed_prefs);
+
+    /* Min DH Group Size */
+    kMinDhGroupSizeDefaultValue = SSLPreferencesGetInteger(CFSTR("SSLMinDhGroupSize"), managed_prefs);
+
+    /* Default Min Prototcol Version */
+    kMinProtocolVersionDefaultValue = SSLPreferencesGetInteger(CFSTR("SSLMinProtocolVersion"), managed_prefs);
+
+    /* Default Config */
+    kSSLSessionConfigDefaultValue = SSLPreferencesCopyString(CFSTR("SSLSessionConfig"), managed_prefs);
+
+    CFReleaseSafe(managed_prefs);
+}
+
+/* This functions initialize global variables, run once per process */
+static void SSLContextOnce(void)
+{
+    _SSLContextReadDefault();
+    g_session_cache = tls_cache_create();
 }
 
 CFGiblisWithHashFor(SSLContext)
 }
 
 CFGiblisWithHashFor(SSLContext)
@@ -269,6 +291,13 @@ SSLContextRef SSLCreateContextWithRecordFuncs(CFAllocatorRef alloc, SSLProtocolS
         return NULL;
     }
 
         return NULL;
     }
 
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        SSLContextOnce();
+    });
+
+    ctx->cache = g_session_cache;
+
     tls_handshake_set_callbacks(ctx->hdsk,
                                 &tls_handshake_callbacks,
                                 ctx);
     tls_handshake_set_callbacks(ctx->hdsk,
                                 &tls_handshake_callbacks,
                                 ctx);
@@ -297,33 +326,24 @@ SSLContextRef SSLCreateContextWithRecordFuncs(CFAllocatorRef alloc, SSLProtocolS
        /* Default for RSA blinding is ENABLED */
        ctx->rsaBlindingEnable = true;
 
        /* Default for RSA blinding is ENABLED */
        ctx->rsaBlindingEnable = true;
 
-       /* Default for sending one-byte app data record is DISABLED */
-       ctx->oneByteRecordEnable = false;
+       /* Default for sending one-byte app data record is ENABLED */
+    ctx->oneByteRecordEnable = !kSSLDisableRecordSplittingDefaultValue;
 
     /* Dont enable fallback behavior by default */
     ctx->fallbackEnabled = false;
 
 
     /* Dont enable fallback behavior by default */
     ctx->fallbackEnabled = false;
 
-       /* Consult global system preference for default behavior:
-        * 0 = disabled, 1 = split every write, 2 = split second and subsequent writes
-        * (caller can override by setting kSSLSessionOptionSendOneByteRecord)
-        */
-       static pthread_once_t sReadDefault = PTHREAD_ONCE_INIT;
-       pthread_once(&sReadDefault, _SSLContextReadDefault);
-    if (kSplitDefaultValue > 0) {
-               ctx->oneByteRecordEnable = true;
-    }
-
-    /* Default for server is DHE enabled, default for client is disabled */
-    if(ctx->protocolSide == kSSLServerSide) {
-        SSLSetDHEEnabled(ctx, true);
-    } else {
-        SSLSetDHEEnabled(ctx, false);
+    if(kSSLSessionConfigDefaultValue) {
+        SSLSetSessionConfig(ctx, kSSLSessionConfigDefaultValue);
     }
 
     if(kMinDhGroupSizeDefaultValue) {
         tls_handshake_set_min_dh_group_size(ctx->hdsk, (unsigned)kMinDhGroupSizeDefaultValue);
     }
 
     }
 
     if(kMinDhGroupSizeDefaultValue) {
         tls_handshake_set_min_dh_group_size(ctx->hdsk, (unsigned)kMinDhGroupSizeDefaultValue);
     }
 
+    if(kMinProtocolVersionDefaultValue) {
+        SSLSetProtocolVersionMin(ctx, (unsigned)kMinProtocolVersionDefaultValue);
+    }
+
        /* default for anonymous ciphers is DISABLED */
        ctx->anonCipherEnable = false;
 
        /* default for anonymous ciphers is DISABLED */
        ctx->anonCipherEnable = false;
 
@@ -334,8 +354,6 @@ SSLContextRef SSLCreateContextWithRecordFuncs(CFAllocatorRef alloc, SSLProtocolS
     ctx->signalCertRequest = false;
     ctx->signalClientAuth = false;
 
     ctx->signalCertRequest = false;
     ctx->signalClientAuth = false;
 
-       ctx->negAuthType = SSLClientAuthNone;           /* ditto */
-
        return ctx;
 }
 
        return ctx;
 }
 
@@ -404,18 +422,17 @@ void SSLContextDestroy(CFTypeRef arg)
     SSLFreeBuffer(&ctx->peerID);
     SSLFreeBuffer(&ctx->resumableSession);
     SSLFreeBuffer(&ctx->receivedDataBuffer);
     SSLFreeBuffer(&ctx->peerID);
     SSLFreeBuffer(&ctx->resumableSession);
     SSLFreeBuffer(&ctx->receivedDataBuffer);
+    SSLFreeBuffer(&ctx->contextConfigurationBuffer);
 
     CFReleaseSafe(ctx->acceptableCAs);
 
     CFReleaseSafe(ctx->acceptableCAs);
+#if !TARGET_OS_IPHONE
     CFReleaseSafe(ctx->trustedLeafCerts);
     CFReleaseSafe(ctx->trustedLeafCerts);
+#endif
     CFReleaseSafe(ctx->localCertArray);
     CFReleaseSafe(ctx->encryptCertArray);
     CFReleaseSafe(ctx->localCertArray);
     CFReleaseSafe(ctx->encryptCertArray);
-    CFReleaseSafe(ctx->peerCert);
     CFReleaseSafe(ctx->trustedCerts);
     CFReleaseSafe(ctx->peerSecTrust);
 
     CFReleaseSafe(ctx->trustedCerts);
     CFReleaseSafe(ctx->peerSecTrust);
 
-    sslFreePrivKey(&ctx->signingPrivKeyRef);
-
-    sslFreeLocalCert(ctx);
     sslFreeDnList(ctx);
 
     SSLFreeBuffer(&ctx->ownVerifyData);
     sslFreeDnList(ctx);
 
     SSLFreeBuffer(&ctx->ownVerifyData);
@@ -426,9 +443,10 @@ void SSLContextDestroy(CFTypeRef arg)
 
     SSLFreeBuffer(&ctx->dhParamsEncoded);
 
 
     SSLFreeBuffer(&ctx->dhParamsEncoded);
 
-    memset(((uint8_t*) ctx) + sizeof(CFRuntimeBase), 0, sizeof(SSLContext) - sizeof(CFRuntimeBase));
+    if(ctx->cache)
+        tls_cache_cleanup(ctx->cache);
 
 
-       sslCleanupSession();
+    memset(((uint8_t*) ctx) + sizeof(CFRuntimeBase), 0, sizeof(SSLContext) - sizeof(CFRuntimeBase));
 }
 
 /*
 }
 
 /*
@@ -453,6 +471,7 @@ SSLGetSessionState                  (SSLContextRef          context,
                        break;
                case SSL_HdskStateErrorClose:
                case SSL_HdskStateNoNotifyClose:
                        break;
                case SSL_HdskStateErrorClose:
                case SSL_HdskStateNoNotifyClose:
+        case SSL_HdskStateOutOfBandError:
                        rtnState = kSSLAborted;
                        break;
                case SSL_HdskStateReady:
                        rtnState = kSSLAborted;
                        break;
                case SSL_HdskStateReady:
@@ -474,13 +493,15 @@ SSLSetSessionOption                       (SSLContextRef          context,
                                                         SSLSessionOption       option,
                                                         Boolean                        value)
 {
                                                         SSLSessionOption       option,
                                                         Boolean                        value)
 {
-    if(context == NULL) {
-       return errSecParam;
+    if (context == NULL) {
+        return errSecParam;
     }
     }
-    if(sslIsSessionActive(context)) {
-       /* can't do this with an active session */
-       return errSecBadReq;
+
+    if (sslIsSessionActive(context)) {
+        /* can't do this with an active session */
+        return errSecBadReq;
     }
     }
+
     switch(option) {
         case kSSLSessionOptionBreakOnServerAuth:
             context->breakOnServerAuth = value;
     switch(option) {
         case kSSLSessionOptionBreakOnServerAuth:
             context->breakOnServerAuth = value;
@@ -495,11 +516,13 @@ SSLSetSessionOption                       (SSLContextRef          context,
             break;
         case kSSLSessionOptionSendOneByteRecord:
             /* Only call the record layer function if the value changed */
             break;
         case kSSLSessionOptionSendOneByteRecord:
             /* Only call the record layer function if the value changed */
-            if(value != context->oneByteRecordEnable)
+            if (value != context->oneByteRecordEnable) {
                 context->recFuncs->setOption(context->recCtx, kSSLRecordOptionSendOneByteRecord, value);
                 context->recFuncs->setOption(context->recCtx, kSSLRecordOptionSendOneByteRecord, value);
+            }
             context->oneByteRecordEnable = value;
             break;
         case kSSLSessionOptionFalseStart:
             context->oneByteRecordEnable = value;
             break;
         case kSSLSessionOptionFalseStart:
+            tls_handshake_set_false_start(context->hdsk, value);
             context->falseStartEnabled = value;
             break;
         case kSSLSessionOptionFallback:
             context->falseStartEnabled = value;
             break;
         case kSSLSessionOptionFallback:
@@ -511,6 +534,15 @@ SSLSetSessionOption                        (SSLContextRef          context,
             break;
         case kSSLSessionOptionAllowServerIdentityChange:
             tls_handshake_set_server_identity_change(context->hdsk, value);
             break;
         case kSSLSessionOptionAllowServerIdentityChange:
             tls_handshake_set_server_identity_change(context->hdsk, value);
+            context->allowServerIdentityChange = true;
+            break;
+        case kSSLSessionOptionAllowRenegotiation:
+            tls_handshake_set_renegotiation(context->hdsk, value);
+            context->allowRenegotiation = true;
+            break;
+        case kSSLSessionOptionEnableSessionTickets:
+            tls_handshake_set_session_ticket_enabled(context->hdsk, value);
+            context->enableSessionTickets = true;
             break;
         default:
             return errSecParam;
             break;
         default:
             return errSecParam;
@@ -699,25 +731,135 @@ SSLSetALPNData(SSLContextRef      context,
 
 const void *
 SSLGetALPNData(SSLContextRef      context,
 
 const void *
 SSLGetALPNData(SSLContextRef      context,
-              size_t                           *length)
+               size_t             *length)
 {
 {
-    if (context == NULL || length == NULL)
+    if (context == NULL || length == NULL) {
         return NULL;
         return NULL;
+    }
 
 
-    const tls_buffer *alpn_data;
+    const tls_buffer *alpnData = tls_handshake_get_peer_alpn_data(context->hdsk);
 
 
-    alpn_data = tls_handshake_get_peer_alpn_data(context->hdsk);
+    if (alpnData) {
+        *length = alpnData->length;
+        return alpnData->data;
+    } else {
+      return NULL;
+    }
+}
+
+OSStatus
+SSLSetALPNProtocols(SSLContextRef      context,
+                    CFArrayRef         protocols)
+{
+    if (context == NULL || protocols == NULL || CFArrayGetCount(protocols) == 0) {
+        return errSecParam;
+    }
+
+    // Per RFC 7301, the protocol name can be at most 32B long.
+    const int maxBufferLength = 32;
+
+    // Append each element in the array to a mutable buffer
+    CFMutableDataRef alpnData = CFDataCreateMutable(NULL, 0);
+    CFArrayForEach(protocols, ^(const void *value) {
+        CFStringRef protocolString = (CFStringRef) value;
+        uint8_t len = CFStringGetLength(protocolString);
+        if (len <= maxBufferLength) {
+            char stringBytes[maxBufferLength];
+            if (CFStringGetCString(protocolString, stringBytes, maxBufferLength, kCFStringEncodingASCII)) {
+                CFDataAppendBytes(alpnData, (const UInt8 *) &len, sizeof(len));
+                CFDataAppendBytes(alpnData, (const UInt8 *) stringBytes, len);
+            }
+        }
+    });
+
+    // Length check
+    if (CFDataGetLength(alpnData) > 255) {
+        CFRelease(alpnData);
+        return errSecParam;
+    }
+
+    // Pass the buffer down to coreTLS
+    tls_buffer payload;
+    payload.data = (uint8_t *) CFDataGetBytePtr(alpnData);
+    payload.length = CFDataGetLength(alpnData);
+    int success = tls_handshake_set_alpn_data(context->hdsk, payload);
+
+    // Free up memory and return
+    CFRelease(alpnData);
+
+    return success;
+}
 
 
-    if(alpn_data) {
-        *length = alpn_data->length;
-        return alpn_data->data;
+OSStatus
+SSLCopyALPNProtocols(SSLContextRef      context,
+                     CFArrayRef         *protocolArray)
+{
+    if (context == NULL || protocolArray == NULL) {
+        return errSecParam;
+    }
+
+    CFMutableArrayRef array = CFArrayCreateMutableForCFTypes(NULL);
+
+    const tls_buffer *alpnData = tls_handshake_get_peer_alpn_data(context->hdsk);
+    if (alpnData) {
+        size_t offset = 0;
+
+        // Extract each encoded parameter, wrap it in a CFStringRef, and append it to the running list
+        while (offset < alpnData->length) {
+            char length = alpnData->data[offset];
+            offset++;
+
+            // Make sure we don't exceed the buffer bounds
+            if (offset + length > alpnData->length) {
+                CFReleaseNull(array);
+                *protocolArray = NULL;
+                return errSecParam;
+            }
+
+            CFStringRef protocol = CFStringCreateWithBytes(NULL, alpnData->data + offset, length, kCFStringEncodingASCII, false);
+            offset += length;
+            CFArrayAppendValue(array, protocol);
+            CFReleaseNull(protocol);
+
+            // Sanity check
+            if (offset > alpnData->length) {
+                CFReleaseNull(array);
+                *protocolArray = NULL;
+                return errSecParam;
+            }
+        }
+
+        *protocolArray = array;
+        return errSecSuccess;
     } else {
     } else {
-        return NULL;
+        CFReleaseNull(array);
+        *protocolArray = NULL;
+        return errSecParam;
     }
 }
 
 // ALPN end
 
     }
 }
 
 // ALPN end
 
+// OCSP response begin
+
+OSStatus
+SSLSetOCSPResponse(SSLContextRef      context,
+                   CFDataRef          response)
+{
+    if (context == NULL || response == NULL) {
+        return errSecParam;
+    }
+
+    tls_buffer responsePayload;
+    responsePayload.data = (uint8_t *) CFDataGetBytePtr(response);
+    responsePayload.length = CFDataGetLength(response);
+
+    int success = tls_handshake_set_ocsp_response(context->hdsk, &responsePayload);
+    return success;
+}
+
+// OCSP response end
+
 OSStatus
 SSLSetConnection                       (SSLContextRef          ctx,
                                                         SSLConnectionRef       connection)
 OSStatus
 SSLSetConnection                       (SSLContextRef          ctx,
                                                         SSLConnectionRef       connection)
@@ -1053,12 +1195,12 @@ SSLSetProtocolVersionMax  (SSLContextRef      ctx,
         if (version > MINIMUM_DATAGRAM_VERSION ||
             version < MAXIMUM_DATAGRAM_VERSION)
             return errSSLIllegalParam;
         if (version > MINIMUM_DATAGRAM_VERSION ||
             version < MAXIMUM_DATAGRAM_VERSION)
             return errSSLIllegalParam;
-        if (version > ctx->minProtocolVersion)
+        if (version > (SSLProtocolVersion)ctx->minProtocolVersion)
             ctx->minProtocolVersion = version;
     } else {
         if (version < MINIMUM_STREAM_VERSION || version > MAXIMUM_STREAM_VERSION)
             return errSSLIllegalParam;
             ctx->minProtocolVersion = version;
     } else {
         if (version < MINIMUM_STREAM_VERSION || version > MAXIMUM_STREAM_VERSION)
             return errSSLIllegalParam;
-        if (version < ctx->minProtocolVersion)
+        if (version < (SSLProtocolVersion)ctx->minProtocolVersion)
             ctx->minProtocolVersion = version;
     }
     ctx->maxProtocolVersion = version;
             ctx->minProtocolVersion = version;
     }
     ctx->maxProtocolVersion = version;
@@ -1079,6 +1221,49 @@ SSLGetProtocolVersionMax  (SSLContextRef      ctx,
     return errSecSuccess;
 }
 
     return errSecSuccess;
 }
 
+tls_protocol_version
+_SSLProtocolVersionToWireFormatValue   (SSLProtocol protocol)
+{
+    switch (protocol) {
+        case kSSLProtocol3: {
+            return tls_protocol_version_SSL_3;
+        }
+        case kTLSProtocol1: {
+            return tls_protocol_version_TLS_1_0;
+        }
+        case kTLSProtocol11: {
+            return tls_protocol_version_TLS_1_1;
+        }
+        case kTLSProtocol12: {
+            return tls_protocol_version_TLS_1_2;
+        }
+        case kTLSProtocol13: {
+            return tls_protocol_version_TLS_1_3;
+        }
+        case kTLSProtocolMaxSupported: {
+            return tls_protocol_version_TLS_1_3;
+        }
+        case kDTLSProtocol1: {
+            return tls_protocol_version_DTLS_1_0;
+        }
+        case kDTLSProtocol12: {
+            return tls_protocol_version_DTLS_1_2;
+        }
+        case kSSLProtocolUnknown: {
+            return tls_protocol_version_Undertermined;
+        }
+        case kSSLProtocol2:
+        case kSSLProtocol3Only:
+        case kTLSProtocol1Only:
+        case kSSLProtocolAll: {
+            sslErrorLog("SSLProtocol %d is deprecated. Setting to the default value (%d)", protocol, tls_protocol_version_Undertermined);
+            return tls_protocol_version_Undertermined;
+        }
+    }
+
+    return tls_protocol_version_Undertermined;
+}
+
 #define max(x,y) ((x)<(y)?(y):(x))
 
 OSStatus
 #define max(x,y) ((x)<(y)?(y):(x))
 
 OSStatus
@@ -1107,12 +1292,12 @@ SSLSetProtocolVersionEnabled(SSLContextRef     ctx,
                        if (version < MINIMUM_STREAM_VERSION || version > MAXIMUM_STREAM_VERSION) {
                                return errSecParam;
                        }
                        if (version < MINIMUM_STREAM_VERSION || version > MAXIMUM_STREAM_VERSION) {
                                return errSecParam;
                        }
-            if (version > ctx->maxProtocolVersion) {
+            if (version > (SSLProtocolVersion)ctx->maxProtocolVersion) {
                 ctx->maxProtocolVersion = version;
                 if (ctx->minProtocolVersion == SSL_Version_Undetermined)
                     ctx->minProtocolVersion = version;
             }
                 ctx->maxProtocolVersion = version;
                 if (ctx->minProtocolVersion == SSL_Version_Undetermined)
                     ctx->minProtocolVersion = version;
             }
-            if (version < ctx->minProtocolVersion) {
+            if (version < (SSLProtocolVersion)ctx->minProtocolVersion) {
                 ctx->minProtocolVersion = version;
             }
         } else {
                 ctx->minProtocolVersion = version;
             }
         } else {
@@ -1142,7 +1327,7 @@ SSLSetProtocolVersionEnabled(SSLContextRef     ctx,
                                        nextVersion = SSL_Version_Undetermined;
                                        break;
                        }
                                        nextVersion = SSL_Version_Undetermined;
                                        break;
                        }
-                       ctx->minProtocolVersion = max(ctx->minProtocolVersion, nextVersion);
+                       ctx->minProtocolVersion = (tls_protocol_version)max((SSLProtocolVersion)ctx->minProtocolVersion, nextVersion);
                        if (ctx->minProtocolVersion > ctx->maxProtocolVersion) {
                                ctx->minProtocolVersion = SSL_Version_Undetermined;
                                ctx->maxProtocolVersion = SSL_Version_Undetermined;
                        if (ctx->minProtocolVersion > ctx->maxProtocolVersion) {
                                ctx->minProtocolVersion = SSL_Version_Undetermined;
                                ctx->maxProtocolVersion = SSL_Version_Undetermined;
@@ -1176,8 +1361,8 @@ SSLGetProtocolVersionEnabled(SSLContextRef                ctx,
         case kTLSProtocol12:
         {
             SSLProtocolVersion version = SSLProtocolToProtocolVersion(protocol);
         case kTLSProtocol12:
         {
             SSLProtocolVersion version = SSLProtocolToProtocolVersion(protocol);
-                       *enable = (ctx->minProtocolVersion <= version
-                       && ctx->maxProtocolVersion >= version);
+                       *enable = ((SSLProtocolVersion)ctx->minProtocolVersion <= version
+                       && (SSLProtocolVersion)ctx->maxProtocolVersion >= version);
                        break;
         }
                case kSSLProtocolAll:
                        break;
         }
                case kSSLProtocolAll:
@@ -1331,56 +1516,32 @@ OSStatus
 SSLSetAllowsExpiredCerts(SSLContextRef         ctx,
                                                 Boolean                        allowExpired)
 {
 SSLSetAllowsExpiredCerts(SSLContextRef         ctx,
                                                 Boolean                        allowExpired)
 {
-       if(ctx == NULL) {
-               return errSecParam;
-       }
-       sslCertDebug("SSLSetAllowsExpiredCerts %s",
-               allowExpired ? "true" : "false");
-       if(sslIsSessionActive(ctx)) {
-               /* can't do this with an active session */
-               return errSecBadReq;
-       }
-       ctx->allowExpiredCerts = allowExpired;
-       return errSecSuccess;
+    /* This has been deprecated since 10.9, and non-functional since at least 10.10 */
+    return 0;
 }
 
 OSStatus
 SSLGetAllowsExpiredCerts       (SSLContextRef          ctx,
                                                         Boolean                        *allowExpired)
 {
 }
 
 OSStatus
 SSLGetAllowsExpiredCerts       (SSLContextRef          ctx,
                                                         Boolean                        *allowExpired)
 {
-       if(ctx == NULL) {
-               return errSecParam;
-       }
-       *allowExpired = ctx->allowExpiredCerts;
-       return errSecSuccess;
+    /* This has been deprecated since 10.9, and non-functional since at least 10.10 */
+    return errSecUnimplemented;
 }
 
 OSStatus
 SSLSetAllowsExpiredRoots(SSLContextRef         ctx,
                                                 Boolean                        allowExpired)
 {
 }
 
 OSStatus
 SSLSetAllowsExpiredRoots(SSLContextRef         ctx,
                                                 Boolean                        allowExpired)
 {
-       if(ctx == NULL) {
-               return errSecParam;
-       }
-       sslCertDebug("SSLSetAllowsExpiredRoots %s",
-               allowExpired ? "true" : "false");
-       if(sslIsSessionActive(ctx)) {
-               /* can't do this with an active session */
-               return errSecBadReq;
-       }
-       ctx->allowExpiredRoots = allowExpired;
-       return errSecSuccess;
+    /* This has been deprecated since 10.9, and non-functional since at least 10.10 */
+    return 0;
 }
 
 OSStatus
 SSLGetAllowsExpiredRoots       (SSLContextRef          ctx,
                                                         Boolean                        *allowExpired)
 {
 }
 
 OSStatus
 SSLGetAllowsExpiredRoots       (SSLContextRef          ctx,
                                                         Boolean                        *allowExpired)
 {
-       if(ctx == NULL) {
-               return errSecParam;
-       }
-       *allowExpired = ctx->allowExpiredRoots;
-       return errSecSuccess;
+    /* This has been deprecated since 10.9, and non-functional since at least 10.10 */
+    return errSecUnimplemented;
 }
 
 OSStatus SSLSetAllowsAnyRoot(
 }
 
 OSStatus SSLSetAllowsAnyRoot(
@@ -1474,7 +1635,7 @@ SSLCopyTrustedRoots                       (SSLContextRef          ctx,
                CFRetain(ctx->trustedCerts);
                return errSecSuccess;
        }
                CFRetain(ctx->trustedCerts);
                return errSecSuccess;
        }
-#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
+#if TARGET_OS_OSX
        /* use default system roots */
     return sslDefaultSystemRoots(ctx, trustedRoots);
 #else
        /* use default system roots */
     return sslDefaultSystemRoots(ctx, trustedRoots);
 #else
@@ -1483,6 +1644,7 @@ SSLCopyTrustedRoots                       (SSLContextRef          ctx,
 #endif
 }
 
 #endif
 }
 
+#if !TARGET_OS_IPHONE
 OSStatus
 SSLSetTrustedLeafCertificates  (SSLContextRef          ctx,
                                                                 CFArrayRef             trustedCerts)
 OSStatus
 SSLSetTrustedLeafCertificates  (SSLContextRef          ctx,
                                                                 CFArrayRef             trustedCerts)
@@ -1498,8 +1660,7 @@ SSLSetTrustedLeafCertificates     (SSLContextRef          ctx,
        if(ctx->trustedLeafCerts) {
                CFRelease(ctx->trustedLeafCerts);
        }
        if(ctx->trustedLeafCerts) {
                CFRelease(ctx->trustedLeafCerts);
        }
-       ctx->trustedLeafCerts = trustedCerts;
-       CFRetain(trustedCerts);
+       ctx->trustedLeafCerts = CFRetainSafe(trustedCerts);
        return errSecSuccess;
 }
 
        return errSecSuccess;
 }
 
@@ -1518,6 +1679,7 @@ SSLCopyTrustedLeafCertificates    (SSLContextRef          ctx,
        *trustedCerts = NULL;
        return errSecSuccess;
 }
        *trustedCerts = NULL;
        return errSecSuccess;
 }
+#endif
 
 OSStatus
 SSLSetClientSideAuthenticate   (SSLContext                     *ctx,
 
 OSStatus
 SSLSetClientSideAuthenticate   (SSLContext                     *ctx,
@@ -1568,7 +1730,7 @@ SSLGetClientCertificateState      (SSLContextRef                          ctx,
                *clientState = kSSLClientCertNone;
                break;
            case kSSLClientCertRequested:
                *clientState = kSSLClientCertNone;
                break;
            case kSSLClientCertRequested:
-               if(ctx->localCert) {
+               if(ctx->localCertArray) {
                    *clientState = kSSLClientCertSent;
                } else {
                    *clientState = kSSLClientCertRequested;
                    *clientState = kSSLClientCertSent;
                } else {
                    *clientState = kSSLClientCertRequested;
@@ -1587,7 +1749,7 @@ SSLGetClientCertificateState      (SSLContextRef                          ctx,
                 *clientState = ctx->clientCertState;
                 break;
             case kSSLClientCertRequested:
                 *clientState = ctx->clientCertState;
                 break;
             case kSSLClientCertRequested:
-                if(ctx->peerCert) {
+                if(ctx->peerSecTrust) {
                     *clientState = kSSLClientCertSent;
                 } else {
                     *clientState = kSSLClientCertRequested;
                     *clientState = kSSLClientCertSent;
                 } else {
                     *clientState = kSSLClientCertRequested;
@@ -1602,10 +1764,13 @@ SSLGetClientCertificateState    (SSLContextRef                          ctx,
        return errSecSuccess;
 }
 
        return errSecSuccess;
 }
 
+#include <tls_helpers.h>
+
 OSStatus
 SSLSetCertificate                      (SSLContextRef          ctx,
 OSStatus
 SSLSetCertificate                      (SSLContextRef          ctx,
-                                                        CFArrayRef                     certRefs)
+                                                        CFArrayRef                     _Nullable certRefs)
 {
 {
+    OSStatus ortn;
        /*
         * -- free localCerts if we have any
         * -- Get raw cert data, convert to ctx->localCert
        /*
         * -- free localCerts if we have any
         * -- Get raw cert data, convert to ctx->localCert
@@ -1617,23 +1782,17 @@ SSLSetCertificate                       (SSLContextRef          ctx,
        }
 
     CFReleaseNull(ctx->localCertArray);
        }
 
     CFReleaseNull(ctx->localCertArray);
-       /* changing the client cert invalidates negotiated auth type */
-       ctx->negAuthType = SSLClientAuthNone;
        if(certRefs == NULL) {
                return errSecSuccess; // we have cleared the cert, as requested
        }
        if(certRefs == NULL) {
                return errSecSuccess; // we have cleared the cert, as requested
        }
-    sslFreeLocalCert(ctx);
-       OSStatus ortn = parseIncomingCerts(ctx,
-               certRefs,
-               &ctx->localCert,
-        &ctx->signingPrivKeyRef);
-    if(ortn == errSecSuccess) {
-               ctx->localCertArray = certRefs;
-               CFRetain(certRefs);
-        if(ctx->protocolSide==kSSLClientSide)
-            SSLUpdateNegotiatedClientAuthType(ctx);
-        tls_handshake_set_identity(ctx->hdsk, ctx->localCert, ctx->signingPrivKeyRef);
+
+    ortn = tls_helper_set_identity_from_array(ctx->hdsk, certRefs);
+
+    if(ortn == noErr) {
+        ctx->localCertArray = certRefs;
+        CFRetain(certRefs);
     }
     }
+
        return ortn;
 }
 
        return ortn;
 }
 
@@ -1931,46 +2090,34 @@ SSLCopyDistinguishedNames       (SSLContextRef          ctx,
 /*
  * Request peer certificates. Valid anytime, subsequent to
  * a handshake attempt.
 /*
  * Request peer certificates. Valid anytime, subsequent to
  * a handshake attempt.
- * Common code for SSLGetPeerCertificates() and SSLCopyPeerCertificates().
- * TODO: the 'legacy' argument is not used anymore.
  */
  */
-static OSStatus
-sslCopyPeerCertificates                (SSLContextRef          ctx,
-                                                        CFArrayRef                     *certs,
-                                                        Boolean                        legacy)
+OSStatus
+SSLCopyPeerCertificates        (SSLContextRef ctx, CFArrayRef *certs)
 {
        if(ctx == NULL) {
                return errSecParam;
        }
 
 {
        if(ctx == NULL) {
                return errSecParam;
        }
 
-       if (!ctx->peerCert) {
+       if (!ctx->peerSecTrust) {
                *certs = NULL;
                return errSecBadReq;
        }
 
                *certs = NULL;
                return errSecBadReq;
        }
 
-    CFArrayRef ca = CFArrayCreateCopy(kCFAllocatorDefault, ctx->peerCert);
-    *certs = ca;
+    CFIndex count = SecTrustGetCertificateCount(ctx->peerSecTrust);
+    CFMutableArrayRef ca = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks);
     if (ca == NULL) {
         return errSecAllocate;
     }
 
     if (ca == NULL) {
         return errSecAllocate;
     }
 
-       if (legacy) {
-               CFIndex ix, count = CFArrayGetCount(ca);
-               for (ix = 0; ix < count; ++ix) {
-                       CFRetain(CFArrayGetValueAtIndex(ca, ix));
-               }
-       }
+    for (CFIndex ix = 0; ix < count; ++ix) {
+        CFArrayAppendValue(ca, SecTrustGetCertificateAtIndex(ctx->peerSecTrust, ix));
+    }
 
 
+    *certs = ca;
+    
        return errSecSuccess;
 }
 
        return errSecSuccess;
 }
 
-OSStatus
-SSLCopyPeerCertificates                (SSLContextRef          ctx,
-                                                        CFArrayRef                     *certs)
-{
-       return sslCopyPeerCertificates(ctx, certs, false);
-}
-
 #if !TARGET_OS_IPHONE
 // Permanently removing from iOS, keep for OSX (deprecated), removed from headers.
 // <rdar://problem/14215831> Mailsmith Crashes While Getting New Mail Under Mavericks Developer Preview
 #if !TARGET_OS_IPHONE
 // Permanently removing from iOS, keep for OSX (deprecated), removed from headers.
 // <rdar://problem/14215831> Mailsmith Crashes While Getting New Mail Under Mavericks Developer Preview
@@ -1981,7 +2128,7 @@ OSStatus
 SSLGetPeerCertificates (SSLContextRef ctx,
                         CFArrayRef *certs)
 {
 SSLGetPeerCertificates (SSLContextRef ctx,
                         CFArrayRef *certs)
 {
-    return sslCopyPeerCertificates(ctx, certs, true);
+    return errSecUnimplemented;
 }
 #endif
 
 }
 #endif
 
@@ -2105,12 +2252,8 @@ SSLCopyPeerTrust(
 
        /* Create a SecTrustRef if this was a resumed session and we
           didn't have one yet. */
 
        /* Create a SecTrustRef if this was a resumed session and we
           didn't have one yet. */
-    if (!ctx->peerCert) {
-        ctx->peerCert = tls_get_peer_certs(tls_handshake_get_peer_certificates(ctx->hdsk));
-    }
-       if (!ctx->peerSecTrust && ctx->peerCert) {
-               status = sslCreateSecTrust(ctx, ctx->peerCert,
-                       &ctx->peerSecTrust);
+       if (!ctx->peerSecTrust) {
+               status = sslCreateSecTrust(ctx, &ctx->peerSecTrust);
     }
 
        *trust = ctx->peerSecTrust;
     }
 
        *trust = ctx->peerSecTrust;
@@ -2130,9 +2273,8 @@ OSStatus SSLGetPeerSecTrust(
 
        /* Create a SecTrustRef if this was a resumed session and we
           didn't have one yet. */
 
        /* Create a SecTrustRef if this was a resumed session and we
           didn't have one yet. */
-       if (!ctx->peerSecTrust && ctx->peerCert) {
-               status = sslCreateSecTrust(ctx, ctx->peerCert,
-                       &ctx->peerSecTrust);
+       if (!ctx->peerSecTrust) {
+               status = sslCreateSecTrust(ctx, &ctx->peerSecTrust);
     }
 
        *trust = ctx->peerSecTrust;
     }
 
        *trust = ctx->peerSecTrust;
@@ -2376,8 +2518,11 @@ OSStatus SSLGetECDSACurves(
        if(*numCurves < ctx->ecdhNumCurves) {
                return errSecParam;
        }
        if(*numCurves < ctx->ecdhNumCurves) {
                return errSecParam;
        }
-       memmove(namedCurves, ctx->ecdhCurves,
-               (ctx->ecdhNumCurves * sizeof(SSL_ECDSA_NamedCurve)));
+       static_assert(sizeof(*namedCurves) >= sizeof(*(ctx->ecdhCurves)),
+               "SSL_ECDSA_NamedCurve must be large enough for SSLContext ecdhCurves.");
+       for (unsigned i = 0; i < ctx->ecdhNumCurves; i++) {
+               namedCurves[i] = ctx->ecdhCurves[i];
+       }
        *numCurves = ctx->ecdhNumCurves;
        return errSecSuccess;
 }
        *numCurves = ctx->ecdhNumCurves;
        return errSecSuccess;
 }
@@ -2398,20 +2543,26 @@ OSStatus SSLSetECDSACurves(
                return errSecBadReq;
        }
 
                return errSecBadReq;
        }
 
-       size_t size = numCurves * sizeof(uint16_t);
-       ctx->ecdhCurves = (uint16_t *)sslMalloc(size);
+       if (SIZE_MAX / sizeof(*(ctx->ecdhCurves)) < (size_t)numCurves) {
+               return errSecParam;
+       }
+       ctx->ecdhCurves = sslMalloc((size_t)numCurves * sizeof(*(ctx->ecdhCurves)));
        if(ctx->ecdhCurves == NULL) {
                ctx->ecdhNumCurves = 0;
                return errSecAllocate;
        }
 
        if(ctx->ecdhCurves == NULL) {
                ctx->ecdhNumCurves = 0;
                return errSecAllocate;
        }
 
-    for (unsigned i=0; i<numCurves; i++) {
-        ctx->ecdhCurves[i] = namedCurves[i];
-    }
+       for (unsigned i=0; i<numCurves; i++) {
+               if (namedCurves[i] > UINT16_MAX - 1) {
+                       ctx->ecdhCurves[i] = SSL_Curve_None;
+                       continue;
+               }
+               ctx->ecdhCurves[i] = namedCurves[i];
+       }
 
        ctx->ecdhNumCurves = numCurves;
 
 
        ctx->ecdhNumCurves = numCurves;
 
-    tls_handshake_set_curves(ctx->hdsk, ctx->ecdhCurves, ctx->ecdhNumCurves);
+       tls_handshake_set_curves(ctx->hdsk, ctx->ecdhCurves, ctx->ecdhNumCurves);
        return errSecSuccess;
 }
 
        return errSecSuccess;
 }
 
@@ -2454,92 +2605,13 @@ OSStatus SSLGetClientAuthTypes(
 }
 
 /*
 }
 
 /*
- * Obtain the SSLClientAuthenticationType actually performed.
- * Only valid if client certificate state is kSSLClientCertSent
- * or kSSLClientCertRejected; returns errSecParam otherwise.
+ * -- DEPRECATED -- Return errSecUnimplemented.
  */
 OSStatus SSLGetNegotiatedClientAuthType(
    SSLContextRef ctx,
    SSLClientAuthenticationType *authType)              /* RETURNED */
 {
  */
 OSStatus SSLGetNegotiatedClientAuthType(
    SSLContextRef ctx,
    SSLClientAuthenticationType *authType)              /* RETURNED */
 {
-       if(ctx == NULL) {
-               return errSecParam;
-       }
-
-       *authType = ctx->negAuthType;
-
-       return errSecSuccess;
-}
-
-/*
- * Update the negotiated client authentication type.
- * This function may be called at any time; however, note that
- * the negotiated authentication type will be SSLClientAuthNone
- * until both of the following have taken place (in either order):
- *   - a CertificateRequest message from the server has been processed
- *   - a client certificate has been specified
- * As such, this function (only) needs to be called from (both)
- * SSLProcessCertificateRequest and SSLSetCertificate.
- */
-OSStatus SSLUpdateNegotiatedClientAuthType(
-       SSLContextRef ctx)
-{
-       if(ctx == NULL) {
-               return errSecParam;
-       }
-    assert(ctx->protocolSide==kSSLClientSide);
-       /*
-        * See if we have a signing cert that matches one of the
-        * allowed auth types. The x509Requested flag indicates "we
-        * have a cert that we think the server will accept".
-        */
-       ctx->x509Requested = 0;
-       ctx->negAuthType = SSLClientAuthNone;
-       if(ctx->signingPrivKeyRef != NULL) {
-        CFIndex ourKeyAlg = sslPrivKeyGetAlgorithmID((SecKeyRef)tls_private_key_get_context(ctx->signingPrivKeyRef));
-
-               unsigned i;
-               for(i=0; i<ctx->numAuthTypes; i++) {
-                       switch(ctx->clientAuthTypes[i]) {
-                               case SSLClientAuth_RSASign:
-                                       if(ourKeyAlg == kSecRSAAlgorithmID) {
-                                               ctx->x509Requested = 1;
-                                               ctx->negAuthType = SSLClientAuth_RSASign;
-                                       }
-                                       break;
-                               case SSLClientAuth_ECDSASign:
-                       #if SSL_ENABLE_ECDSA_FIXED_ECDH_AUTH
-                               case SSLClientAuth_ECDSAFixedECDH:
-                       #endif
-                    if(ourKeyAlg == kSecECDSAAlgorithmID) {
-                                               ctx->x509Requested = 1;
-                                               ctx->negAuthType = ctx->clientAuthTypes[i];
-                                       }
-                                       break;
-                       #if SSL_ENABLE_RSA_FIXED_ECDH_AUTH
-                               case SSLClientAuth_RSAFixedECDH:
-                                       /* Odd case, we differ from our signer */
-                                       if((ourKeyAlg == kSecECDSAAlgorithmID) &&
-                                          (ctx->ourSignerAlg == kSecRSAAlgorithmID)) {
-                                               ctx->x509Requested = 1;
-                                               ctx->negAuthType = SSLClientAuth_RSAFixedECDH;
-                                       }
-                                       break;
-                       #endif
-                               default:
-                                       /* None others supported */
-                                       break;
-                       }
-                       if(ctx->x509Requested) {
-                               sslLogNegotiateDebug("===CHOOSING authType %d", (int)ctx->negAuthType);
-                               break;
-                       }
-               }       /* parsing authTypes */
-       }       /* we have a signing key */
-
-    tls_handshake_set_client_auth_type(ctx->hdsk, ctx->negAuthType);
-
-       return errSecSuccess;
+    return errSecUnimplemented;
 }
 
 OSStatus SSLGetNumberOfSignatureAlgorithms(
 }
 
 OSStatus SSLGetNumberOfSignatureAlgorithms(
@@ -2642,14 +2714,6 @@ OSStatus SSLInternal_PRF(
                                       vout, outLen);
 }
 
                                       vout, outLen);
 }
 
-/* To be implemented */
-OSStatus
-SSLSetSessionStrengthPolicy(SSLContextRef context,
-                            SSLSessionStrengthPolicy policyStrength)
-{
-    return errSecSuccess;
-}
-
 const CFStringRef kSSLSessionConfig_default = CFSTR("default");
 const CFStringRef kSSLSessionConfig_ATSv1 = CFSTR("ATSv1");
 const CFStringRef kSSLSessionConfig_ATSv1_noPFS = CFSTR("ATSv1_noPFS");
 const CFStringRef kSSLSessionConfig_default = CFSTR("default");
 const CFStringRef kSSLSessionConfig_ATSv1 = CFSTR("ATSv1");
 const CFStringRef kSSLSessionConfig_ATSv1_noPFS = CFSTR("ATSv1_noPFS");
@@ -2659,61 +2723,43 @@ const CFStringRef kSSLSessionConfig_RC4_fallback = CFSTR("RC4_fallback");
 const CFStringRef kSSLSessionConfig_TLSv1_fallback = CFSTR("TLSv1_fallback");
 const CFStringRef kSSLSessionConfig_TLSv1_RC4_fallback = CFSTR("TLSv1_RC4_fallback");
 const CFStringRef kSSLSessionConfig_legacy_DHE = CFSTR("legacy_DHE");
 const CFStringRef kSSLSessionConfig_TLSv1_fallback = CFSTR("TLSv1_fallback");
 const CFStringRef kSSLSessionConfig_TLSv1_RC4_fallback = CFSTR("TLSv1_RC4_fallback");
 const CFStringRef kSSLSessionConfig_legacy_DHE = CFSTR("legacy_DHE");
+const CFStringRef kSSLSessionConfig_anonymous = CFSTR("anonymous");
+const CFStringRef kSSLSessionConfig_3DES_fallback = CFSTR("3DES_fallback");
+const CFStringRef kSSLSessionConfig_TLSv1_3DES_fallback = CFSTR("TLSv1_3DES_fallback");
+
 
 static
 tls_handshake_config_t SSLSessionConfig_to_tls_handshake_config(CFStringRef config)
 {
     if(CFEqual(config, kSSLSessionConfig_ATSv1)){
         return tls_handshake_config_ATSv1;
 
 static
 tls_handshake_config_t SSLSessionConfig_to_tls_handshake_config(CFStringRef config)
 {
     if(CFEqual(config, kSSLSessionConfig_ATSv1)){
         return tls_handshake_config_ATSv1;
-    } else  if(CFEqual(config, kSSLSessionConfig_ATSv1_noPFS)){
+    } else if(CFEqual(config, kSSLSessionConfig_ATSv1_noPFS)){
         return tls_handshake_config_ATSv1_noPFS;
         return tls_handshake_config_ATSv1_noPFS;
-    } else  if(CFEqual(config, kSSLSessionConfig_standard)){
+    } else if(CFEqual(config, kSSLSessionConfig_standard)){
         return tls_handshake_config_standard;
         return tls_handshake_config_standard;
-    } else  if(CFEqual(config, kSSLSessionConfig_TLSv1_fallback)){
+    } else if(CFEqual(config, kSSLSessionConfig_TLSv1_fallback)){
         return tls_handshake_config_TLSv1_fallback;
         return tls_handshake_config_TLSv1_fallback;
-    } else  if(CFEqual(config, kSSLSessionConfig_TLSv1_RC4_fallback)){
+    } else if(CFEqual(config, kSSLSessionConfig_TLSv1_RC4_fallback)){
         return tls_handshake_config_TLSv1_RC4_fallback;
         return tls_handshake_config_TLSv1_RC4_fallback;
-    } else  if(CFEqual(config, kSSLSessionConfig_RC4_fallback)){
+    } else if(CFEqual(config, kSSLSessionConfig_RC4_fallback)){
         return tls_handshake_config_RC4_fallback;
         return tls_handshake_config_RC4_fallback;
-    } else  if(CFEqual(config, kSSLSessionConfig_legacy)){
+    } else if(CFEqual(config, kSSLSessionConfig_3DES_fallback)){
+        return tls_handshake_config_3DES_fallback;
+    } else if(CFEqual(config, kSSLSessionConfig_TLSv1_3DES_fallback)){
+        return tls_handshake_config_TLSv1_3DES_fallback;
+    } else if(CFEqual(config, kSSLSessionConfig_legacy)){
         return tls_handshake_config_legacy;
         return tls_handshake_config_legacy;
-    } else  if(CFEqual(config, kSSLSessionConfig_legacy_DHE)){
+    } else if(CFEqual(config, kSSLSessionConfig_legacy_DHE)){
         return tls_handshake_config_legacy_DHE;
         return tls_handshake_config_legacy_DHE;
-    } else  if(CFEqual(config, kSSLSessionConfig_default)){
+    } else if(CFEqual(config, kSSLSessionConfig_anonymous)){
+        return tls_handshake_config_anonymous;
+    } else if(CFEqual(config, kSSLSessionConfig_default)){
         return tls_handshake_config_default;
     } else {
         return tls_handshake_config_none;
     }
 }
 
         return tls_handshake_config_default;
     } else {
         return tls_handshake_config_none;
     }
 }
 
-static
-const CFStringRef tls_handshake_config_to_SSLSessionConfig(tls_handshake_config_t config)
-{
-    switch(config) {
-        case tls_handshake_config_ATSv1:
-            return kSSLSessionConfig_ATSv1;
-        case tls_handshake_config_ATSv1_noPFS:
-            return kSSLSessionConfig_ATSv1_noPFS;
-        case tls_handshake_config_standard:
-            return kSSLSessionConfig_standard;
-        case tls_handshake_config_RC4_fallback:
-            return kSSLSessionConfig_RC4_fallback;
-        case tls_handshake_config_TLSv1_fallback:
-            return kSSLSessionConfig_TLSv1_fallback;
-        case tls_handshake_config_TLSv1_RC4_fallback:
-            return kSSLSessionConfig_TLSv1_RC4_fallback;
-        case tls_handshake_config_legacy:
-            return kSSLSessionConfig_legacy;
-        case tls_handshake_config_legacy_DHE:
-            return kSSLSessionConfig_legacy_DHE;
-        case tls_handshake_config_default:
-            return kSSLSessionConfig_default;
-        case tls_handshake_config_none:
-            return NULL;
-    }
-}
-
-
 /* Set Predefined TLS Configuration */
 OSStatus
 SSLSetSessionConfig(SSLContextRef context,
 /* Set Predefined TLS Configuration */
 OSStatus
 SSLSetSessionConfig(SSLContextRef context,
@@ -2728,17 +2774,77 @@ SSLSetSessionConfig(SSLContextRef context,
 }
 
 OSStatus
 }
 
 OSStatus
-SSLGetSessionConfig(SSLContextRef context,
-                    CFStringRef *config)
+SSLGetSessionConfigurationIdentifier(SSLContext *ctx, SSLBuffer *buffer)
 {
 {
-    tls_handshake_config_t cfg;
-    OSStatus err = tls_handshake_get_config(context->hdsk, &cfg);
-    if(err) {
-        return err;
+    if (buffer == NULL) {
+        return errSecParam;
     }
 
     }
 
-    *config =  tls_handshake_config_to_SSLSessionConfig(cfg);
+    // Don't recompute the buffer if we've done it before and cached the result.
+    // Just copy out the result.
+    if (ctx->contextConfigurationBuffer.data != NULL) {
+        buffer->length = ctx->contextConfigurationBuffer.length;
+        buffer->data = (uint8_t *) malloc(buffer->length);
+        if (buffer->data == NULL) {
+            return errSecAllocate;
+        }
+        memcpy(buffer->data, ctx->contextConfigurationBuffer.data, buffer->length);
+        return errSecSuccess;
+    }
 
 
-    return noErr;
-}
+    // Allocate the buffer, freeing up any data that was previously stored
+    // 10 here is the number of attributes we're adding below. Change it as needed.
+    buffer->length = 10 * sizeof(Boolean);
+    if (buffer->data) {
+        free(buffer->data);
+    }
+    buffer->data = malloc(buffer->length);
+    if (buffer->data == NULL) {
+        return errSecAllocate;
+    }
+
+    // Copy in the session configuration options
+    int offset = 0;
+    memcpy(buffer->data + offset, &ctx->breakOnServerAuth, sizeof(ctx->breakOnServerAuth));
+    offset += sizeof(ctx->breakOnServerAuth);
+
+    memcpy(buffer->data + offset, &ctx->breakOnCertRequest, sizeof(ctx->breakOnCertRequest));
+    offset += sizeof(ctx->breakOnCertRequest);
+
+    memcpy(buffer->data + offset, &ctx->breakOnClientAuth, sizeof(ctx->breakOnClientAuth));
+    offset += sizeof(ctx->breakOnClientAuth);
+
+    memcpy(buffer->data + offset, &ctx->signalServerAuth, sizeof(ctx->signalServerAuth));
+    offset += sizeof(ctx->signalServerAuth);
+
+    memcpy(buffer->data + offset, &ctx->signalCertRequest, sizeof(ctx->signalCertRequest));
+    offset += sizeof(ctx->signalCertRequest);
+
+    memcpy(buffer->data + offset, &ctx->signalClientAuth, sizeof(ctx->signalClientAuth));
+    offset += sizeof(ctx->signalClientAuth);
+
+    memcpy(buffer->data + offset, &ctx->breakOnClientHello, sizeof(ctx->breakOnClientHello));
+    offset += sizeof(ctx->breakOnClientHello);
 
 
+    memcpy(buffer->data + offset, &ctx->allowServerIdentityChange, sizeof(ctx->allowServerIdentityChange));
+    offset += sizeof(ctx->allowServerIdentityChange);
+
+    memcpy(buffer->data + offset, &ctx->allowRenegotiation, sizeof(ctx->allowRenegotiation));
+    offset += sizeof(ctx->allowRenegotiation);
+
+    memcpy(buffer->data + offset, &ctx->enableSessionTickets, sizeof(ctx->enableSessionTickets));
+    offset += sizeof(ctx->enableSessionTickets);
+
+    // Sanity check on the length
+    if (offset != buffer->length) {
+        free(buffer->data);
+        return errSecInternal;
+    }
+
+    // Save the configuration buffer for later use
+    ctx->contextConfigurationBuffer.length = buffer->length;
+    ctx->contextConfigurationBuffer.data = (uint8_t *) malloc(buffer->length);
+    memcpy(ctx->contextConfigurationBuffer.data, buffer->data, buffer->length);
+
+    return errSecSuccess;
+}