How to do tls/ssl handshake with NWConnection in macOS app

313 Views Asked by At

I am developing a macOS App with Swift. Currently, the app can connect successfully to a server in local network with host and port only "XXX.XXX.XXX.XXX:YYYY" without any prefix of the host (eg: "http or https", "ws or wss").

let nwConnection = NWConnection(host: "10.1.xxx.xx", port: 1515, using: .tcp) nwConnection.start(queue: .global())

After connected to the server, the app will receive a message contains "TLS" from server for tls/ssl handshake operation.

how can I do tls/ssl handshake operation with a server certificate file to send a encrypted data to server or receive a decrypted data from server.

1

There are 1 best solutions below

0
On

You can configure NWConnection with a custom server trust verification using TLS options, i.e:

let tlsOptions = NWProtocolTLS.Options()

sec_protocol_options_set_verify_block(tlsOptions.securityProtocolOptions, { meta, trust, completeVerification in
    let secTrust = sec_trust_copy_ref(trust).takeRetainedValue()

    // Set SSL policy with or without SSL hostname (SNI)
    let policy = SecPolicyCreateSSL(true, 
       /* "ssl.hostname.com" as CFString */ nil
    )
    guard SecTrustSetPolicies(secTrust, policy) == errSecSuccess else {
        completeVerification(false)
        return
    }

    // Pin certificate.
    let certificateURL = Bundle.main.url(forResource: "server", withExtension: "cert")!
    let certificateData = try! Data(contentsOf: certificateURL)
    let serverCertificate = SecCertificateCreateWithData(nil, certificateData as CFData)
    guard SecTrustSetAnchorCertificates(secTrust, [serverCertificate] as CFArray) == errSecSuccess else {
        completeVerification(false)
        return
    }
    guard SecTrustSetAnchorCertificatesOnly(secTrust, true) == errSecSuccess else {
        completeVerification(false)
        return
    }

    // Verify server trust.
    var error: CFError?
    let isValidCertificate = SecTrustEvaluateWithError(secTrust, &error)
    if let error {
        print("SecTrustEvaluate error: \(error)")
    }

    completeVerification(isValidCertificate)
}, .main)

let parameters = NWParameters(tls: tlsOptions)
let connection = NWConnection(host: "10.1.xxx.xx", port: 1515, using: parameters)
connection.start(queue: .main)