case SSL_HdskStateUninit:
case SSL_HdskStateGracefulClose:
case SSL_HdskStateErrorClose:
+ case SSL_HdskStateOutOfBandError:
return false;
default:
return true;
if(!value && managed_prefs) {
value = CFDictionaryGetValue(managed_prefs, key);
+ if (value)
+ CFRetain(value);
}
return value;
SSLFreeBuffer(&ctx->peerID);
SSLFreeBuffer(&ctx->resumableSession);
SSLFreeBuffer(&ctx->receivedDataBuffer);
+ SSLFreeBuffer(&ctx->contextConfigurationBuffer);
CFReleaseSafe(ctx->acceptableCAs);
#if !TARGET_OS_IPHONE
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 *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;
+ }
- const tls_buffer *alpn_data;
+ // 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);
- alpn_data = tls_handshake_get_peer_alpn_data(context->hdsk);
+ // 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)
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 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
return errSecParam;
}
}
+
+OSStatus
+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;
+}