Unable to set 'encrypt-then-mac' headers in TLS using network.framework

In order to use TLS-PSK with an iOS device, it seems to require that we use ciphersuites with an ETM header enabled in the TLS handshake- I'm only able to connect to an OpenSSL server when this is enabled.

How can I set this header in the network framework? It can be included by adding {0x00,0x16,0x00,0x00} in the extensions hex dump, is there a dirty way to include this if there's no API implementation?

In order to use TLS-PSK with an iOS device, it seems to require that we use ciphersuites with an ETM header enabled in the TLS handshake- I'm only able to connect to an OpenSSL server when this is enabled. How can I set this header in the network framework?

I want to make sure that I understand you question correctly; are you wanting to know how to use TLS with a preshared key in Network Framework, or are you wanting to configure something specific in how the handshake behavior is performed? If you are wanting to perform TLS with a preshared key in Network framework take a look at the function for sec_protocol_options_add_pre_shared_key. Otherwise, please tell me more about your configuration so I can best assist.

Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com

I want to connect to a server with PSK-TLS without the use of certificates, but when it attempts to send the client key exchange after saying hello to the openssl server it fails with 'bad record / mac' from the server side which the guys at OpenSSL say is an issue with the encryption on the client side. This is my code:

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

    dispatch_data_t psk = dispatch_data_create("abc123", 6, nil, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
    dispatch_data_t client_id = dispatch_data_create("test", 4, nil, DISPATCH_DATA_DESTRUCTOR_DEFAULT);

    sec_protocol_options_set_min_tls_protocol_version(sec_options, tls_protocol_version_TLSv12);
    sec_protocol_options_set_tls_max_version(sec_options, tls_protocol_version_TLSv12);

    sec_protocol_options_add_tls_ciphersuite(sec_options, (SSLCipherSuite)TLS_PSK_WITH_AES_256_GCM_SHA384);
    sec_protocol_options_set_tls_ocsp_enabled(sec_options, false);
    sec_protocol_options_set_tls_sct_enabled(sec_options, false);
    sec_protocol_options_set_peer_authentication_required(sec_options, true);
    sec_protocol_options_set_tls_renegotiation_enabled(sec_options, true);
    sec_protocol_options_set_tls_tickets_enabled(sec_options, true);
    sec_protocol_options_set_tls_resumption_enabled(sec_options, true);
    sec_protocol_options_add_pre_shared_key(sec_options, psk, client_id);
  };

  nw_parameters_t parameters = nw_parameters_create_secure_tcp(configure_tls, NW_PARAMETERS_DEFAULT_CONFIGURATION);
  nw_endpoint_t endpoint = nw_endpoint_create_host("192.168.0.29", "8888");

  nw_connection_t connection = nw_connection_create(endpoint, parameters);
  nw_connection_set_state_changed_handler(connection, ^(nw_connection_state_t state, nw_error_t error) {
    switch (state) {
      case nw_connection_state_waiting:
        NSLog(@"waiting");
        break;
      case nw_connection_state_failed:
        NSLog(@"failed");
        break;
      case nw_connection_state_ready:
        NSLog(@"connection is ready");
        break;
      case nw_connection_state_cancelled:
        NSLog(@"connection is cancelled");
        break;
      default:
        NSLog(@"other");
        break;
    }
  });
  nw_connection_set_queue(connection, dispatch_get_main_queue());
  nw_connection_start(connection);

I'm using the OpenSSL server to establish the connection with the command:

openssl3 s_server -tls1_2 -accept 8888 -nocert -psk abc123 -psk_identity test -cipher PSK-AES128-GCM-SHA384

I've tested the connection works using:

openssl3 s_client -tls1_2 -connect localhost:8888 -psk abc123 -psk_identity test -cipher PSK-AES128-GCM-SHA384

But for some reason it always fails when trying to do the iOS network.framework equivilant. I've tried with a number of ciphersuites that use PSK too so it doesn't seem to be that it is because of i.e. a deprecated ciphersuite.

I’m posting a link to Jeeeeef’s other thread, just for context.

Share and Enjoy

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

Thank you very much for including this extra context, it is very helpful. Normally in this situation I would recommend not pinning the cipher suite and letting BoringSSL and OpenSSL work this out. So I tried this and it does seem to make progress on the cipher suite negotiation:

Internet Protocol Version 4, Src: x.x.x.x, Dst: x.x.x.x
Transmission Control Protocol, Src Port: 8888, Dst Port: xxxxx, Seq: 1, Ack: 120, Len: 71
Transport Layer Security
    TLSv1.2 Record Layer: Handshake Protocol: Server Hello
        Content Type: Handshake (22)
        Version: TLS 1.2 (0x0303)
        Length: 57
        Handshake Protocol: Server Hello
            Handshake Type: Server Hello (2)
            Length: 53
            Version: TLS 1.2 (0x0303)
            Random: ***
            Session ID Length: 0
            Cipher Suite: TLS_PSK_WITH_AES_256_GCM_SHA384 (0x00a9)
            Compression Method: null (0)
            Extensions Length: 13
            Extension: renegotiation_info (len=1)
            Extension: session_ticket (len=0)
            Extension: extended_master_secret (len=0)
    TLSv1.2 Record Layer: Handshake Protocol: Server Hello Done

The key exchange is attempted:

12	1.343862	x.x.x.x - x.x.x.x	TLSv1.2	132	Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message

And then the Bad Record MAC fatal error is thrown from the OpenSSL side:

13	1.346335	x.x.x.x - x.x.x.x	TLSv1.2	73	Alert (Level: Fatal, Description: Bad Record MAC)

Again, this is run without pinning the cipher on the s_server side or the iOS side:

$ openssl s_server -tls1_2 -accept 8888 -nocert -psk abc123 -psk_identity test 
...
Using default temp DH parameters
ACCEPT
ERROR
139793020596672:error:1408F119:SSL routines:ssl3_get_record:decryption failed or bad record mac:ssl/record/ssl3_record.c:669:
shutting down SSL
CONNECTION CLOSED

So, if you continue to experience issues here, please open a TSI and I will dig further into this to try and get to the bottom of what is happening.

Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
Unable to set 'encrypt-then-mac' headers in TLS using network.framework
 
 
Q