-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for additional TLS options in NIOTS transport #18
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couple of nits but mostly looks good. I assume the tests are in #20?
|
||
switch tlsConfig.trustRoots.wrapped { | ||
case .certificates(let certificates): | ||
let verifyQueue = DispatchQueue(label: "certificateVerificationQueue") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: should be prefixed with io.grpc
, we can also drop "queue" from the name, it's a bit redundant here.
let verifyQueue = DispatchQueue(label: "certificateVerificationQueue") | |
let verifyQueue = DispatchQueue(label: "io.grpc.CertificateVerification") |
certificateBytes = Data(bytes) | ||
|
||
case .file(_, let format), .bytes(_, let format): | ||
fatalError("Certificate format must be DER, but was \(format).") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm – do we document this requirement somewhere?
switch tlsConfig.trustRoots.wrapped { | ||
case .certificates(let certificates): | ||
let verifyQueue = DispatchQueue(label: "certificateVerificationQueue") | ||
let verifyBlock: sec_protocol_verify_t = { (metadata, trust, verifyCompleteCallback) in | ||
let actualTrust = sec_trust_copy_ref(trust).takeRetainedValue() | ||
|
||
let customAnchors: [SecCertificate] | ||
do { | ||
customAnchors = try certificates.map { certificateSource in | ||
let certificateBytes: Data | ||
switch certificateSource.wrapped { | ||
case .file(let path, .der): | ||
certificateBytes = try Data(contentsOf: URL(filePath: path)) | ||
|
||
case .bytes(let bytes, .der): | ||
certificateBytes = Data(bytes) | ||
|
||
case .file(_, let format), .bytes(_, let format): | ||
fatalError("Certificate format must be DER, but was \(format).") | ||
} | ||
|
||
guard let certificate = SecCertificateCreateWithData(nil, certificateBytes as CFData) | ||
else { | ||
fatalError("Certificate was not a valid DER-encoded X509 certificate.") | ||
} | ||
return certificate | ||
} | ||
} catch { | ||
verifyCompleteCallback(false) | ||
return | ||
} | ||
|
||
SecTrustSetAnchorCertificates(actualTrust, customAnchors as CFArray) | ||
SecTrustEvaluateAsyncWithError(actualTrust, verifyQueue) { _, trusted, _ in | ||
verifyCompleteCallback(trusted) | ||
} | ||
} | ||
|
||
sec_protocol_options_set_verify_block( | ||
self.securityProtocolOptions, | ||
verifyBlock, | ||
verifyQueue | ||
) | ||
|
||
case .systemDefault: | ||
() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is all copy-pasta from the client equivalent, can we avoid the duplication?
This PR adds support for a few additional TLS options in the NIOTS transport, to bring it in line with the NIOPosix implementation. In particular, it now supports custom trust roots, which means mTLS can be enabled when using NIOTS, and E2E testing is possible (because we can use self-signed certificates).
Some code has been refactored to be shared across transport implementations, and a small bug with how errors were being surfaced has been fixed.