Skip to content

Commit 115ce64

Browse files
committed
Generate trust roots SecCertificate for Transport Services
1 parent b075d19 commit 115ce64

File tree

1 file changed

+51
-20
lines changed

1 file changed

+51
-20
lines changed

Diff for: Sources/AsyncHTTPClient/NIOTransportServices/TLSConfiguration.swift

+51-20
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,6 @@
8686
}
8787
}
8888

89-
// the certificate chain
90-
if self.certificateChain.count > 0 {
91-
preconditionFailure("TLSConfiguration.certificateChain is not supported")
92-
}
93-
9489
// cipher suites
9590
if self.cipherSuites.count > 0 {
9691
// TODO: Requires NIOSSL to provide list of cipher values before we can continue
@@ -102,6 +97,11 @@
10297
preconditionFailure("TLSConfiguration.keyLogCallback is not supported")
10398
}
10499

100+
// the certificate chain
101+
if self.certificateChain.count > 0 {
102+
preconditionFailure("TLSConfiguration.certificateChain is not supported")
103+
}
104+
105105
// private key
106106
if self.privateKey != nil {
107107
preconditionFailure("TLSConfiguration.privateKey is not supported")
@@ -110,29 +110,60 @@
110110
// renegotiation support key is unsupported
111111

112112
// trust roots
113-
if let trustRoots = self.trustRoots {
114-
guard case .default = trustRoots else {
115-
preconditionFailure("TLSConfiguration.trustRoots != .default is not supported")
113+
var secTrustRoots: [SecCertificate]?
114+
switch trustRoots {
115+
case .some(.certificates(let certificates)):
116+
do {
117+
secTrustRoots = try certificates.compactMap { certificate in
118+
return try SecCertificateCreateWithData(nil, Data(certificate.toDERBytes()) as CFData)
119+
}
120+
} catch {
121+
// failed to load
116122
}
123+
case .some(.file):
124+
preconditionFailure("TLSConfiguration.trustRoots.file is not supported")
125+
break
126+
127+
case .some(.default), .none:
128+
break
117129
}
118130

119-
switch self.certificateVerification {
120-
case .none:
131+
precondition(self.certificateVerification != .noHostnameVerification, "TLSConfiguration.certificateVerification = .noHostnameVerification is not supported")
132+
133+
if certificateVerification != .fullVerification || trustRoots != nil {
121134
// add verify block to control certificate verification
122135
sec_protocol_options_set_verify_block(
123136
options.securityProtocolOptions,
124-
{ _, _, sec_protocol_verify_complete in
125-
sec_protocol_verify_complete(true)
126-
}, TLSConfiguration.tlsDispatchQueue
137+
{ sec_metadata, sec_trust, sec_protocol_verify_complete in
138+
guard self.certificateVerification != .none else {
139+
sec_protocol_verify_complete(true)
140+
return
141+
}
142+
143+
let trust = sec_trust_copy_ref(sec_trust).takeRetainedValue()
144+
if let trustRootCertificates = secTrustRoots {
145+
SecTrustSetAnchorCertificates(trust, trustRootCertificates as CFArray)
146+
}
147+
if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) {
148+
SecTrustEvaluateAsyncWithError(trust, Self.tlsDispatchQueue) { (trust, result, error) in
149+
if let error = error {
150+
print("Trust failed: \(error.localizedDescription)")
151+
}
152+
sec_protocol_verify_complete(result)
153+
}
154+
} else {
155+
SecTrustEvaluateAsync(trust, Self.tlsDispatchQueue) { (trust, result) in
156+
switch result {
157+
case .proceed, .unspecified:
158+
sec_protocol_verify_complete(true)
159+
default:
160+
sec_protocol_verify_complete(false)
161+
}
162+
}
163+
}
164+
}, Self.tlsDispatchQueue
127165
)
128-
129-
case .noHostnameVerification:
130-
precondition(self.certificateVerification != .noHostnameVerification, "TLSConfiguration.certificateVerification = .noHostnameVerification is not supported")
131-
132-
case .fullVerification:
133-
break
134166
}
135-
136167
return options
137168
}
138169
}

0 commit comments

Comments
 (0)