#include "SecureTransport.h"
#include "SSLRecordInternal.h"
#include "SecureTransportPriv.h"
#include "ssl.h"
#include "sslCipherSpecs.h"
#include "sslContext.h"
#include "sslCrypto.h"
#include "sslDebug.h"
#include "sslKeychain.h"
#include "sslMemory.h"
#include "tlsCallbacks.h"
#include <AssertMacros.h>
#include <CoreFoundation/CFData.h>
#include <CoreFoundation/CFPreferences.h>
#include <Security/SecCertificate.h>
#include <Security/SecCertificatePriv.h>
#include <Security/SecTrust.h>
#include <Security/SecTrustSettingsPriv.h>
#include <Security/oidsalg.h>
#include "utilities/SecCFRelease.h"
#include "utilities/SecCFWrappers.h"
#include <pthread.h>
#include <string.h>
#if TARGET_OS_IPHONE
#include <Security/SecCertificateInternal.h>
#else
#include <Security/oidsalg.h>
#include <Security/oidscert.h>
#include <Security/SecTrustSettingsPriv.h>
#endif
static void sslFreeDnList(SSLContext *ctx)
{
DNListElem *dn, *nextDN;
dn = ctx->acceptableDNList;
while (dn)
{
SSLFreeBuffer(&dn->derDN);
nextDN = dn->next;
sslFree(dn);
dn = nextDN;
}
ctx->acceptableDNList = NULL;
}
Boolean sslIsSessionActive(const SSLContext *ctx)
{
assert(ctx != NULL);
switch(ctx->state) {
case SSL_HdskStateUninit:
case SSL_HdskStateGracefulClose:
case SSL_HdskStateErrorClose:
case SSL_HdskStateOutOfBandError:
return false;
default:
return true;
}
}
#define MINIMUM_STREAM_VERSION SSL_Version_3_0
#define MAXIMUM_STREAM_VERSION TLS_Version_1_2
#define MINIMUM_DATAGRAM_VERSION DTLS_Version_1_0
#define MAXIMUM_DATAGRAM_VERSION DTLS_Version_1_0
#define SSL_ENABLE_ECDSA_SIGN_AUTH 1
#define SSL_ENABLE_RSA_FIXED_ECDH_AUTH 0
#define SSL_ENABLE_ECDSA_FIXED_ECDH_AUTH 0
#define DEFAULT_DTLS_TIMEOUT 1
#define DEFAULT_DTLS_MTU 1400
#define MIN_ALLOWED_DTLS_MTU 64 underflow when calculating max write size */
CFIndex kMinDhGroupSizeDefaultValue;
CFIndex kMinProtocolVersionDefaultValue;
CFStringRef kSSLSessionConfigDefaultValue;
Boolean kSSLDisableRecordSplittingDefaultValue;
static tls_cache_t g_session_cache = NULL;
#if TARGET_OS_IPHONE
static CFPropertyListRef
CopyPlistFromFile(CFURLRef url)
{
CFDictionaryRef d = NULL;
CFReadStreamRef s = CFReadStreamCreateWithFile(kCFAllocatorDefault, url);
if (s && CFReadStreamOpen(s)) {
d = (CFDictionaryRef)CFPropertyListCreateWithStream(kCFAllocatorDefault, s, 0, kCFPropertyListImmutable, NULL, NULL);
}
CFReleaseSafe(s);
return d;
}
#endif
static
CFTypeRef SSLPreferencesCopyValue(CFStringRef key, CFPropertyListRef managed_prefs)
{
CFTypeRef value = (CFTypeRef) CFPreferencesCopyAppValue(CFSTR("SSLSessionConfig"), kCFPreferencesCurrentApplication);
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
CFURLRef prefURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, CFSTR("/Library/Managed Preferences/mobile/.GlobalPreferences.plist"), kCFURLPOSIXPathStyle, false);
if(prefURL) {
managed_prefs = CopyPlistFromFile(prefURL);
}
CFReleaseSafe(prefURL);
#endif
kSSLDisableRecordSplittingDefaultValue = SSLPreferencesGetBoolean(CFSTR("SSLDisableRecordSplitting"), managed_prefs);
kMinDhGroupSizeDefaultValue = SSLPreferencesGetInteger(CFSTR("SSLMinDhGroupSize"), managed_prefs);
kMinProtocolVersionDefaultValue = SSLPreferencesGetInteger(CFSTR("SSLMinProtocolVersion"), managed_prefs);
kSSLSessionConfigDefaultValue = SSLPreferencesCopyString(CFSTR("SSLSessionConfig"), managed_prefs);
CFReleaseSafe(managed_prefs);
}
static void SSLContextOnce(void)
{
_SSLContextReadDefault();
g_session_cache = tls_cache_create();
}
CFGiblisWithHashFor(SSLContext)
OSStatus
SSLNewContext (Boolean isServer,
SSLContextRef *contextPtr)
{
if(contextPtr == NULL) {
return errSecParam;
}
*contextPtr = SSLCreateContext(kCFAllocatorDefault, isServer?kSSLServerSide:kSSLClientSide, kSSLStreamType);
if (*contextPtr == NULL)
return errSecAllocate;
return errSecSuccess;
}
SSLContextRef SSLCreateContext(CFAllocatorRef alloc, SSLProtocolSide protocolSide, SSLConnectionType connectionType)
{
SSLContextRef ctx;
SSLRecordContextRef recCtx;
ctx = SSLCreateContextWithRecordFuncs(alloc, protocolSide, connectionType, &SSLRecordLayerInternal);
if(ctx==NULL)
return NULL;
recCtx = SSLCreateInternalRecordLayer(ctx);
if(recCtx==NULL) {
CFRelease(ctx);
return NULL;
}
SSLSetRecordContext(ctx, recCtx);
return ctx;
}
SSLContextRef SSLCreateContextWithRecordFuncs(CFAllocatorRef alloc, SSLProtocolSide protocolSide, SSLConnectionType connectionType, const struct SSLRecordFuncs *recFuncs)
{
SSLContext *ctx = (SSLContext*) _CFRuntimeCreateInstance(alloc, SSLContextGetTypeID(), sizeof(SSLContext) - sizeof(CFRuntimeBase), NULL);
if(ctx == NULL) {
return NULL;
}
memset(((uint8_t*) ctx) + sizeof(CFRuntimeBase), 0, sizeof(SSLContext) - sizeof(CFRuntimeBase));
ctx->hdsk = tls_handshake_create(connectionType==kSSLDatagramType, protocolSide==kSSLServerSide);
if(ctx->hdsk == NULL) {
CFRelease(ctx);
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);
ctx->isDTLS = (connectionType==kSSLDatagramType);
ctx->state = SSL_HdskStateUninit;
ctx->timeout_duration = DEFAULT_DTLS_TIMEOUT;
ctx->mtu = DEFAULT_DTLS_MTU;
tls_handshake_get_min_protocol_version(ctx->hdsk, &ctx->minProtocolVersion);
tls_handshake_get_max_protocol_version(ctx->hdsk, &ctx->maxProtocolVersion);
if(protocolSide == kSSLClientSide) {
tls_handshake_set_sct_enable(ctx->hdsk, true);
tls_handshake_set_ocsp_enable(ctx->hdsk, true);
}
ctx->negProtocolVersion = SSL_Version_Undetermined;
ctx->protocolSide = protocolSide;
ctx->recFuncs = recFuncs;
ctx->enableCertVerify = true;
ctx->rsaBlindingEnable = true;
ctx->oneByteRecordEnable = !kSSLDisableRecordSplittingDefaultValue;
ctx->fallbackEnabled = 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);
}
ctx->anonCipherEnable = false;
ctx->breakOnServerAuth = false;
ctx->breakOnCertRequest = false;
ctx->breakOnClientAuth = false;
ctx->signalServerAuth = false;
ctx->signalCertRequest = false;
ctx->signalClientAuth = false;
return ctx;
}
OSStatus
SSLNewDatagramContext (Boolean isServer,
SSLContextRef *contextPtr)
{
if (contextPtr == NULL)
return errSecParam;
*contextPtr = SSLCreateContext(kCFAllocatorDefault, isServer?kSSLServerSide:kSSLClientSide, kSSLDatagramType);
if (*contextPtr == NULL)
return errSecAllocate;
return errSecSuccess;
}
OSStatus
SSLDisposeContext (SSLContextRef context)
{
if(context == NULL) {
return errSecParam;
}
CFRelease(context);
return errSecSuccess;
}
CFStringRef SSLContextCopyFormatDescription(CFTypeRef arg, CFDictionaryRef formatOptions)
{
SSLContext* ctx = (SSLContext*) arg;
if (ctx == NULL) {
return NULL;
} else {
CFStringRef result = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<SSLContext(%p) { ... }>"), ctx);
return result;
}
}
Boolean SSLContextCompare(CFTypeRef a, CFTypeRef b)
{
return a == b;
}
CFHashCode SSLContextHash(CFTypeRef arg)
{
return (CFHashCode) arg;
}
void SSLContextDestroy(CFTypeRef arg)
{
SSLContext* ctx = (SSLContext*) arg;
tls_handshake_destroy(ctx->hdsk);
if(ctx->recFuncs==&SSLRecordLayerInternal)
SSLDestroyInternalRecordLayer(ctx->recCtx);
SSLFreeBuffer(&ctx->sessionTicket);
SSLFreeBuffer(&ctx->sessionID);
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->trustedCerts);
CFReleaseSafe(ctx->peerSecTrust);
sslFreeDnList(ctx);
SSLFreeBuffer(&ctx->ownVerifyData);
SSLFreeBuffer(&ctx->peerVerifyData);
SSLFreeBuffer(&ctx->pskIdentity);
SSLFreeBuffer(&ctx->pskSharedSecret);
SSLFreeBuffer(&ctx->dhParamsEncoded);
if(ctx->cache)
tls_cache_cleanup(ctx->cache);
memset(((uint8_t*) ctx) + sizeof(CFRuntimeBase), 0, sizeof(SSLContext) - sizeof(CFRuntimeBase));
}
OSStatus
SSLGetSessionState (SSLContextRef context,
SSLSessionState *state)
{
SSLSessionState rtnState = kSSLIdle;
if(context == NULL) {
return errSecParam;
}
*state = rtnState;
switch(context->state) {
case SSL_HdskStateUninit:
rtnState = kSSLIdle;
break;
case SSL_HdskStateGracefulClose:
rtnState = kSSLClosed;
break;
case SSL_HdskStateErrorClose:
case SSL_HdskStateNoNotifyClose:
case SSL_HdskStateOutOfBandError:
rtnState = kSSLAborted;
break;
case SSL_HdskStateReady:
rtnState = kSSLConnected;
break;
case SSL_HdskStatePending:
rtnState = kSSLHandshake;
break;
}
*state = rtnState;
return errSecSuccess;
}
OSStatus
SSLSetSessionOption (SSLContextRef context,
SSLSessionOption option,
Boolean value)
{
if (context == NULL) {
return errSecParam;
}
if (sslIsSessionActive(context)) {
return errSecBadReq;
}
switch(option) {
case kSSLSessionOptionBreakOnServerAuth:
context->breakOnServerAuth = value;
context->enableCertVerify = !value;
break;
case kSSLSessionOptionBreakOnCertRequested:
context->breakOnCertRequest = value;
break;
case kSSLSessionOptionBreakOnClientAuth:
context->breakOnClientAuth = value;
context->enableCertVerify = !value;
break;
case kSSLSessionOptionSendOneByteRecord:
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:
tls_handshake_set_fallback(context->hdsk, value);
context->fallbackEnabled = value;
break;
case kSSLSessionOptionBreakOnClientHello:
context->breakOnClientHello = 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;
}
return errSecSuccess;
}
OSStatus
SSLGetSessionOption (SSLContextRef context,
SSLSessionOption option,
Boolean *value)
{
if(context == NULL || value == NULL) {
return errSecParam;
}
switch(option) {
case kSSLSessionOptionBreakOnServerAuth:
*value = context->breakOnServerAuth;
break;
case kSSLSessionOptionBreakOnCertRequested:
*value = context->breakOnCertRequest;
break;
case kSSLSessionOptionBreakOnClientAuth:
*value = context->breakOnClientAuth;
break;
case kSSLSessionOptionSendOneByteRecord:
*value = context->oneByteRecordEnable;
break;
case kSSLSessionOptionFalseStart:
*value = context->falseStartEnabled;
break;
case kSSLSessionOptionBreakOnClientHello:
*value = context->breakOnClientHello;
break;
case kSSLSessionOptionAllowServerIdentityChange:
tls_handshake_get_server_identity_change(context->hdsk, (bool *)value);
break;
default:
return errSecParam;
}
return errSecSuccess;
}
OSStatus
SSLSetRecordContext (SSLContextRef ctx,
SSLRecordContextRef recCtx)
{
if(ctx == NULL) {
return errSecParam;
}
if(sslIsSessionActive(ctx)) {
return errSecBadReq;
}
ctx->recCtx = recCtx;
return errSecSuccess;
}
OSStatus
SSLSetIOFuncs (SSLContextRef ctx,
SSLReadFunc readFunc,
SSLWriteFunc writeFunc)
{
if(ctx == NULL) {
return errSecParam;
}
if(ctx->recFuncs!=&SSLRecordLayerInternal) {
check(0);
return errSecBadReq;
}
if(sslIsSessionActive(ctx)) {
return errSecBadReq;
}
ctx->ioCtx.read=readFunc;
ctx->ioCtx.write=writeFunc;
return 0;
}
void
SSLSetNPNFunc(SSLContextRef context,
SSLNPNFunc npnFunc,
void *info)
{
if (context == NULL) {
return;
}
if (sslIsSessionActive(context)) {
return;
}
context->npnFunc = npnFunc;
context->npnFuncInfo = info;
if(context->protocolSide==kSSLClientSide) {
tls_handshake_set_npn_enable(context->hdsk, npnFunc!=NULL);
}
}
OSStatus
SSLSetNPNData(SSLContextRef context,
const void *data,
size_t length)
{
if (context == NULL || data == NULL || length == 0) {
return errSecParam;
}
if (length > 255) {
return errSecParam;
}
tls_buffer npn_data;
npn_data.data = (uint8_t *)data;
npn_data.length = length;
return tls_handshake_set_npn_data(context->hdsk, npn_data);
}
const void *
SSLGetNPNData(SSLContextRef context,
size_t *length)
{
if (context == NULL || length == NULL)
return NULL;
const tls_buffer *npn_data;
npn_data = tls_handshake_get_peer_npn_data(context->hdsk);
if(npn_data) {
*length = npn_data->length;
return npn_data->data;
} else {
return NULL;
}
}
void
SSLSetALPNFunc(SSLContextRef context,
SSLALPNFunc alpnFunc,
void *info)
{
if (context == NULL) {
return;
}
if (sslIsSessionActive(context)) {
return;
}
context->alpnFunc = alpnFunc;
context->alpnFuncInfo = info;
if(context->protocolSide==kSSLServerSide) {
}
}
OSStatus
SSLSetALPNData(SSLContextRef context,
const void *data,
size_t length)
{
if (context == NULL || data == NULL || length == 0) {
return errSecParam;
}
if (length > 255) {
return errSecParam;
}
tls_buffer alpn_data;
alpn_data.data = (uint8_t *)data;
alpn_data.length = length;
return tls_handshake_set_alpn_data(context->hdsk, alpn_data);
}
const void *
SSLGetALPNData(SSLContextRef context,
size_t *length)
{
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;
}
const int maxBufferLength = 32;
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);
}
}
});
if (CFDataGetLength(alpnData) > 255) {
CFRelease(alpnData);
return errSecParam;
}
tls_buffer payload;
payload.data = (uint8_t *) CFDataGetBytePtr(alpnData);
payload.length = CFDataGetLength(alpnData);
int success = tls_handshake_set_alpn_data(context->hdsk, payload);
CFRelease(alpnData);
return success;
}
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;
while (offset < alpnData->length) {
char length = alpnData->data[offset];
offset++;
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);
if (offset > alpnData->length) {
CFReleaseNull(array);
*protocolArray = NULL;
return errSecParam;
}
}
*protocolArray = array;
return errSecSuccess;
} else {
CFReleaseNull(array);
*protocolArray = NULL;
return errSecParam;
}
}
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;
}
OSStatus
SSLSetConnection (SSLContextRef ctx,
SSLConnectionRef connection)
{
if(ctx == NULL) {
return errSecParam;
}
if(ctx->recFuncs!=&SSLRecordLayerInternal) {
check(0);
return errSecBadReq;
}
if(sslIsSessionActive(ctx)) {
return errSecBadReq;
}
ctx->ioCtx.ioRef = connection;
return 0;
}
OSStatus
SSLGetConnection (SSLContextRef ctx,
SSLConnectionRef *connection)
{
if((ctx == NULL) || (connection == NULL)) {
return errSecParam;
}
*connection = ctx->ioCtx.ioRef;
return errSecSuccess;
}
OSStatus
SSLSetPeerDomainName (SSLContextRef ctx,
const char *peerName,
size_t peerNameLen)
{
if(ctx == NULL) {
return errSecParam;
}
if(sslIsSessionActive(ctx)) {
return errSecBadReq;
}
if(ctx->protocolSide == kSSLClientSide) {
return tls_handshake_set_peer_hostname(ctx->hdsk, peerName, peerNameLen);
} else {
return 0; }
}
OSStatus
SSLGetPeerDomainNameLength (SSLContextRef ctx,
size_t *peerNameLen) {
if(ctx == NULL) {
return errSecParam;
}
const char *hostname;
return tls_handshake_get_peer_hostname(ctx->hdsk, &hostname, peerNameLen);
}
OSStatus
SSLGetPeerDomainName (SSLContextRef ctx,
char *peerName, size_t *peerNameLen) {
const char *hostname;
size_t len;
int err;
if(ctx == NULL) {
return errSecParam;
}
err=tls_handshake_get_peer_hostname(ctx->hdsk, &hostname, &len);
if(err) {
return err;
} else if(*peerNameLen<len) {
return errSSLBufferOverflow;
} else {
memcpy(peerName, hostname, len);
*peerNameLen = len;
return 0;
}
}
OSStatus
SSLCopyRequestedPeerNameLength (SSLContextRef ctx,
size_t *peerNameLen) {
const tls_buffer *hostname;
if(ctx == NULL) {
return errSecParam;
}
hostname = tls_handshake_get_sni_hostname(ctx->hdsk);
if(!hostname) {
return errSecParam;
} else {
*peerNameLen = hostname->length;
}
return 0;
}
OSStatus
SSLCopyRequestedPeerName (SSLContextRef ctx,
char *peerName, size_t *peerNameLen) {
const tls_buffer *hostname;
if(ctx == NULL) {
return errSecParam;
}
hostname = tls_handshake_get_sni_hostname(ctx->hdsk);
if(!hostname) {
return errSecParam;
} else if(*peerNameLen < hostname->length) {
return errSSLBufferOverflow;
} else {
memcpy(peerName, hostname->data, hostname->length);
*peerNameLen = hostname->length;
return 0;
}
}
OSStatus
SSLSetDatagramHelloCookie (SSLContextRef ctx,
const void *cookie,
size_t cookieLen)
{
OSStatus err;
if(ctx == NULL) {
return errSecParam;
}
if(!ctx->isDTLS) return errSecParam;
if((ctx == NULL) || (cookieLen>32)) {
return errSecParam;
}
if(sslIsSessionActive(ctx)) {
return errSecBadReq;
}
if(ctx->dtlsCookie.data) {
SSLFreeBuffer(&ctx->dtlsCookie);
}
if((err=SSLAllocBuffer(&ctx->dtlsCookie, cookieLen)))
return err;
memmove(ctx->dtlsCookie.data, cookie, cookieLen);
return errSecSuccess;
}
OSStatus
SSLSetMaxDatagramRecordSize (SSLContextRef ctx,
size_t maxSize)
{
if(ctx == NULL) return errSecParam;
if(!ctx->isDTLS) return errSecParam;
tls_handshake_set_mtu(ctx->hdsk, maxSize);
return errSecSuccess;
}
OSStatus
SSLGetMaxDatagramRecordSize (SSLContextRef ctx,
size_t *maxSize)
{
if(ctx == NULL) return errSecParam;
if(!ctx->isDTLS) return errSecParam;
*maxSize = ctx->mtu;
return errSecSuccess;
}
OSStatus
SSLGetDatagramWriteSize (SSLContextRef ctx,
size_t *bufSize)
{
if(ctx == NULL) return errSecParam;
if(!ctx->isDTLS) return errSecParam;
if(bufSize == NULL) return errSecParam;
size_t max_fragment_size = ctx->mtu-13;
#if 0
SSLCipherSpecParams *currCipher = &ctx->selectedCipherSpecParams;
size_t blockSize = currCipher->blockSize;
size_t macSize = currCipher->macSize;
#else
size_t blockSize = 16;
size_t macSize = 32;
#endif
if (blockSize > 0) {
max_fragment_size = max_fragment_size & ~(blockSize-1);
max_fragment_size -= blockSize;
max_fragment_size -= 1;
}
max_fragment_size -= macSize;
assert(max_fragment_size<ctx->mtu);
*bufSize = max_fragment_size;
return errSecSuccess;
}
static tls_protocol_version SSLProtocolToProtocolVersion(SSLProtocol protocol) {
switch (protocol) {
case kSSLProtocol2: return SSL_Version_2_0;
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 kDTLSProtocol1: return tls_protocol_version_DTLS_1_0;
default: return tls_protocol_version_Undertermined;
}
}
static SSLProtocol SSLProtocolVersionToProtocol(SSLProtocolVersion version)
{
switch(version) {
case tls_protocol_version_SSL_3: return kSSLProtocol3;
case tls_protocol_version_TLS_1_0: return kTLSProtocol1;
case tls_protocol_version_TLS_1_1: return kTLSProtocol11;
case tls_protocol_version_TLS_1_2: return kTLSProtocol12;
case tls_protocol_version_DTLS_1_0: return kDTLSProtocol1;
default:
sslErrorLog("SSLProtocolVersionToProtocol: bad prot (%04x)\n",
version);
case tls_protocol_version_Undertermined: return kSSLProtocolUnknown;
}
}
OSStatus
SSLSetProtocolVersionMin (SSLContextRef ctx,
SSLProtocol minVersion)
{
if(ctx == NULL) return errSecParam;
tls_protocol_version version = SSLProtocolToProtocolVersion(minVersion);
if (ctx->isDTLS) {
if (version > MINIMUM_DATAGRAM_VERSION ||
version < MAXIMUM_DATAGRAM_VERSION)
return errSSLIllegalParam;
if (version < ctx->maxProtocolVersion)
ctx->maxProtocolVersion = version;
} else {
if (version < MINIMUM_STREAM_VERSION || version > MAXIMUM_STREAM_VERSION)
return errSSLIllegalParam;
if (version > ctx->maxProtocolVersion)
ctx->maxProtocolVersion = version;
}
ctx->minProtocolVersion = version;
tls_handshake_set_min_protocol_version(ctx->hdsk, ctx->minProtocolVersion);
tls_handshake_set_max_protocol_version(ctx->hdsk, ctx->maxProtocolVersion);
return errSecSuccess;
}
OSStatus
SSLGetProtocolVersionMin (SSLContextRef ctx,
SSLProtocol *minVersion)
{
if(ctx == NULL) return errSecParam;
*minVersion = SSLProtocolVersionToProtocol(ctx->minProtocolVersion);
return errSecSuccess;
}
OSStatus
SSLSetProtocolVersionMax (SSLContextRef ctx,
SSLProtocol maxVersion)
{
if(ctx == NULL) return errSecParam;
SSLProtocolVersion version = SSLProtocolToProtocolVersion(maxVersion);
if (ctx->isDTLS) {
if (version > MINIMUM_DATAGRAM_VERSION ||
version < MAXIMUM_DATAGRAM_VERSION)
return errSSLIllegalParam;
if (version > (SSLProtocolVersion)ctx->minProtocolVersion)
ctx->minProtocolVersion = version;
} else {
if (version < MINIMUM_STREAM_VERSION || version > MAXIMUM_STREAM_VERSION)
return errSSLIllegalParam;
if (version < (SSLProtocolVersion)ctx->minProtocolVersion)
ctx->minProtocolVersion = version;
}
ctx->maxProtocolVersion = version;
tls_handshake_set_min_protocol_version(ctx->hdsk, ctx->minProtocolVersion);
tls_handshake_set_max_protocol_version(ctx->hdsk, ctx->maxProtocolVersion);
return errSecSuccess;
}
OSStatus
SSLGetProtocolVersionMax (SSLContextRef ctx,
SSLProtocol *maxVersion)
{
if(ctx == NULL) return errSecParam;
*maxVersion = SSLProtocolVersionToProtocol(ctx->maxProtocolVersion);
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
SSLSetProtocolVersionEnabled(SSLContextRef ctx,
SSLProtocol protocol,
Boolean enable)
{
if(ctx == NULL) {
return errSecParam;
}
if(sslIsSessionActive(ctx) || ctx->isDTLS) {
return errSecBadReq;
}
if (protocol == kSSLProtocolAll) {
if (enable) {
ctx->minProtocolVersion = MINIMUM_STREAM_VERSION;
ctx->maxProtocolVersion = MAXIMUM_STREAM_VERSION;
} else {
ctx->minProtocolVersion = SSL_Version_Undetermined;
ctx->maxProtocolVersion = SSL_Version_Undetermined;
}
} else {
SSLProtocolVersion version = SSLProtocolToProtocolVersion(protocol);
if (enable) {
if (version < MINIMUM_STREAM_VERSION || version > MAXIMUM_STREAM_VERSION) {
return errSecParam;
}
if (version > (SSLProtocolVersion)ctx->maxProtocolVersion) {
ctx->maxProtocolVersion = version;
if (ctx->minProtocolVersion == SSL_Version_Undetermined)
ctx->minProtocolVersion = version;
}
if (version < (SSLProtocolVersion)ctx->minProtocolVersion) {
ctx->minProtocolVersion = version;
}
} else {
if (version < SSL_Version_2_0 || version > MAXIMUM_STREAM_VERSION) {
return errSecParam;
}
SSLProtocolVersion nextVersion;
switch (version) {
case SSL_Version_2_0:
nextVersion = SSL_Version_3_0;
break;
case SSL_Version_3_0:
nextVersion = TLS_Version_1_0;
break;
case TLS_Version_1_0:
nextVersion = TLS_Version_1_1;
break;
case TLS_Version_1_1:
nextVersion = TLS_Version_1_2;
break;
case TLS_Version_1_2:
default:
nextVersion = SSL_Version_Undetermined;
break;
}
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;
}
}
}
tls_handshake_set_min_protocol_version(ctx->hdsk, ctx->minProtocolVersion);
tls_handshake_set_max_protocol_version(ctx->hdsk, ctx->maxProtocolVersion);
return errSecSuccess;
}
OSStatus
SSLGetProtocolVersionEnabled(SSLContextRef ctx,
SSLProtocol protocol,
Boolean *enable)
{
if(ctx == NULL) {
return errSecParam;
}
if(ctx->isDTLS) {
return errSecBadReq;
}
switch(protocol) {
case kSSLProtocol2:
case kSSLProtocol3:
case kTLSProtocol1:
case kTLSProtocol11:
case kTLSProtocol12:
{
SSLProtocolVersion version = SSLProtocolToProtocolVersion(protocol);
*enable = ((SSLProtocolVersion)ctx->minProtocolVersion <= version
&& (SSLProtocolVersion)ctx->maxProtocolVersion >= version);
break;
}
case kSSLProtocolAll:
*enable = (ctx->minProtocolVersion <= MINIMUM_STREAM_VERSION
&& ctx->maxProtocolVersion >= MAXIMUM_STREAM_VERSION);
break;
default:
return errSecParam;
}
return errSecSuccess;
}
OSStatus
SSLSetProtocolVersion (SSLContextRef ctx,
SSLProtocol version)
{
if(ctx == NULL) {
return errSecParam;
}
if(sslIsSessionActive(ctx) || ctx->isDTLS) {
return errSecBadReq;
}
switch(version) {
case kSSLProtocol3:
ctx->minProtocolVersion = MINIMUM_STREAM_VERSION;
ctx->maxProtocolVersion = SSL_Version_3_0;
break;
case kSSLProtocol3Only:
ctx->minProtocolVersion = SSL_Version_3_0;
ctx->maxProtocolVersion = SSL_Version_3_0;
break;
case kTLSProtocol1:
ctx->minProtocolVersion = MINIMUM_STREAM_VERSION;
ctx->maxProtocolVersion = TLS_Version_1_0;
break;
case kTLSProtocol1Only:
ctx->minProtocolVersion = TLS_Version_1_0;
ctx->maxProtocolVersion = TLS_Version_1_0;
break;
case kTLSProtocol11:
ctx->minProtocolVersion = MINIMUM_STREAM_VERSION;
ctx->maxProtocolVersion = TLS_Version_1_1;
break;
case kTLSProtocol12:
case kSSLProtocolAll:
case kSSLProtocolUnknown:
ctx->minProtocolVersion = MINIMUM_STREAM_VERSION;
ctx->maxProtocolVersion = MAXIMUM_STREAM_VERSION;
break;
default:
return errSecParam;
}
tls_handshake_set_min_protocol_version(ctx->hdsk, ctx->minProtocolVersion);
tls_handshake_set_max_protocol_version(ctx->hdsk, ctx->maxProtocolVersion);
return errSecSuccess;
}
OSStatus
SSLGetProtocolVersion (SSLContextRef ctx,
SSLProtocol *protocol)
{
if(ctx == NULL) {
return errSecParam;
}
if (ctx->maxProtocolVersion == MAXIMUM_STREAM_VERSION) {
if(ctx->minProtocolVersion == MINIMUM_STREAM_VERSION) {
*protocol = kSSLProtocolAll;
return errSecSuccess;
}
} else if (ctx->maxProtocolVersion == TLS_Version_1_1) {
if(ctx->minProtocolVersion == MINIMUM_STREAM_VERSION) {
*protocol = kTLSProtocol11;
return errSecSuccess;
}
} else if (ctx->maxProtocolVersion == TLS_Version_1_0) {
if(ctx->minProtocolVersion == MINIMUM_STREAM_VERSION) {
*protocol = kTLSProtocol1;
return errSecSuccess;
} else if(ctx->minProtocolVersion == TLS_Version_1_0) {
*protocol = kTLSProtocol1Only;
}
} else if(ctx->maxProtocolVersion == SSL_Version_3_0) {
if(ctx->minProtocolVersion == MINIMUM_STREAM_VERSION) {
*protocol = kSSLProtocol3;
return errSecSuccess;
}
}
return errSecParam;
}
OSStatus
SSLGetNegotiatedProtocolVersion (SSLContextRef ctx,
SSLProtocol *protocol)
{
if(ctx == NULL) {
return errSecParam;
}
*protocol = SSLProtocolVersionToProtocol(ctx->negProtocolVersion);
return errSecSuccess;
}
OSStatus
SSLSetEnableCertVerify (SSLContextRef ctx,
Boolean enableVerify)
{
if(ctx == NULL) {
return errSecParam;
}
sslCertDebug("SSLSetEnableCertVerify %s",
enableVerify ? "true" : "false");
if(sslIsSessionActive(ctx)) {
return errSecBadReq;
}
ctx->enableCertVerify = enableVerify;
return errSecSuccess;
}
OSStatus
SSLGetEnableCertVerify (SSLContextRef ctx,
Boolean *enableVerify)
{
if(ctx == NULL) {
return errSecParam;
}
*enableVerify = ctx->enableCertVerify;
return errSecSuccess;
}
OSStatus
SSLSetAllowsExpiredCerts(SSLContextRef ctx,
Boolean allowExpired)
{
return 0;
}
OSStatus
SSLGetAllowsExpiredCerts (SSLContextRef ctx,
Boolean *allowExpired)
{
return errSecUnimplemented;
}
OSStatus
SSLSetAllowsExpiredRoots(SSLContextRef ctx,
Boolean allowExpired)
{
return 0;
}
OSStatus
SSLGetAllowsExpiredRoots (SSLContextRef ctx,
Boolean *allowExpired)
{
return errSecUnimplemented;
}
OSStatus SSLSetAllowsAnyRoot(
SSLContextRef ctx,
Boolean anyRoot)
{
if(ctx == NULL) {
return errSecParam;
}
sslCertDebug("SSLSetAllowsAnyRoot %s", anyRoot ? "true" : "false");
ctx->allowAnyRoot = anyRoot;
return errSecSuccess;
}
OSStatus
SSLGetAllowsAnyRoot(
SSLContextRef ctx,
Boolean *anyRoot)
{
if(ctx == NULL) {
return errSecParam;
}
*anyRoot = ctx->allowAnyRoot;
return errSecSuccess;
}
#if !TARGET_OS_IPHONE
static OSStatus sslDefaultSystemRoots(
SSLContextRef ctx,
CFArrayRef *systemRoots)
{
const char *hostname;
size_t len;
tls_handshake_get_peer_hostname(ctx->hdsk, &hostname, &len);
return SecTrustSettingsCopyQualifiedCerts(&CSSMOID_APPLE_TP_SSL,
hostname,
(uint32_t)len,
(ctx->protocolSide == kSSLServerSide) ?
CSSM_KEYUSE_VERIFY : CSSM_KEYUSE_ENCRYPT,
systemRoots);
}
#endif
OSStatus
SSLSetTrustedRoots (SSLContextRef ctx,
CFArrayRef trustedRoots,
Boolean replaceExisting)
{
if (sslIsSessionActive(ctx)) {
return errSecBadReq;
}
sslCertDebug("SSLSetTrustedRoot numCerts %d replaceExist %s",
(int)CFArrayGetCount(trustedRoots), replaceExisting ? "true" : "false");
if (replaceExisting) {
ctx->trustedCertsOnly = true;
CFReleaseNull(ctx->trustedCerts);
}
if (ctx->trustedCerts) {
CFIndex count = CFArrayGetCount(trustedRoots);
CFRange range = { 0, count };
CFArrayAppendArray(ctx->trustedCerts, trustedRoots, range);
} else {
require(ctx->trustedCerts =
CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, trustedRoots),
errOut);
}
return errSecSuccess;
errOut:
return errSecAllocate;
}
OSStatus
SSLCopyTrustedRoots (SSLContextRef ctx,
CFArrayRef *trustedRoots)
{
if(ctx == NULL || trustedRoots == NULL) {
return errSecParam;
}
if(ctx->trustedCerts != NULL) {
*trustedRoots = ctx->trustedCerts;
CFRetain(ctx->trustedCerts);
return errSecSuccess;
}
#if TARGET_OS_OSX
return sslDefaultSystemRoots(ctx, trustedRoots);
#else
*trustedRoots = NULL;
return errSecSuccess;
#endif
}
#if !TARGET_OS_IPHONE
OSStatus
SSLSetTrustedLeafCertificates (SSLContextRef ctx,
CFArrayRef trustedCerts)
{
if(ctx == NULL) {
return errSecParam;
}
if(sslIsSessionActive(ctx)) {
return errSecBadReq;
}
if(ctx->trustedLeafCerts) {
CFRelease(ctx->trustedLeafCerts);
}
ctx->trustedLeafCerts = CFRetainSafe(trustedCerts);
return errSecSuccess;
}
OSStatus
SSLCopyTrustedLeafCertificates (SSLContextRef ctx,
CFArrayRef *trustedCerts)
{
if(ctx == NULL) {
return errSecParam;
}
if(ctx->trustedLeafCerts != NULL) {
*trustedCerts = ctx->trustedLeafCerts;
CFRetain(ctx->trustedCerts);
return errSecSuccess;
}
*trustedCerts = NULL;
return errSecSuccess;
}
#endif
OSStatus
SSLSetClientSideAuthenticate (SSLContext *ctx,
SSLAuthenticate auth)
{
if(ctx == NULL) {
return errSecParam;
}
if(sslIsSessionActive(ctx)) {
return errSecBadReq;
}
ctx->clientAuth = auth;
switch(auth) {
case kNeverAuthenticate:
tls_handshake_set_client_auth(ctx->hdsk, false);
break;
case kAlwaysAuthenticate:
case kTryAuthenticate:
tls_handshake_set_client_auth(ctx->hdsk, true);
break;
}
return errSecSuccess;
}
OSStatus
SSLGetClientSideAuthenticate (SSLContext *ctx,
SSLAuthenticate *auth)
{
if(ctx == NULL || auth == NULL) {
return errSecParam;
}
*auth = ctx->clientAuth;
return errSecSuccess;
}
OSStatus
SSLGetClientCertificateState (SSLContextRef ctx,
SSLClientCertificateState *clientState)
{
if(ctx == NULL) {
return errSecParam;
}
if(ctx->protocolSide == kSSLClientSide) {
switch(ctx->clientCertState) {
case kSSLClientCertNone:
*clientState = kSSLClientCertNone;
break;
case kSSLClientCertRequested:
if(ctx->localCertArray) {
*clientState = kSSLClientCertSent;
} else {
*clientState = kSSLClientCertRequested;
}
break;
default:
sslErrorLog("TLS client has invalid internal clientCertState (%d)\n", ctx->clientCertState);
return errSSLInternal;
}
} else {
switch(ctx->clientCertState) {
case kSSLClientCertNone:
case kSSLClientCertRejected:
*clientState = ctx->clientCertState;
break;
case kSSLClientCertRequested:
if(ctx->peerSecTrust) {
*clientState = kSSLClientCertSent;
} else {
*clientState = kSSLClientCertRequested;
}
break;
default:
sslErrorLog("TLS server has invalid internal clientCertState (%d)\n", ctx->clientCertState);
return errSSLInternal;
}
}
return errSecSuccess;
}
#include <tls_helpers.h>
OSStatus
SSLSetCertificate (SSLContextRef ctx,
CFArrayRef _Nullable certRefs)
{
OSStatus ortn;
if(ctx == NULL) {
return errSecParam;
}
CFReleaseNull(ctx->localCertArray);
if(certRefs == NULL) {
return errSecSuccess; }
ortn = tls_helper_set_identity_from_array(ctx->hdsk, certRefs);
if(ortn == noErr) {
ctx->localCertArray = certRefs;
CFRetain(certRefs);
}
return ortn;
}
OSStatus
SSLSetEncryptionCertificate (SSLContextRef ctx,
CFArrayRef certRefs)
{
if(ctx == NULL) {
return errSecParam;
}
if(sslIsSessionActive(ctx)) {
return errSecBadReq;
}
CFReleaseNull(ctx->encryptCertArray);
ctx->encryptCertArray = certRefs;
CFRetain(certRefs);
return errSecSuccess;
}
OSStatus SSLGetCertificate(SSLContextRef ctx,
CFArrayRef *certRefs)
{
if(ctx == NULL) {
return errSecParam;
}
*certRefs = ctx->localCertArray;
return errSecSuccess;
}
OSStatus SSLGetEncryptionCertificate(SSLContextRef ctx,
CFArrayRef *certRefs)
{
if(ctx == NULL) {
return errSecParam;
}
*certRefs = ctx->encryptCertArray;
return errSecSuccess;
}
OSStatus
SSLSetPeerID (SSLContext *ctx,
const void *peerID,
size_t peerIDLen)
{
OSStatus serr;
if((ctx == NULL) ||
(peerID == NULL) ||
(peerIDLen == 0)) {
return errSecParam;
}
if(sslIsSessionActive(ctx) &&
(ctx->clientCertState != kSSLClientCertRequested))
{
return errSecBadReq;
}
SSLFreeBuffer(&ctx->peerID);
serr = SSLAllocBuffer(&ctx->peerID, peerIDLen);
if(serr) {
return serr;
}
tls_handshake_set_resumption(ctx->hdsk, true);
memmove(ctx->peerID.data, peerID, peerIDLen);
return errSecSuccess;
}
OSStatus
SSLGetPeerID (SSLContextRef ctx,
const void **peerID,
size_t *peerIDLen)
{
*peerID = ctx->peerID.data; *peerIDLen = ctx->peerID.length;
return errSecSuccess;
}
OSStatus
SSLGetNegotiatedCipher (SSLContextRef ctx,
SSLCipherSuite *cipherSuite)
{
if(ctx == NULL) {
return errSecParam;
}
if(!sslIsSessionActive(ctx)) {
return errSecBadReq;
}
*cipherSuite = (SSLCipherSuite)tls_handshake_get_negotiated_cipherspec(ctx->hdsk);
return errSecSuccess;
}
OSStatus
SSLAddDistinguishedName(
SSLContextRef ctx,
const void *derDN,
size_t derDNLen)
{
DNListElem *dn;
OSStatus err;
if(ctx == NULL) {
return errSecParam;
}
if(sslIsSessionActive(ctx)) {
return errSecBadReq;
}
dn = (DNListElem *)sslMalloc(sizeof(DNListElem));
if(dn == NULL) {
return errSecAllocate;
}
if ((err = SSLAllocBuffer(&dn->derDN, derDNLen)))
{
sslFree(dn);
return err;
}
memcpy(dn->derDN.data, derDN, derDNLen);
dn->next = ctx->acceptableDNList;
ctx->acceptableDNList = dn;
tls_handshake_set_acceptable_dn_list(ctx->hdsk, dn);
return errSecSuccess;
}
static OSStatus
sslAddCA(SSLContextRef ctx,
SecCertificateRef cert)
{
OSStatus ortn = errSecParam;
#if TARGET_OS_IPHONE
CFDataRef subjectName = NULL;
subjectName = SecCertificateCopySubjectSequence(cert);
require(subjectName, errOut);
#else
CSSM_DATA_PTR subjectName = NULL;
ortn = SecCertificateCopyFirstFieldValue(cert, &CSSMOID_X509V1SubjectNameStd, &subjectName);
require_noerr(ortn, errOut);
#endif
if(ctx->acceptableCAs == NULL) {
require(ctx->acceptableCAs = CFArrayCreateMutable(NULL, 0,
&kCFTypeArrayCallBacks), errOut);
if(ctx->acceptableCAs == NULL) {
return errSecAllocate;
}
}
CFArrayAppendValue(ctx->acceptableCAs, cert);
#if TARGET_OS_IPHONE
ortn = SSLAddDistinguishedName(ctx,
CFDataGetBytePtr(subjectName),
CFDataGetLength(subjectName));
#else
ortn = SSLAddDistinguishedName(ctx, subjectName->Data, subjectName->Length);
#endif
errOut:
#if TARGET_OS_IPHONE
CFReleaseSafe(subjectName);
#endif
return ortn;
}
OSStatus
SSLSetCertificateAuthorities(SSLContextRef ctx,
CFTypeRef certificateOrArray,
Boolean replaceExisting)
{
CFTypeID itemType;
OSStatus ortn = errSecSuccess;
if((ctx == NULL) || sslIsSessionActive(ctx) ||
(ctx->protocolSide != kSSLServerSide)) {
return errSecParam;
}
if(replaceExisting) {
sslFreeDnList(ctx);
if(ctx->acceptableCAs) {
CFRelease(ctx->acceptableCAs);
ctx->acceptableCAs = NULL;
}
}
itemType = CFGetTypeID(certificateOrArray);
if(itemType == SecCertificateGetTypeID()) {
ortn = sslAddCA(ctx, (SecCertificateRef)certificateOrArray);
}
else if(itemType == CFArrayGetTypeID()) {
CFArrayRef cfa = (CFArrayRef)certificateOrArray;
CFIndex numCerts = CFArrayGetCount(cfa);
CFIndex dex;
for(dex=0; dex<numCerts; dex++) {
SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(cfa, dex);
if(CFGetTypeID(cert) != SecCertificateGetTypeID()) {
return errSecParam;
}
ortn = sslAddCA(ctx, cert);
if(ortn) {
break;
}
}
}
else {
ortn = errSecParam;
}
return ortn;
}
OSStatus
SSLCopyCertificateAuthorities(SSLContextRef ctx,
CFArrayRef *certificates)
{
if((ctx == NULL) || (certificates == NULL)) {
return errSecParam;
}
if(ctx->acceptableCAs == NULL) {
*certificates = NULL;
return errSecSuccess;
}
*certificates = ctx->acceptableCAs;
CFRetain(ctx->acceptableCAs);
return errSecSuccess;
}
OSStatus
SSLCopyDistinguishedNames (SSLContextRef ctx,
CFArrayRef *names)
{
CFMutableArrayRef outArray = NULL;
const DNListElem *dn;
if((ctx == NULL) || (names == NULL)) {
return errSecParam;
}
if(ctx->protocolSide==kSSLServerSide) {
dn = ctx->acceptableDNList;
} else {
dn = tls_handshake_get_peer_acceptable_dn_list(ctx->hdsk); }
if(dn == NULL) {
*names = NULL;
return errSecSuccess;
}
outArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
while (dn) {
CFDataRef cfDn = CFDataCreate(NULL, dn->derDN.data, dn->derDN.length);
CFArrayAppendValue(outArray, cfDn);
CFRelease(cfDn);
dn = dn->next;
}
*names = outArray;
return errSecSuccess;
}
OSStatus
SSLCopyPeerCertificates (SSLContextRef ctx, CFArrayRef *certs)
{
if(ctx == NULL) {
return errSecParam;
}
if (!ctx->peerSecTrust) {
*certs = NULL;
return errSecBadReq;
}
CFIndex count = SecTrustGetCertificateCount(ctx->peerSecTrust);
CFMutableArrayRef ca = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks);
if (ca == NULL) {
return errSecAllocate;
}
for (CFIndex ix = 0; ix < count; ++ix) {
CFArrayAppendValue(ca, SecTrustGetCertificateAtIndex(ctx->peerSecTrust, ix));
}
*certs = ca;
return errSecSuccess;
}
#if !TARGET_OS_IPHONE
OSStatus
SSLGetPeerCertificates (SSLContextRef ctx,
CFArrayRef *certs);
OSStatus
SSLGetPeerCertificates (SSLContextRef ctx,
CFArrayRef *certs)
{
return errSecUnimplemented;
}
#endif
OSStatus SSLSetDiffieHellmanParams(
SSLContextRef ctx,
const void *dhParams,
size_t dhParamsLen)
{
#if APPLE_DH
if(ctx == NULL) {
return errSecParam;
}
if(sslIsSessionActive(ctx)) {
return errSecBadReq;
}
SSLFreeBuffer(&ctx->dhParamsEncoded);
OSStatus ortn;
ortn = SSLCopyBufferFromData(dhParams, dhParamsLen,
&ctx->dhParamsEncoded);
if(ortn) {
return ortn;
} else {
return tls_handshake_set_dh_parameters(ctx->hdsk, &ctx->dhParamsEncoded);
}
#endif
}
OSStatus SSLGetDiffieHellmanParams(
SSLContextRef ctx,
const void **dhParams,
size_t *dhParamsLen)
{
#if APPLE_DH
if(ctx == NULL) {
return errSecParam;
}
*dhParams = ctx->dhParamsEncoded.data;
*dhParamsLen = ctx->dhParamsEncoded.length;
return errSecSuccess;
#else
return errSecUnimplemented;
#endif
}
OSStatus SSLSetDHEEnabled(SSLContextRef ctx, bool enabled)
{
ctx->dheEnabled = enabled;
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;
}
OSStatus SSLGetDHEEnabled(SSLContextRef ctx, bool *enabled)
{
*enabled = ctx->dheEnabled;
return noErr;
}
OSStatus SSLSetMinimumDHGroupSize(SSLContextRef ctx, unsigned nbits)
{
return tls_handshake_set_min_dh_group_size(ctx->hdsk, nbits);
}
OSStatus SSLGetMinimumDHGroupSize(SSLContextRef ctx, unsigned *nbits)
{
return tls_handshake_get_min_dh_group_size(ctx->hdsk, nbits);
}
OSStatus SSLSetRsaBlinding(
SSLContextRef ctx,
Boolean blinding)
{
if(ctx == NULL) {
return errSecParam;
}
ctx->rsaBlindingEnable = blinding;
return errSecSuccess;
}
OSStatus SSLGetRsaBlinding(
SSLContextRef ctx,
Boolean *blinding)
{
if(ctx == NULL) {
return errSecParam;
}
*blinding = ctx->rsaBlindingEnable;
return errSecSuccess;
}
OSStatus
SSLCopyPeerTrust(
SSLContextRef ctx,
SecTrustRef *trust)
{
OSStatus status = errSecSuccess;
if (ctx == NULL || trust == NULL) {
return errSecParam;
}
if (!ctx->peerSecTrust) {
status = sslCreateSecTrust(ctx, &ctx->peerSecTrust);
}
*trust = ctx->peerSecTrust;
if (ctx->peerSecTrust) {
CFRetain(ctx->peerSecTrust);
}
return status;
}
OSStatus SSLGetPeerSecTrust(
SSLContextRef ctx,
SecTrustRef *trust)
{
OSStatus status = errSecSuccess;
if (ctx == NULL || trust == NULL)
return errSecParam;
if (!ctx->peerSecTrust) {
status = sslCreateSecTrust(ctx, &ctx->peerSecTrust);
}
*trust = ctx->peerSecTrust;
return status;
}
OSStatus SSLInternalMasterSecret(
SSLContextRef ctx,
void *secret, size_t *secretSize) {
if((ctx == NULL) || (secret == NULL) || (secretSize == NULL)) {
return errSecParam;
}
return tls_handshake_internal_master_secret(ctx->hdsk, secret, secretSize);
}
OSStatus SSLInternalServerRandom(
SSLContextRef ctx,
void *randBuf, size_t *randSize) {
if((ctx == NULL) || (randBuf == NULL) || (randSize == NULL)) {
return errSecParam;
}
return tls_handshake_internal_server_random(ctx->hdsk, randBuf, randSize);
}
OSStatus SSLInternalClientRandom(
SSLContextRef ctx,
void *randBuf, size_t *randSize) {
if((ctx == NULL) || (randBuf == NULL) || (randSize == NULL)) {
return errSecParam;
}
return tls_handshake_internal_client_random(ctx->hdsk, randBuf, randSize);
}
OSStatus SSLGetCipherSizes(
SSLContextRef ctx,
size_t *digestSize,
size_t *symmetricKeySize,
size_t *ivSize)
{
if((ctx == NULL) || (digestSize == NULL) ||
(symmetricKeySize == NULL) || (ivSize == NULL)) {
return errSecParam;
}
SSLCipherSuite cipher=tls_handshake_get_negotiated_cipherspec(ctx->hdsk);
*digestSize = sslCipherSuiteGetMacSize(cipher);
*symmetricKeySize = sslCipherSuiteGetSymmetricCipherKeySize(cipher);
*ivSize = sslCipherSuiteGetSymmetricCipherBlockIvSize(cipher);
return errSecSuccess;
}
OSStatus
SSLGetResumableSessionInfo(
SSLContextRef ctx,
Boolean *sessionWasResumed, void *sessionID, size_t *sessionIDLength) {
if((ctx == NULL) || (sessionWasResumed == NULL) ||
(sessionID == NULL) || (sessionIDLength == NULL) ||
(*sessionIDLength < MAX_SESSION_ID_LENGTH)) {
return errSecParam;
}
SSLBuffer localSessionID;
bool sessionMatch = tls_handshake_get_session_match(ctx->hdsk, &localSessionID);
if(sessionMatch) {
*sessionWasResumed = true;
if(localSessionID.length > *sessionIDLength) {
return errSecParam;
}
if(localSessionID.length) {
memmove(sessionID, localSessionID.data, localSessionID.length);
}
*sessionIDLength = localSessionID.length;
}
else {
*sessionWasResumed = false;
*sessionIDLength = 0;
}
return errSecSuccess;
}
OSStatus
SSLSetAllowAnonymousCiphers(
SSLContextRef ctx,
Boolean enable)
{
return errSecSuccess;
}
OSStatus
SSLGetAllowAnonymousCiphers(
SSLContextRef ctx,
Boolean *enable)
{
return errSecSuccess;
}
OSStatus
SSLSetSessionCacheTimeout(
SSLContextRef ctx,
uint32_t timeoutInSeconds)
{
if(ctx == NULL) {
return errSecParam;
}
ctx->sessionCacheTimeout = timeoutInSeconds;
return errSecSuccess;
}
static
void tls_handshake_master_secret_function(const void *arg,
void *secret,
size_t *secretLength)
{
SSLContextRef ctx = (SSLContextRef) arg;
ctx->masterSecretCallback(ctx, ctx->masterSecretArg, secret, secretLength);
}
OSStatus
SSLInternalSetMasterSecretFunction(
SSLContextRef ctx,
SSLInternalMasterSecretFunction mFunc,
const void *arg)
{
if(ctx == NULL) {
return errSecParam;
}
ctx->masterSecretArg = arg;
ctx->masterSecretCallback = mFunc;
return tls_handshake_internal_set_master_secret_function(ctx->hdsk, &tls_handshake_master_secret_function, ctx);
}
OSStatus SSLInternalSetSessionTicket(
SSLContextRef ctx,
const void *ticket,
size_t ticketLength)
{
if(ctx == NULL) {
return errSecParam;
}
if(sslIsSessionActive(ctx)) {
return errSecBadReq;
}
return tls_handshake_internal_set_session_ticket(ctx->hdsk, ticket, ticketLength);
}
OSStatus SSLGetNegotiatedCurve(
SSLContextRef ctx,
SSL_ECDSA_NamedCurve *namedCurve)
{
if((ctx == NULL) || (namedCurve == NULL)) {
return errSecParam;
}
unsigned int curve = tls_handshake_get_negotiated_curve(ctx->hdsk);
if(curve == SSL_Curve_None) {
return errSecParam;
}
*namedCurve = curve;
return errSecSuccess;
}
OSStatus SSLGetNumberOfECDSACurves(
SSLContextRef ctx,
unsigned *numCurves)
{
if((ctx == NULL) || (numCurves == NULL)) {
return errSecParam;
}
*numCurves = ctx->ecdhNumCurves;
return errSecSuccess;
}
OSStatus SSLGetECDSACurves(
SSLContextRef ctx,
SSL_ECDSA_NamedCurve *namedCurves,
unsigned *numCurves)
{
if((ctx == NULL) || (namedCurves == NULL) || (numCurves == NULL)) {
return errSecParam;
}
if(*numCurves < ctx->ecdhNumCurves) {
return errSecParam;
}
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;
}
OSStatus SSLSetECDSACurves(
SSLContextRef ctx,
const SSL_ECDSA_NamedCurve *namedCurves,
unsigned numCurves)
{
if((ctx == NULL) || (namedCurves == NULL) || (numCurves == 0)) {
return errSecParam;
}
if(sslIsSessionActive(ctx)) {
return errSecBadReq;
}
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++) {
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);
return errSecSuccess;
}
OSStatus SSLGetNumberOfClientAuthTypes(
SSLContextRef ctx,
unsigned *numTypes)
{
if((ctx == NULL) || (ctx->clientCertState == kSSLClientCertNone)) {
return errSecParam;
}
*numTypes = ctx->numAuthTypes;
return errSecSuccess;
}
OSStatus SSLGetClientAuthTypes(
SSLContextRef ctx,
SSLClientAuthenticationType *authTypes,
unsigned *numTypes)
{
if((ctx == NULL) || (ctx->clientCertState == kSSLClientCertNone)) {
return errSecParam;
}
memmove(authTypes, ctx->clientAuthTypes,
ctx->numAuthTypes * sizeof(SSLClientAuthenticationType));
*numTypes = ctx->numAuthTypes;
return errSecSuccess;
}
OSStatus SSLGetNegotiatedClientAuthType(
SSLContextRef ctx,
SSLClientAuthenticationType *authType)
{
return errSecUnimplemented;
}
OSStatus SSLGetNumberOfSignatureAlgorithms(
SSLContextRef ctx,
unsigned *numSigAlgs)
{
if(ctx == NULL){
return errSecParam;
}
tls_handshake_get_peer_signature_algorithms(ctx->hdsk, numSigAlgs);
return errSecSuccess;
}
_Static_assert(sizeof(SSLSignatureAndHashAlgorithm)==sizeof(tls_signature_and_hash_algorithm),
"SSLSignatureAndHashAlgorithm and tls_signature_and_hash_algorithm do not match");
OSStatus SSLGetSignatureAlgorithms(
SSLContextRef ctx,
SSLSignatureAndHashAlgorithm *sigAlgs,
unsigned *numSigAlgs)
{
if(ctx == NULL) {
return errSecParam;
}
unsigned numPeerSigAlgs;
const tls_signature_and_hash_algorithm *peerAlgs = tls_handshake_get_peer_signature_algorithms(ctx->hdsk, &numPeerSigAlgs);
memmove(sigAlgs, peerAlgs,
numPeerSigAlgs * sizeof(SSLSignatureAndHashAlgorithm));
*numSigAlgs = numPeerSigAlgs;
return errSecSuccess;
}
OSStatus SSLSetPSKSharedSecret(SSLContextRef ctx,
const void *secret,
size_t secretLen)
{
if(ctx == NULL) return errSecParam;
if(ctx->pskSharedSecret.data)
SSLFreeBuffer(&ctx->pskSharedSecret);
if(SSLCopyBufferFromData(secret, secretLen, &ctx->pskSharedSecret))
return errSecAllocate;
tls_handshake_set_psk_secret(ctx->hdsk, &ctx->pskSharedSecret);
return errSecSuccess;
}
OSStatus SSLSetPSKIdentity(SSLContextRef ctx,
const void *pskIdentity,
size_t pskIdentityLen)
{
if((ctx == NULL) || (pskIdentity == NULL) || (pskIdentityLen == 0)) return errSecParam;
if(ctx->pskIdentity.data)
SSLFreeBuffer(&ctx->pskIdentity);
if(SSLCopyBufferFromData(pskIdentity, pskIdentityLen, &ctx->pskIdentity))
return errSecAllocate;
tls_handshake_set_psk_identity(ctx->hdsk, &ctx->pskIdentity);
return errSecSuccess;
}
OSStatus SSLGetPSKIdentity(SSLContextRef ctx,
const void **pskIdentity,
size_t *pskIdentityLen)
{
if((ctx == NULL) || (pskIdentity == NULL) || (pskIdentityLen == NULL)) return errSecParam;
*pskIdentity=ctx->pskIdentity.data;
*pskIdentityLen=ctx->pskIdentity.length;
return errSecSuccess;
}
OSStatus SSLInternal_PRF(
SSLContext *ctx,
const void *vsecret,
size_t secretLen,
const void *label, size_t labelLen,
const void *seed,
size_t seedLen,
void *vout, size_t outLen)
{
return tls_handshake_internal_prf(ctx->hdsk,
vsecret, secretLen,
label, labelLen,
seed, seedLen,
vout, outLen);
}
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;
}
}
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
SSLGetSessionConfigurationIdentifier(SSLContext *ctx, SSLBuffer *buffer)
{
if (buffer == NULL) {
return errSecParam;
}
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;
}
buffer->length = 10 * sizeof(Boolean);
if (buffer->data) {
free(buffer->data);
}
buffer->data = malloc(buffer->length);
if (buffer->data == NULL) {
return errSecAllocate;
}
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);
if (offset != buffer->length) {
free(buffer->data);
return errSecInternal;
}
ctx->contextConfigurationBuffer.length = buffer->length;
ctx->contextConfigurationBuffer.data = (uint8_t *) malloc(buffer->length);
memcpy(ctx->contextConfigurationBuffer.data, buffer->data, buffer->length);
return errSecSuccess;
}