Skip to content

Commit f19017c

Browse files
glbrnttdnadoba
authored andcommitted
Log TLS version (grpc#1509)
* Log TLS version * Use released versions, reformat Co-authored-by: David Nadoba <d_nadoba@apple.com>
1 parent 5ab7cb2 commit f19017c

File tree

5 files changed

+145
-2
lines changed

5 files changed

+145
-2
lines changed

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ let packageDependencies: [Package.Dependency] = [
4040
),
4141
.package(
4242
url: "https://github.com/apple/swift-nio-transport-services.git",
43-
from: "1.11.1"
43+
from: "1.15.0"
4444
),
4545
.package(
4646
url: "https://github.com/apple/swift-nio-extras.git",

Package@swift-5.5.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ let packageDependencies: [Package.Dependency] = [
4040
),
4141
.package(
4242
url: "https://github.com/apple/swift-nio-transport-services.git",
43-
from: "1.11.1"
43+
from: "1.15.0"
4444
),
4545
.package(
4646
url: "https://github.com/apple/swift-nio-extras.git",

Sources/GRPC/GRPCIdleHandler.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import Logging
1717
import NIOCore
1818
import NIOHTTP2
19+
import NIOTLS
1920

2021
internal final class GRPCIdleHandler: ChannelInboundHandler {
2122
typealias InboundIn = HTTP2Frame
@@ -247,6 +248,13 @@ internal final class GRPCIdleHandler: ChannelInboundHandler {
247248
} else if event is ChannelShouldQuiesceEvent {
248249
self.perform(operations: self.stateMachine.initiateGracefulShutdown())
249250
// Swallow this event.
251+
} else if case let .handshakeCompleted(negotiatedProtocol) = event as? TLSUserEvent {
252+
let tlsVersion = try? context.channel.getTLSVersionSync()
253+
self.stateMachine.logger.debug("TLS handshake completed", metadata: [
254+
"alpn": "\(negotiatedProtocol ?? "nil")",
255+
"tls_version": "\(tlsVersion.map(String.init(describing:)) ?? "nil")",
256+
])
257+
context.fireUserInboundEventTriggered(event)
250258
} else {
251259
context.fireUserInboundEventTriggered(event)
252260
}

Sources/GRPC/GRPCServerPipelineConfigurator.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,8 +231,10 @@ final class GRPCServerPipelineConfigurator: ChannelInboundHandler, RemovableChan
231231
) {
232232
switch event {
233233
case let .handshakeCompleted(negotiatedProtocol):
234+
let tlsVersion = try? context.channel.getTLSVersionSync()
234235
self.configuration.logger.debug("TLS handshake completed", metadata: [
235236
"alpn": "\(negotiatedProtocol ?? "nil")",
237+
"tls_version": "\(tlsVersion.map(String.init(describing:)) ?? "nil")",
236238
])
237239

238240
switch negotiatedProtocol {

Sources/GRPC/TLSVersion.swift

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/*
2+
* Copyright 2022, 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+
17+
import NIOCore
18+
#if canImport(NIOSSL)
19+
import NIOSSL
20+
#endif
21+
#if canImport(Network)
22+
import Network
23+
import NIOTransportServices
24+
#endif
25+
26+
// The same as 'TLSVersion' which is defined in NIOSSL which we don't always have.
27+
enum GRPCTLSVersion: Hashable {
28+
case tlsv1
29+
case tlsv11
30+
case tlsv12
31+
case tlsv13
32+
}
33+
34+
#if canImport(NIOSSL)
35+
extension GRPCTLSVersion {
36+
init(_ tlsVersion: TLSVersion) {
37+
switch tlsVersion {
38+
case .tlsv1:
39+
self = .tlsv1
40+
case .tlsv11:
41+
self = .tlsv11
42+
case .tlsv12:
43+
self = .tlsv12
44+
case .tlsv13:
45+
self = .tlsv13
46+
}
47+
}
48+
}
49+
#endif
50+
51+
#if canImport(Network)
52+
@available(macOS 10.14, iOS 12.0, tvOS 12.0, watchOS 6.0, *)
53+
extension GRPCTLSVersion {
54+
init?(_ metadata: NWProtocolTLS.Metadata) {
55+
let protocolMetadata = metadata.securityProtocolMetadata
56+
57+
if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) {
58+
let nwTLSVersion = sec_protocol_metadata_get_negotiated_tls_protocol_version(protocolMetadata)
59+
switch nwTLSVersion {
60+
case .TLSv10:
61+
self = .tlsv1
62+
case .TLSv11:
63+
self = .tlsv11
64+
case .TLSv12:
65+
self = .tlsv12
66+
case .TLSv13:
67+
self = .tlsv13
68+
case .DTLSv10, .DTLSv12:
69+
return nil
70+
@unknown default:
71+
return nil
72+
}
73+
} else {
74+
let sslVersion = sec_protocol_metadata_get_negotiated_protocol_version(protocolMetadata)
75+
switch sslVersion {
76+
case .sslProtocolUnknown:
77+
return nil
78+
case .tlsProtocol1, .tlsProtocol1Only:
79+
self = .tlsv1
80+
case .tlsProtocol11:
81+
self = .tlsv11
82+
case .tlsProtocol12:
83+
self = .tlsv12
84+
case .tlsProtocol13:
85+
self = .tlsv13
86+
case .dtlsProtocol1,
87+
.dtlsProtocol12,
88+
.sslProtocol2,
89+
.sslProtocol3,
90+
.sslProtocol3Only,
91+
.sslProtocolAll,
92+
.tlsProtocolMaxSupported:
93+
return nil
94+
@unknown default:
95+
return nil
96+
}
97+
}
98+
}
99+
}
100+
#endif
101+
102+
extension Channel {
103+
/// This method tries to get the TLS version from either the Network.framework or NIOSSL
104+
/// - Precondition: Must be called on the `EventLoop` the `Channel` is running on.
105+
func getTLSVersionSync(
106+
file: StaticString = #fileID,
107+
line: UInt = #line
108+
) throws -> GRPCTLSVersion? {
109+
#if canImport(Network)
110+
if #available(macOS 10.14, iOS 12.0, tvOS 12.0, watchOS 6.0, *) {
111+
do {
112+
// cast can never fail because we explicitly ask for the NWProtocolTLS Metadata.
113+
// it may still be nil if Network.framework isn't used for TLS in which case we will
114+
// fall through and try to get the TLS version from NIOSSL
115+
if let metadata = try self.getMetadataSync(
116+
definition: NWProtocolTLS.definition,
117+
file: file,
118+
line: line
119+
) as! NWProtocolTLS.Metadata? {
120+
return GRPCTLSVersion(metadata)
121+
}
122+
} catch is NIOTSChannelIsNotANIOTSConnectionChannel {
123+
// Not a NIOTS channel, we might be using NIOSSL so try that next.
124+
}
125+
}
126+
#endif
127+
#if canImport(NIOSSL)
128+
return try self.pipeline.syncOperations.nioSSL_tlsVersion().map(GRPCTLSVersion.init)
129+
#else
130+
return nil
131+
#endif
132+
}
133+
}

0 commit comments

Comments
 (0)