#include "SSLRecordInternal.h"
#include "SecureTransportPriv.h"
-#include "appleSession.h"
#include "ssl.h"
#include "sslCipherSpecs.h"
#include "sslContext.h"
#include "sslDebug.h"
#include "sslKeychain.h"
#include "sslMemory.h"
-#include "sslUtils.h"
#include "tlsCallbacks.h"
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);
case SSL_HdskStateUninit:
case SSL_HdskStateGracefulClose:
case SSL_HdskStateErrorClose:
+ case SSL_HdskStateOutOfBandError:
return false;
default:
return true;
#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.
*/
#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
- /* 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 <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)
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);
/* 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) {
- 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(kMinProtocolVersionDefaultValue) {
+ SSLSetProtocolVersionMin(ctx, (unsigned)kMinProtocolVersionDefaultValue);
+ }
+
/* default for anonymous ciphers is DISABLED */
ctx->anonCipherEnable = false;
ctx->signalCertRequest = false;
ctx->signalClientAuth = false;
- ctx->negAuthType = SSLClientAuthNone; /* ditto */
-
return ctx;
}
SSLFreeBuffer(&ctx->peerID);
SSLFreeBuffer(&ctx->resumableSession);
SSLFreeBuffer(&ctx->receivedDataBuffer);
+ 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);
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));
}
/*
break;
case SSL_HdskStateErrorClose:
case SSL_HdskStateNoNotifyClose:
+ case SSL_HdskStateOutOfBandError:
rtnState = kSSLAborted;
break;
case SSL_HdskStateReady:
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;
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:
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;
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 *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 {
- 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)
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;
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
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 {
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;
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:
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(
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
#endif
}
+#if !TARGET_OS_IPHONE
OSStatus
SSLSetTrustedLeafCertificates (SSLContextRef ctx,
CFArrayRef trustedCerts)
if(ctx->trustedLeafCerts) {
CFRelease(ctx->trustedLeafCerts);
}
- ctx->trustedLeafCerts = trustedCerts;
- CFRetain(trustedCerts);
+ ctx->trustedLeafCerts = CFRetainSafe(trustedCerts);
return errSecSuccess;
}
*trustedCerts = NULL;
return errSecSuccess;
}
+#endif
OSStatus
SSLSetClientSideAuthenticate (SSLContext *ctx,
*clientState = kSSLClientCertNone;
break;
case kSSLClientCertRequested:
- if(ctx->localCert) {
+ if(ctx->localCertArray) {
*clientState = kSSLClientCertSent;
} else {
*clientState = kSSLClientCertRequested;
*clientState = ctx->clientCertState;
break;
case kSSLClientCertRequested:
- if(ctx->peerCert) {
+ if(ctx->peerSecTrust) {
*clientState = kSSLClientCertSent;
} else {
*clientState = kSSLClientCertRequested;
return errSecSuccess;
}
+#include <tls_helpers.h>
+
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
}
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;
}
/*
* 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.
// <rdar://problem/14215831> Mailsmith Crashes While Getting New Mail Under Mavericks Developer Preview
SSLGetPeerCertificates (SSLContextRef ctx,
CFArrayRef *certs)
{
- return sslCopyPeerCertificates(ctx, certs, true);
+ return errSecUnimplemented;
}
#endif
/* 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;
/* 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;
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;
}
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; 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;
- tls_handshake_set_curves(ctx->hdsk, ctx->ecdhCurves, ctx->ecdhNumCurves);
+ tls_handshake_set_curves(ctx->hdsk, ctx->ecdhCurves, ctx->ecdhNumCurves);
return errSecSuccess;
}
}
/*
- * 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; 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(
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_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)){
+ } else if(CFEqual(config, kSSLSessionConfig_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;
- } else if(CFEqual(config, kSSLSessionConfig_TLSv1_fallback)){
+ } else if(CFEqual(config, kSSLSessionConfig_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;
- } else if(CFEqual(config, kSSLSessionConfig_RC4_fallback)){
+ } else if(CFEqual(config, kSSLSessionConfig_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;
- } else if(CFEqual(config, kSSLSessionConfig_legacy_DHE)){
+ } else if(CFEqual(config, kSSLSessionConfig_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;
}
}
-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,
}
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;
+}