Skip to content

Commit da330cd

Browse files
committed
Build set of TLS versions from S2Av2's GetTlsConfigResp.
1 parent 35084af commit da330cd

File tree

5 files changed

+100
-21
lines changed

5 files changed

+100
-21
lines changed

s2a/src/main/java/io/grpc/s2a/handshaker/ProtoUtil.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package io.grpc.s2a.handshaker;
1818

19+
import com.google.common.collect.ImmutableSet;
20+
1921
/** Converts proto messages to Netty strings. */
2022
final class ProtoUtil {
2123
/**
@@ -68,5 +70,27 @@ static String convertTlsProtocolVersion(TLSVersion tlsVersion) {
6870
}
6971
}
7072

73+
/**
74+
* Builds a set of strings representing all {@link TLSVersion}s between {@code minTlsVersion} and
75+
* {@code maxTlsVersion}.
76+
*/
77+
static ImmutableSet<String> buildTlsProtocolVersionSet(
78+
TLSVersion minTlsVersion, TLSVersion maxTlsVersion) {
79+
ImmutableSet.Builder<String> tlsVersions = ImmutableSet.<String>builder();
80+
for (TLSVersion tlsVersion : TLSVersion.values()) {
81+
int versionNumber;
82+
try {
83+
versionNumber = tlsVersion.getNumber();
84+
} catch (IllegalArgumentException e) {
85+
continue;
86+
}
87+
if (versionNumber < minTlsVersion.getNumber() || versionNumber > maxTlsVersion.getNumber()) {
88+
continue;
89+
}
90+
tlsVersions.add(convertTlsProtocolVersion(tlsVersion));
91+
}
92+
return tlsVersions.build();
93+
}
94+
7195
private ProtoUtil() {}
7296
}

s2a/src/main/java/io/grpc/s2a/handshaker/SslContextFactory.java

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import static com.google.common.base.Preconditions.checkNotNull;
2020
import static java.nio.charset.StandardCharsets.UTF_8;
2121

22-
import com.google.common.collect.ImmutableList;
22+
import com.google.common.collect.ImmutableSet;
2323
import io.grpc.netty.GrpcSslContexts;
2424
import io.grpc.s2a.handshaker.S2AIdentity;
2525
import io.netty.handler.ssl.OpenSslContextOption;
@@ -138,14 +138,13 @@ private static void configureSslContextWithClientTlsConfiguration(
138138
NoSuchAlgorithmException,
139139
UnrecoverableKeyException {
140140
sslContextBuilder.keyManager(createKeylessManager(clientTlsConfiguration));
141-
sslContextBuilder.protocols(
142-
ProtoUtil.convertTlsProtocolVersion(clientTlsConfiguration.getMinTlsVersion()),
143-
ProtoUtil.convertTlsProtocolVersion(clientTlsConfiguration.getMaxTlsVersion()));
144-
ImmutableList.Builder<String> ciphersuites = ImmutableList.<String>builder();
145-
for (int i = 0; i < clientTlsConfiguration.getCiphersuitesCount(); ++i) {
146-
ciphersuites.add(ProtoUtil.convertCiphersuite(clientTlsConfiguration.getCiphersuites(i)));
141+
ImmutableSet<String> tlsVersions =
142+
ProtoUtil.buildTlsProtocolVersionSet(
143+
clientTlsConfiguration.getMinTlsVersion(), clientTlsConfiguration.getMaxTlsVersion());
144+
if (tlsVersions.isEmpty()) {
145+
throw new S2AConnectionException("Set of TLS versions received from S2A server is empty.");
147146
}
148-
sslContextBuilder.ciphers(ciphersuites.build());
147+
sslContextBuilder.protocols(tlsVersions);
149148
}
150149

151150
private static KeyManager createKeylessManager(

s2a/src/test/java/io/grpc/s2a/handshaker/FakeWriter.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package io.grpc.s2a.handshaker;
1818

19+
import static io.grpc.s2a.handshaker.TLSVersion.TLS_VERSION_1_2;
1920
import static io.grpc.s2a.handshaker.TLSVersion.TLS_VERSION_1_3;
2021

2122
import com.google.common.collect.ImmutableMap;
@@ -39,7 +40,8 @@ enum Behavior {
3940
EMPTY_RESPONSE,
4041
ERROR_STATUS,
4142
ERROR_RESPONSE,
42-
COMPLETE_STATUS
43+
COMPLETE_STATUS,
44+
BAD_TLS_VERSION_RESPONSE,
4345
}
4446

4547
enum VerificationResult {
@@ -213,6 +215,20 @@ public void onNext(SessionReq sessionReq) {
213215
case COMPLETE_STATUS:
214216
reader.onCompleted();
215217
break;
218+
case BAD_TLS_VERSION_RESPONSE:
219+
reader.onNext(
220+
SessionResp.newBuilder()
221+
.setGetTlsConfigurationResp(
222+
GetTlsConfigurationResp.newBuilder()
223+
.setClientTlsConfiguration(
224+
GetTlsConfigurationResp.ClientTlsConfiguration.newBuilder()
225+
.addCertificateChain(LEAF_CERT)
226+
.addCertificateChain(INTERMEDIATE_CERT_2)
227+
.addCertificateChain(INTERMEDIATE_CERT_1)
228+
.setMinTlsVersion(TLS_VERSION_1_3)
229+
.setMaxTlsVersion(TLS_VERSION_1_2)))
230+
.build());
231+
break;
216232
default:
217233
reader.onNext(handleResponse(sessionReq));
218234
}

s2a/src/test/java/io/grpc/s2a/handshaker/ProtoUtilTest.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import static org.junit.Assert.assertThrows;
2020

21+
import com.google.common.collect.ImmutableSet;
2122
import com.google.common.truth.Expect;
2223
import org.junit.Rule;
2324
import org.junit.Test;
@@ -92,4 +93,39 @@ public void convertTlsProtocolVersion_withUnknownTlsVersion_fails() {
9293
() -> ProtoUtil.convertTlsProtocolVersion(TLSVersion.TLS_VERSION_UNSPECIFIED));
9394
expect.that(expected).hasMessageThat().isEqualTo("TLS version 0 is not supported.");
9495
}
96+
97+
@Test
98+
public void buildTlsProtocolVersionSet_success() {
99+
expect
100+
.that(
101+
ProtoUtil.buildTlsProtocolVersionSet(
102+
TLSVersion.TLS_VERSION_1_0, TLSVersion.TLS_VERSION_1_3))
103+
.isEqualTo(ImmutableSet.of("TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"));
104+
expect
105+
.that(
106+
ProtoUtil.buildTlsProtocolVersionSet(
107+
TLSVersion.TLS_VERSION_1_2, TLSVersion.TLS_VERSION_1_2))
108+
.isEqualTo(ImmutableSet.of("TLSv1.2"));
109+
expect
110+
.that(
111+
ProtoUtil.buildTlsProtocolVersionSet(
112+
TLSVersion.TLS_VERSION_1_3, TLSVersion.TLS_VERSION_1_3))
113+
.isEqualTo(ImmutableSet.of("TLSv1.3"));
114+
expect
115+
.that(
116+
ProtoUtil.buildTlsProtocolVersionSet(
117+
TLSVersion.TLS_VERSION_1_3, TLSVersion.TLS_VERSION_1_2))
118+
.isEmpty();
119+
}
120+
121+
@Test
122+
public void buildTlsProtocolVersionSet_failure() {
123+
AssertionError expected =
124+
assertThrows(
125+
AssertionError.class,
126+
() ->
127+
ProtoUtil.buildTlsProtocolVersionSet(
128+
TLSVersion.TLS_VERSION_UNSPECIFIED, TLSVersion.TLS_VERSION_1_3));
129+
expect.that(expected).hasMessageThat().isEqualTo("TLS version 0 is not supported.");
130+
}
95131
}

s2a/src/test/java/io/grpc/s2a/handshaker/SslContextFactoryTest.java

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,6 @@ public void createForClient_returnsValidSslContext() throws Exception {
5858
expect.that(sslContext.sessionTimeout()).isEqualTo(300);
5959
expect.that(sslContext.isClient()).isTrue();
6060
expect.that(sslContext.applicationProtocolNegotiator().protocols()).containsExactly("h2");
61-
expect
62-
.that(sslContext.cipherSuites())
63-
.containsExactly(
64-
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
65-
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
66-
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256");
6761
SSLSessionContext sslSessionContext = sslContext.sessionContext();
6862
if (sslSessionContext instanceof OpenSslSessionContext) {
6963
OpenSslSessionContext openSslSessionContext = (OpenSslSessionContext) sslSessionContext;
@@ -82,12 +76,6 @@ public void createForClient_withLocalIdentity_returnsValidSslContext() throws Ex
8276
expect.that(sslContext.sessionTimeout()).isEqualTo(300);
8377
expect.that(sslContext.isClient()).isTrue();
8478
expect.that(sslContext.applicationProtocolNegotiator().protocols()).containsExactly("h2");
85-
expect
86-
.that(sslContext.cipherSuites())
87-
.containsExactly(
88-
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
89-
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
90-
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256");
9179
SSLSessionContext sslSessionContext = sslContext.sessionContext();
9280
if (sslSessionContext instanceof OpenSslSessionContext) {
9381
OpenSslSessionContext openSslSessionContext = (OpenSslSessionContext) sslSessionContext;
@@ -141,6 +129,22 @@ public void createForClient_getsErrorFromServer_throwsError() throws Exception {
141129
.contains("Failed to get client TLS configuration from S2A.");
142130
}
143131

132+
@Test
133+
public void createForClient_getsBadTlsVersionsFromServer_throwsError() throws Exception {
134+
writer.setBehavior(FakeWriter.Behavior.BAD_TLS_VERSION_RESPONSE);
135+
136+
S2AConnectionException expected =
137+
assertThrows(
138+
S2AConnectionException.class,
139+
() ->
140+
SslContextFactory.createForClient(
141+
stub, FAKE_TARGET_NAME, /* localIdentity= */ Optional.empty()));
142+
143+
assertThat(expected)
144+
.hasMessageThat()
145+
.contains("Set of TLS versions received from S2A server is empty.");
146+
}
147+
144148
@Test
145149
public void createForClient_nullStub_throwsError() throws Exception {
146150
writer.sendUnexpectedResponse();

0 commit comments

Comments
 (0)