|
27 | 27 | import java.security.interfaces.RSAPrivateKey; |
28 | 28 | import java.util.*; |
29 | 29 | import java.util.concurrent.CountDownLatch; |
| 30 | +import java.util.concurrent.atomic.AtomicBoolean; |
30 | 31 | import java.util.concurrent.atomic.AtomicInteger; |
31 | 32 | import java.util.concurrent.atomic.AtomicReference; |
| 33 | +import java.util.function.BiConsumer; |
32 | 34 | import java.util.function.Function; |
33 | 35 | import java.util.function.Supplier; |
34 | 36 |
|
35 | 37 | import javax.net.ssl.*; |
36 | 38 |
|
37 | 39 | import io.vertx.core.*; |
38 | 40 | import io.vertx.core.impl.VertxThread; |
39 | | -import io.vertx.core.net.SSLOptions; |
40 | 41 | import io.vertx.core.net.impl.KeyStoreHelper; |
41 | 42 | import org.junit.Assume; |
42 | 43 | import org.junit.Rule; |
@@ -2105,4 +2106,193 @@ public PrivateKey getPrivateKey(String alias) { |
2105 | 2106 | // It is fine using worker threads in this case |
2106 | 2107 | } |
2107 | 2108 | } |
| 2109 | + |
| 2110 | + /** |
| 2111 | + * Test that for HttpServer, the peer host and port info is available in the SSLEngine |
| 2112 | + * when the X509ExtendedKeyManager.chooseEngineServerAlias is called. |
| 2113 | + * |
| 2114 | + * @throws Exception if an error occurs |
| 2115 | + */ |
| 2116 | + @Test |
| 2117 | + public void testTLSServerSSLEnginePeerHost() throws Exception { |
| 2118 | + AtomicBoolean called = new AtomicBoolean(false); |
| 2119 | + testTLS(Cert.NONE, Trust.SERVER_JKS, testPeerHostServerCert(Cert.SERVER_JKS, called), Trust.NONE).pass(); |
| 2120 | + assertTrue("X509ExtendedKeyManager.chooseEngineServerAlias is not called", called.get()); |
| 2121 | + } |
| 2122 | + |
| 2123 | + /** |
| 2124 | + * Test that for HttpServer with SNI, the peer host and port info is available in the SSLEngine |
| 2125 | + * when the X509ExtendedKeyManager.chooseEngineServerAlias is called. |
| 2126 | + * |
| 2127 | + * @throws Exception if an error occurs |
| 2128 | + */ |
| 2129 | + @Test |
| 2130 | + public void testSNIServerSSLEnginePeerHost() throws Exception { |
| 2131 | + AtomicBoolean called = new AtomicBoolean(false); |
| 2132 | + TLSTest test = testTLS(Cert.NONE, Trust.SNI_JKS_HOST2, testPeerHostServerCert(Cert.SNI_JKS, called), Trust.NONE) |
| 2133 | + .serverSni() |
| 2134 | + .requestOptions(new RequestOptions().setSsl(true).setPort(DEFAULT_HTTPS_PORT).setHost("host2.com")) |
| 2135 | + .pass(); |
| 2136 | + assertEquals("host2.com", TestUtils.cnOf(test.clientPeerCert())); |
| 2137 | + assertEquals("host2.com", test.indicatedServerName); |
| 2138 | + assertTrue("X509ExtendedKeyManager.chooseEngineServerAlias is not called", called.get()); |
| 2139 | + } |
| 2140 | + |
| 2141 | + /** |
| 2142 | + * Create a {@link Cert} that will verify the peer host is not null and port is not -1 in the {@link SSLEngine} |
| 2143 | + * when the {@link X509ExtendedKeyManager#chooseEngineServerAlias(String, Principal[], SSLEngine)} |
| 2144 | + * is called. |
| 2145 | + * |
| 2146 | + * @param delegate The delegated Cert |
| 2147 | + * @param chooseEngineServerAliasCalled Will be set to true when the |
| 2148 | + * X509ExtendedKeyManager.chooseEngineServerAlias is called |
| 2149 | + * @return The {@link Cert} |
| 2150 | + */ |
| 2151 | + public static Cert<KeyCertOptions> testPeerHostServerCert(Cert<? extends KeyCertOptions> delegate, AtomicBoolean chooseEngineServerAliasCalled) { |
| 2152 | + return testPeerHostServerCert(delegate, (peerHost, peerPort) -> { |
| 2153 | + chooseEngineServerAliasCalled.set(true); |
| 2154 | + if (peerHost == null || peerPort == -1) { |
| 2155 | + throw new RuntimeException("Missing peer host/port"); |
| 2156 | + } |
| 2157 | + }); |
| 2158 | + } |
| 2159 | + |
| 2160 | + /** |
| 2161 | + * Create a {@link Cert} that will verify the peer host and port in the {@link SSLEngine} |
| 2162 | + * when the {@link X509ExtendedKeyManager#chooseEngineServerAlias(String, Principal[], SSLEngine)} |
| 2163 | + * is called. |
| 2164 | + * |
| 2165 | + * @param delegate The delegated Cert |
| 2166 | + * @param peerHostVerifier The consumer to verify the peer host and port when the |
| 2167 | + * X509ExtendedKeyManager.chooseEngineServerAlias is called |
| 2168 | + * @return The {@link Cert} |
| 2169 | + */ |
| 2170 | + public static Cert<KeyCertOptions> testPeerHostServerCert(Cert<? extends KeyCertOptions> delegate, BiConsumer<String, Integer> peerHostVerifier) { |
| 2171 | + return () -> new VerifyServerPeerHostKeyCertOptions(delegate.get(), peerHostVerifier); |
| 2172 | + } |
| 2173 | + |
| 2174 | + private static class VerifyServerPeerHostKeyCertOptions implements KeyCertOptions { |
| 2175 | + private final KeyCertOptions delegate; |
| 2176 | + private final BiConsumer<String, Integer> peerHostVerifier; |
| 2177 | + |
| 2178 | + VerifyServerPeerHostKeyCertOptions(KeyCertOptions delegate, BiConsumer<String, Integer> peerHostVerifier) { |
| 2179 | + this.delegate = delegate; |
| 2180 | + this.peerHostVerifier = peerHostVerifier; |
| 2181 | + } |
| 2182 | + |
| 2183 | + @Override |
| 2184 | + public KeyCertOptions copy() { |
| 2185 | + return new VerifyServerPeerHostKeyCertOptions(delegate.copy(), peerHostVerifier); |
| 2186 | + } |
| 2187 | + |
| 2188 | + @Override |
| 2189 | + public KeyManagerFactory getKeyManagerFactory(Vertx vertx) throws Exception { |
| 2190 | + return new VerifyServerPeerHostKeyManagerFactory(delegate.getKeyManagerFactory(vertx), peerHostVerifier); |
| 2191 | + } |
| 2192 | + |
| 2193 | + @Override |
| 2194 | + public Function<String, KeyManagerFactory> keyManagerFactoryMapper(Vertx vertx) throws Exception { |
| 2195 | + Function<String, KeyManagerFactory> mapper = delegate.keyManagerFactoryMapper(vertx); |
| 2196 | + return serverName -> new VerifyServerPeerHostKeyManagerFactory(mapper.apply(serverName), peerHostVerifier); |
| 2197 | + } |
| 2198 | + } |
| 2199 | + |
| 2200 | + private static class VerifyServerPeerHostKeyManagerFactory extends KeyManagerFactory { |
| 2201 | + VerifyServerPeerHostKeyManagerFactory(KeyManagerFactory delegate, BiConsumer<String, Integer> peerHostVerifier) { |
| 2202 | + super(new KeyManagerFactorySpiWrapper(delegate, peerHostVerifier), delegate.getProvider(), delegate.getAlgorithm()); |
| 2203 | + } |
| 2204 | + |
| 2205 | + private static class KeyManagerFactorySpiWrapper extends KeyManagerFactorySpi { |
| 2206 | + private final KeyManagerFactory delegate; |
| 2207 | + private final BiConsumer<String, Integer> peerHostVerifier; |
| 2208 | + |
| 2209 | + KeyManagerFactorySpiWrapper(KeyManagerFactory delegate, BiConsumer<String, Integer> peerHostVerifier) { |
| 2210 | + super(); |
| 2211 | + this.delegate = delegate; |
| 2212 | + this.peerHostVerifier = peerHostVerifier; |
| 2213 | + } |
| 2214 | + |
| 2215 | + @Override |
| 2216 | + protected void engineInit(KeyStore keyStore, char[] chars) throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException { |
| 2217 | + delegate.init(keyStore, chars); |
| 2218 | + } |
| 2219 | + |
| 2220 | + @Override |
| 2221 | + protected void engineInit(ManagerFactoryParameters managerFactoryParameters) throws InvalidAlgorithmParameterException { |
| 2222 | + delegate.init(managerFactoryParameters); |
| 2223 | + } |
| 2224 | + |
| 2225 | + @Override |
| 2226 | + protected KeyManager[] engineGetKeyManagers() { |
| 2227 | + KeyManager[] keyManagers = delegate.getKeyManagers().clone(); |
| 2228 | + for (int i = 0; i < keyManagers.length; ++i) { |
| 2229 | + KeyManager km = keyManagers[i]; |
| 2230 | + if (km instanceof X509KeyManager) { |
| 2231 | + keyManagers[i] = new VerifyServerPeerHostKeyManager((X509KeyManager) km, peerHostVerifier); |
| 2232 | + } |
| 2233 | + } |
| 2234 | + |
| 2235 | + return keyManagers; |
| 2236 | + } |
| 2237 | + } |
| 2238 | + } |
| 2239 | + |
| 2240 | + private static class VerifyServerPeerHostKeyManager extends X509ExtendedKeyManager { |
| 2241 | + private final X509KeyManager delegate; |
| 2242 | + private final BiConsumer<String, Integer> peerHostVerifier; |
| 2243 | + |
| 2244 | + VerifyServerPeerHostKeyManager(X509KeyManager delegate, BiConsumer<String, Integer> peerHostVerifier) { |
| 2245 | + this.delegate = delegate; |
| 2246 | + this.peerHostVerifier = peerHostVerifier; |
| 2247 | + } |
| 2248 | + |
| 2249 | + @Override |
| 2250 | + public String chooseEngineClientAlias(String[] keyType, Principal[] issuers, SSLEngine engine) { |
| 2251 | + if (delegate instanceof X509ExtendedKeyManager) { |
| 2252 | + return ((X509ExtendedKeyManager) delegate).chooseEngineClientAlias(keyType, issuers, engine); |
| 2253 | + } else { |
| 2254 | + return delegate.chooseClientAlias(keyType, issuers, null); |
| 2255 | + } |
| 2256 | + } |
| 2257 | + |
| 2258 | + @Override |
| 2259 | + public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine) { |
| 2260 | + peerHostVerifier.accept(engine.getPeerHost(), engine.getPeerPort()); |
| 2261 | + if (delegate instanceof X509ExtendedKeyManager) { |
| 2262 | + return ((X509ExtendedKeyManager) delegate).chooseEngineServerAlias(keyType, issuers, engine); |
| 2263 | + } else { |
| 2264 | + return delegate.chooseServerAlias(keyType, issuers, null); |
| 2265 | + } |
| 2266 | + } |
| 2267 | + |
| 2268 | + @Override |
| 2269 | + public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) { |
| 2270 | + return delegate.chooseClientAlias(keyType, issuers, socket); |
| 2271 | + } |
| 2272 | + |
| 2273 | + @Override |
| 2274 | + public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) { |
| 2275 | + return delegate.chooseServerAlias(keyType, issuers, socket); |
| 2276 | + } |
| 2277 | + |
| 2278 | + @Override |
| 2279 | + public String[] getClientAliases(String s, Principal[] principals) { |
| 2280 | + return delegate.getClientAliases(s, principals); |
| 2281 | + } |
| 2282 | + |
| 2283 | + @Override |
| 2284 | + public String[] getServerAliases(String s, Principal[] principals) { |
| 2285 | + return delegate.getServerAliases(s, principals); |
| 2286 | + } |
| 2287 | + |
| 2288 | + @Override |
| 2289 | + public X509Certificate[] getCertificateChain(String s) { |
| 2290 | + return delegate.getCertificateChain(s); |
| 2291 | + } |
| 2292 | + |
| 2293 | + @Override |
| 2294 | + public PrivateKey getPrivateKey(String s) { |
| 2295 | + return delegate.getPrivateKey(s); |
| 2296 | + } |
| 2297 | + } |
2108 | 2298 | } |
0 commit comments