X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5c19dc3ae3bd8e40a9c028b0deddd50ff337692c..7e6b461318c8a779d91381531435a68ee4e8b6ed:/OSX/libsecurity_ssl/lib/sslContext.c?ds=sidebyside diff --git a/OSX/libsecurity_ssl/lib/sslContext.c b/OSX/libsecurity_ssl/lib/sslContext.c index eb3d0ae3..fc1826fe 100644 --- a/OSX/libsecurity_ssl/lib/sslContext.c +++ b/OSX/libsecurity_ssl/lib/sslContext.c @@ -29,7 +29,6 @@ #include "SSLRecordInternal.h" #include "SecureTransportPriv.h" -#include "appleSession.h" #include "ssl.h" #include "sslCipherSpecs.h" #include "sslContext.h" @@ -37,7 +36,6 @@ #include "sslDebug.h" #include "sslKeychain.h" #include "sslMemory.h" -#include "sslUtils.h" #include "tlsCallbacks.h" @@ -78,26 +76,6 @@ static void sslFreeDnList(SSLContext *ctx) 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); @@ -107,6 +85,7 @@ Boolean sslIsSessionActive(const SSLContext *ctx) case SSL_HdskStateUninit: case SSL_HdskStateGracefulClose: case SSL_HdskStateErrorClose: + case SSL_HdskStateOutOfBandError: 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 */ -int kSplitDefaultValue; +/* Preferences values */ 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 - * CFURLCopyResourcePropertyForKey() andCF pulls in CoreServices for + * CFURLCopyResourcePropertyForKey() and CF pulls in CoreServices for * CFURLCopyResourcePropertyForKey() and that doesn't work in install * enviroment. */ @@ -161,55 +145,93 @@ CopyPlistFromFile(CFURLRef url) #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 and */ - 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 - /* 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. - 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 + /* Disable record splitting */ + /* Enabled by default, this may cause some interop issues, see and */ + 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) @@ -269,6 +291,13 @@ SSLContextRef SSLCreateContextWithRecordFuncs(CFAllocatorRef alloc, SSLProtocolS 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); @@ -297,33 +326,24 @@ SSLContextRef SSLCreateContextWithRecordFuncs(CFAllocatorRef alloc, SSLProtocolS /* 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; - /* 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) { - ctx->dheEnabled = true; - } else { - ctx->dheEnabled = false; + if(kSSLSessionConfigDefaultValue) { + SSLSetSessionConfig(ctx, kSSLSessionConfigDefaultValue); } 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; @@ -334,8 +354,6 @@ SSLContextRef SSLCreateContextWithRecordFuncs(CFAllocatorRef alloc, SSLProtocolS ctx->signalCertRequest = false; ctx->signalClientAuth = false; - ctx->negAuthType = SSLClientAuthNone; /* ditto */ - return ctx; } @@ -404,22 +422,17 @@ void SSLContextDestroy(CFTypeRef arg) SSLFreeBuffer(&ctx->peerID); SSLFreeBuffer(&ctx->resumableSession); SSLFreeBuffer(&ctx->receivedDataBuffer); - - sslFree(ctx->validCipherSuites); - ctx->validCipherSuites = NULL; - ctx->numValidCipherSuites = 0; + SSLFreeBuffer(&ctx->contextConfigurationBuffer); CFReleaseSafe(ctx->acceptableCAs); +#if !TARGET_OS_IPHONE CFReleaseSafe(ctx->trustedLeafCerts); +#endif CFReleaseSafe(ctx->localCertArray); CFReleaseSafe(ctx->encryptCertArray); - CFReleaseSafe(ctx->peerCert); CFReleaseSafe(ctx->trustedCerts); CFReleaseSafe(ctx->peerSecTrust); - sslFreePrivKey(&ctx->signingPrivKeyRef); - - sslFreeLocalCert(ctx); sslFreeDnList(ctx); SSLFreeBuffer(&ctx->ownVerifyData); @@ -430,9 +443,10 @@ void SSLContextDestroy(CFTypeRef arg) 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)); } /* @@ -457,6 +471,7 @@ SSLGetSessionState (SSLContextRef context, break; case SSL_HdskStateErrorClose: case SSL_HdskStateNoNotifyClose: + case SSL_HdskStateOutOfBandError: rtnState = kSSLAborted; break; case SSL_HdskStateReady: @@ -478,13 +493,15 @@ SSLSetSessionOption (SSLContextRef context, 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; @@ -499,11 +516,13 @@ SSLSetSessionOption (SSLContextRef context, 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->oneByteRecordEnable = value; break; case kSSLSessionOptionFalseStart: + tls_handshake_set_false_start(context->hdsk, value); context->falseStartEnabled = value; break; case kSSLSessionOptionFallback: @@ -515,6 +534,15 @@ SSLSetSessionOption (SSLContextRef context, 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; @@ -703,25 +731,135 @@ SSLSetALPNData(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; + } + + const tls_buffer *alpnData = 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); - const tls_buffer *alpn_data; + return success; +} - alpn_data = tls_handshake_get_peer_alpn_data(context->hdsk); +OSStatus +SSLCopyALPNProtocols(SSLContextRef context, + CFArrayRef *protocolArray) +{ + if (context == NULL || protocolArray == NULL) { + return errSecParam; + } - if(alpn_data) { - *length = alpn_data->length; - return alpn_data->data; + 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 { - return NULL; + CFReleaseNull(array); + *protocolArray = NULL; + return errSecParam; } } // 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) @@ -1057,12 +1195,12 @@ SSLSetProtocolVersionMax (SSLContextRef ctx, 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; - if (version < ctx->minProtocolVersion) + if (version < (SSLProtocolVersion)ctx->minProtocolVersion) ctx->minProtocolVersion = version; } ctx->maxProtocolVersion = version; @@ -1083,6 +1221,49 @@ SSLGetProtocolVersionMax (SSLContextRef ctx, 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 @@ -1111,12 +1292,12 @@ SSLSetProtocolVersionEnabled(SSLContextRef ctx, 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; } - if (version < ctx->minProtocolVersion) { + if (version < (SSLProtocolVersion)ctx->minProtocolVersion) { ctx->minProtocolVersion = version; } } else { @@ -1146,7 +1327,7 @@ SSLSetProtocolVersionEnabled(SSLContextRef ctx, 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; @@ -1180,8 +1361,8 @@ SSLGetProtocolVersionEnabled(SSLContextRef ctx, 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: @@ -1335,56 +1516,32 @@ OSStatus 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) { - 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) { - 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) { - 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( @@ -1478,7 +1635,7 @@ SSLCopyTrustedRoots (SSLContextRef ctx, 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 @@ -1487,6 +1644,7 @@ SSLCopyTrustedRoots (SSLContextRef ctx, #endif } +#if !TARGET_OS_IPHONE OSStatus SSLSetTrustedLeafCertificates (SSLContextRef ctx, CFArrayRef trustedCerts) @@ -1502,8 +1660,7 @@ SSLSetTrustedLeafCertificates (SSLContextRef ctx, if(ctx->trustedLeafCerts) { CFRelease(ctx->trustedLeafCerts); } - ctx->trustedLeafCerts = trustedCerts; - CFRetain(trustedCerts); + ctx->trustedLeafCerts = CFRetainSafe(trustedCerts); return errSecSuccess; } @@ -1522,6 +1679,7 @@ SSLCopyTrustedLeafCertificates (SSLContextRef ctx, *trustedCerts = NULL; return errSecSuccess; } +#endif OSStatus SSLSetClientSideAuthenticate (SSLContext *ctx, @@ -1572,7 +1730,7 @@ SSLGetClientCertificateState (SSLContextRef ctx, *clientState = kSSLClientCertNone; break; case kSSLClientCertRequested: - if(ctx->localCert) { + if(ctx->localCertArray) { *clientState = kSSLClientCertSent; } else { *clientState = kSSLClientCertRequested; @@ -1591,7 +1749,7 @@ SSLGetClientCertificateState (SSLContextRef ctx, *clientState = ctx->clientCertState; break; case kSSLClientCertRequested: - if(ctx->peerCert) { + if(ctx->peerSecTrust) { *clientState = kSSLClientCertSent; } else { *clientState = kSSLClientCertRequested; @@ -1606,10 +1764,13 @@ SSLGetClientCertificateState (SSLContextRef ctx, return errSecSuccess; } +#include + 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 @@ -1621,23 +1782,17 @@ SSLSetCertificate (SSLContextRef ctx, } 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 } - 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; } @@ -1935,46 +2090,34 @@ SSLCopyDistinguishedNames (SSLContextRef ctx, /* * 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->peerCert) { + if (!ctx->peerSecTrust) { *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 (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; } -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. // Mailsmith Crashes While Getting New Mail Under Mavericks Developer Preview @@ -1985,7 +2128,7 @@ OSStatus SSLGetPeerCertificates (SSLContextRef ctx, CFArrayRef *certs) { - return sslCopyPeerCertificates(ctx, certs, true); + return errSecUnimplemented; } #endif @@ -2046,6 +2189,17 @@ OSStatus SSLGetDiffieHellmanParams( OSStatus SSLSetDHEEnabled(SSLContextRef ctx, bool enabled) { ctx->dheEnabled = enabled; + /* Hack a little so that only the ciphersuites change */ + tls_protocol_version min, max; + unsigned nbits; + tls_handshake_get_min_protocol_version(ctx->hdsk, &min); + tls_handshake_get_max_protocol_version(ctx->hdsk, &max); + tls_handshake_get_min_dh_group_size(ctx->hdsk, &nbits); + tls_handshake_set_config(ctx->hdsk, enabled?tls_handshake_config_legacy_DHE:tls_handshake_config_legacy); + tls_handshake_set_min_protocol_version(ctx->hdsk, min); + tls_handshake_set_max_protocol_version(ctx->hdsk, max); + tls_handshake_set_min_dh_group_size(ctx->hdsk, nbits); + return noErr; } @@ -2098,12 +2252,8 @@ SSLCopyPeerTrust( /* 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; @@ -2123,9 +2273,8 @@ OSStatus SSLGetPeerSecTrust( /* 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; @@ -2369,8 +2518,11 @@ OSStatus SSLGetECDSACurves( 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; } @@ -2391,20 +2543,26 @@ OSStatus SSLSetECDSACurves( 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; } - for (unsigned i=0; iecdhCurves[i] = namedCurves[i]; - } + for (unsigned i=0; i UINT16_MAX - 1) { + ctx->ecdhCurves[i] = SSL_Curve_None; + continue; + } + ctx->ecdhCurves[i] = namedCurves[i]; + } 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; } @@ -2447,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 */ { - 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; inumAuthTypes; 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( @@ -2635,10 +2714,137 @@ OSStatus SSLInternal_PRF( vout, outLen); } -/* To be implemented */ +const CFStringRef kSSLSessionConfig_default = CFSTR("default"); +const CFStringRef kSSLSessionConfig_ATSv1 = CFSTR("ATSv1"); +const CFStringRef kSSLSessionConfig_ATSv1_noPFS = CFSTR("ATSv1_noPFS"); +const CFStringRef kSSLSessionConfig_legacy = CFSTR("legacy"); +const CFStringRef kSSLSessionConfig_standard = CFSTR("standard"); +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_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; + } else if(CFEqual(config, kSSLSessionConfig_ATSv1_noPFS)){ + return tls_handshake_config_ATSv1_noPFS; + } else if(CFEqual(config, kSSLSessionConfig_standard)){ + return tls_handshake_config_standard; + } else if(CFEqual(config, kSSLSessionConfig_TLSv1_fallback)){ + return tls_handshake_config_TLSv1_fallback; + } else if(CFEqual(config, kSSLSessionConfig_TLSv1_RC4_fallback)){ + return tls_handshake_config_TLSv1_RC4_fallback; + } else if(CFEqual(config, kSSLSessionConfig_RC4_fallback)){ + return tls_handshake_config_RC4_fallback; + } 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; + } else if(CFEqual(config, kSSLSessionConfig_legacy_DHE)){ + return tls_handshake_config_legacy_DHE; + } 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; + } +} + +/* Set Predefined TLS Configuration */ +OSStatus +SSLSetSessionConfig(SSLContextRef context, + CFStringRef config) +{ + tls_handshake_config_t cfg = SSLSessionConfig_to_tls_handshake_config(config); + if(cfg>=0) { + return tls_handshake_set_config(context->hdsk, cfg); + } else { + return errSecParam; + } +} + OSStatus -SSLSetSessionStrengthPolicy(SSLContextRef context, - SSLSessionStrengthPolicy policyStrength) +SSLGetSessionConfigurationIdentifier(SSLContext *ctx, SSLBuffer *buffer) { + if (buffer == NULL) { + return errSecParam; + } + + // 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; + } + + // 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; }