From b705df9f21a7e216ab75d9c5c4849530128c1567 Mon Sep 17 00:00:00 2001 From: David Nadoba Date: Wed, 15 Jun 2022 12:24:51 +0200 Subject: [PATCH 1/2] Add `testSelfSignedCertificateIsRejectedWithCorrectError` --- Package.swift | 4 ++ .../NIOTransportServices/NWErrorHandler.swift | 6 +-- .../HTTPClientTests+XCTest.swift | 1 + .../HTTPClientTests.swift | 40 ++++++++++++++ ...onnectionPool+HTTP2StateMachineTests.swift | 2 +- .../Resources/self_signed_cert.pem | 27 ++++++++++ .../Resources/self_signed_key.pem | 52 +++++++++++++++++++ 7 files changed, 128 insertions(+), 4 deletions(-) create mode 100644 Tests/AsyncHTTPClientTests/Resources/self_signed_cert.pem create mode 100644 Tests/AsyncHTTPClientTests/Resources/self_signed_key.pem diff --git a/Package.swift b/Package.swift index 5deb0de31..20484832d 100644 --- a/Package.swift +++ b/Package.swift @@ -61,6 +61,10 @@ let package = Package( .product(name: "NIOHTTP2", package: "swift-nio-http2"), .product(name: "NIOSOCKS", package: "swift-nio-extras"), .product(name: "Logging", package: "swift-log"), + ], + resources: [ + .copy("Resources/self_signed_cert.pem"), + .copy("Resources/self_signed_key.pem"), ] ), ] diff --git a/Sources/AsyncHTTPClient/NIOTransportServices/NWErrorHandler.swift b/Sources/AsyncHTTPClient/NIOTransportServices/NWErrorHandler.swift index 4334bb9f9..f732c37f4 100644 --- a/Sources/AsyncHTTPClient/NIOTransportServices/NWErrorHandler.swift +++ b/Sources/AsyncHTTPClient/NIOTransportServices/NWErrorHandler.swift @@ -60,7 +60,7 @@ extension HTTPClient { } #endif - class NWErrorHandler: ChannelInboundHandler { + final class NWErrorHandler: ChannelInboundHandler { typealias InboundIn = HTTPClientResponsePart func errorCaught(context: ChannelHandlerContext, error: Error) { @@ -73,9 +73,9 @@ extension HTTPClient { if let error = error as? NWError { switch error { case .tls(let status): - return NWTLSError(status, reason: error.localizedDescription) + return NWTLSError(status, reason: String(describing: error)) case .posix(let errorCode): - return NWPOSIXError(errorCode, reason: error.localizedDescription) + return NWPOSIXError(errorCode, reason: String(describing: error)) default: return error } diff --git a/Tests/AsyncHTTPClientTests/HTTPClientTests+XCTest.swift b/Tests/AsyncHTTPClientTests/HTTPClientTests+XCTest.swift index d6fe77e47..aee08dea9 100644 --- a/Tests/AsyncHTTPClientTests/HTTPClientTests+XCTest.swift +++ b/Tests/AsyncHTTPClientTests/HTTPClientTests+XCTest.swift @@ -78,6 +78,7 @@ extension HTTPClientTests { ("testSubsequentRequestsWorkWithServerAlternatingBetweenKeepAliveAndClose", testSubsequentRequestsWorkWithServerAlternatingBetweenKeepAliveAndClose), ("testStressGetHttps", testStressGetHttps), ("testStressGetHttpsSSLError", testStressGetHttpsSSLError), + ("testSelfSignedCertificateIsRejectedWithCorrectError", testSelfSignedCertificateIsRejectedWithCorrectError), ("testFailingConnectionIsReleased", testFailingConnectionIsReleased), ("testResponseDelayGet", testResponseDelayGet), ("testIdleTimeoutNoReuse", testIdleTimeoutNoReuse), diff --git a/Tests/AsyncHTTPClientTests/HTTPClientTests.swift b/Tests/AsyncHTTPClientTests/HTTPClientTests.swift index 726809415..04fbed09e 100644 --- a/Tests/AsyncHTTPClientTests/HTTPClientTests.swift +++ b/Tests/AsyncHTTPClientTests/HTTPClientTests.swift @@ -1228,6 +1228,46 @@ class HTTPClientTests: XCTestCase { } } } + + func testSelfSignedCertificateIsRejectedWithCorrectError() throws { + /// key + cert was created with the follwing command: + /// openssl req -x509 -newkey rsa:4096 -keyout self_signed_key.pem -out self_signed_cert.pem -sha256 -days 99999 -nodes -subj '/CN=localhost' + let certPath = Bundle.module.path(forResource: "self_signed_cert", ofType: "pem")! + let keyPath = Bundle.module.path(forResource: "self_signed_key", ofType: "pem")! + let configuration = TLSConfiguration.makeServerConfiguration( + certificateChain: try NIOSSLCertificate.fromPEMFile(certPath).map { .certificate($0) }, + privateKey: .file(keyPath) + ) + let sslContext = try NIOSSLContext(configuration: configuration) + + let server = ServerBootstrap(group: serverGroup) + .childChannelInitializer { channel in + channel.pipeline.addHandler(NIOSSLServerHandler(context: sslContext)) + } + let serverChannel = try server.bind(host: "localhost", port: 0).wait() + defer { XCTAssertNoThrow(try serverChannel.close().wait()) } + let port = serverChannel.localAddress!.port! + + var config = HTTPClient.Configuration() + config.timeout.connect = .seconds(2) + let localClient = HTTPClient(eventLoopGroupProvider: .shared(self.clientGroup), configuration: config) + defer { XCTAssertNoThrow(try localClient.syncShutdown()) } + XCTAssertThrowsError(try localClient.get(url: "https://localhost:\(port)").wait()) { error in + #if canImport(Network) + guard let nwTLSError = error as? HTTPClient.NWTLSError else { + XCTFail("could not cast \(error) of type \(type(of: error)) to \(HTTPClient.NWTLSError.self)") + return + } + XCTAssertEqual(nwTLSError.status, errSSLBadCert, "unexpected tls error: \(nwTLSError)") + #else + guard let sslError = error as? NIOSSLError, + case .handshakeFailed(.sslError) = sslError else { + XCTFail("unexpected error \(error)") + return + } + #endif + } + } func testFailingConnectionIsReleased() { let localHTTPBin = HTTPBin(.refuse) diff --git a/Tests/AsyncHTTPClientTests/HTTPConnectionPool+HTTP2StateMachineTests.swift b/Tests/AsyncHTTPClientTests/HTTPConnectionPool+HTTP2StateMachineTests.swift index 825ffc9b3..2574d3da2 100644 --- a/Tests/AsyncHTTPClientTests/HTTPConnectionPool+HTTP2StateMachineTests.swift +++ b/Tests/AsyncHTTPClientTests/HTTPConnectionPool+HTTP2StateMachineTests.swift @@ -1242,7 +1242,7 @@ func XCTAssertEqualTypeAndValue( let lhs = try lhs() let rhs = try rhs() guard let lhsAsRhs = lhs as? Right else { - XCTFail("could not cast \(lhs) of type \(Right.self) to \(Left.self)") + XCTFail("could not cast \(lhs) of type \(type(of: lhs)) to \(type(of: rhs))") return } XCTAssertEqual(lhsAsRhs, rhs) diff --git a/Tests/AsyncHTTPClientTests/Resources/self_signed_cert.pem b/Tests/AsyncHTTPClientTests/Resources/self_signed_cert.pem new file mode 100644 index 000000000..20b46f355 --- /dev/null +++ b/Tests/AsyncHTTPClientTests/Resources/self_signed_cert.pem @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEpjCCAo4CCQCeTmfiTQcJrzANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls +b2NhbGhvc3QwIBcNMjIwNjE0MTI1NDQ4WhgPMjI5NjAzMjgxMjU0NDhaMBQxEjAQ +BgNVBAMMCWxvY2FsaG9zdDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +AK16gPDwP/Xbaf36x5BNd6yHDxCPIIJP4JLfMEuozwLE0YRqwmZOuklb4jUbAXf7 +u9u24ANrC4XS6VVWkfPdugokAUkaKPpwkV4GOiMCXeSDjDiLt1dYxlbp+MLV78a5 +oUDbCAqfFKebIgv1oiK+L6/p818eAHSBWEXXMhTeBDEQAIpJLTG88iVu6r3fMJeH +FbMWuPmAajmx2AEGmwD1x6+NHZLJv1zaufa7j0sHADraagXnfKn6rkLn1is6QFu4 +v7xaNlEwsRCYbh0nrtCtEdJIqnEHc0GCu/gnw5GE3CuRG3FYBTZStIF7d9h+XZQB +ky/YEWSGw9DXFBbebOZugopvl91qaZLqo6Wg0J8qCodgFtJHOSVMq/SAOBmKyw+b +7FYZbj4tQKpuuhwCN+gwEveTy+BK+zGY/sVzPwR8PNjpCgT/HiOBM7dNt4+2r9pY +Ld/mcMvakgRzM4Iqqntem9ltuckZev0TRjdrIylVWsAlNYVXm4ncMLkbzxFkv5Gb +AlhAuTwxyFkIo0M7+GS4lXCZ2bX2umJ0DTl3/NGJserFdkOhvHZSHHC9BzDBysmc +SejX/cGOFQ8O3sFeJdVMGlO64dU482O0FbBcLHmTLXWR4t8dlhrzJuXZ4X6WtHqY +83RwyD1gacYRZnT0eL+Z7XGrO1/qypji1RNaFIaGUt7DAgMBAAEwDQYJKoZIhvcN +AQELBQADggIBAIigOuEVirgqXoUMStTwYObs/DcNIPEugn9gAq9Lt1cr6fm7CvhG +AupxoJTbKLHQX6FegvFSA+4Kt3KYXX9Qi9SJF3Vr4zOhV0q203d4Aui6Lamo5Yye +nhbzzXuDSIyxpaWPFRC2RqCA6+hV8/Ar9Bx0TCI4NQxWxQEPerwqzqWCuTbViccw +WzlwRD2AHibaQaCbpzXg9lOX0fRJHoSM3exYQd91pDoSoL3f/EV3I/czssq+10M8 +F4GhE4bQjaKD7jL5U59dlvfy73nLAzzxzsxsFuYTAgzZwDg586sdbrqqFjzjoZ9A +dF8NuVYkHyFDQkpe66e1isNZi7eFdSjeVmj8llp4b6in59ik7ZS7arzGOxhZZzmv +Jf3nfE4hJzMS/4GJsKMdtcI+6K+hMi6Yt9OoPh82SQ2q8gK4QSWWrwAKuQ4F4UeO +pgiWBryKrkOXlGARBbsR/ZDhlqyAskeGuhIpEY5NLCByFfQ5KlcrX+n4TVLRZMvb +/7PZqboGgU+CUVawm/suPAs8jOlFQOzrxWQPRfWVvFII62ABgozS8N/xZ/WbgTVj +kOtWj85NpaBSCUliIY/7z1FkjpMZO8Kds45WQzAq4YChDLZGbgV0MkyXqO/LEYFJ +zqGOP1yGxVcKxu6t8Xh0hL6JPFmKWiMEWVrd1wut6NAIu6WNftmWZX6J +-----END CERTIFICATE----- diff --git a/Tests/AsyncHTTPClientTests/Resources/self_signed_key.pem b/Tests/AsyncHTTPClientTests/Resources/self_signed_key.pem new file mode 100644 index 000000000..8811c2d81 --- /dev/null +++ b/Tests/AsyncHTTPClientTests/Resources/self_signed_key.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 ++HYZkcyQcpDwfC+2NOWOU7NQj+IDIA== +-----END PRIVATE KEY----- From a1354a24b16a7a52486b502ead852267976b6319 Mon Sep 17 00:00:00 2001 From: David Nadoba Date: Wed, 15 Jun 2022 14:13:44 +0200 Subject: [PATCH 2/2] SwiftFormat --- Tests/AsyncHTTPClientTests/HTTPClientTests.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/AsyncHTTPClientTests/HTTPClientTests.swift b/Tests/AsyncHTTPClientTests/HTTPClientTests.swift index 04fbed09e..d49d4cbb9 100644 --- a/Tests/AsyncHTTPClientTests/HTTPClientTests.swift +++ b/Tests/AsyncHTTPClientTests/HTTPClientTests.swift @@ -1228,7 +1228,7 @@ class HTTPClientTests: XCTestCase { } } } - + func testSelfSignedCertificateIsRejectedWithCorrectError() throws { /// key + cert was created with the follwing command: /// openssl req -x509 -newkey rsa:4096 -keyout self_signed_key.pem -out self_signed_cert.pem -sha256 -days 99999 -nodes -subj '/CN=localhost' @@ -1247,7 +1247,7 @@ class HTTPClientTests: XCTestCase { let serverChannel = try server.bind(host: "localhost", port: 0).wait() defer { XCTAssertNoThrow(try serverChannel.close().wait()) } let port = serverChannel.localAddress!.port! - + var config = HTTPClient.Configuration() config.timeout.connect = .seconds(2) let localClient = HTTPClient(eventLoopGroupProvider: .shared(self.clientGroup), configuration: config)