Skip to content

Commit de93e16

Browse files
committed
Support SNI during TLS handshake
1 parent 13a82b0 commit de93e16

File tree

3 files changed

+61
-30
lines changed

3 files changed

+61
-30
lines changed

proxybase/src/main/java/com/dajudge/proxybase/DownstreamSslHandlerFactory.java

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,54 +20,76 @@
2020
import com.dajudge.proxybase.certs.Filesystem;
2121
import com.dajudge.proxybase.certs.KeyStoreManager;
2222
import com.dajudge.proxybase.config.DownstreamSslConfig;
23+
import com.dajudge.proxybase.config.Endpoint;
24+
import io.netty.channel.Channel;
2325
import io.netty.channel.ChannelHandler;
24-
import io.netty.handler.ssl.SslHandler;
26+
import io.netty.channel.socket.SocketChannel;
27+
import io.netty.handler.ssl.SslContext;
28+
import io.netty.handler.ssl.SslContextBuilder;
2529

26-
import javax.net.ssl.SSLContext;
27-
import javax.net.ssl.SSLEngine;
28-
import javax.net.ssl.X509TrustManager;
30+
import javax.net.ssl.*;
2931
import java.security.KeyManagementException;
3032
import java.security.NoSuchAlgorithmException;
3133
import java.util.Optional;
34+
import java.util.function.Function;
3235
import java.util.function.Supplier;
3336

3437
import static com.dajudge.proxybase.HostnameCheck.NULL_VERIFIER;
35-
import static com.dajudge.proxybase.SslUtils.createKeyManagers;
36-
import static com.dajudge.proxybase.SslUtils.createTrustManagers;
38+
import static com.dajudge.proxybase.SslUtils.*;
3739
import static com.dajudge.proxybase.certs.ReloadingKeyStoreManager.createReloader;
3840

3941
public class DownstreamSslHandlerFactory {
40-
public static ChannelHandler createDownstreamSslHandler(
42+
public static Function<Channel, ChannelHandler> createDownstreamSslHandler(
4143
final DownstreamSslConfig config,
42-
final String downstreamHostname,
44+
final Endpoint downstreamEndpoint,
4345
final Supplier<Long> clock,
4446
final Filesystem filesystem
45-
) {
47+
) {
4648
final HostnameCheck hostnameCheck = config.isHostnameVerificationEnabled()
47-
? new HttpClientHostnameCheck(downstreamHostname)
49+
? new HttpClientHostnameCheck(downstreamEndpoint.getHost())
4850
: NULL_VERIFIER;
4951
return createDownstreamSslHandler(
5052
hostnameCheck,
5153
createReloader(config.getTrustStore(), clock, filesystem),
52-
config.getKeyStore().map(it -> createReloader(it, clock, filesystem))
54+
config.getKeyStore().map(it -> createReloader(it, clock, filesystem)),
55+
Optional.of(downstreamEndpoint)
5356
);
5457
}
5558

56-
public static ChannelHandler createDownstreamSslHandler(
59+
public static Function<Channel, ChannelHandler> createDownstreamSslHandler(
5760
final HostnameCheck hostnameCheck,
5861
final KeyStoreManager trustStoreManager,
59-
final Optional<KeyStoreManager> keyStoreManager
62+
final Optional<KeyStoreManager> keyStoreManager,
63+
final Optional<Endpoint> peerEndpoint
6064
) {
6165
try {
6266
final SSLContext clientContext = SSLContext.getInstance("TLS");
67+
final HostCheckingTrustManager trustManager = new HostCheckingTrustManager(
68+
createTrustManagers(trustStoreManager),
69+
hostnameCheck
70+
);
6371
final X509TrustManager[] trustManagers = {
64-
new HostCheckingTrustManager(createTrustManagers(trustStoreManager), hostnameCheck)
72+
trustManager
6573
};
66-
clientContext.init(createKeyManagers(keyStoreManager), trustManagers, null);
67-
final SSLEngine engine = clientContext.createSSLEngine();
74+
final X509KeyManager[] keyManagers = createKeyManagers(keyStoreManager);
75+
clientContext.init(keyManagers, trustManagers, null);
76+
final SSLEngine engine = peerEndpoint
77+
.map(it -> clientContext.createSSLEngine(it.getHost(), it.getPort()))
78+
.orElse(clientContext.createSSLEngine());
6879
engine.setUseClientMode(true);
69-
return new SslHandler(engine);
70-
} catch (final NoSuchAlgorithmException | KeyManagementException e) {
80+
final SslContext context = SslContextBuilder.forClient()
81+
.keyManager(createKeyManagerFactory(keyStoreManager))
82+
.trustManager(trustManager)
83+
.build();
84+
if (peerEndpoint.isPresent()) {
85+
return ch -> {
86+
final Endpoint endpoint = peerEndpoint.get();
87+
return context.newHandler(ch.alloc(), endpoint.getHost(), endpoint.getPort());
88+
};
89+
} else {
90+
return ch -> context.newHandler(ch.alloc());
91+
}
92+
} catch (final NoSuchAlgorithmException | KeyManagementException | SSLException e) {
7193
throw new RuntimeException("Failed to initialize downstream SSL handler", e);
7294
}
7395
}

proxybase/src/main/java/com/dajudge/proxybase/SslUtils.java

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,18 +58,26 @@ static X509KeyManager[] createKeyManagers(final KeyStoreManager keyStoreManager)
5858
}
5959

6060
static X509KeyManager[] createKeyManagers(final Optional<KeyStoreManager> keyStoreManager) {
61+
if (!keyStoreManager.isPresent()) {
62+
return new X509KeyManager[]{};
63+
}
64+
return Arrays.stream(createKeyManagerFactory(keyStoreManager).getKeyManagers())
65+
.filter(it -> it instanceof X509KeyManager)
66+
.map(it -> (X509KeyManager) it)
67+
.toArray(X509KeyManager[]::new);
68+
}
69+
70+
public static KeyManagerFactory createKeyManagerFactory(final Optional<KeyStoreManager> keyStoreManager) {
6171
try {
62-
if (!keyStoreManager.isPresent()) {
63-
return new X509KeyManager[]{};
64-
}
6572
final KeyManagerFactory factory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
66-
final KeyStoreManager keyStoreWrapper = keyStoreManager.get();
67-
final KeyStoreWrapper keyStore = keyStoreWrapper.getKeyStore();
68-
factory.init(keyStore.getKeyStore(), keyStore.getKeyPassword());
69-
return Arrays.stream(factory.getKeyManagers())
70-
.filter(it -> it instanceof X509KeyManager)
71-
.map(it -> (X509KeyManager) it)
72-
.toArray(X509KeyManager[]::new);
73+
if (keyStoreManager.isPresent()) {
74+
final KeyStoreManager keyStoreWrapper = keyStoreManager.get();
75+
final KeyStoreWrapper keyStore = keyStoreWrapper.getKeyStore();
76+
factory.init(keyStore.getKeyStore(), keyStore.getKeyPassword());
77+
} else {
78+
factory.init(null, null);
79+
}
80+
return factory;
7381
} catch (final UnrecoverableKeyException | KeyStoreException | NoSuchAlgorithmException e) {
7482
throw new RuntimeException("Failed to setup key manager", e);
7583
}

proxybase/src/test/java/com/dajudge/proxybase/util/TestSslConfiguration.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,9 @@ public void configureDownstreamPipeline(final ChannelPipeline pipeline) {
204204
createDownstreamSslHandler(
205205
HostnameCheck.NULL_VERIFIER,
206206
clientTrustStoreManager,
207-
Optional.ofNullable(getClientKeyStoreManager())
208-
)
207+
Optional.ofNullable(getClientKeyStoreManager()),
208+
Optional.empty()
209+
).apply(pipeline.channel())
209210
);
210211
}
211212

0 commit comments

Comments
 (0)