TLS 1.3 in SecureTransport

Wikipedia mentions that SecureTransport supports TLS version 1.3 (though they just refer to a twit from a cUrl's developer). Headers in Security framework, indeed, contain those two constants: kTLSProtocol13 and kTLSProtocolMaxSupported. However, if I try to set an upper limit to kTLSProtocol13, SSLSetProtocolVersionMax returns errIllegalParam. Worse so, I'm not able to set version to kTLSProtocolMaxSupported (the same error) and as a result I have max hardcoded to 1.2, which is not very smart/require fixes in future. Looking into the latest available source for SecureTransport:


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;

}

}


Looks like none of those two constants is handled propery (I'm not sure about the actual implementation/binaries I have in SDK). SSLSetProtocolVersionMax will return an error on 'conversion' failure - the value tls_protocol_version_Undertermined == 0 and is < MIN_STREAM_VERSION:


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 > ctx->minProtocolVersion)

ctx->minProtocolVersion = version;

} else {

if (version < MINIMUM_STREAM_VERSION || version > MAXIMUM_STREAM_VERSION)

return errSSLIllegalParam;

if (version < 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;

}


So the question is: if TLS 1.3 is supported by SecureTransport and how do I enable it or enable the future versions too using 'max supported'?

Two things:

  • iOS includes TLS 1.3 supported but it’s disabled by default. We have announced that will will enable it by default at some point in the future, but we’ve not given a concrete timeline for that.

    You can learn more about this in WWDC 2017 Session 701 Your Apps and Evolving Network Security Standards.

  • You wrote:

    Worse so, I'm not able to set version to kTLSProtocolMaxSupported (the same error) and as a result I have max hardcoded to 1.2, which is not very smart/require fixes in future.

    I recommend that you not set a max, which will give you the default maximum (TLS 1.2 currently, and TLS 1.3 at some point in the future).

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

I have enabled it on both iOS and Mac. But still get errIllegalParam when trying to set SSLSetProtocolVersionMax to kTLSProtocol13

I have enabled it on both iOS and Mac.

Enabled what? TLS 1.3? Via the configuration profile?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Yes via configuration file.

The profile should change the default maximum to TLS 1.3. What happens if you don’t call

SSLSetProtocolVersionMax
at all?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

If I dont call SSLSetProtocolVersionMax at all, it works fine. This function function work fine until kTLSProtocol12. But if I restrict my server to accept only tls1.3, I get errSSLPeerProtocolVersion error from SSLHandshake function.

If I dont call

SSLSetProtocolVersionMax
at all, it works fine.

I think your definition of “works fine” is different from mine (-: If it fails to connect to a TLS 1.3 server, it sounds like TLS 1.3 isn’t kicking in at all. You should look at a packet trace (see QA1176) to see exactly what TLS version the Client Hello is offering.

Hmmmm, this may be a Secure Transport thing. Have you tried using a high-level API for your TLS connection? For example, create a small test app that uses the Network framework to connect to your server. If you run that app with the TLS 1.3 profile installed, does the client offer TLS 1.3?

And because there’s not a lot of Network framework code out there on the ’net, I’ve pasted in a minimal example below.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
class ViewController : UIViewController {

    func start() -> NWConnection {
        NSLog("connection will state")
        let connection = NWConnection(host: "example.com", port: 443, using: .tls)
        connection.stateUpdateHandler = { state in
            let stateStr: String
            let shouldStop: Bool
            switch state {
            case .setup:
                stateStr = "setup"
                shouldStop = false
            case .waiting:
                stateStr = "waiting"
                shouldStop = false
            case .preparing:
                stateStr = "preparing"
                shouldStop = false
            case .ready:
                stateStr = "ready"
                shouldStop = false
            case .failed:
                stateStr = "failed"
                shouldStop = true
            case .cancelled:
                stateStr = "cancelled"
                shouldStop = true
            }
            NSLog("connection did update state, state: %@", stateStr)
            if shouldStop {
                self.stop(connection: connection)
            }
        }
        connection.start(queue: .main)
        return connection
    }

    func stop(connection: NWConnection) {
        NSLog("connection will stop")
        connection.stateUpdateHandler = nil
        connection.cancel()
    }

    var connection: NWConnection? = nil

    func startStop() {
        if let connection = self.connection {
            self.connection = nil
            self.stop(connection: connection)
        } else {
            self.connection = self.start()
        }
    }

    …
}
TLS 1.3 in SecureTransport
 
 
Q