Is it possible using the network framework to retrieve the list of certificates presented by the host alone, and not the reconstructed chain assembled by the system?
For example, in OpenSSL one can call SSL_get_peer_cert_chain
which will return exactly this - a list of the certificates presented by the server. This is useful for when you may want to manually reconstruct the chain, or if the server is misconfigured (for example, is missing an intermediate cert).
Is something like this possible with the network framework?
If I connect to a host that I know only returns 1 certificate, the trust ref already has the reconstructed chain by the time my code is called:
sec_protocol_options_set_verify_block(tlsOptions.securityProtocolOptions, { metadata, trustRef, verifyComplete in let trust = sec_trust_copy_ref(trustRef).takeRetainedValue() let numberOfCertificates = SecTrustGetCertificateCount(trust) // Returns 3 even though the server only sent 1
I believe the droid you’re looking for is sec_protocol_metadata_access_peer_certificate_chain
. Pasted in below is a small demo of how to get it working. It prints:
state: preparing cert: <SecConcrete_sec_certificate: 0x6000036b0460> trustCount: 3 state: ready
which reflects the fact that the trust object has the resolved chain but sec_protocol_metadata_access_peer_certificate_chain
just returns the leaf that was presented by the server.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
import Foundation import Network func main() { let tls = NWProtocolTLS.Options() let sec = tls.securityProtocolOptions sec_protocol_options_set_verify_block(sec, { meta, trust, completionHandler in sec_protocol_metadata_access_peer_certificate_chain(meta) { cert in print("cert: \(cert)") } let trust = sec_trust_copy_ref(trust).takeRetainedValue() let trustCount = SecTrustGetCertificateCount(trust) print("trustCount: \(trustCount)") completionHandler(true) }, .main) let params = NWParameters(tls: tls, tcp: .init()) let conn = NWConnection(host: "incomplete-chain.badssl.com", port: 443, using: params) conn.stateUpdateHandler = { state in print("state: \(state)") } conn.start(queue: .main) dispatchMain() } main()