4
4
import com .google .common .base .Suppliers ;
5
5
import com .google .common .cache .Cache ;
6
6
import com .google .common .cache .CacheBuilder ;
7
+ import io .netty .buffer .ByteBufAllocator ;
8
+ import io .netty .handler .ssl .SslContext ;
9
+ import io .netty .handler .ssl .SslContextBuilder ;
7
10
import net .lightbody .bmp .mitm .CertificateAndKey ;
8
11
import net .lightbody .bmp .mitm .CertificateAndKeySource ;
9
12
import net .lightbody .bmp .mitm .CertificateInfo ;
25
28
import org .slf4j .Logger ;
26
29
import org .slf4j .LoggerFactory ;
27
30
28
- import javax .net .ssl .KeyManager ;
29
- import javax .net .ssl .SSLContext ;
30
31
import javax .net .ssl .SSLEngine ;
32
+ import javax .net .ssl .SSLException ;
31
33
import javax .net .ssl .SSLParameters ;
32
34
import javax .net .ssl .SSLSession ;
33
35
import java .security .KeyPair ;
34
- import java .security .KeyStore ;
35
36
import java .security .PrivateKey ;
36
37
import java .security .cert .X509Certificate ;
37
38
import java .util .Collections ;
47
48
public class ImpersonatingMitmManager implements MitmManager {
48
49
private static final Logger log = LoggerFactory .getLogger (ImpersonatingMitmManager .class );
49
50
50
- /**
51
- * The KeyStore password for impersonated server KeyStores. This value can be anything, since it is only used to store and immediately extract
52
- * the Java KeyManagers after creating an impersonated server certificate.
53
- */
54
- private static final String IMPERSONATED_SERVER_KEYSTORE_PASSWORD = "impersonationPassword" ;
55
-
56
- /**
57
- * The alias for the impersonated server certificate. This value can be anything, since it is only used to store the cert in the KeyStore.
58
- */
59
- private static final String IMPERSONATED_CERTIFICATE_ALIAS = "impersonatedCertificate" ;
60
-
61
51
/**
62
52
* The SSLContext that will be used for communications with all upstream servers. This can be reused, so store it as a lazily-loaded singleton.
63
53
*/
64
- private final Supplier <SSLContext > upstreamServerSslContext = Suppliers .memoize (new Supplier <SSLContext >() {
54
+ private final Supplier <SslContext > upstreamServerSslContext = Suppliers .memoize (new Supplier <SslContext >() {
65
55
@ Override
66
- public SSLContext get () {
56
+ public SslContext get () {
67
57
return SslUtil .getUpstreamServerSslContext (trustAllUpstreamServers );
68
58
}
69
59
});
70
60
71
61
/**
72
- * Cache for impersonating SSLContexts. SSLContexts can be safely reused, so caching the impersonating contexts avoids
62
+ * Cache for impersonating netty SslContexts. SslContexts can be safely reused, so caching the impersonating contexts avoids
73
63
* repeatedly re-impersonating upstream servers.
74
64
*/
75
- private final Cache <String , SSLContext > sslContextCache ;
65
+ private final Cache <String , SslContext > sslContextCache ;
76
66
77
67
/**
78
68
* Generator used to create public and private keys for the server certificates.
@@ -175,7 +165,7 @@ public ImpersonatingMitmManager(CertificateAndKeySource rootCertificateSource,
175
165
@ Override
176
166
public SSLEngine serverSslEngine (String peerHost , int peerPort ) {
177
167
try {
178
- SSLEngine sslEngine = upstreamServerSslContext .get ().createSSLEngine ( peerHost , peerPort );
168
+ SSLEngine sslEngine = upstreamServerSslContext .get ().newEngine ( ByteBufAllocator . DEFAULT , peerHost , peerPort );
179
169
180
170
// support SNI by setting the endpoint identification algorithm. this requires Java 7+.
181
171
SSLParameters sslParams = new SSLParameters ();
@@ -191,9 +181,9 @@ public SSLEngine serverSslEngine(String peerHost, int peerPort) {
191
181
@ Override
192
182
public SSLEngine clientSslEngineFor (SSLSession sslSession ) {
193
183
try {
194
- SSLContext ctx = getHostnameImpersonatingSslContext (sslSession );
184
+ SslContext ctx = getHostnameImpersonatingSslContext (sslSession );
195
185
196
- return ctx .createSSLEngine ( );
186
+ return ctx .newEngine ( ByteBufAllocator . DEFAULT );
197
187
} catch (RuntimeException e ) {
198
188
throw new MitmException ("Error creating SSLEngine for connection to client to impersonate upstream host: " + sslSession .getPeerHost (), e );
199
189
}
@@ -207,15 +197,15 @@ public SSLEngine clientSslEngineFor(SSLSession sslSession) {
207
197
* @param sslSession the upstream server SSLSession
208
198
* @return SSLContext which will present an impersonated certificate
209
199
*/
210
- private SSLContext getHostnameImpersonatingSslContext (final SSLSession sslSession ) {
200
+ private SslContext getHostnameImpersonatingSslContext (final SSLSession sslSession ) {
211
201
final String hostnameToImpersonate = sslSession .getPeerHost ();
212
202
213
203
//TODO: generate wildcard certificates, rather than one certificate per host, to reduce the number of certs generated
214
204
215
205
try {
216
- return sslContextCache .get (hostnameToImpersonate , new Callable <SSLContext >() {
206
+ return sslContextCache .get (hostnameToImpersonate , new Callable <SslContext >() {
217
207
@ Override
218
- public SSLContext call () throws Exception {
208
+ public SslContext call () throws Exception {
219
209
return createImpersonatingSslContext (sslSession , hostnameToImpersonate );
220
210
}
221
211
});
@@ -231,7 +221,7 @@ public SSLContext call() throws Exception {
231
221
* @param hostnameToImpersonate hostname (supplied by the client's HTTP CONNECT) that will be impersonated
232
222
* @return an SSLContext presenting a certificate matching the hostnameToImpersonate
233
223
*/
234
- private SSLContext createImpersonatingSslContext (SSLSession sslSession , String hostnameToImpersonate ) {
224
+ private SslContext createImpersonatingSslContext (SSLSession sslSession , String hostnameToImpersonate ) {
235
225
long impersonationStart = System .currentTimeMillis ();
236
226
237
227
// generate a Java KeyStore which contains the impersonated server certificate and the certificate's private key.
@@ -272,25 +262,21 @@ private SSLContext createImpersonatingSslContext(SSLSession sslSession, String h
272
262
serverKeyPair ,
273
263
serverCertificateMessageDigest );
274
264
275
- // bundle the newly-forged server certificate into a java KeyStore, for use by the SSLContext
276
- KeyStore impersonatedServerKeyStore = securityProviderTool . createServerKeyStore (
277
- MitmConstants . DEFAULT_KEYSTORE_TYPE ,
278
- impersonatedCertificateAndKey ,
279
- caRootCertificate ,
280
- IMPERSONATED_CERTIFICATE_ALIAS , IMPERSONATED_SERVER_KEYSTORE_PASSWORD
281
- );
265
+ X509Certificate [] certChain = { impersonatedCertificateAndKey . getCertificate (), caRootCertificate };
266
+ SslContext sslContext ;
267
+ try {
268
+ sslContext = SslContextBuilder . forServer ( impersonatedCertificateAndKey . getPrivateKey (), certChain ). build ();
269
+ } catch ( SSLException e ) {
270
+ throw new MitmException ( "Error creating SslContext for connection to client using impersonated certificate and private key" , e );
271
+ }
282
272
283
273
long impersonationFinish = System .currentTimeMillis ();
284
274
285
275
statistics .certificateCreated (impersonationStart , impersonationFinish );
286
276
287
277
log .debug ("Impersonated certificate for {} in {}ms" , hostnameToImpersonate , impersonationFinish - impersonationStart );
288
278
289
- // retrieve the Java KeyManagers that the SSLContext will use to retrieve the impersonated certificate and private key
290
- KeyManager [] keyManagers = securityProviderTool .getKeyManagers (impersonatedServerKeyStore , IMPERSONATED_SERVER_KEYSTORE_PASSWORD );
291
-
292
- // create an SSLContext for this communication with the client that will present the impersonated upstream server credentials
293
- return SslUtil .getClientSslContext (keyManagers );
279
+ return sslContext ;
294
280
}
295
281
296
282
/**
0 commit comments