]> git.saurik.com Git - apple/security.git/blobdiff - OSX/libsecurity_ssl/lib/sslContext.c
Security-58286.41.2.tar.gz
[apple/security.git] / OSX / libsecurity_ssl / lib / sslContext.c
index 21dd4628a3e7c9ea47687f005a2fe2e5194e8871..eed80f1b744e52470069ae6e0eeb1400eb71c5ee 100644 (file)
@@ -85,6 +85,7 @@ Boolean sslIsSessionActive(const SSLContext *ctx)
                case SSL_HdskStateUninit:
                case SSL_HdskStateGracefulClose:
                case SSL_HdskStateErrorClose:
+        case SSL_HdskStateOutOfBandError:
                        return false;
                default:
                        return true;
@@ -151,6 +152,8 @@ CFTypeRef SSLPreferencesCopyValue(CFStringRef key, CFPropertyListRef managed_pre
 
     if(!value && managed_prefs) {
         value =  CFDictionaryGetValue(managed_prefs, key);
+        if (value)
+            CFRetain(value);
     }
 
     return value;
@@ -419,6 +422,7 @@ void SSLContextDestroy(CFTypeRef arg)
     SSLFreeBuffer(&ctx->peerID);
     SSLFreeBuffer(&ctx->resumableSession);
     SSLFreeBuffer(&ctx->receivedDataBuffer);
+    SSLFreeBuffer(&ctx->contextConfigurationBuffer);
 
     CFReleaseSafe(ctx->acceptableCAs);
 #if !TARGET_OS_IPHONE
@@ -467,6 +471,7 @@ SSLGetSessionState                  (SSLContextRef          context,
                        break;
                case SSL_HdskStateErrorClose:
                case SSL_HdskStateNoNotifyClose:
+        case SSL_HdskStateOutOfBandError:
                        rtnState = kSSLAborted;
                        break;
                case SSL_HdskStateReady:
@@ -488,13 +493,15 @@ SSLSetSessionOption                       (SSLContextRef          context,
                                                         SSLSessionOption       option,
                                                         Boolean                        value)
 {
-    if(context == NULL) {
-       return errSecParam;
+    if (context == NULL) {
+        return errSecParam;
     }
-    if(sslIsSessionActive(context)) {
-       /* can't do this with an active session */
-       return errSecBadReq;
+
+    if (sslIsSessionActive(context)) {
+        /* can't do this with an active session */
+        return errSecBadReq;
     }
+
     switch(option) {
         case kSSLSessionOptionBreakOnServerAuth:
             context->breakOnServerAuth = value;
@@ -509,11 +516,13 @@ SSLSetSessionOption                       (SSLContextRef          context,
             break;
         case kSSLSessionOptionSendOneByteRecord:
             /* Only call the record layer function if the value changed */
-            if(value != context->oneByteRecordEnable)
+            if (value != context->oneByteRecordEnable) {
                 context->recFuncs->setOption(context->recCtx, kSSLRecordOptionSendOneByteRecord, value);
+            }
             context->oneByteRecordEnable = value;
             break;
         case kSSLSessionOptionFalseStart:
+            tls_handshake_set_false_start(context->hdsk, value);
             context->falseStartEnabled = value;
             break;
         case kSSLSessionOptionFallback:
@@ -525,9 +534,15 @@ SSLSetSessionOption                        (SSLContextRef          context,
             break;
         case kSSLSessionOptionAllowServerIdentityChange:
             tls_handshake_set_server_identity_change(context->hdsk, value);
+            context->allowServerIdentityChange = true;
             break;
         case kSSLSessionOptionAllowRenegotiation:
             tls_handshake_set_renegotiation(context->hdsk, value);
+            context->allowRenegotiation = true;
+            break;
+        case kSSLSessionOptionEnableSessionTickets:
+            tls_handshake_set_session_ticket_enabled(context->hdsk, value);
+            context->enableSessionTickets = true;
             break;
         default:
             return errSecParam;
@@ -716,25 +731,135 @@ SSLSetALPNData(SSLContextRef      context,
 
 const void *
 SSLGetALPNData(SSLContextRef      context,
-              size_t                           *length)
+               size_t             *length)
 {
-    if (context == NULL || length == NULL)
+    if (context == NULL || length == NULL) {
         return NULL;
+    }
+
+    const tls_buffer *alpnData = tls_handshake_get_peer_alpn_data(context->hdsk);
+
+    if (alpnData) {
+        *length = alpnData->length;
+        return alpnData->data;
+    } else {
+      return NULL;
+    }
+}
+
+OSStatus
+SSLSetALPNProtocols(SSLContextRef      context,
+                    CFArrayRef         protocols)
+{
+    if (context == NULL || protocols == NULL || CFArrayGetCount(protocols) == 0) {
+        return errSecParam;
+    }
+
+    // Per RFC 7301, the protocol name can be at most 32B long.
+    const int maxBufferLength = 32;
+
+    // Append each element in the array to a mutable buffer
+    CFMutableDataRef alpnData = CFDataCreateMutable(NULL, 0);
+    CFArrayForEach(protocols, ^(const void *value) {
+        CFStringRef protocolString = (CFStringRef) value;
+        uint8_t len = CFStringGetLength(protocolString);
+        if (len <= maxBufferLength) {
+            char stringBytes[maxBufferLength];
+            if (CFStringGetCString(protocolString, stringBytes, maxBufferLength, kCFStringEncodingASCII)) {
+                CFDataAppendBytes(alpnData, (const UInt8 *) &len, sizeof(len));
+                CFDataAppendBytes(alpnData, (const UInt8 *) stringBytes, len);
+            }
+        }
+    });
+
+    // Length check
+    if (CFDataGetLength(alpnData) > 255) {
+        CFRelease(alpnData);
+        return errSecParam;
+    }
 
-    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)
@@ -1096,6 +1221,46 @@ SSLGetProtocolVersionMax  (SSLContextRef      ctx,
     return errSecSuccess;
 }
 
+tls_protocol_version
+_SSLProtocolVersionToWireFormatValue   (SSLProtocol protocol)
+{
+    switch (protocol) {
+        case kSSLProtocol3: {
+            return tls_protocol_version_SSL_3;
+        }
+        case kTLSProtocol1: {
+            return tls_protocol_version_TLS_1_0;
+        }
+        case kTLSProtocol11: {
+            return tls_protocol_version_TLS_1_1;
+        }
+        case kTLSProtocol12: {
+            return tls_protocol_version_TLS_1_2;
+        }
+        case kTLSProtocol13: {
+            return tls_protocol_version_TLS_1_3;
+        }
+        case kTLSProtocolMaxSupported: {
+            return tls_protocol_version_TLS_1_3;
+        }
+        case kDTLSProtocol1: {
+            return tls_protocol_version_DTLS_1_0;
+        }
+        case 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
@@ -2595,3 +2760,79 @@ SSLSetSessionConfig(SSLContextRef context,
         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;
+}