package com.paypal.core; import java.io.FileInputStream; import java.io.IOException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.util.HashMap; import java.util.Map; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import com.paypal.exception.SSLConfigurationException; public abstract class SSLUtil { /** * KeyManagerFactory used for {@link SSLContext} {@link KeyManager} */ private static final KeyManagerFactory KMF; /** * Private {@link Map} used for caching {@link KeyStore}s */ private static final Map<String, KeyStore> STOREMAP; /** *Map used for dynamic configuration */ private static final Map<String, String> CONFIG_MAP; static { try { // Initialize KeyManagerFactory and local KeyStore cache KMF = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); STOREMAP = new HashMap<String, KeyStore>(); CONFIG_MAP = SDKUtil.combineDefaultMap(ConfigManager.getInstance().getConfigurationMap()); } catch (NoSuchAlgorithmException e) { throw new ExceptionInInitializerError(e); } } /** * Returns a SSLContext * * @param keymanagers * KeyManager[] The key managers * @return SSLContext with proper client certificate * @throws SSLConfigurationException * @throws IOException * if an IOException occurs */ public static SSLContext getSSLContext(KeyManager[] keymanagers) throws SSLConfigurationException { try { SSLContext ctx; String protocol = CONFIG_MAP.get(Constants.SSLUTIL_PROTOCOL); try { ctx = SSLContext.getInstance("TLSv1.2"); } catch (NoSuchAlgorithmException e) { LoggingManager.warn(SSLUtil.class, "WARNING: Your system does not support TLSv1.2. Per PCI Security Council mandate (https://github.com/paypal/TLS-update), you MUST update to latest security library."); ctx = SSLContext.getInstance(protocol); } ctx.init(keymanagers, null, null); return ctx; } catch (Exception e) { throw new SSLConfigurationException(e.getMessage(), e); } } /** * Retrieves keyStore from the cached {@link Map}, if not present loads * certificate into java keyStore and caches it for further references * * @param p12Path * Path to the client certificate * @param password * {@link KeyStore} password * @return keyStore {@link KeyStore} loaded with the certificate * @throws NoSuchProviderException * @throws KeyStoreException * @throws CertificateException * @throws NoSuchAlgorithmException * @throws FileNotFoundException * @throws IOException */ private static KeyStore p12ToKeyStore(String p12Path, String password) throws NoSuchProviderException, KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException { KeyStore keyStore = STOREMAP.get(p12Path); if (keyStore == null) { keyStore = KeyStore.getInstance("PKCS12", CONFIG_MAP.get(Constants.SSLUTIL_JRE)); FileInputStream in = null; try { in = new FileInputStream(p12Path); keyStore.load(in, password.toCharArray()); STOREMAP.put(p12Path, keyStore); } finally { if (in != null) { in.close(); } } } return keyStore; } /** * Create a SSLContext with provided client certificate * * @param certPath * @param certPassword * @return SSLContext * @throws SSLConfigurationException */ public static SSLContext setupClientSSL(String certPath, String certPassword) throws SSLConfigurationException { SSLContext sslContext; try { KeyStore ks = p12ToKeyStore(certPath, certPassword); KMF.init(ks, certPassword.toCharArray()); sslContext = getSSLContext(KMF.getKeyManagers()); } catch (NoSuchAlgorithmException e) { throw new SSLConfigurationException(e.getMessage(), e); } catch (KeyStoreException e) { throw new SSLConfigurationException(e.getMessage(), e); } catch (UnrecoverableKeyException e) { throw new SSLConfigurationException(e.getMessage(), e); } catch (CertificateException e) { throw new SSLConfigurationException(e.getMessage(), e); } catch (NoSuchProviderException e) { throw new SSLConfigurationException(e.getMessage(), e); } catch (IOException e) { throw new SSLConfigurationException(e.getMessage(), e); } return sslContext; } }