Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.rocketmq.remoting.netty; import io.netty.handler.ssl.ClientAuth; import io.netty.handler.ssl.OpenSsl; import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContextBuilder; import io.netty.handler.ssl.SslProvider; import io.netty.handler.ssl.util.InsecureTrustManagerFactory; import io.netty.handler.ssl.util.SelfSignedCertificate; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.security.cert.CertificateException; import java.util.Properties; import org.apache.rocketmq.remoting.common.RemotingHelper; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.logging.InternalLoggerFactory; import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_CLIENT_AUTHSERVER; import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_CLIENT_CERTPATH; import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_CLIENT_KEYPASSWORD; import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_CLIENT_KEYPATH; import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_CLIENT_TRUSTCERTPATH; import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_SERVER_AUTHCLIENT; import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_SERVER_CERTPATH; import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_SERVER_KEYPASSWORD; import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_SERVER_KEYPATH; import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_SERVER_NEED_CLIENT_AUTH; import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_SERVER_TRUSTCERTPATH; import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.TLS_TEST_MODE_ENABLE; import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsClientAuthServer; import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsClientCertPath; import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsClientKeyPassword; import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsClientKeyPath; import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsClientTrustCertPath; import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsServerAuthClient; import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsServerCertPath; import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsServerKeyPassword; import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsServerKeyPath; import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsServerNeedClientAuth; import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsServerTrustCertPath; import static org.apache.rocketmq.remoting.netty.TlsSystemConfig.tlsTestModeEnable; public class TlsHelper { public interface DecryptionStrategy { /** * Decrypt the target encrpted private key file. * * @param privateKeyEncryptPath A pathname string * @param forClient tells whether it's a client-side key file * @return An input stream for a decrypted key file * @throws IOException if an I/O error has occurred */ InputStream decryptPrivateKey(String privateKeyEncryptPath, boolean forClient) throws IOException; } private static final InternalLogger LOGGER = InternalLoggerFactory.getLogger(RemotingHelper.ROCKETMQ_REMOTING); private static DecryptionStrategy decryptionStrategy = new DecryptionStrategy() { @Override public InputStream decryptPrivateKey(final String privateKeyEncryptPath, final boolean forClient) throws IOException { return new FileInputStream(privateKeyEncryptPath); } }; public static void registerDecryptionStrategy(final DecryptionStrategy decryptionStrategy) { TlsHelper.decryptionStrategy = decryptionStrategy; } public static SslContext buildSslContext(boolean forClient) throws IOException, CertificateException { File configFile = new File(TlsSystemConfig.tlsConfigFile); extractTlsConfigFromFile(configFile); logTheFinalUsedTlsConfig(); SslProvider provider; if (OpenSsl.isAvailable()) { provider = SslProvider.OPENSSL; LOGGER.info("Using OpenSSL provider"); } else { provider = SslProvider.JDK; LOGGER.info("Using JDK SSL provider"); } if (forClient) { if (tlsTestModeEnable) { return SslContextBuilder.forClient().sslProvider(SslProvider.JDK) .trustManager(InsecureTrustManagerFactory.INSTANCE).build(); } else { SslContextBuilder sslContextBuilder = SslContextBuilder.forClient().sslProvider(SslProvider.JDK); if (!tlsClientAuthServer) { sslContextBuilder.trustManager(InsecureTrustManagerFactory.INSTANCE); } else { if (!isNullOrEmpty(tlsClientTrustCertPath)) { sslContextBuilder.trustManager(new File(tlsClientTrustCertPath)); } } return sslContextBuilder .keyManager( !isNullOrEmpty(tlsClientCertPath) ? new FileInputStream(tlsClientCertPath) : null, !isNullOrEmpty(tlsClientKeyPath) ? decryptionStrategy.decryptPrivateKey(tlsClientKeyPath, true) : null, !isNullOrEmpty(tlsClientKeyPassword) ? tlsClientKeyPassword : null) .build(); } } else { if (tlsTestModeEnable) { SelfSignedCertificate selfSignedCertificate = new SelfSignedCertificate(); return SslContextBuilder .forServer(selfSignedCertificate.certificate(), selfSignedCertificate.privateKey()) .sslProvider(SslProvider.JDK).clientAuth(ClientAuth.OPTIONAL).build(); } else { SslContextBuilder sslContextBuilder = SslContextBuilder .forServer( !isNullOrEmpty(tlsServerCertPath) ? new FileInputStream(tlsServerCertPath) : null, !isNullOrEmpty(tlsServerKeyPath) ? decryptionStrategy.decryptPrivateKey(tlsServerKeyPath, false) : null, !isNullOrEmpty(tlsServerKeyPassword) ? tlsServerKeyPassword : null) .sslProvider(provider); if (!tlsServerAuthClient) { sslContextBuilder.trustManager(InsecureTrustManagerFactory.INSTANCE); } else { if (!isNullOrEmpty(tlsServerTrustCertPath)) { sslContextBuilder.trustManager(new File(tlsServerTrustCertPath)); } } sslContextBuilder.clientAuth(parseClientAuthMode(tlsServerNeedClientAuth)); return sslContextBuilder.build(); } } } private static void extractTlsConfigFromFile(final File configFile) { if (!(configFile.exists() && configFile.isFile() && configFile.canRead())) { LOGGER.info("Tls config file doesn't exist, skip it"); return; } Properties properties; properties = new Properties(); InputStream inputStream = null; try { inputStream = new FileInputStream(configFile); properties.load(inputStream); } catch (IOException ignore) { } finally { if (null != inputStream) { try { inputStream.close(); } catch (IOException ignore) { } } } tlsTestModeEnable = Boolean .parseBoolean(properties.getProperty(TLS_TEST_MODE_ENABLE, String.valueOf(tlsTestModeEnable))); tlsServerNeedClientAuth = properties.getProperty(TLS_SERVER_NEED_CLIENT_AUTH, tlsServerNeedClientAuth); tlsServerKeyPath = properties.getProperty(TLS_SERVER_KEYPATH, tlsServerKeyPath); tlsServerKeyPassword = properties.getProperty(TLS_SERVER_KEYPASSWORD, tlsServerKeyPassword); tlsServerCertPath = properties.getProperty(TLS_SERVER_CERTPATH, tlsServerCertPath); tlsServerAuthClient = Boolean .parseBoolean(properties.getProperty(TLS_SERVER_AUTHCLIENT, String.valueOf(tlsServerAuthClient))); tlsServerTrustCertPath = properties.getProperty(TLS_SERVER_TRUSTCERTPATH, tlsServerTrustCertPath); tlsClientKeyPath = properties.getProperty(TLS_CLIENT_KEYPATH, tlsClientKeyPath); tlsClientKeyPassword = properties.getProperty(TLS_CLIENT_KEYPASSWORD, tlsClientKeyPassword); tlsClientCertPath = properties.getProperty(TLS_CLIENT_CERTPATH, tlsClientCertPath); tlsClientAuthServer = Boolean .parseBoolean(properties.getProperty(TLS_CLIENT_AUTHSERVER, String.valueOf(tlsClientAuthServer))); tlsClientTrustCertPath = properties.getProperty(TLS_CLIENT_TRUSTCERTPATH, tlsClientTrustCertPath); } private static void logTheFinalUsedTlsConfig() { LOGGER.info("Log the final used tls related configuration"); LOGGER.info("{} = {}", TLS_TEST_MODE_ENABLE, tlsTestModeEnable); LOGGER.info("{} = {}", TLS_SERVER_NEED_CLIENT_AUTH, tlsServerNeedClientAuth); LOGGER.info("{} = {}", TLS_SERVER_KEYPATH, tlsServerKeyPath); LOGGER.info("{} = {}", TLS_SERVER_KEYPASSWORD, tlsServerKeyPassword); LOGGER.info("{} = {}", TLS_SERVER_CERTPATH, tlsServerCertPath); LOGGER.info("{} = {}", TLS_SERVER_AUTHCLIENT, tlsServerAuthClient); LOGGER.info("{} = {}", TLS_SERVER_TRUSTCERTPATH, tlsServerTrustCertPath); LOGGER.info("{} = {}", TLS_CLIENT_KEYPATH, tlsClientKeyPath); LOGGER.info("{} = {}", TLS_CLIENT_KEYPASSWORD, tlsClientKeyPassword); LOGGER.info("{} = {}", TLS_CLIENT_CERTPATH, tlsClientCertPath); LOGGER.info("{} = {}", TLS_CLIENT_AUTHSERVER, tlsClientAuthServer); LOGGER.info("{} = {}", TLS_CLIENT_TRUSTCERTPATH, tlsClientTrustCertPath); } private static ClientAuth parseClientAuthMode(String authMode) { if (null == authMode || authMode.trim().isEmpty()) { return ClientAuth.NONE; } for (ClientAuth clientAuth : ClientAuth.values()) { if (clientAuth.name().equals(authMode.toUpperCase())) { return clientAuth; } } return ClientAuth.NONE; } /** * Determine if a string is {@code null} or {@link String#isEmpty()} returns {@code true}. */ private static boolean isNullOrEmpty(String s) { return s == null || s.isEmpty(); } }