GRPCTLSConfiguration.swift 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  1. /*
  2. * Copyright 2021, 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(NIOSSL)
  17. import NIOSSL
  18. #endif
  19. #if canImport(Network)
  20. import Network
  21. import NIOTransportServices
  22. import Security
  23. #endif
  24. /// TLS configuration.
  25. ///
  26. /// This structure allow configuring TLS for a wide range of TLS implementations. Some
  27. /// options are removed from the user's control to ensure the configuration complies with
  28. /// the gRPC specification.
  29. public struct GRPCTLSConfiguration {
  30. fileprivate enum Backend {
  31. #if canImport(NIOSSL)
  32. /// Configuration for NIOSSSL.
  33. case nio(NIOConfiguration)
  34. #endif
  35. #if canImport(Network)
  36. /// Configuration for Network.framework.
  37. case network(NetworkConfiguration)
  38. #endif
  39. }
  40. /// The TLS backend.
  41. private var backend: Backend
  42. #if canImport(NIOSSL)
  43. fileprivate init(nio: NIOConfiguration) {
  44. self.backend = .nio(nio)
  45. }
  46. #endif
  47. #if canImport(Network)
  48. fileprivate init(network: NetworkConfiguration) {
  49. self.backend = .network(network)
  50. }
  51. #endif
  52. /// Return the configuration for NIOSSL or `nil` if Network.framework is being used as the
  53. /// TLS backend.
  54. #if canImport(NIOSSL)
  55. internal var nioConfiguration: NIOConfiguration? {
  56. switch self.backend {
  57. case let .nio(configuration):
  58. return configuration
  59. #if canImport(Network)
  60. case .network:
  61. return nil
  62. #endif
  63. }
  64. }
  65. #endif // canImport(NIOSSL)
  66. internal var isNetworkFrameworkTLSBackend: Bool {
  67. switch self.backend {
  68. #if canImport(NIOSSL)
  69. case .nio:
  70. return false
  71. #endif
  72. #if canImport(Network)
  73. case .network:
  74. return true
  75. #endif
  76. }
  77. }
  78. /// The server hostname override as used by the TLS SNI extension.
  79. ///
  80. /// This value is ignored when the configuration is used for a server.
  81. ///
  82. /// - Note: when using the Network.framework backend, this value may not be set to `nil`.
  83. internal var hostnameOverride: String? {
  84. get {
  85. switch self.backend {
  86. #if canImport(NIOSSL)
  87. case let .nio(config):
  88. return config.hostnameOverride
  89. #endif
  90. #if canImport(Network)
  91. case let .network(config):
  92. return config.hostnameOverride
  93. #endif
  94. }
  95. }
  96. set {
  97. switch self.backend {
  98. #if canImport(NIOSSL)
  99. case var .nio(config):
  100. config.hostnameOverride = newValue
  101. self.backend = .nio(config)
  102. #endif
  103. #if canImport(Network)
  104. case var .network(config):
  105. if #available(macOS 10.14, iOS 12.0, watchOS 6.0, tvOS 12.0, *) {
  106. if let hostnameOverride = newValue {
  107. config.updateHostnameOverride(to: hostnameOverride)
  108. } else {
  109. // We can't unset the value so error instead.
  110. fatalError("Can't unset hostname override when using Network.framework TLS backend.")
  111. // FIXME: lazily set the value on the backend when applying the options.
  112. }
  113. } else {
  114. // We can only make the `.network` backend if we meet the above availability checks so
  115. // this should be unreachable.
  116. preconditionFailure()
  117. }
  118. self.backend = .network(config)
  119. #endif
  120. }
  121. }
  122. }
  123. /// Whether the configuration requires ALPN to be used.
  124. ///
  125. /// The Network.framework backend does not support this option and always requires ALPN.
  126. internal var requireALPN: Bool {
  127. get {
  128. switch self.backend {
  129. #if canImport(NIOSSL)
  130. case let .nio(config):
  131. return config.requireALPN
  132. #endif
  133. #if canImport(Network)
  134. case .network:
  135. return true
  136. #endif
  137. }
  138. }
  139. set {
  140. switch self.backend {
  141. #if canImport(NIOSSL)
  142. case var .nio(config):
  143. config.requireALPN = newValue
  144. self.backend = .nio(config)
  145. #endif
  146. #if canImport(Network)
  147. case .network:
  148. ()
  149. #endif
  150. }
  151. }
  152. }
  153. #if canImport(NIOSSL)
  154. // Marked to silence the deprecation warning
  155. @available(*, deprecated)
  156. internal init(transforming deprecated: ClientConnection.Configuration.TLS) {
  157. self.backend = .nio(
  158. .init(
  159. configuration: deprecated.configuration,
  160. customVerificationCallback: deprecated.customVerificationCallback,
  161. hostnameOverride: deprecated.hostnameOverride,
  162. requireALPN: false // Not currently supported.
  163. )
  164. )
  165. }
  166. // Marked to silence the deprecation warning
  167. @available(*, deprecated)
  168. internal init(transforming deprecated: Server.Configuration.TLS) {
  169. self.backend = .nio(
  170. .init(configuration: deprecated.configuration, requireALPN: deprecated.requireALPN)
  171. )
  172. }
  173. @available(*, deprecated)
  174. internal var asDeprecatedClientConfiguration: ClientConnection.Configuration.TLS? {
  175. if case let .nio(config) = self.backend {
  176. var tls = ClientConnection.Configuration.TLS(
  177. configuration: config.configuration,
  178. hostnameOverride: config.hostnameOverride
  179. )
  180. tls.customVerificationCallback = config.customVerificationCallback
  181. return tls
  182. }
  183. return nil
  184. }
  185. @available(*, deprecated)
  186. internal var asDeprecatedServerConfiguration: Server.Configuration.TLS? {
  187. if case let .nio(config) = self.backend {
  188. return Server.Configuration.TLS(configuration: config.configuration)
  189. }
  190. return nil
  191. }
  192. #endif // canImport(NIOSSL)
  193. }
  194. // MARK: - NIO Backend
  195. #if canImport(NIOSSL)
  196. extension GRPCTLSConfiguration {
  197. internal struct NIOConfiguration {
  198. var configuration: TLSConfiguration
  199. var customVerificationCallback: NIOSSLCustomVerificationCallback?
  200. var hostnameOverride: String?
  201. // The client doesn't support this yet (https://github.com/grpc/grpc-swift/issues/1042).
  202. var requireALPN: Bool
  203. }
  204. /// TLS Configuration with suitable defaults for clients, using `NIOSSL`.
  205. ///
  206. /// This is a wrapper around `NIOSSL.TLSConfiguration` to restrict input to values which comply
  207. /// with the gRPC protocol.
  208. ///
  209. /// - Parameter certificateChain: The certificate to offer during negotiation, defaults to an
  210. /// empty array.
  211. /// - Parameter privateKey: The private key associated with the leaf certificate. This defaults
  212. /// to `nil`.
  213. /// - Parameter trustRoots: The trust roots to validate certificates, this defaults to using a
  214. /// root provided by the platform.
  215. /// - Parameter certificateVerification: Whether to verify the remote certificate. Defaults to
  216. /// `.fullVerification`.
  217. /// - Parameter hostnameOverride: Value to use for TLS SNI extension; this must not be an IP
  218. /// address, defaults to `nil`.
  219. /// - Parameter customVerificationCallback: A callback to provide to override the certificate verification logic,
  220. /// defaults to `nil`.
  221. public static func makeClientConfigurationBackedByNIOSSL(
  222. certificateChain: [NIOSSLCertificateSource] = [],
  223. privateKey: NIOSSLPrivateKeySource? = nil,
  224. trustRoots: NIOSSLTrustRoots = .default,
  225. certificateVerification: CertificateVerification = .fullVerification,
  226. hostnameOverride: String? = nil,
  227. customVerificationCallback: NIOSSLCustomVerificationCallback? = nil
  228. ) -> GRPCTLSConfiguration {
  229. var configuration = TLSConfiguration.makeClientConfiguration()
  230. configuration.minimumTLSVersion = .tlsv12
  231. configuration.certificateVerification = certificateVerification
  232. configuration.trustRoots = trustRoots
  233. configuration.certificateChain = certificateChain
  234. configuration.privateKey = privateKey
  235. configuration.applicationProtocols = GRPCApplicationProtocolIdentifier.client
  236. return GRPCTLSConfiguration.makeClientConfigurationBackedByNIOSSL(
  237. configuration: configuration,
  238. hostnameOverride: hostnameOverride,
  239. customVerificationCallback: customVerificationCallback
  240. )
  241. }
  242. /// Creates a gRPC TLS Configuration using the given `NIOSSL.TLSConfiguration`.
  243. ///
  244. /// - Note: If no ALPN tokens are set in `configuration.applicationProtocols` then "grpc-exp"
  245. /// and "h2" will be used.
  246. /// - Parameters:
  247. /// - configuration: The `NIOSSL.TLSConfiguration` to base this configuration on.
  248. /// - hostnameOverride: The hostname override to use for the TLS SNI extension.
  249. public static func makeClientConfigurationBackedByNIOSSL(
  250. configuration: TLSConfiguration,
  251. hostnameOverride: String? = nil,
  252. customVerificationCallback: NIOSSLCustomVerificationCallback? = nil
  253. ) -> GRPCTLSConfiguration {
  254. var configuration = configuration
  255. // Set the ALPN tokens if none were set.
  256. if configuration.applicationProtocols.isEmpty {
  257. configuration.applicationProtocols = GRPCApplicationProtocolIdentifier.client
  258. }
  259. let nioConfiguration = NIOConfiguration(
  260. configuration: configuration,
  261. customVerificationCallback: customVerificationCallback,
  262. hostnameOverride: hostnameOverride,
  263. requireALPN: false // We don't currently support this.
  264. )
  265. return GRPCTLSConfiguration(nio: nioConfiguration)
  266. }
  267. /// TLS Configuration with suitable defaults for servers.
  268. ///
  269. /// This is a wrapper around `NIOSSL.TLSConfiguration` to restrict input to values which comply
  270. /// with the gRPC protocol.
  271. ///
  272. /// - Parameter certificateChain: The certificate to offer during negotiation.
  273. /// - Parameter privateKey: The private key associated with the leaf certificate.
  274. /// - Parameter trustRoots: The trust roots to validate certificates, this defaults to using a
  275. /// root provided by the platform.
  276. /// - Parameter certificateVerification: Whether to verify the remote certificate. Defaults to
  277. /// `.none`.
  278. /// - Parameter requireALPN: Whether ALPN is required or not.
  279. public static func makeServerConfigurationBackedByNIOSSL(
  280. certificateChain: [NIOSSLCertificateSource],
  281. privateKey: NIOSSLPrivateKeySource,
  282. trustRoots: NIOSSLTrustRoots = .default,
  283. certificateVerification: CertificateVerification = .none,
  284. requireALPN: Bool = true
  285. ) -> GRPCTLSConfiguration {
  286. var configuration = TLSConfiguration.makeServerConfiguration(
  287. certificateChain: certificateChain,
  288. privateKey: privateKey
  289. )
  290. configuration.minimumTLSVersion = .tlsv12
  291. configuration.certificateVerification = certificateVerification
  292. configuration.trustRoots = trustRoots
  293. configuration.applicationProtocols = GRPCApplicationProtocolIdentifier.server
  294. return GRPCTLSConfiguration.makeServerConfigurationBackedByNIOSSL(
  295. configuration: configuration,
  296. requireALPN: requireALPN
  297. )
  298. }
  299. /// Creates a gRPC TLS Configuration suitable for servers using the given
  300. /// `NIOSSL.TLSConfiguration`.
  301. ///
  302. /// - Note: If no ALPN tokens are set in `configuration.applicationProtocols` then "grpc-exp",
  303. /// "h2", and "http/1.1" will be used.
  304. /// - Parameters:
  305. /// - configuration: The `NIOSSL.TLSConfiguration` to base this configuration on.
  306. /// - requiresALPN: Whether the server enforces ALPN. Defaults to `true`.
  307. public static func makeServerConfigurationBackedByNIOSSL(
  308. configuration: TLSConfiguration,
  309. requireALPN: Bool = true
  310. ) -> GRPCTLSConfiguration {
  311. var configuration = configuration
  312. // Set the ALPN tokens if none were set.
  313. if configuration.applicationProtocols.isEmpty {
  314. configuration.applicationProtocols = GRPCApplicationProtocolIdentifier.server
  315. }
  316. let nioConfiguration = NIOConfiguration(
  317. configuration: configuration,
  318. customVerificationCallback: nil,
  319. hostnameOverride: nil,
  320. requireALPN: requireALPN
  321. )
  322. return GRPCTLSConfiguration(nio: nioConfiguration)
  323. }
  324. @usableFromInline
  325. internal func makeNIOSSLContext() throws -> NIOSSLContext? {
  326. switch self.backend {
  327. case let .nio(configuration):
  328. return try NIOSSLContext(configuration: configuration.configuration)
  329. #if canImport(Network)
  330. case .network:
  331. return nil
  332. #endif
  333. }
  334. }
  335. internal var nioSSLCustomVerificationCallback: NIOSSLCustomVerificationCallback? {
  336. switch self.backend {
  337. case let .nio(configuration):
  338. return configuration.customVerificationCallback
  339. #if canImport(Network)
  340. case .network:
  341. return nil
  342. #endif
  343. }
  344. }
  345. internal mutating func updateNIOCertificateChain(to certificateChain: [NIOSSLCertificate]) {
  346. self.modifyingNIOConfiguration {
  347. $0.configuration.certificateChain = certificateChain.map { .certificate($0) }
  348. }
  349. }
  350. internal mutating func updateNIOPrivateKey(to privateKey: NIOSSLPrivateKey) {
  351. self.modifyingNIOConfiguration {
  352. $0.configuration.privateKey = .privateKey(privateKey)
  353. }
  354. }
  355. internal mutating func updateNIOTrustRoots(to trustRoots: NIOSSLTrustRoots) {
  356. self.modifyingNIOConfiguration {
  357. $0.configuration.trustRoots = trustRoots
  358. }
  359. }
  360. internal mutating func updateNIOCertificateVerification(
  361. to verification: CertificateVerification
  362. ) {
  363. self.modifyingNIOConfiguration {
  364. $0.configuration.certificateVerification = verification
  365. }
  366. }
  367. internal mutating func updateNIOCustomVerificationCallback(
  368. to callback: @escaping NIOSSLCustomVerificationCallback
  369. ) {
  370. self.modifyingNIOConfiguration {
  371. $0.customVerificationCallback = callback
  372. }
  373. }
  374. private mutating func modifyingNIOConfiguration(_ modify: (inout NIOConfiguration) -> Void) {
  375. switch self.backend {
  376. case var .nio(configuration):
  377. modify(&configuration)
  378. self.backend = .nio(configuration)
  379. #if canImport(Network)
  380. case .network:
  381. preconditionFailure()
  382. #endif
  383. }
  384. }
  385. }
  386. #endif // canImport(NIOSSL)
  387. // MARK: - Network Backend
  388. #if canImport(Network)
  389. extension GRPCTLSConfiguration {
  390. internal struct NetworkConfiguration {
  391. @available(macOS 10.14, iOS 12.0, watchOS 6.0, tvOS 12.0, *)
  392. internal var options: NWProtocolTLS.Options {
  393. get {
  394. return self._options as! NWProtocolTLS.Options
  395. }
  396. set {
  397. self._options = newValue
  398. }
  399. }
  400. /// Always a NWProtocolTLS.Options.
  401. ///
  402. /// This somewhat insane type-erasure is necessary because we need to availability-guard the NWProtocolTLS.Options
  403. /// (it isn't available in older SDKs), but we cannot have stored properties guarded by availability in this way, only
  404. /// computed ones. To that end, we have to erase the type and then un-erase it. This is fairly silly.
  405. private var _options: Any
  406. // This is set privately via `updateHostnameOverride(to:)` because we require availability
  407. // guards to update the value in the underlying `sec_protocol_options`.
  408. internal private(set) var hostnameOverride: String?
  409. @available(macOS 10.14, iOS 12.0, watchOS 6.0, tvOS 12.0, *)
  410. init(options: NWProtocolTLS.Options, hostnameOverride: String?) {
  411. self._options = options
  412. self.hostnameOverride = hostnameOverride
  413. }
  414. @available(macOS 10.14, iOS 12.0, watchOS 6.0, tvOS 12.0, *)
  415. internal mutating func updateHostnameOverride(to hostnameOverride: String) {
  416. self.hostnameOverride = hostnameOverride
  417. sec_protocol_options_set_tls_server_name(
  418. self.options.securityProtocolOptions,
  419. hostnameOverride
  420. )
  421. }
  422. }
  423. @available(macOS 10.14, iOS 12.0, watchOS 6.0, tvOS 12.0, *)
  424. public static func makeClientConfigurationBackedByNetworkFramework(
  425. identity: SecIdentity? = nil,
  426. hostnameOverride: String? = nil,
  427. verifyCallbackWithQueue: (sec_protocol_verify_t, DispatchQueue)? = nil
  428. ) -> GRPCTLSConfiguration {
  429. let options = NWProtocolTLS.Options()
  430. if let identity = identity {
  431. sec_protocol_options_set_local_identity(
  432. options.securityProtocolOptions,
  433. sec_identity_create(identity)!
  434. )
  435. }
  436. if let hostnameOverride = hostnameOverride {
  437. sec_protocol_options_set_tls_server_name(
  438. options.securityProtocolOptions,
  439. hostnameOverride
  440. )
  441. }
  442. if let verifyCallbackWithQueue = verifyCallbackWithQueue {
  443. sec_protocol_options_set_verify_block(
  444. options.securityProtocolOptions,
  445. verifyCallbackWithQueue.0,
  446. verifyCallbackWithQueue.1
  447. )
  448. }
  449. if #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) {
  450. sec_protocol_options_set_min_tls_protocol_version(options.securityProtocolOptions, .TLSv12)
  451. } else {
  452. sec_protocol_options_set_tls_min_version(options.securityProtocolOptions, .tlsProtocol12)
  453. }
  454. for `protocol` in GRPCApplicationProtocolIdentifier.client {
  455. sec_protocol_options_add_tls_application_protocol(
  456. options.securityProtocolOptions,
  457. `protocol`
  458. )
  459. }
  460. return .makeClientConfigurationBackedByNetworkFramework(
  461. options: options,
  462. hostnameOverride: hostnameOverride
  463. )
  464. }
  465. @available(macOS 10.14, iOS 12.0, watchOS 6.0, tvOS 12.0, *)
  466. public static func makeClientConfigurationBackedByNetworkFramework(
  467. options: NWProtocolTLS.Options,
  468. hostnameOverride: String? = nil
  469. ) -> GRPCTLSConfiguration {
  470. let network = NetworkConfiguration(options: options, hostnameOverride: hostnameOverride)
  471. return GRPCTLSConfiguration(network: network)
  472. }
  473. @available(macOS 10.14, iOS 12.0, watchOS 6.0, tvOS 12.0, *)
  474. public static func makeServerConfigurationBackedByNetworkFramework(
  475. identity: SecIdentity
  476. ) -> GRPCTLSConfiguration {
  477. let options = NWProtocolTLS.Options()
  478. sec_protocol_options_set_local_identity(
  479. options.securityProtocolOptions,
  480. sec_identity_create(identity)!
  481. )
  482. if #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) {
  483. sec_protocol_options_set_min_tls_protocol_version(options.securityProtocolOptions, .TLSv12)
  484. } else {
  485. sec_protocol_options_set_tls_min_version(options.securityProtocolOptions, .tlsProtocol12)
  486. }
  487. for `protocol` in GRPCApplicationProtocolIdentifier.server {
  488. sec_protocol_options_add_tls_application_protocol(
  489. options.securityProtocolOptions,
  490. `protocol`
  491. )
  492. }
  493. return GRPCTLSConfiguration.makeServerConfigurationBackedByNetworkFramework(options: options)
  494. }
  495. @available(macOS 10.14, iOS 12.0, watchOS 6.0, tvOS 12.0, *)
  496. public static func makeServerConfigurationBackedByNetworkFramework(
  497. options: NWProtocolTLS.Options
  498. ) -> GRPCTLSConfiguration {
  499. let network = NetworkConfiguration(options: options, hostnameOverride: nil)
  500. return GRPCTLSConfiguration(network: network)
  501. }
  502. @available(macOS 10.14, iOS 12.0, watchOS 6.0, tvOS 12.0, *)
  503. internal mutating func updateNetworkLocalIdentity(to identity: SecIdentity) {
  504. self.modifyingNetworkConfiguration {
  505. sec_protocol_options_set_local_identity(
  506. $0.options.securityProtocolOptions,
  507. sec_identity_create(identity)!
  508. )
  509. }
  510. }
  511. @available(macOS 10.14, iOS 12.0, watchOS 6.0, tvOS 12.0, *)
  512. internal mutating func updateNetworkVerifyCallbackWithQueue(
  513. callback: @escaping sec_protocol_verify_t,
  514. queue: DispatchQueue
  515. ) {
  516. self.modifyingNetworkConfiguration {
  517. sec_protocol_options_set_verify_block(
  518. $0.options.securityProtocolOptions,
  519. callback,
  520. queue
  521. )
  522. }
  523. }
  524. private mutating func modifyingNetworkConfiguration(
  525. _ modify: (inout NetworkConfiguration) -> Void
  526. ) {
  527. switch self.backend {
  528. case var .network(_configuration):
  529. modify(&_configuration)
  530. self.backend = .network(_configuration)
  531. #if canImport(NIOSSL)
  532. case .nio:
  533. preconditionFailure()
  534. #endif // canImport(NIOSSL)
  535. }
  536. }
  537. }
  538. #endif
  539. #if canImport(Network)
  540. extension GRPCTLSConfiguration {
  541. @available(macOS 10.14, iOS 12.0, watchOS 6.0, tvOS 12.0, *)
  542. internal func applyNetworkTLSOptions(
  543. to bootstrap: NIOTSConnectionBootstrap
  544. ) -> NIOTSConnectionBootstrap {
  545. switch self.backend {
  546. case let .network(_configuration):
  547. return bootstrap.tlsOptions(_configuration.options)
  548. #if canImport(NIOSSL)
  549. case .nio:
  550. // We're using NIOSSL with Network.framework; that's okay and permitted for backwards
  551. // compatibility.
  552. return bootstrap
  553. #endif // canImport(NIOSSL)
  554. }
  555. }
  556. @available(macOS 10.14, iOS 12.0, watchOS 6.0, tvOS 12.0, *)
  557. internal func applyNetworkTLSOptions(
  558. to bootstrap: NIOTSListenerBootstrap
  559. ) -> NIOTSListenerBootstrap {
  560. switch self.backend {
  561. case let .network(_configuration):
  562. return bootstrap.tlsOptions(_configuration.options)
  563. #if canImport(NIOSSL)
  564. case .nio:
  565. // We're using NIOSSL with Network.framework; that's okay and permitted for backwards
  566. // compatibility.
  567. return bootstrap
  568. #endif // canImport(NIOSSL)
  569. }
  570. }
  571. }
  572. @available(macOS 10.14, iOS 12.0, watchOS 6.0, tvOS 12.0, *)
  573. extension NIOTSConnectionBootstrap {
  574. internal func tlsOptions(
  575. from _configuration: GRPCTLSConfiguration
  576. ) -> NIOTSConnectionBootstrap {
  577. return _configuration.applyNetworkTLSOptions(to: self)
  578. }
  579. }
  580. @available(macOS 10.14, iOS 12.0, watchOS 6.0, tvOS 12.0, *)
  581. extension NIOTSListenerBootstrap {
  582. internal func tlsOptions(
  583. from _configuration: GRPCTLSConfiguration
  584. ) -> NIOTSListenerBootstrap {
  585. return _configuration.applyNetworkTLSOptions(to: self)
  586. }
  587. }
  588. #endif