NWProtocolTLS.Options init() supported default cipher suites iOS 13 ?

Hello,


I have a local WebSocket server running inside an iOS app on iOS 13+. I'm using Swift NIO Transport Services for the server.


I'm using NWProtocolTLS.Options from Network framework to specify TLS options for my server.


I am providing my server as an XCFramework and want to let users to be able to specify different parameters when launching the server.


For specifiying the TLS supported version, everything is working fine by using :


public func sec_protocol_options_set_max_tls_protocol_version(_ options: sec_protocol_options_t, _ version: tls_protocol_version_t)


public func sec_protocol_options_set_min_tls_protocol_version(_ options: sec_protocol_options_t, _ version: tls_protocol_version_t)


But I also want to be able to specify some cipher suites. I saw that I can use :


public func sec_protocol_options_append_tls_ciphersuite(_ options: sec_protocol_options_t, _ ciphersuite: tls_ciphersuite_t)


But it seems that some cipher suites are enabled by default and I can't restrict the cipher suites just to the ones I want, I can just append others.


NWProtocolTLS.Options class has an init() function which states "Initializes a default set of TLS connection options" on Apple documentation.


So my question is, is there a way to know what TLS parameters this initialization does ? Especially the list of cipher suites enabled by default ? Because I can't find any information about it from my research. I used a tool to test handshake with my server to discover the cipher suites supported and enabled by default but I don't think it is a good way to be sure about this information.


And is there a way to specify only cipher suites I want to be supported by my server by using NWProtocolTLS.Options ?


Thank you in advance,


Christophe

Answered by DTS Engineer in 786222022

Any updates on this?

I asked about this internally and things haven’t changed. sec_protocol_options_t has routines that let you add cyphersuites, but none that let you remove them.

ChristopheB, Did you end up filing an enhancement request for this? If so, what was the bug number.

matamatangi, Regardless of the answer to the above, I think it’d be a good idea for you to file your own enhancement request for this. Make sure to include info about why you need to disallow specific cyphersuites. And please post your bug number, just for the record.

There’s an obvious, albeit less than ideal workaround here, which is to:

  1. Accept the connection.

  2. Get the TLS protocol metadata.

  3. Get the cyphersuite from that (sec_protocol_metadata_get_negotiated_tls_ciphersuite).

  4. Drop the connection if you’re not happy with that.

This is less than ideal because a client that uses an disallowed cyphersuite gets further than it should, but it should be secure as long as you don’t transfer any data on the connection before checking the metadata.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Yes, a default set of cipher suites is not documented anywhere because different cipher suites could apply to different situations. For example, certain cipher suites used in TLS 1.2 versus TLS 1.3. tls_ciphersuite_t, does have each of the available optionslisted here by AES, Cha Cha Poly, Elliptic Curve, and RSA in case this helps.



Matt Eaton

DTS Engineering, CoreOS

meaton3 at apple.com

Hi,


Thanks for the reply, I understand.

I have seen the tls_ciphersuite_t enum but it does not help with knowing what cipher suites are supported by default when I call NWProtocolTLS.Options initializer.


So, when using NWProtocolTLS.Options initializer, I have no way to retrieve the list of cipher suites that are enabled by default in the current environment, correct ? Therefore, I cannot restrict to some specific cipher suites if I wanted to ? I can only append ones from tls_ciphersuite_t enum ?


Thanks,

Christophe B.

Accepted Answer

No, NWProtocolTLS.Options does not provide a default list of Cipher Suites.

| So, when using NWProtocolTLS.Options initializer, I have no way to retrieve the list of

| cipher suites that are enabled by default in the current environment, correct ?


There is no API to restrict NWProtocolTLS.Options to a specific Cipher Suite on a connection. I would open an enhancement request for this and follow up with the specific feedback number on this thread.

| Therefore, I cannot restrict to some specific cipher suites if I wanted to ? I can only

| append ones from tls_ciphersuite_t enum ?



Matt Eaton

DTS Engineering, CoreOS

meaton3 at apple.com

Hi,


Thank you very much for your answer, it's clear.


Okay, thanks, it would be great to be able to specify only certain cipher suites.


Christophe B.

Any updates on this? I have a macOS app that creates a network listener and I need to limit what ciphers are available due to security requirements. It is easy enough to limit the version of TLS, but removing a default cipher doesn't seem to currently be an option.

I want to remove TLS_RSA_WITH_3DES_EDE_CBC_SHA and TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 from TLS1v.2 and TLS_AKE_WITH_CHACHA20_POLY1305_SHA256 from TLS 1.3.

I can see what ciphers are available using nmap:

nmap -Pn  --script ssl-enum-ciphers -p 4116 sra.local

4116/tcp open  smartcard-tls
| ssl-enum-ciphers: 
|   TLSv1.2: 
|     ciphers: 
|       TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA (secp256r1) - C
|       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (secp256r1) - A
|       TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (secp256r1) - A
|       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (secp256r1) - A
|       TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (secp256r1) - A
|       TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (secp256r1) - A
|       TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C
|       TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_AES_128_GCM_SHA256 (rsa 2048) - A
|       TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_AES_256_GCM_SHA384 (rsa 2048) - A
|     compressors: 
|       NULL
|     cipher preference: client
|     warnings: 
|       64-bit block cipher 3DES vulnerable to SWEET32 attack
|   TLSv1.3: 
|     ciphers: 
|       TLS_AKE_WITH_AES_128_GCM_SHA256 (secp256r1) - A
|       TLS_AKE_WITH_AES_256_GCM_SHA384 (secp256r1) - A
|       TLS_AKE_WITH_CHACHA20_POLY1305_SHA256 (secp256r1) - A
|     cipher preference: client
|_  least strength: C

and I set up the listener this way:

nw_parameters_configure_protocol_block_t configure_tls = NW_PARAMETERS_DISABLE_PROTOCOL;

configure_tls = ^(nw_protocol_options_t tls_options) {
sec_protocol_options_t sec_options = nw_tls_copy_sec_protocol_options(tls_options);

sec_identity_t sec_identity=sec_identity_create(identity);
sec_protocol_options_set_local_identity(sec_options, sec_identity);
sec_protocol_options_set_min_tls_protocol_version(sec_options, tls_protocol_version_TLSv12);
sec_options=nil;
};


nw_parameters_configure_protocol_block_t configure_tcp;

configure_tcp = ^(nw_protocol_options_t tcp_options) {
nw_tcp_options_set_enable_keepalive(tcp_options,true);
nw_tcp_options_set_keepalive_count(tcp_options, 15);
nw_tcp_options_set_keepalive_interval(tcp_options, 15);
nw_tcp_options_set_keepalive_idle_time(tcp_options, 15);
};

parameters = nw_parameters_create_secure_tcp(configure_tls,
configure_tcp);

// Bind to local address and port
const char *address = name; // Treat name as local address if not bonjour
if (localOnly) address="127.0.0.1";
if (address || port) {
nw_endpoint_t local_endpoint = nw_endpoint_create_host(address?address:"::",port?port:"0" );
nw_parameters_set_local_endpoint(parameters, local_endpoint);
local_endpoint=nil;
}

nw_listener_t listener = nw_listener_create(parameters);

Any guidance would be most appreciated!

Any updates on this?

I asked about this internally and things haven’t changed. sec_protocol_options_t has routines that let you add cyphersuites, but none that let you remove them.

ChristopheB, Did you end up filing an enhancement request for this? If so, what was the bug number.

matamatangi, Regardless of the answer to the above, I think it’d be a good idea for you to file your own enhancement request for this. Make sure to include info about why you need to disallow specific cyphersuites. And please post your bug number, just for the record.

There’s an obvious, albeit less than ideal workaround here, which is to:

  1. Accept the connection.

  2. Get the TLS protocol metadata.

  3. Get the cyphersuite from that (sec_protocol_metadata_get_negotiated_tls_ciphersuite).

  4. Drop the connection if you’re not happy with that.

This is less than ideal because a client that uses an disallowed cyphersuite gets further than it should, but it should be secure as long as you don’t transfer any data on the connection before checking the metadata.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thanks Quinn. FB13755719 filed.

It worked. In nw_connection_set_state_changed_handler, i did this:

     if (state == nw_connection_state_ready) {
            fprintf(stderr, "Connection to %s port %u (%s) succeeded!\n",
                    nw_endpoint_get_hostname(remote),
                    nw_endpoint_get_port(remote),
                    "tcp");

        nw_protocol_definition_t definition=nw_protocol_copy_tls_definition();

        if (definition==0){
            tcslogdebug(@"nw_protocol_copy_tls_definition failed. Dropping.");

            [self disconnect];
            return;
        }
        nw_protocol_metadata_t metadata =  nw_connection_copy_protocol_metadata(connection, definition);
        if (metadata==0){

            tcslogdebug(@"nw_connection_copy_protocol_metadata failed. Dropping.");
            [self disconnect];
            return;

        }
        sec_protocol_metadata_t sec_metadata = nw_tls_copy_sec_protocol_metadata(metadata);

        if (sec_metadata == 0){
            tcslogdebug(@"nw_tls_copy_sec_protocol_metadata failed. Dropping.");

            [self disconnect];
            return;
        }
        tls_ciphersuite_t ciphersuite = sec_protocol_metadata_get_negotiated_tls_ciphersuite(sec_metadata);
        tcslogdebug(@"ciphersuite: 0x%x",ciphersuite);

        if (ciphersuite==0 || ciphersuite == 0xFFFF){
            tcslogdebug(@"sec_protocol_metadata_get_negotiated_tls_ciphersuite failed. Dropping.");
            [self disconnect];
            return;
        }
        switch (ciphersuite) {
            case tls_ciphersuite_RSA_WITH_3DES_EDE_CBC_SHA:
            case tls_ciphersuite_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
            case tls_ciphersuite_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
                tcslogdebug(@"disallowed cipher suite. dropping");
                [self disconnect];
                return;
                break;
            default:
                break;
        }

On a related note, I am looking to return the certificate chain of trust. I posted that here:

https://forums.developer.apple.com/forums/thread/758154

NWProtocolTLS.Options init() supported default cipher suites iOS 13 ?
 
 
Q