Not sure if I made progress or not, I updated the parameters like this:
let options = NWProtocolQUIC.Options(alpn: ["srdp"])
options.direction = .bidirectional
if let identity = createIdentity() {
logMsg("identity is \(isValidIdentity(identity) ? "valid" : "invalid")")
setLocalIdentityBridge(options.securityProtocolOptions, identity)
}
let securityProtocolOptions: sec_protocol_options_t = options.securityProtocolOptions
sec_protocol_options_set_verify_block(securityProtocolOptions,
{ (_: sec_protocol_metadata_t,
_: sec_trust_t,
complete: @escaping sec_protocol_verify_complete_t) in
complete(true)
}, dataQueue)
return NWParameters(quic: options)
Right now when the client connecting, the server won't hit .failed with blaming of missing certificate, instead it hits .preparing and then the server app crashed at SecIdentityCopyCertificate, but identify was validated after loaded from P12.
Post
Replies
Boosts
Views
Activity
Thank you Quinn, I tried remove alpn out(leave as empty []), the QUIC server listener will fail to start, and I asked ChatGPT, DeepSeek, they said we cannot remove alpn(Not sure if they were right).
About the DNS error I mentioned, actually it is the same error as before, but the failed(let error)'s error says DNS error (the same NO_CERTIFICATE_SET in the dump)
3-06 08:22:05.461 QuicServer.swift:L172 Server is ready and listening on port 8780
03-06 08:23:15.894 QuicServer.swift:L181 Accepted new connection on port 8780 from 192.168.68.53:52471
boringssl_context_handle_fatal_alert(2170) [C2:1][0x151e086e0] write alert, level: fatal, description: internal error
boringssl_context_error_print(2160) [C2:1][0x151e086e0] Error: 5668644992: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:
boringssl_session_handshake_incomplete(241) [C2:1][0x151e086e0] SSL library error
boringssl_session_handshake_error_print(44) [C2:1][0x151e086e0] Error: 5668644992: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:
nw_endpoint_flow_failed_with_error [C2 192.168.68.53:52471 in_progress socket-flow (satisfied (Path is satisfied), viable, interface: en0, scoped, ipv4, dns)] already failing, returning
I dig into it yesterday, come to my conclusions:
I'm sure the client is working if I try to connect to other QUIC server not with macOS (by enabling HTTP3 of my nginx server)
The server self-signed certificate (both p12 and key + csr) shall be correct.
The problem is here:
var securityProtocolOptions: sec_protocol_options_t { get }
NWProtocolQUIC.Options.securityProtocolOptions is readonly, even the TLS options loaded the certificate successfully, we cannot set to QUIC options, I suspect network.framework doesn't support QUIC server yet.
Is there any working QUIC server sample code written with network.framework?
Thanks Quinn for the answer, the server started the listener w/o problem and the self-signed p12 was loaded correctly, in the client side, I updated to give green light to everything from the server side according to what you suggested:
let params = NWParameters.quic(alpn: ["srdp"])
let tlsOptions = NWProtocolTLS.Options()
sec_protocol_options_set_verify_block(tlsOptions.securityProtocolOptions, { _, _, completionHandler in
completionHandler(true)
}, .global())
/*
sec_protocol_options_set_verify_block(
...
*/
params.defaultProtocolStack.applicationProtocols.insert(tlsOptions, at: 0)
When the client tries to connect the server, before the server sends back anything, the server hit the failed state with dns error, I suspect if the client side greenlight update could help the problem @ the server side:
override func handleConnection(_ connection: NWConnection) {
connection.stateUpdateHandler = { state in
switch state {
case .ready:
logMsg("Server: Connection is ready on port \(self.getPort())")
self.receivePacket(connection)
case .failed(let error):
logMsg("Server: Connection failed on port \(self.getPort()) with error: \(error)") // error: (Network.NWError) dns
case .cancelled:
logMsg("Server: Connection cancelled on port \(self.getPort())")
default:
break
}
}
connection.start(queue: DispatchQueue.global())
}
I suspect if it is the problem in the way I created the self-signed certificate, I created it via
$ openssl genrsa -out sersrdp.key 2048
$ openssl req -new -key sersrdp.key -out sersrdp.csr -subj "/CN=localhost"
$ openssl x509 -req -days 365 -in sersrdp.csr -signkey sersrdp.key -out sersrdp.crt
$ openssl pkcs12 -export -inkey sersrdp.key -in sersrdp.crt -out sersrdp.p12 -name "sersrdp"
Is there any problem of above? I also tried 4096 and it didn't work either.
Great appreciate your help .
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:
I installed both 2030 and 2036 Apple Worldwide Developer Relations Certification Authority, evaluate the Apple Development certificate, restarted the system, the problem finally got fixed🎉🎉🎉🎉🎉
I removed all existing Apple Development keys, added a new one 2/5/25 via ManageCertificates from Accounts in Xcode, the keyChain still tell me the newly pulled Apple Development certificate is not trusted, my system time is fine the expire time of the certificate is 2026, Is it possible the develop certificate issues server has bug?
Issued by: Apple Worldwide Developer Relations Certification Authority
Expires: Thursday, February 5, 2026 at 8:11:07 AM Mountain Standard Time
===========================
steventang@Mac-mini ~ % codesign -s "Apple Development: Steven Tang (4XXXXXX4)" -f MyTrue
MyTrue: replacing existing signature
Warning: unable to build chain to self-signed root for signer "Apple Development: Steven Tang (4XXXXXXX4)"
MyTrue: errSecInternalComponent
I got
steventang@Mac-mini ~ % codesign -s "Apple Development: Steven Tang (4XXXXXXX4)" -f MyTrue
Apple Development: Steven Tang (4XXXXXX4): ambiguous (matches "Apple Development: Steven Tang (4XXXXXX4)" and "Apple Development: Steven Tang (4XXXXXXX4)" in /Volumes/TwoTSSD/steventang/Library/Keychains/login.keychain-db)
The error:
Automatic signing failed
Xcode failed to provision this target. Please file a bug report at https://feedbackassistant.apple.com and include the Update Signing report from the Report navigator.
Unfortunately, it won't fix my issue, in my case, all items in Key Chain certificates are green, and the code sign is valid
steventang@Mac-mini ~ % security find-identity -p codesigning
Policy: Code Signing
Matching identities
DC4B46A359AF226XXXXXXXXXXXXXXXXXXD "Apple Development: Steven Tang (XXXXXXX)"
1 identities found
Valid identities only
DC4B46A359AF226XXXXXXXXXXXXXXXXXXD "Apple Development: Steven Tang (XXXXXXX)"
1 valid identities found
==========================
But when I build project, still get
unable to build chain to self-signed root for signer "Apple Development: Steven Tang (XXXXXXX)"
/Volumes/TwoTSSD/steventang/Library/Developer/Xcode/DerivedData/XXXX-ddbilgyraofrdyfeljyuknusunza/Build/Products/Release/XXXX.app: errSecInternalComponent
I signed out and signed in again, remove account and add again, the problem is still happening.
BTW, this problem happened only after I upgraded macOS to 15.3, before upgrading(15.2), I don't have this issue, I supposed there would be an Xcode 16.3 but it is not there, aka, 16.2 is the latest.
Thanks a lot and it works!
Thanks to ycc_ch, I did the stupid way to resolve the problem: created both projects with Xcode 16, and then copy the code over.
Did you try setPreparationID to your memory descriptor?
My kext is still working with M1 laptop, I just need recompile it into both X86_64 and arm64e to get both platform working!