GRPCTLSConfiguration.swift 24 KB

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