| /** |
| * 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.zookeeper.common; |
| |
| |
| import javax.net.ssl.KeyManager; |
| import javax.net.ssl.KeyManagerFactory; |
| import javax.net.ssl.SSLContext; |
| import javax.net.ssl.TrustManager; |
| import javax.net.ssl.TrustManagerFactory; |
| import javax.net.ssl.X509KeyManager; |
| import javax.net.ssl.X509TrustManager; |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.IOException; |
| import java.security.KeyStore; |
| |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import static org.apache.zookeeper.common.X509Exception.KeyManagerException; |
| import static org.apache.zookeeper.common.X509Exception.SSLContextException; |
| import static org.apache.zookeeper.common.X509Exception.TrustManagerException; |
| |
| /** |
| * Utility code for X509 handling |
| */ |
| public class X509Util { |
| private static final Logger LOG = LoggerFactory.getLogger(X509Util.class); |
| |
| /** |
| * @deprecated Use {@link ZKConfig#SSL_KEYSTORE_LOCATION} |
| * instead. |
| */ |
| @Deprecated |
| public static final String SSL_KEYSTORE_LOCATION = "zookeeper.ssl.keyStore.location"; |
| /** |
| * @deprecated Use {@link ZKConfig#SSL_KEYSTORE_PASSWD} |
| * instead. |
| */ |
| @Deprecated |
| public static final String SSL_KEYSTORE_PASSWD = "zookeeper.ssl.keyStore.password"; |
| /** |
| * @deprecated Use {@link ZKConfig#SSL_TRUSTSTORE_LOCATION} |
| * instead. |
| */ |
| @Deprecated |
| public static final String SSL_TRUSTSTORE_LOCATION = "zookeeper.ssl.trustStore.location"; |
| /** |
| * @deprecated Use {@link ZKConfig#SSL_TRUSTSTORE_PASSWD} |
| * instead. |
| */ |
| @Deprecated |
| public static final String SSL_TRUSTSTORE_PASSWD = "zookeeper.ssl.trustStore.password"; |
| /** |
| * @deprecated Use {@link ZKConfig#SSL_AUTHPROVIDER} |
| * instead. |
| */ |
| @Deprecated |
| public static final String SSL_AUTHPROVIDER = "zookeeper.ssl.authProvider"; |
| |
| public static SSLContext createSSLContext() throws SSLContextException { |
| /** |
| * Since Configuration initializes the key store and trust store related |
| * configuration from system property. Reading property from |
| * configuration will be same reading from system property |
| */ |
| ZKConfig config=new ZKConfig(); |
| return createSSLContext(config); |
| } |
| |
| public static SSLContext createSSLContext(ZKConfig config) throws SSLContextException { |
| KeyManager[] keyManagers = null; |
| TrustManager[] trustManagers = null; |
| |
| String keyStoreLocationProp = config.getProperty(ZKConfig.SSL_KEYSTORE_LOCATION); |
| String keyStorePasswordProp = config.getProperty(ZKConfig.SSL_KEYSTORE_PASSWD); |
| |
| // There are legal states in some use cases for null KeyManager or TrustManager. |
| // But if a user wanna specify one, location and password are required. |
| |
| if (keyStoreLocationProp == null && keyStorePasswordProp == null) { |
| LOG.warn("keystore not specified for client connection"); |
| } else { |
| if (keyStoreLocationProp == null) { |
| throw new SSLContextException("keystore location not specified for client connection"); |
| } |
| if (keyStorePasswordProp == null) { |
| throw new SSLContextException("keystore password not specified for client connection"); |
| } |
| try { |
| keyManagers = new KeyManager[]{ |
| createKeyManager(keyStoreLocationProp, keyStorePasswordProp)}; |
| } catch (KeyManagerException e) { |
| throw new SSLContextException("Failed to create KeyManager", e); |
| } |
| } |
| |
| String trustStoreLocationProp = config.getProperty(ZKConfig.SSL_TRUSTSTORE_LOCATION); |
| String trustStorePasswordProp = config.getProperty(ZKConfig.SSL_TRUSTSTORE_PASSWD); |
| |
| if (trustStoreLocationProp == null && trustStorePasswordProp == null) { |
| LOG.warn("keystore not specified for client connection"); |
| } else { |
| if (trustStoreLocationProp == null) { |
| throw new SSLContextException("keystore location not specified for client connection"); |
| } |
| if (trustStorePasswordProp == null) { |
| throw new SSLContextException("keystore password not specified for client connection"); |
| } |
| try { |
| trustManagers = new TrustManager[]{ |
| createTrustManager(trustStoreLocationProp, trustStorePasswordProp)}; |
| } catch (TrustManagerException e) { |
| throw new SSLContextException("Failed to create KeyManager", e); |
| } |
| } |
| |
| SSLContext sslContext = null; |
| try { |
| sslContext = SSLContext.getInstance("TLSv1"); |
| sslContext.init(keyManagers, trustManagers, null); |
| } catch (Exception e) { |
| throw new SSLContextException(e); |
| } |
| return sslContext; |
| } |
| |
| public static X509KeyManager createKeyManager(String keyStoreLocation, String keyStorePassword) |
| throws KeyManagerException { |
| FileInputStream inputStream = null; |
| try { |
| char[] keyStorePasswordChars = keyStorePassword.toCharArray(); |
| File keyStoreFile = new File(keyStoreLocation); |
| KeyStore ks = KeyStore.getInstance("JKS"); |
| inputStream = new FileInputStream(keyStoreFile); |
| ks.load(inputStream, keyStorePasswordChars); |
| KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); |
| kmf.init(ks, keyStorePasswordChars); |
| |
| for (KeyManager km : kmf.getKeyManagers()) { |
| if (km instanceof X509KeyManager) { |
| return (X509KeyManager) km; |
| } |
| } |
| throw new KeyManagerException("Couldn't find X509KeyManager"); |
| |
| } catch (Exception e) { |
| throw new KeyManagerException(e); |
| } finally { |
| if (inputStream != null) { |
| try { |
| inputStream.close(); |
| } catch (IOException e) {} |
| } |
| } |
| } |
| |
| public static X509TrustManager createTrustManager(String trustStoreLocation, String trustStorePassword) |
| throws TrustManagerException { |
| FileInputStream inputStream = null; |
| try { |
| char[] trustStorePasswordChars = trustStorePassword.toCharArray(); |
| File trustStoreFile = new File(trustStoreLocation); |
| KeyStore ts = KeyStore.getInstance("JKS"); |
| inputStream = new FileInputStream(trustStoreFile); |
| ts.load(inputStream, trustStorePasswordChars); |
| TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); |
| tmf.init(ts); |
| |
| for (TrustManager tm : tmf.getTrustManagers()) { |
| if (tm instanceof X509TrustManager) { |
| return (X509TrustManager) tm; |
| } |
| } |
| throw new TrustManagerException("Couldn't find X509TrustManager"); |
| } catch (Exception e) { |
| throw new TrustManagerException(e); |
| } finally { |
| if (inputStream != null) { |
| try { |
| inputStream.close(); |
| } catch (IOException e) {} |
| } |
| } |
| } |
| } |