Network.framework TLS / self-signed

Any advice on how to go about validating a self-signed certificate with Network.framework? I've been able to connect with TLS to various services that have a chain of trust that iOS / MacOS can validate, but simply get a:


POSIXErrorCode: Network is down


when attempting to connect to a service that presents a self-signed cert. Network.framework is extremely cool. Many thanks to anyone involved in getting out there for third party consumption!

Replies

You can override server trust evaluation by via

sec_protocol_options_set_verify_block
. See
<Network/tls_options.h>
and
<Security/SecProtocolOptions.h>
.

Share and Enjoy

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

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

Hi! I am trying to figure out how to do this from Swift. Is there any example code?

I need to do certificate pinning to one of our internal servers?



-michael

Hello eskimo,


I have trouble making the definition of sec_protocol_options_set_verify_block work.

I am not sure what to pass as metadata. Regarding the verify block, it does not seem to return anything, so I am not sure how to accept or reject a self-signed certificate (and yes the parameters are cryptic as well).


Do you have any useful pointers, either as code example, expanded documentation, tutorials, etc.


I will take anything that could put me on track 🙂


Thanks !

Hello,


I could put together an example.

You can generate your NWParameters as follow:

fileprivate func getTLSParameters(allowInsecure: Bool, queue: DispatchQueue) -> NWParameters {
    let options = NWProtocolTLS.Options()

    sec_protocol_options_set_verify_block(options.securityProtocolOptions, { (sec_protocol_metadata, sec_trust, sec_protocol_verify_complete) in
        
        let trust = sec_trust_copy_ref(sec_trust).takeRetainedValue()
        
        var error: CFError?
        if SecTrustEvaluateWithError(trust, &error) {
            sec_protocol_verify_complete(true)
        } else {
            if allowInsecure == true {
                sec_protocol_verify_complete(true)
            } else {
                sec_protocol_verify_complete(false)
            }
        }
        
    }, queue)
    
    return NWParameters(tls: options)
}

Basically, it defines a sec_protocol_options_set_verify_block that is call when the certificate received from server needs to be checked. If you allowInsecure connections, it will accept the certificate, even if it is self signed or expired, for example.


Then, you can initiate your NWConnection with it:

        let parameters = getTLSParameters(allowInsecure: allowInsecure, queue: queue)
        let connection = NWConnection.init(to: endpoint, using: parameters)


It is certainly possible to be more subtile, but it should do the job during the development phase. You definitely do not want to allow insecure certificate for production.

Thanks for posting your code snippet.

You definitely do not want to allow insecure certificate for production.

Personally I don’t think you should do this during development either. I explain this, and a better approach, in QA1948 HTTPS and Test Servers.

Share and Enjoy

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

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

Thanks, this is a very good suggestion. I will give it a try.

@eskimo This is slight deviation from the actual question, I am trying to make an API call using Network framework in iOS, i am completely ignoring URLSession because of my usecase.

i found the above snippet a bit helpful for headstart, This seems to be the configuration that we set before we make the actual network request, the SecTrust is something that we use to get it in the URLSession delegate whenever a request is made, so at this point i am not able to fetch the server certificate from this sec_protocol_options_set_verify_block.

So how can get cert pinning to work using Network framework? any help would be greatly appreciated, thanks.

So how can get cert pinning to work using Network framework?

Using sec_protocol_options_set_verify_block.

at this point i am not able to fetch the server certificate from this sec_protocol_options_set_verify_block.

Please elaborate. The expected pattern here is:

  1. You call sec_protocol_options_set_verify_block to set up a verify callback.

  2. That gets called when NWConnection evaluates trust on the server.

  3. It’s passed a sec_trust_t value.

  4. It converts it to SecTrust value using sec_trust_copy_ref.

  5. It can then access the server’s certificate using SecTrust API.

Which bit is failing?

Share and Enjoy

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