|
12 | 12 | //===----------------------------------------------------------------------===// |
13 | 13 |
|
14 | 14 | public import NIOCertificateReloading |
15 | | -public import NIOCore |
16 | | -public import NIOSSL |
| 15 | +import NIOCore |
| 16 | +import NIOSSL |
17 | 17 | public import X509 |
18 | 18 |
|
19 | 19 | /// Configuration settings for ``NIOHTTPServer``. |
@@ -54,26 +54,6 @@ public struct NIOHTTPServerConfiguration: Sendable { |
54 | 54 | /// Provides options for running the server with or without TLS encryption. |
55 | 55 | /// When using TLS, you must either provide a certificate chain and private key, or a `CertificateReloader`. |
56 | 56 | public struct TransportSecurity: Sendable { |
57 | | - /// A callback that replaces `NIOSSL`'s default certificate verification with custom verification logic. |
58 | | - /// |
59 | | - /// This is just a `Sendable` version of `NIOSSLCustomVerificationCallbackWithMetadata`. |
60 | | - /// |
61 | | - /// ## Usage |
62 | | - /// |
63 | | - /// The callback receives: |
64 | | - /// - **certificates**: The certificates presented by the peer. You are responsible for building and validating |
65 | | - /// a chain of trust from these certificates. |
66 | | - /// - **promise**: A promise that must be completed. Call `promise.succeed(...)` with the subset of certificates |
67 | | - /// that formed the validated chain of trust, or `promise.fail()` if verification fails. |
68 | | - /// |
69 | | - /// - Warning: This callback completely replaces NIOSSL's certificate verification logic and must be used with |
70 | | - /// caution. |
71 | | - public typealias CustomCertificateVerificationCallback = |
72 | | - @Sendable ( |
73 | | - [NIOSSLCertificate], |
74 | | - EventLoopPromise<NIOSSLVerificationResultWithMetadata> |
75 | | - ) -> Void |
76 | | - |
77 | 57 | enum Backing { |
78 | 58 | case plaintext |
79 | 59 | case tls( |
@@ -258,3 +238,61 @@ public struct NIOHTTPServerConfiguration: Sendable { |
258 | 238 | self.http2 = http2 |
259 | 239 | } |
260 | 240 | } |
| 241 | + |
| 242 | +@available(macOS 26.0, iOS 26.0, watchOS 26.0, tvOS 26.0, visionOS 26.0, *) |
| 243 | +extension NIOHTTPServerConfiguration.TransportSecurity { |
| 244 | + /// Represents the outcome of certificate verification. |
| 245 | + /// |
| 246 | + /// Indicates whether certificate verification succeeded or failed, and provides associated metadata when |
| 247 | + /// verification is successful. |
| 248 | + public enum CertificateVerificationResult: Sendable, Hashable { |
| 249 | + /// An error representing certificate verification failure. |
| 250 | + public struct VerificationError: Swift.Error, Hashable { |
| 251 | + let description: String |
| 252 | + |
| 253 | + /// Creates a verification error with a description of the failure. |
| 254 | + /// - Parameter description: A description of why certificate verification failed. |
| 255 | + public init(description: String) { |
| 256 | + self.description = description |
| 257 | + } |
| 258 | + } |
| 259 | + |
| 260 | + /// Metadata resulting from successful certificate verification. |
| 261 | + public struct VerificationMetadata: Sendable, Hashable { |
| 262 | + /// A container for the validated certificate chain: an array of certificates forming a verified and ordered |
| 263 | + /// chain of trust, starting from the peer's leaf certificate to a trusted root certificate. |
| 264 | + public var validatedCertificateChain: X509.ValidatedCertificateChain? |
| 265 | + |
| 266 | + /// Creates an instance with the peer's *validated* certificate chain. |
| 267 | + /// |
| 268 | + /// - Parameter validatedCertificateChain: An optional *validated* certificate chain. If provided, it must |
| 269 | + /// **only** contain the **validated** chain of trust that was built and verified from the certificates |
| 270 | + /// presented by the peer. |
| 271 | + public init(_ validatedCertificateChain: X509.ValidatedCertificateChain?) { |
| 272 | + self.validatedCertificateChain = validatedCertificateChain |
| 273 | + } |
| 274 | + } |
| 275 | + |
| 276 | + /// Certificate verification succeeded. |
| 277 | + /// |
| 278 | + /// The associated metadata contains information captured during verification. |
| 279 | + case certificateVerified(VerificationMetadata) |
| 280 | + |
| 281 | + /// Certificate verification failed. |
| 282 | + case failed(VerificationError) |
| 283 | + } |
| 284 | + |
| 285 | + /// A callback for implementing custom certificate verification logic. |
| 286 | + /// |
| 287 | + /// Use this callback to perform custom certificate verification. The callback receives the certificates presented |
| 288 | + /// by the peer as `[X509.Certificate]`. Within the callback, you must validate these certificates against your |
| 289 | + /// trust roots and derive a validated chain of trust per [RFC 4158](https://datatracker.ietf.org/doc/html/rfc4158). |
| 290 | + /// |
| 291 | + /// Return ``CertificateVerificationResult/certificateVerified(_:)`` if verification succeeds, optionally including |
| 292 | + /// the validated certificate chain you derived. Returning the validated certificate chain allows ``NIOHTTPServer`` |
| 293 | + /// to provide access to it in the request handler through ``NIOHTTPServer/ConnectionContext/peerCertificateChain``, |
| 294 | + /// accessed via the task-local ``NIOHTTPServer/connectionContext`` property. Otherwise, return |
| 295 | + /// ``CertificateVerificationResult/failed(_:)`` if verification fails. |
| 296 | + public typealias CustomCertificateVerificationCallback = |
| 297 | + @Sendable ([Certificate]) async throws -> CertificateVerificationResult |
| 298 | +} |
0 commit comments