I loaded the self-signed certificate in the server and applied the server validation at the client side
client:
func createQUICClientParameters() -> NWParameters {
let params = NWParameters.quic(alpn: ["srdp"])
guard let certUrl = Bundle.main.url(forResource: "sersrdp", withExtension: "der"),
let certData = try? Data(contentsOf: certUrl),
let certificate = SecCertificateCreateWithData(nil, certData as CFData) else {
fatalError("Unable to load server.crt from bundle")
}
// Allow self-signed certificates for testing
let tlsOptions = NWProtocolTLS.Options()
sec_protocol_options_set_verify_block(
tlsOptions.securityProtocolOptions,
{ (metadata, sec_trust, completion) in
// We'll compare the server's leaf certificate with our pinned certificate.
var trustRef: SecTrust?
let status = SecTrustCreateWithCertificates(sec_trust, nil, &trustRef)
guard status == errSecSuccess, let trust = trustRef else {
completion(false)
return
}
// Retrieve the leaf certificate (server's certificate at index 0)
guard let certificateChain = SecTrustCopyCertificateChain(trust) as? [SecCertificate],
let serverCertificate = certificateChain.first else {
completion(false)
return
}
// Compare it to our pinned certificate
if CFEqual(serverCertificate, certificate) {
// Certificates match, trust the connection
completion(true)
} else {
// Mismatch -> fail the connection
completion(false)
}
},
DispatchQueue.global()
)
params.defaultProtocolStack.applicationProtocols.insert(tlsOptions, at: 0)
return params
}
Server:
func loadIdentity() -> SecIdentity? {
if let p12URL = Bundle.main.url(forResource: "sersrdp", withExtension: "p12"),
let p12Data = try? Data(contentsOf: p12URL) {
let password = "NotEvenClose"
let options: [String: Any] = [
kSecImportExportPassphrase as String: password
]
var items: CFArray?
let status = SecPKCS12Import(p12Data as CFData, options as CFDictionary, &items)
guard status == errSecSuccess,
let itemsArray = items as? [[String: Any]],
let identityRef = itemsArray.first?[kSecImportItemIdentity as String] else {
fatalError("Failed to import identity from p12: \(status)")
}
guard CFGetTypeID(identityRef as CFTypeRef) == SecIdentityGetTypeID() else {
fatalError("The imported object is not a SecIdentity.")
}
// 2. Now that we've confirmed the type, force-cast is safe:
let identity = identityRef as! SecIdentity
return identity
}
return nil
}
....
let tlsOptions = NWProtocolTLS.Options()
guard let identity = loadIdentity() else {
fatalError("Could not load TLS identity!")
}
if let secIdentity = sec_identity_create(identity) {
sec_protocol_options_set_local_identity(tlsOptions.securityProtocolOptions, secIdentity)
} else {
fatalError(" Failed to create sec_identity_t from SecIdentity")
}
params.defaultProtocolStack.applicationProtocols.insert(tlsOptions, at: 0)
when the client tries to connect, still hit
error:
03-03 16:00:13.591 QuicServer.swift:L99 Accepted new connection on port 8780 from 192.168.68.53:63785
boringssl_context_handle_fatal_alert(2170) [C2:1][0x124605e40] write alert, level: fatal, description: internal error
boringssl_context_error_print(2160) [C2:1][0x124605e40] Error: 4905268928:error:100000ae:SSL
routines:OPENSSL_internal:NO_CERTIFICATE_SET:/AppleInternal/Library/BuildRoots/cf117d38-cf63-11ef-b315-aabfac210453/Library/Caches/com.apple.xbs/Sources/boringssl/ssl/tls13_server.cc:286: