Config+TLS.swift 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. /*
  2. * Copyright 2024, gRPC Authors All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #if canImport(Network)
  17. public import GRPCNIOTransportCore
  18. public import Network
  19. private import struct Foundation.Data
  20. private import struct Foundation.URL
  21. extension HTTP2ServerTransport.TransportServices {
  22. /// The security configuration for this connection.
  23. public struct TransportSecurity: Sendable {
  24. package enum Wrapped: Sendable {
  25. case plaintext
  26. case tls(TLS)
  27. }
  28. package let wrapped: Wrapped
  29. /// This connection is plaintext: no encryption will take place.
  30. public static let plaintext = Self(wrapped: .plaintext)
  31. /// Secures connections with the given TLS configuration.
  32. public static func tls(_ tls: TLS) -> Self {
  33. Self(wrapped: .tls(tls))
  34. }
  35. /// Secures connections with the TLS.
  36. ///
  37. /// - Parameters:
  38. /// - identityProvider: A provider for the `SecIdentity` to be used when setting up TLS.
  39. /// - configure: A closure allowing you to modify the configuration before returning it.
  40. public static func tls(
  41. identityProvider: @Sendable @escaping () throws -> SecIdentity,
  42. configure: (_ config: inout TLS) -> Void = { _ in }
  43. ) -> Self {
  44. let tlsConfig: TLS = .defaults(
  45. identityProvider: identityProvider,
  46. configure: configure
  47. )
  48. return .tls(tlsConfig)
  49. }
  50. /// Secures connections with the mutual TLS.
  51. ///
  52. /// - Parameters:
  53. /// - identityProvider: A provider for the `SecIdentity` to be used when setting up TLS.
  54. /// - configure: A closure allowing you to modify the configuration before returning it.
  55. public static func mTLS(
  56. identityProvider: @Sendable @escaping () throws -> SecIdentity,
  57. configure: (_ config: inout TLS) -> Void = { _ in }
  58. ) -> Self {
  59. let tlsConfig: TLS = .mTLS(
  60. identityProvider: identityProvider,
  61. configure: configure
  62. )
  63. return .tls(tlsConfig)
  64. }
  65. }
  66. }
  67. extension HTTP2ServerTransport.TransportServices {
  68. public struct TLS: Sendable {
  69. /// How to verify the client certificate, if one is presented.
  70. public var clientCertificateVerification: TLSConfig.CertificateVerification
  71. /// The trust roots to be used when verifying client certificates.
  72. public var trustRoots: TLSConfig.TrustRootsSource
  73. /// Whether ALPN is required.
  74. ///
  75. /// If this is set to `true` but the client does not support ALPN, then the connection will be rejected.
  76. public var requireALPN: Bool
  77. /// A provider for the `SecIdentity` to be used when setting up TLS.
  78. public var identityProvider: @Sendable () throws -> SecIdentity
  79. /// Create a new HTTP2 NIO Transport Services transport TLS config.
  80. /// - Parameters:
  81. /// - clientCertificateVerification: How to verify the client certificate, if one is presented.
  82. /// - trustRoots: The trust roots to be used when verifying client certificates.
  83. /// - requireALPN: Whether ALPN is required.
  84. /// - identityProvider: A provider for the `SecIdentity` to be used when setting up TLS.
  85. public init(
  86. clientCertificateVerification: TLSConfig.CertificateVerification,
  87. trustRoots: TLSConfig.TrustRootsSource,
  88. requireALPN: Bool,
  89. identityProvider: @Sendable @escaping () throws -> SecIdentity
  90. ) {
  91. self.clientCertificateVerification = clientCertificateVerification
  92. self.trustRoots = trustRoots
  93. self.requireALPN = requireALPN
  94. self.identityProvider = identityProvider
  95. }
  96. /// Create a new HTTP2 NIO Transport Services transport TLS config, with some values defaulted:
  97. /// - `clientCertificateVerificationMode` equals `doNotVerify`
  98. /// - `trustRoots` equals `systemDefault`
  99. /// - `requireALPN` equals `false`
  100. ///
  101. /// - Parameters:
  102. /// - identityProvider: A provider for the `SecIdentity` to be used when setting up TLS.
  103. /// - configure: A closure which allows you to modify the defaults before returning them.
  104. /// - Returns: A new HTTP2 NIO Transport Services transport TLS config.
  105. public static func defaults(
  106. identityProvider: @Sendable @escaping () throws -> SecIdentity,
  107. configure: (_ config: inout Self) -> Void = { _ in }
  108. ) -> Self {
  109. var config = Self(
  110. clientCertificateVerification: .noVerification,
  111. trustRoots: .systemDefault,
  112. requireALPN: false,
  113. identityProvider: identityProvider
  114. )
  115. configure(&config)
  116. return config
  117. }
  118. /// Create a new HTTP2 NIO Transport Services transport TLS config, with some values defaulted to match
  119. /// the requirements of mTLS:
  120. /// - `clientCertificateVerificationMode` equals `noHostnameVerification`
  121. /// - `trustRoots` equals `systemDefault`
  122. /// - `requireALPN` equals `false`
  123. ///
  124. /// - Parameters:
  125. /// - identityProvider: A provider for the `SecIdentity` to be used when setting up TLS.
  126. /// - configure: A closure which allows you to modify the defaults before returning them.
  127. /// - Returns: A new HTTP2 NIO Transport Services transport TLS config.
  128. public static func mTLS(
  129. identityProvider: @Sendable @escaping () throws -> SecIdentity,
  130. configure: (_ config: inout Self) -> Void = { _ in }
  131. ) -> Self {
  132. var config = Self(
  133. clientCertificateVerification: .noHostnameVerification,
  134. trustRoots: .systemDefault,
  135. requireALPN: false,
  136. identityProvider: identityProvider
  137. )
  138. configure(&config)
  139. return config
  140. }
  141. }
  142. }
  143. extension HTTP2ClientTransport.TransportServices {
  144. /// The security configuration for this connection.
  145. public struct TransportSecurity: Sendable {
  146. package enum Wrapped: Sendable {
  147. case plaintext
  148. case tls(TLS)
  149. }
  150. package let wrapped: Wrapped
  151. /// This connection is plaintext: no encryption will take place.
  152. public static let plaintext = Self(wrapped: .plaintext)
  153. /// Secure connections with the given TLS configuration.
  154. public static func tls(_ tls: TLS) -> Self {
  155. Self(wrapped: .tls(tls))
  156. }
  157. /// Secure connections with TLS.
  158. ///
  159. /// - Parameters:
  160. /// - configure: A closure which allows you to modify the defaults before returning them.
  161. public static func tls(
  162. configure: (_ config: inout TLS) -> Void = { _ in }
  163. ) -> Self {
  164. let tlsConfig: TLS = .defaults(configure: configure)
  165. return .tls(tlsConfig)
  166. }
  167. /// Secure connections with TLS.
  168. public static var tls: Self {
  169. return .tls()
  170. }
  171. /// Secure connections with mutual TLS.
  172. ///
  173. /// - Parameters:
  174. /// - identityProvider: A provider for the `SecIdentity` to be used when setting up TLS.
  175. /// - configure: A closure which allows you to modify the defaults before returning them.
  176. public static func mTLS(
  177. identityProvider: @Sendable @escaping () throws -> SecIdentity,
  178. configure: (_ config: inout TLS) -> Void = { _ in }
  179. ) -> Self {
  180. let tlsConfig: TLS = .mTLS(
  181. identityProvider: identityProvider,
  182. configure: configure
  183. )
  184. return .tls(tlsConfig)
  185. }
  186. }
  187. }
  188. extension HTTP2ClientTransport.TransportServices {
  189. public struct TLS: Sendable {
  190. /// How to verify the server certificate, if one is presented.
  191. public var serverCertificateVerification: TLSConfig.CertificateVerification
  192. /// The trust roots to be used when verifying server certificates.
  193. /// - Important: If specifying custom certificates, they must be DER-encoded X509 certificates.
  194. public var trustRoots: TLSConfig.TrustRootsSource
  195. /// An optional provider for the `SecIdentity` to be used when setting up TLS.
  196. public var identityProvider: (@Sendable () throws -> SecIdentity)?
  197. /// Create a new HTTP2 NIO Transport Services transport TLS config.
  198. /// - Parameters:
  199. /// - serverCertificateVerification: How to verify the server certificate, if one is presented.
  200. /// - trustRoots: The trust roots to be used when verifying server certificates.
  201. /// - identityProvider: A provider for the `SecIdentity` to be used when setting up TLS.
  202. public init(
  203. serverCertificateVerification: TLSConfig.CertificateVerification,
  204. trustRoots: TLSConfig.TrustRootsSource,
  205. identityProvider: (@Sendable () throws -> SecIdentity)?
  206. ) {
  207. self.serverCertificateVerification = serverCertificateVerification
  208. self.trustRoots = trustRoots
  209. self.identityProvider = identityProvider
  210. }
  211. /// Create a new HTTP2 NIO Transport Services transport TLS config, with some values defaulted:
  212. /// - `serverCertificateVerification` equals `fullVerification`
  213. /// - `trustRoots` equals `systemDefault`
  214. /// - `identityProvider` equals `nil`
  215. ///
  216. /// - Parameters:
  217. /// - configure: A closure which allows you to modify the defaults before returning them.
  218. /// - Returns: A new HTTP2 NIO Posix transport TLS config.
  219. public static func defaults(
  220. configure: (_ config: inout Self) -> Void = { _ in }
  221. ) -> Self {
  222. var config = Self(
  223. serverCertificateVerification: .fullVerification,
  224. trustRoots: .systemDefault,
  225. identityProvider: nil
  226. )
  227. configure(&config)
  228. return config
  229. }
  230. /// Create a new HTTP2 NIO Transport Services transport TLS config, with some values defaulted:
  231. /// - `serverCertificateVerification` equals `fullVerification`
  232. /// - `trustRoots` equals `systemDefault`
  233. /// - `identityProvider` equals `nil`
  234. public static var defaults: Self { .defaults() }
  235. /// Create a new HTTP2 NIO Transport Services transport TLS config, with some values defaulted to match
  236. /// the requirements of mTLS:
  237. /// - `serverCertificateVerification` equals `fullVerification`
  238. /// - `trustRoots` equals `systemDefault`
  239. ///
  240. /// - Parameters:
  241. /// - identityProvider: A provider for the `SecIdentity` to be used when setting up TLS.
  242. /// - configure: A closure which allows you to modify the defaults before returning them.
  243. /// - Returns: A new HTTP2 NIO Posix transport TLS config.
  244. public static func mTLS(
  245. identityProvider: @Sendable @escaping () throws -> SecIdentity,
  246. configure: (_ config: inout Self) -> Void = { _ in }
  247. ) -> Self {
  248. var config = Self(
  249. serverCertificateVerification: .fullVerification,
  250. trustRoots: .systemDefault,
  251. identityProvider: identityProvider
  252. )
  253. configure(&config)
  254. return config
  255. }
  256. }
  257. }
  258. extension NWProtocolTLS.Options {
  259. func setUpVerifyBlock(trustRootsSource: TLSConfig.TrustRootsSource) {
  260. if let (verifyQueue, verifyBlock) = trustRootsSource.makeTrustRootsConfig() {
  261. sec_protocol_options_set_verify_block(
  262. self.securityProtocolOptions,
  263. verifyBlock,
  264. verifyQueue
  265. )
  266. }
  267. }
  268. }
  269. extension TLSConfig.TrustRootsSource {
  270. internal func makeTrustRootsConfig() -> (DispatchQueue, sec_protocol_verify_t)? {
  271. switch self.wrapped {
  272. case .certificates(let certificates):
  273. let verifyQueue = DispatchQueue(label: "io.grpc.CertificateVerification")
  274. let verifyBlock: sec_protocol_verify_t = { (metadata, trust, verifyCompleteCallback) in
  275. let actualTrust = sec_trust_copy_ref(trust).takeRetainedValue()
  276. let customAnchors: [SecCertificate]
  277. do {
  278. customAnchors = try certificates.map { certificateSource in
  279. let certificateBytes: Data
  280. switch certificateSource.wrapped {
  281. case .file(let path, .der):
  282. certificateBytes = try Data(contentsOf: URL(filePath: path))
  283. case .bytes(let bytes, .der):
  284. certificateBytes = Data(bytes)
  285. case .file(_, let format), .bytes(_, let format):
  286. fatalError("Certificate format must be DER, but was \(format).")
  287. }
  288. guard let certificate = SecCertificateCreateWithData(nil, certificateBytes as CFData)
  289. else {
  290. fatalError("Certificate was not a valid DER-encoded X509 certificate.")
  291. }
  292. return certificate
  293. }
  294. } catch {
  295. verifyCompleteCallback(false)
  296. return
  297. }
  298. SecTrustSetAnchorCertificates(actualTrust, customAnchors as CFArray)
  299. SecTrustEvaluateAsyncWithError(actualTrust, verifyQueue) { _, trusted, _ in
  300. verifyCompleteCallback(trusted)
  301. }
  302. }
  303. return (verifyQueue, verifyBlock)
  304. case .systemDefault:
  305. return nil
  306. }
  307. }
  308. }
  309. #endif