protected SSLEngine createSSLEngine(String sniHostName, List<Cipher> clientRequestedCiphers) { SSLHostConfig sslHostConfig = getSSLHostConfig(sniHostName); SSLHostConfigCertificate certificate = selectCertificate(sslHostConfig, clientRequestedCiphers); SSLContextWrapper sslContextWrapper = certificate.getSslContextWrapper(); if (sslContextWrapper == null) { throw new IllegalStateException(sm.getString("endpoint.jsse.noSslContext", sniHostName)); } SSLEngine engine = sslContextWrapper.getSSLContext().createSSLEngine(); switch (sslHostConfig.getCertificateVerification()) { case NONE: engine.setNeedClientAuth(false); engine.setWantClientAuth(false); break; case OPTIONAL: case OPTIONAL_NO_CA: engine.setWantClientAuth(true); break; case REQUIRED: engine.setNeedClientAuth(true); break; } engine.setUseClientMode(false); engine.setEnabledCipherSuites(sslContextWrapper.getEnabledCiphers()); engine.setEnabledProtocols(sslContextWrapper.getEnabledProtocols()); SSLParameters sslParameters = engine.getSSLParameters(); sslParameters.setUseCipherSuitesOrder(sslHostConfig.getHonorCipherOrder()); // In case the getter returns a defensive copy engine.setSSLParameters(sslParameters); return engine; }
/** * Tests opening an SSL/TLS connection to redis using the loopback address of 127.0.0.1. This test * should fail because "127.0.0.1" does not match the certificate subject common name and there * are no subject alternative names in the certificate. * * <p>NOTE: This test relies on a feature that is only available as of Java 7 and later. It is * commented out but not removed in case support for Java 6 is dropped or we find a way to have * the CI run a specific set of tests on Java 7 and above. */ @Test public void connectWithShardInfoByIpAddress() throws Exception { final URI uri = URI.create("rediss://127.0.0.1:6390"); final SSLSocketFactory sslSocketFactory = createTrustStoreSslSocketFactory(); // These SSL parameters ensure that we use the same hostname verifier used // for HTTPS. // Note: this options is only available in Java 7. final SSLParameters sslParameters = new SSLParameters(); sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); JedisShardInfo shardInfo = new JedisShardInfo(uri, sslSocketFactory, sslParameters, null); shardInfo.setPassword("foobared"); Jedis jedis = new Jedis(shardInfo); try { jedis.get("foo"); Assert.fail("The code did not throw the expected JedisConnectionException."); } catch (JedisConnectionException e) { Assert.assertEquals( "Unexpected first inner exception.", SSLHandshakeException.class, e.getCause().getClass()); Assert.assertEquals( "Unexpected second inner exception.", CertificateException.class, e.getCause().getCause().getClass()); } try { jedis.close(); } catch (Throwable e1) { // Expected. } }
/** * Returns server ssl engine. * * @param context - SSLContext to get SSLEngine from. * @param useSNI - flag used to enable or disable using SNI extension. Needed for Kerberos. */ public static SSLEngine getServerSSLEngine(SSLContext context, boolean useSNI) { SSLEngine serverEngine = context.createSSLEngine(); serverEngine.setUseClientMode(false); if (useSNI) { SNIMatcher matcher = SNIHostName.createSNIMatcher(SNI_PATTERN); List<SNIMatcher> matchers = new ArrayList<>(); matchers.add(matcher); SSLParameters params = serverEngine.getSSLParameters(); params.setSNIMatchers(matchers); serverEngine.setSSLParameters(params); } return serverEngine; }
/** * Returns client ssl engine. * * @param context - SSLContext to get SSLEngine from. * @param useSNI - flag used to enable or disable using SNI extension. Needed for Kerberos. */ public static SSLEngine getClientSSLEngine(SSLContext context, boolean useSNI) { SSLEngine clientEngine = context.createSSLEngine(HOST, 80); clientEngine.setUseClientMode(true); if (useSNI) { SNIHostName serverName = new SNIHostName(SERVER_NAME); List<SNIServerName> serverNames = new ArrayList<>(); serverNames.add(serverName); SSLParameters params = clientEngine.getSSLParameters(); params.setServerNames(serverNames); clientEngine.setSSLParameters(params); } return clientEngine; }
/** * Get a <code>List</code> of available <code>Version</code> objects. The list will be sorted in * ascending order, so currently "TLSv1.2" will be the last element. * * @return a sorted list of supported <code>Version</code>s */ private static List<Version> getVersions() { SSLParameters sslParams; List<Version> versions = new ArrayList<Version>(); try { sslParams = SSLContext.getDefault().getSupportedSSLParameters(); String[] protocols = sslParams.getProtocols(); for (int i = 0; i < protocols.length; ++i) { if (protocols[i].startsWith("TLS")) versions.add(new Version(protocols[i])); } Collections.sort(versions); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); System.err.println("this client does not support TLS 1.2"); } return versions; }
/** * Tests opening an SSL/TLS connection to redis. NOTE: This test relies on a feature that is only * available as of Java 7 and later. It is commented out but not removed in case support for Java * 6 is dropped or we find a way to have the CI run a specific set of tests on Java 7 and above. */ @Test public void connectWithShardInfo() throws Exception { final URI uri = URI.create("rediss://localhost:6390"); final SSLSocketFactory sslSocketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault(); // These SSL parameters ensure that we use the same hostname verifier used // for HTTPS. // Note: this options is only available in Java 7. final SSLParameters sslParameters = new SSLParameters(); sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); JedisShardInfo shardInfo = new JedisShardInfo(uri, sslSocketFactory, sslParameters, null); shardInfo.setPassword("foobared"); Jedis jedis = new Jedis(shardInfo); jedis.get("foo"); jedis.disconnect(); jedis.close(); }
/** {@inheritDoc} */ public void configure(HttpsParameters params) { // initialise the SSL context SSLEngine engine = context.createSSLEngine(); // get the default parameters SSLParameters defaultSSLParameters = context.getDefaultSSLParameters(); // Cert authentication is delayed later to the ClientCertAuthenticator params.setWantClientAuth(serverConfig.useSslClientAuthentication()); defaultSSLParameters.setWantClientAuth(serverConfig.useSslClientAuthentication()); // Cipher Suites params.setCipherSuites(serverConfig.getSSLCipherSuites()); defaultSSLParameters.setCipherSuites(serverConfig.getSSLCipherSuites()); // Protocols params.setProtocols(serverConfig.getSSLProtocols()); defaultSSLParameters.setProtocols(serverConfig.getSSLProtocols()); params.setSSLParameters(defaultSSLParameters); }
/** * Does the handshake of the two specified engines according to the {@code mode} specified. * * @param clientEngine - Client SSLEngine. * @param serverEngine - Server SSLEngine. * @param maxPacketSize - Maximum packet size for MFLN of zero for no limit. * @param mode - Handshake mode according to {@link HandshakeMode} enum. * @param enableReplicatedPacks - Set {@code true} to enable replicated packet sending. * @throws SSLException - thrown on engine errors. */ public static void doHandshake( SSLEngine clientEngine, SSLEngine serverEngine, int maxPacketSize, HandshakeMode mode, boolean enableReplicatedPacks) throws SSLException { System.out.println("============================================="); System.out.println("Starting handshake " + mode.name()); int loop = 0; if (maxPacketSize < 0) { throw new Error("Test issue: maxPacketSize is less than zero!"); } SSLParameters params = clientEngine.getSSLParameters(); params.setMaximumPacketSize(maxPacketSize); clientEngine.setSSLParameters(params); params = serverEngine.getSSLParameters(); params.setMaximumPacketSize(maxPacketSize); serverEngine.setSSLParameters(params); SSLEngine firstEngine; SSLEngine secondEngine; switch (mode) { case INITIAL_HANDSHAKE: firstEngine = clientEngine; secondEngine = serverEngine; doUnwrapForNotHandshakingStatus = false; clientEngine.beginHandshake(); serverEngine.beginHandshake(); break; case REHANDSHAKE_BEGIN_CLIENT: firstEngine = clientEngine; secondEngine = serverEngine; doUnwrapForNotHandshakingStatus = true; clientEngine.beginHandshake(); break; case REHANDSHAKE_BEGIN_SERVER: firstEngine = serverEngine; secondEngine = clientEngine; doUnwrapForNotHandshakingStatus = true; serverEngine.beginHandshake(); break; default: throw new Error("Test issue: unknown handshake mode"); } endHandshakeLoop = false; while (!endHandshakeLoop) { if (++loop > MAX_HANDSHAKE_LOOPS) { throw new Error("Too much loops for handshaking"); } System.out.println("============================================"); System.out.println("Handshake loop " + loop + ": round 1"); System.out.println("=========================="); handshakeProcess(firstEngine, secondEngine, maxPacketSize, enableReplicatedPacks); if (endHandshakeLoop) { break; } System.out.println("Handshake loop " + loop + ": round 2"); System.out.println("=========================="); handshakeProcess(secondEngine, firstEngine, maxPacketSize, enableReplicatedPacks); } }
@Override protected void initChannel(Channel channel) throws Exception { SslContext sslContext; SSLParameters sslParams = new SSLParameters(); if (redisURI.isVerifyPeer()) { sslContext = SslContext.newClientContext(SslProvider.JDK); if (JavaRuntime.AT_LEAST_JDK_7) { sslParams.setEndpointIdentificationAlgorithm("HTTPS"); } } else { sslContext = SslContext.newClientContext(SslProvider.JDK, InsecureTrustManagerFactory.INSTANCE); } SSLEngine sslEngine = sslContext.newEngine(channel.alloc(), redisURI.getHost(), redisURI.getPort()); sslEngine.setSSLParameters(sslParams); removeIfExists(channel.pipeline(), SslHandler.class); if (channel.pipeline().get("first") == null) { channel .pipeline() .addFirst( "first", new ChannelDuplexHandler() { @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { eventBus.publish(new ConnectedEvent(local(ctx), remote(ctx))); super.channelActive(ctx); } @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { eventBus.publish(new DisconnectedEvent(local(ctx), remote(ctx))); super.channelInactive(ctx); } }); } SslHandler sslHandler = new SslHandler(sslEngine, redisURI.isStartTls()); channel.pipeline().addLast(sslHandler); if (channel.pipeline().get("channelActivator") == null) { channel .pipeline() .addLast( "channelActivator", new RedisChannelInitializerImpl() { private Command<?, ?, ?> pingCommand; @Override public Future<Boolean> channelInitialized() { return initializedFuture; } @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { initializedFuture = SettableFuture.create(); pingCommand = null; super.channelInactive(ctx); } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { if (initializedFuture.isDone()) { super.channelActive(ctx); } } @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { if (evt instanceof SslHandshakeCompletionEvent && !initializedFuture.isDone()) { SslHandshakeCompletionEvent event = (SslHandshakeCompletionEvent) evt; if (event.isSuccess()) { if (pingBeforeActivate) { pingCommand = INITIALIZING_CMD_BUILDER.ping(); pingBeforeActivate(pingCommand, initializedFuture, ctx, handlers); } else { ctx.fireChannelActive(); } } else { initializedFuture.setException(event.cause()); } } if (evt instanceof ConnectionEvents.Close) { if (ctx.channel().isOpen()) { ctx.channel().close(); } } if (evt instanceof ConnectionEvents.Activated) { if (!initializedFuture.isDone()) { initializedFuture.set(true); eventBus.publish(new ConnectionActivatedEvent(local(ctx), remote(ctx))); } } super.userEventTriggered(ctx, evt); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { if (!initializedFuture.isDone()) { initializedFuture.setException(cause); } super.exceptionCaught(ctx, cause); } }); } for (ChannelHandler handler : handlers) { removeIfExists(channel.pipeline(), handler.getClass()); channel.pipeline().addLast(handler); } }
@Override public List<Attribute> getMonitorData() { ArrayList<Attribute> attrs = new ArrayList<>(13); attrs.add(createAttribute("javaVersion", System.getProperty("java.version"))); attrs.add(createAttribute("javaVendor", System.getProperty("java.vendor"))); attrs.add(createAttribute("jvmVersion", System.getProperty("java.vm.version"))); attrs.add(createAttribute("jvmVendor", System.getProperty("java.vm.vendor"))); attrs.add(createAttribute("javaHome", System.getProperty("java.home"))); attrs.add(createAttribute("classPath", System.getProperty("java.class.path"))); attrs.add(createAttribute("workingDirectory", System.getProperty("user.dir"))); String osInfo = System.getProperty("os.name") + " " + System.getProperty("os.version") + " " + System.getProperty("os.arch"); attrs.add(createAttribute("operatingSystem", osInfo)); String sunOsArchDataModel = System.getProperty("sun.arch.data.model"); if (sunOsArchDataModel != null) { String jvmArch = sunOsArchDataModel; if (!sunOsArchDataModel.toLowerCase().equals("unknown")) { jvmArch += "-bit"; } attrs.add(createAttribute("jvmArchitecture", jvmArch)); } else { attrs.add(createAttribute("jvmArchitecture", "unknown")); } try { attrs.add(createAttribute("systemName", InetAddress.getLocalHost().getCanonicalHostName())); } catch (Exception e) { logger.traceException(e); } Runtime runtime = Runtime.getRuntime(); attrs.add(createAttribute("availableCPUs", runtime.availableProcessors())); attrs.add(createAttribute("maxMemory", runtime.maxMemory())); attrs.add(createAttribute("usedMemory", runtime.totalMemory())); attrs.add(createAttribute("freeUsedMemory", runtime.freeMemory())); String installPath = DirectoryServer.getServerRoot(); if (installPath != null) { attrs.add(createAttribute("installPath", installPath)); } String instancePath = DirectoryServer.getInstanceRoot(); if (instancePath != null) { attrs.add(createAttribute("instancePath", instancePath)); } // Get the JVM input arguments. RuntimeMXBean rtBean = ManagementFactory.getRuntimeMXBean(); List<String> jvmArguments = rtBean.getInputArguments(); if (jvmArguments != null && !jvmArguments.isEmpty()) { StringBuilder argList = new StringBuilder(); for (String jvmArg : jvmArguments) { if (argList.length() > 0) { argList.append(" "); } argList.append("\""); argList.append(jvmArg); argList.append("\""); } attrs.add(createAttribute("jvmArguments", argList.toString())); } // Get the list of supported SSL protocols and ciphers. Collection<String> supportedTlsProtocols; Collection<String> supportedTlsCiphers; try { final SSLContext context = SSLContext.getDefault(); final SSLParameters parameters = context.getSupportedSSLParameters(); supportedTlsProtocols = Arrays.asList(parameters.getProtocols()); supportedTlsCiphers = Arrays.asList(parameters.getCipherSuites()); } catch (Exception e) { // A default SSL context should always be available. supportedTlsProtocols = Collections.emptyList(); supportedTlsCiphers = Collections.emptyList(); } addAttribute(attrs, ATTR_SUPPORTED_TLS_PROTOCOLS, supportedTlsProtocols); addAttribute(attrs, ATTR_SUPPORTED_TLS_CIPHERS, supportedTlsCiphers); return attrs; }