Thanks for being a part of WWDC25!

How did we do? We’d love to know your thoughts on this year’s conference. Take the survey here

iOS 18.4 key usage requirements fails TLS connections

iOS 18.4 introduced some requirements on the Key Usage of 802.1x server certificates, as described here. https://support.apple.com/en-us/121158

When using TLS_ECDHE_RSA or TLS_DHE_RSA cipher suites, 802.1X server certificates containing a Key Usage extension must have Digital Signature key usage set.

When using the TLS_RSA cipher suite, 802.1X server certificates containing a Key Usage extension must have Key Encipherment key usage set.

It reads like the change is supposed to affect 802.1x only. However, we have found out that the new restrictions are actually imposed on all TLS connections using the Network framework, including in Safari.

Unlike other certificate errors which can be either ignored by users (as in Safari) or by code (via sec_protocol_options_set_verify_block), these new ones can't. Even if passing completion(true) in the TLS verification block, the connection still ends up in waiting state with error -9830: illegal parameter.

I understand that these requirements are valid ones but as a generic TLS library I also expect that Network framework could at least allow overriding the behavior. The current treatment is not consistent with those on other certificate errors.

Since I can't upload certificates, here is how to reproduce a certificate that fails.

  1. Create a OpenSSL config file test.cnf
[ req ]
default_bits        = 2048
distinguished_name  = dn
x509_extensions     = v3_ca
prompt              = no

[ dn ]
CN = example.com

[ v3_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = CA:TRUE
keyUsage = critical, keyCertSign, cRLSign
  1. Generate certificate and private key
openssl req -x509 -new -nodes -keyout key.pem -out cert.pem -days 365 -config test.cnf

And here is the client code to test.

    // Target server and port
    let host = NWEndpoint.Host("example.com")
    let port = NWEndpoint.Port("443")!

    // Configure insecure TLS options
    let tlsOptions = NWProtocolTLS.Options()
    sec_protocol_options_set_verify_block(tlsOptions.securityProtocolOptions, { _, _, completion in
        // Always trust
        completion(true)
    }, DispatchQueue.global())
    
    let params = NWParameters(tls: tlsOptions)

    let connection = NWConnection(host: .init(host), port: .init(rawValue: port)!, using: params)

    connection.stateUpdateHandler = { newState in
        switch newState {
        case .ready:
            print("TLS connection established")
        case .failed(let error):
            print("Connection failed: \(error)")
        case .cancelled:
            print("Connection canceled")
        case .preparing:
            print("Connection preparing")
        case .waiting(let error):
            print("Connection waiting: \(error)")
        case .setup:
            print("Connection setup")
        default:
            break
        }
    }

    connection.start(queue: .global())

Output

Connection preparing
Connection waiting: -9830: illegal parameter

Previously reported as FB17099740

Answered by DTS Engineer in 834613022
iOS 18.4 introduced some requirements on the Key Usage of 802.1x server certificates, as described here.

Cool. Time to update my Networking Resources post (-:

It reads like the change is supposed to affect 802.1x only. However, we have found out that the new restrictions are actually imposed on all TLS connections using the Network framework, including in Safari.

Interesting. I’m not sure if that’s expected or not but, if it’s causing grief, then this:

Previously reported as FB17099740

is definitely the best path forward.

Share and Enjoy

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

iOS 18.4 introduced some requirements on the Key Usage of 802.1x server certificates, as described here.

Cool. Time to update my Networking Resources post (-:

It reads like the change is supposed to affect 802.1x only. However, we have found out that the new restrictions are actually imposed on all TLS connections using the Network framework, including in Safari.

Interesting. I’m not sure if that’s expected or not but, if it’s causing grief, then this:

Previously reported as FB17099740

is definitely the best path forward.

Share and Enjoy

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

Thank you, Quinn. The use case here is that we provide VPN client (TLS-based) to users who connect to their own servers. Some of the server certificates may not be properly generated (e.g. self-signed, lacking SAN, wrong key usages etc.).

The VPN client performs standard TLS verification in the first place but allows ignoring certificate errors. It is now a deal-breaker if some errors can't be ignored.

It is now a deal-breaker if some errors can't be ignored.

The TLS policy has long has errors that can’t be ignored. For example, the 825 day limit described in Requirements for trusted certificates in iOS 13 and macOS 10.15 can’t be ignored.

The standard workaround is to switch to the Basic X.509 policy and then do your own limited checking for stuff you care about. That’s requires a bunch of custom code, but it’s certainly doable.

Alternatively, if the certificate is really wonky, you can treat it as an opaque token. You kinda have to do this for self-signed certificates anyway.

Share and Enjoy

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

The TLS policy has long has errors that can’t be ignored.

Well, I am afraid that's not like what we have observed. By using sec_protocol_options_set_verify_block() as in the sample, we are able to ignore the 825 days error, self-signed cert, etc.

Accepted Answer
I am afraid that's not like what we have observed.

Ah, yes.

I asked about this internally and that conversation took a while because I misunderstood where this policy is coming from.

Traditionally, trust evaluation is done by a trust object (SecTrust) which references one or more policy objects (SecPolicy). The TLS policy object (SecPolicyCreateSSL) enforces TLS-specific stuff, like the key usage values and the 825 day limit.

However, Network framework has a different path into this. In 18.4 we added this check to the Network framework path in a way that applies even if you supply your own verification block using sec_protocol_options_set_verify_block.

I don’t see a good way around this. Filing a bug is the best path forward here, and you’ve already done that (FB17099740).

Share and Enjoy

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

iOS 18.4 key usage requirements fails TLS connections
 
 
Q