Skip to content

Commit 794dc9d

Browse files
authored
Add testSelfSignedCertificateIsRejectedWithCorrectError (#594)
1 parent 9a8553e commit 794dc9d

File tree

7 files changed

+128
-4
lines changed

7 files changed

+128
-4
lines changed

Package.swift

+4
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ let package = Package(
6161
.product(name: "NIOHTTP2", package: "swift-nio-http2"),
6262
.product(name: "NIOSOCKS", package: "swift-nio-extras"),
6363
.product(name: "Logging", package: "swift-log"),
64+
],
65+
resources: [
66+
.copy("Resources/self_signed_cert.pem"),
67+
.copy("Resources/self_signed_key.pem"),
6468
]
6569
),
6670
]

Sources/AsyncHTTPClient/NIOTransportServices/NWErrorHandler.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ extension HTTPClient {
6060
}
6161
#endif
6262

63-
class NWErrorHandler: ChannelInboundHandler {
63+
final class NWErrorHandler: ChannelInboundHandler {
6464
typealias InboundIn = HTTPClientResponsePart
6565

6666
func errorCaught(context: ChannelHandlerContext, error: Error) {
@@ -73,9 +73,9 @@ extension HTTPClient {
7373
if let error = error as? NWError {
7474
switch error {
7575
case .tls(let status):
76-
return NWTLSError(status, reason: error.localizedDescription)
76+
return NWTLSError(status, reason: String(describing: error))
7777
case .posix(let errorCode):
78-
return NWPOSIXError(errorCode, reason: error.localizedDescription)
78+
return NWPOSIXError(errorCode, reason: String(describing: error))
7979
default:
8080
return error
8181
}

Tests/AsyncHTTPClientTests/HTTPClientTests+XCTest.swift

+1
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ extension HTTPClientTests {
7878
("testSubsequentRequestsWorkWithServerAlternatingBetweenKeepAliveAndClose", testSubsequentRequestsWorkWithServerAlternatingBetweenKeepAliveAndClose),
7979
("testStressGetHttps", testStressGetHttps),
8080
("testStressGetHttpsSSLError", testStressGetHttpsSSLError),
81+
("testSelfSignedCertificateIsRejectedWithCorrectError", testSelfSignedCertificateIsRejectedWithCorrectError),
8182
("testFailingConnectionIsReleased", testFailingConnectionIsReleased),
8283
("testResponseDelayGet", testResponseDelayGet),
8384
("testIdleTimeoutNoReuse", testIdleTimeoutNoReuse),

Tests/AsyncHTTPClientTests/HTTPClientTests.swift

+40
Original file line numberDiff line numberDiff line change
@@ -1229,6 +1229,46 @@ class HTTPClientTests: XCTestCase {
12291229
}
12301230
}
12311231

1232+
func testSelfSignedCertificateIsRejectedWithCorrectError() throws {
1233+
/// key + cert was created with the follwing command:
1234+
/// openssl req -x509 -newkey rsa:4096 -keyout self_signed_key.pem -out self_signed_cert.pem -sha256 -days 99999 -nodes -subj '/CN=localhost'
1235+
let certPath = Bundle.module.path(forResource: "self_signed_cert", ofType: "pem")!
1236+
let keyPath = Bundle.module.path(forResource: "self_signed_key", ofType: "pem")!
1237+
let configuration = TLSConfiguration.makeServerConfiguration(
1238+
certificateChain: try NIOSSLCertificate.fromPEMFile(certPath).map { .certificate($0) },
1239+
privateKey: .file(keyPath)
1240+
)
1241+
let sslContext = try NIOSSLContext(configuration: configuration)
1242+
1243+
let server = ServerBootstrap(group: serverGroup)
1244+
.childChannelInitializer { channel in
1245+
channel.pipeline.addHandler(NIOSSLServerHandler(context: sslContext))
1246+
}
1247+
let serverChannel = try server.bind(host: "localhost", port: 0).wait()
1248+
defer { XCTAssertNoThrow(try serverChannel.close().wait()) }
1249+
let port = serverChannel.localAddress!.port!
1250+
1251+
var config = HTTPClient.Configuration()
1252+
config.timeout.connect = .seconds(2)
1253+
let localClient = HTTPClient(eventLoopGroupProvider: .shared(self.clientGroup), configuration: config)
1254+
defer { XCTAssertNoThrow(try localClient.syncShutdown()) }
1255+
XCTAssertThrowsError(try localClient.get(url: "https://localhost:\(port)").wait()) { error in
1256+
#if canImport(Network)
1257+
guard let nwTLSError = error as? HTTPClient.NWTLSError else {
1258+
XCTFail("could not cast \(error) of type \(type(of: error)) to \(HTTPClient.NWTLSError.self)")
1259+
return
1260+
}
1261+
XCTAssertEqual(nwTLSError.status, errSSLBadCert, "unexpected tls error: \(nwTLSError)")
1262+
#else
1263+
guard let sslError = error as? NIOSSLError,
1264+
case .handshakeFailed(.sslError) = sslError else {
1265+
XCTFail("unexpected error \(error)")
1266+
return
1267+
}
1268+
#endif
1269+
}
1270+
}
1271+
12321272
func testFailingConnectionIsReleased() {
12331273
let localHTTPBin = HTTPBin(.refuse)
12341274
let localClient = HTTPClient(eventLoopGroupProvider: .shared(self.clientGroup))

Tests/AsyncHTTPClientTests/HTTPConnectionPool+HTTP2StateMachineTests.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -1242,7 +1242,7 @@ func XCTAssertEqualTypeAndValue<Left, Right: Equatable>(
12421242
let lhs = try lhs()
12431243
let rhs = try rhs()
12441244
guard let lhsAsRhs = lhs as? Right else {
1245-
XCTFail("could not cast \(lhs) of type \(Right.self) to \(Left.self)")
1245+
XCTFail("could not cast \(lhs) of type \(type(of: lhs)) to \(type(of: rhs))")
12461246
return
12471247
}
12481248
XCTAssertEqual(lhsAsRhs, rhs)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIEpjCCAo4CCQCeTmfiTQcJrzANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls
3+
b2NhbGhvc3QwIBcNMjIwNjE0MTI1NDQ4WhgPMjI5NjAzMjgxMjU0NDhaMBQxEjAQ
4+
BgNVBAMMCWxvY2FsaG9zdDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
5+
AK16gPDwP/Xbaf36x5BNd6yHDxCPIIJP4JLfMEuozwLE0YRqwmZOuklb4jUbAXf7
6+
u9u24ANrC4XS6VVWkfPdugokAUkaKPpwkV4GOiMCXeSDjDiLt1dYxlbp+MLV78a5
7+
oUDbCAqfFKebIgv1oiK+L6/p818eAHSBWEXXMhTeBDEQAIpJLTG88iVu6r3fMJeH
8+
FbMWuPmAajmx2AEGmwD1x6+NHZLJv1zaufa7j0sHADraagXnfKn6rkLn1is6QFu4
9+
v7xaNlEwsRCYbh0nrtCtEdJIqnEHc0GCu/gnw5GE3CuRG3FYBTZStIF7d9h+XZQB
10+
ky/YEWSGw9DXFBbebOZugopvl91qaZLqo6Wg0J8qCodgFtJHOSVMq/SAOBmKyw+b
11+
7FYZbj4tQKpuuhwCN+gwEveTy+BK+zGY/sVzPwR8PNjpCgT/HiOBM7dNt4+2r9pY
12+
Ld/mcMvakgRzM4Iqqntem9ltuckZev0TRjdrIylVWsAlNYVXm4ncMLkbzxFkv5Gb
13+
AlhAuTwxyFkIo0M7+GS4lXCZ2bX2umJ0DTl3/NGJserFdkOhvHZSHHC9BzDBysmc
14+
SejX/cGOFQ8O3sFeJdVMGlO64dU482O0FbBcLHmTLXWR4t8dlhrzJuXZ4X6WtHqY
15+
83RwyD1gacYRZnT0eL+Z7XGrO1/qypji1RNaFIaGUt7DAgMBAAEwDQYJKoZIhvcN
16+
AQELBQADggIBAIigOuEVirgqXoUMStTwYObs/DcNIPEugn9gAq9Lt1cr6fm7CvhG
17+
AupxoJTbKLHQX6FegvFSA+4Kt3KYXX9Qi9SJF3Vr4zOhV0q203d4Aui6Lamo5Yye
18+
nhbzzXuDSIyxpaWPFRC2RqCA6+hV8/Ar9Bx0TCI4NQxWxQEPerwqzqWCuTbViccw
19+
WzlwRD2AHibaQaCbpzXg9lOX0fRJHoSM3exYQd91pDoSoL3f/EV3I/czssq+10M8
20+
F4GhE4bQjaKD7jL5U59dlvfy73nLAzzxzsxsFuYTAgzZwDg586sdbrqqFjzjoZ9A
21+
dF8NuVYkHyFDQkpe66e1isNZi7eFdSjeVmj8llp4b6in59ik7ZS7arzGOxhZZzmv
22+
Jf3nfE4hJzMS/4GJsKMdtcI+6K+hMi6Yt9OoPh82SQ2q8gK4QSWWrwAKuQ4F4UeO
23+
pgiWBryKrkOXlGARBbsR/ZDhlqyAskeGuhIpEY5NLCByFfQ5KlcrX+n4TVLRZMvb
24+
/7PZqboGgU+CUVawm/suPAs8jOlFQOzrxWQPRfWVvFII62ABgozS8N/xZ/WbgTVj
25+
kOtWj85NpaBSCUliIY/7z1FkjpMZO8Kds45WQzAq4YChDLZGbgV0MkyXqO/LEYFJ
26+
zqGOP1yGxVcKxu6t8Xh0hL6JPFmKWiMEWVrd1wut6NAIu6WNftmWZX6J
27+
-----END CERTIFICATE-----
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
-----BEGIN PRIVATE KEY-----
2+
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
51+
+HYZkcyQcpDwfC+2NOWOU7NQj+IDIA==
52+
-----END PRIVATE KEY-----

0 commit comments

Comments
 (0)