iosssl-certificateios12ssl-client-authentication

create iOS 12 NWConnection that uses client cert


I'm trying to set up an NWConnection that does client side certs:

self.connection = NWConnection(
    host: NWEndpoint.Host("servername"),
    port: NWEndpoint.Port(integerLiteral: 8899),
    using: .tls)

But I think that simple .tls class var needs to be a much more involved NWParameters object, but I'm at a complete loss (documentation is pretty sparse) as to what I create there to attach the client certs to the parameters. Nor do I know how I even move from .crt/.pem file to something the app manages programatically.

What is an example of how one would configure the NWParameters to support the client certs?

Context

I'm trying to set up a client connection to communicate with an MQTT broker using client side certificates. I've been able to proof-of-concept this all on the Linux side using command line. The MQTT broker is set to require client cert, and a command like:

mosquitto_pub -h servername -p 8899 -t 1234/2/Q/8 -m myMessage --cafile myChain.crt --cert client.crt --key client.pem

does the job nicely. But OpenSSL is enough a black box (to me) on iOS that I don't know where to go from here. I have been able to get all of the other MQTT communications work with my NWConnection instances, including server side TLS and even if it's self signed.


Solution

  • The kind folks on the Apple Developer Forums helped work this out. On iOS you have to use the p12 import ability:

    let importOptions = [ kSecImportExportPassphrase as String: "" ]  
    var rawItems: CFArray?  
    let status = SecPKCS12Import(P12Data as CFData, importOptions as CFDictionary, &rawItems)  
    let items = rawItems! as! Array<Dictionary<String, Any>>  
    let firstItem = items[0]  
    let clientIdentity = firstItem[kSecImportItemIdentity as String]! as! SecIdentity  
    print("clientIdentity \(clientIdentity)")
    

    Now that one has an identity, you can use that to configure the securityProtocolOptions of the the TLS options:

    let options = NWProtocolTLS.Options()
    sec_protocol_options_set_local_identity(options.securityProtocolOptions, sec_identity_create(clientIdentity)!)
    
    sec_protocol_options_set_challenge_block(options.securityProtocolOptions, { (_, completionHandler) in
        completionHandler(sec_identity_create(clientIdentity)!)
    }, .main)
    
    let parameters = NWParameters(tls: options) // use this in the NWConnection creation
    

    For reference, the Apple Developer Forum topic where this is discussed.