| /******************************************************************************* |
| * 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.ofbiz.base.util; |
| |
| import java.io.IOException; |
| import java.security.GeneralSecurityException; |
| import java.security.KeyStore; |
| import java.security.Principal; |
| import java.security.SecureRandom; |
| import java.security.cert.CertificateException; |
| import java.security.cert.X509Certificate; |
| import java.util.Arrays; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Map; |
| |
| import javax.net.ssl.HostnameVerifier; |
| import javax.net.ssl.KeyManager; |
| import javax.net.ssl.KeyManagerFactory; |
| import javax.net.ssl.SSLContext; |
| import javax.net.ssl.SSLPeerUnverifiedException; |
| import javax.net.ssl.SSLServerSocketFactory; |
| import javax.net.ssl.SSLSession; |
| import javax.net.ssl.SSLSocketFactory; |
| import javax.net.ssl.TrustManager; |
| import javax.net.ssl.X509KeyManager; |
| import javax.net.ssl.X509TrustManager; |
| |
| import org.ofbiz.base.component.ComponentConfig; |
| import org.ofbiz.base.config.GenericConfigException; |
| |
| /** |
| * KeyStoreUtil - Utilities for setting up SSL connections with specific client certificates |
| * |
| */ |
| public class SSLUtil { |
| |
| public static final String module = SSLUtil.class.getName(); |
| |
| public static final int HOSTCERT_NO_CHECK = 0; |
| public static final int HOSTCERT_MIN_CHECK = 1; |
| public static final int HOSTCERT_NORMAL_CHECK = 2; |
| |
| private static boolean loadedProps = false; |
| |
| static { |
| SSLUtil.loadJsseProperties(); |
| } |
| |
| public static boolean isClientTrusted(X509Certificate[] chain, String authType) { |
| TrustManager[] mgrs = new TrustManager[0]; |
| try { |
| mgrs = SSLUtil.getTrustManagers(); |
| } catch (IOException e) { |
| Debug.logError(e, module); |
| } catch (GeneralSecurityException e) { |
| Debug.logError(e, module); |
| } catch (GenericConfigException e) { |
| Debug.logError(e, module); |
| } |
| |
| if (mgrs != null) { |
| for (TrustManager mgr: mgrs) { |
| if (mgr instanceof X509TrustManager) { |
| try { |
| ((X509TrustManager) mgr).checkClientTrusted(chain, authType); |
| return true; |
| } catch (CertificateException e) { |
| // do nothing; just loop |
| } |
| } |
| } |
| } |
| return false; |
| } |
| |
| public static KeyManager[] getKeyManagers(String alias) throws IOException, GeneralSecurityException, GenericConfigException { |
| List<KeyManager> keyMgrs = new LinkedList<KeyManager>(); |
| for (ComponentConfig.KeystoreInfo ksi: ComponentConfig.getAllKeystoreInfos()) { |
| if (ksi.isCertStore()) { |
| KeyStore ks = ksi.getKeyStore(); |
| if (ks != null) { |
| List<KeyManager> newKeyManagers = Arrays.asList(getKeyManagers(ks, ksi.getPassword(), alias)); |
| keyMgrs.addAll(newKeyManagers); |
| if (Debug.verboseOn()) Debug.logVerbose("Loaded another cert store, adding [" + (newKeyManagers == null ? "0" : newKeyManagers.size()) + "] KeyManagers for alias [" + alias + "] and keystore: " + ksi.createResourceHandler().getFullLocation(), module); |
| } else { |
| throw new IOException("Unable to load keystore: " + ksi.createResourceHandler().getFullLocation()); |
| } |
| } |
| } |
| |
| return keyMgrs.toArray(new KeyManager[keyMgrs.size()]); |
| } |
| |
| public static KeyManager[] getKeyManagers() throws IOException, GeneralSecurityException, GenericConfigException { |
| return getKeyManagers(null); |
| } |
| |
| public static TrustManager[] getTrustManagers() throws IOException, GeneralSecurityException, GenericConfigException { |
| MultiTrustManager tm = new MultiTrustManager(); |
| tm.add(KeyStoreUtil.getSystemTrustStore()); |
| if (tm.getNumberOfKeyStores() < 1) { |
| Debug.logWarning("System truststore not found!", module); |
| } |
| |
| for (ComponentConfig.KeystoreInfo ksi: ComponentConfig.getAllKeystoreInfos()) { |
| if (ksi.isTrustStore()) { |
| KeyStore ks = ksi.getKeyStore(); |
| if (ks != null) { |
| tm.add(ks); |
| } else { |
| throw new IOException("Unable to load keystore: " + ksi.createResourceHandler().getFullLocation()); |
| } |
| } |
| } |
| |
| return new TrustManager[] { tm }; |
| } |
| |
| public static TrustManager[] getTrustAnyManagers() { |
| return new TrustManager[] { new TrustAnyManager() }; |
| } |
| |
| public static KeyManager[] getKeyManagers(KeyStore ks, String password, String alias) throws GeneralSecurityException { |
| KeyManagerFactory factory = KeyManagerFactory.getInstance("SunX509"); |
| factory.init(ks, password.toCharArray()); |
| KeyManager[] keyManagers = factory.getKeyManagers(); |
| if (alias != null) { |
| for (int i = 0; i < keyManagers.length; i++) { |
| if (keyManagers[i] instanceof X509KeyManager) { |
| keyManagers[i] = new AliasKeyManager((X509KeyManager)keyManagers[i], alias); |
| } |
| } |
| } |
| return keyManagers; |
| } |
| |
| public static TrustManager[] getTrustManagers(KeyStore ks) throws GeneralSecurityException { |
| return new TrustManager[] { new MultiTrustManager(ks) }; |
| } |
| |
| public static SSLSocketFactory getSSLSocketFactory(KeyStore ks, String password, String alias) throws IOException, GeneralSecurityException, GenericConfigException { |
| return getSSLContext(ks, password, alias, false).getSocketFactory(); |
| } |
| |
| public static SSLContext getSSLContext(KeyStore ks, String password, String alias, boolean trustAny) throws IOException, GeneralSecurityException, GenericConfigException { |
| KeyManager[] km = SSLUtil.getKeyManagers(ks, password, alias); |
| TrustManager[] tm; |
| if (trustAny) { |
| tm = SSLUtil.getTrustAnyManagers(); |
| } else { |
| tm = SSLUtil.getTrustManagers(); |
| } |
| |
| SSLContext context = SSLContext.getInstance("SSL"); |
| context.init(km, tm, new SecureRandom()); |
| return context; |
| } |
| |
| public static SSLSocketFactory getSSLSocketFactory(String alias, boolean trustAny) throws IOException, GeneralSecurityException, GenericConfigException { |
| return getSSLContext(alias, trustAny).getSocketFactory(); |
| } |
| |
| public static SSLContext getSSLContext(String alias, boolean trustAny) throws IOException, GeneralSecurityException, GenericConfigException { |
| KeyManager[] km = SSLUtil.getKeyManagers(alias); |
| TrustManager[] tm; |
| if (trustAny) { |
| tm = SSLUtil.getTrustAnyManagers(); |
| } else { |
| tm = SSLUtil.getTrustManagers(); |
| } |
| |
| SSLContext context = SSLContext.getInstance("SSL"); |
| context.init(km, tm, new SecureRandom()); |
| return context; |
| } |
| |
| public static SSLSocketFactory getSSLSocketFactory(String alias) throws IOException, GeneralSecurityException, GenericConfigException { |
| return getSSLSocketFactory(alias, false); |
| } |
| |
| public static SSLSocketFactory getSSLSocketFactory() throws IOException, GeneralSecurityException, GenericConfigException { |
| return getSSLSocketFactory(null); |
| } |
| |
| public static SSLServerSocketFactory getSSLServerSocketFactory(KeyStore ks, String password, String alias) throws IOException, GeneralSecurityException, GenericConfigException { |
| return getSSLContext(ks, password, alias, false).getServerSocketFactory(); |
| } |
| |
| public static SSLServerSocketFactory getSSLServerSocketFactory(String alias) throws IOException, GeneralSecurityException, GenericConfigException { |
| return getSSLContext(alias, false).getServerSocketFactory(); |
| } |
| |
| public static HostnameVerifier getHostnameVerifier(int level) { |
| switch (level) { |
| case HOSTCERT_MIN_CHECK: |
| return new HostnameVerifier() { |
| public boolean verify(String hostname, SSLSession session) { |
| javax.security.cert.X509Certificate[] peerCerts; |
| try { |
| peerCerts = session.getPeerCertificateChain(); |
| } catch (SSLPeerUnverifiedException e) { |
| // cert not verified |
| Debug.logWarning(e.getMessage(), module); |
| return false; |
| } |
| for (javax.security.cert.X509Certificate peerCert: peerCerts) { |
| Principal x500s = peerCert.getSubjectDN(); |
| Map<String, String> subjectMap = KeyStoreUtil.getX500Map(x500s); |
| |
| if (Debug.infoOn()) |
| Debug.logInfo(peerCert.getSerialNumber().toString(16) + " :: " + subjectMap.get("CN"), module); |
| |
| try { |
| peerCert.checkValidity(); |
| } catch (Exception e) { |
| // certificate not valid |
| Debug.logWarning("Certificate is not valid!", module); |
| return false; |
| } |
| } |
| return true; |
| } |
| }; |
| case HOSTCERT_NO_CHECK: |
| return new HostnameVerifier() { |
| public boolean verify(String hostname, SSLSession session) { |
| return true; |
| } |
| }; |
| default: |
| return null; |
| } |
| } |
| |
| public static void loadJsseProperties() { |
| loadJsseProperties(false); |
| } |
| |
| public static synchronized void loadJsseProperties(boolean debug) { |
| if (!loadedProps) { |
| String protocol = UtilProperties.getPropertyValue("jsse.properties", "java.protocol.handler.pkgs", "NONE"); |
| String proxyHost = UtilProperties.getPropertyValue("jsse.properties", "https.proxyHost", "NONE"); |
| String proxyPort = UtilProperties.getPropertyValue("jsse.properties", "https.proxyPort", "NONE"); |
| String cypher = UtilProperties.getPropertyValue("jsse.properties", "https.cipherSuites", "NONE"); |
| if (protocol != null && !protocol.equals("NONE")) { |
| System.setProperty("java.protocol.handler.pkgs", protocol); |
| } |
| if (proxyHost != null && !proxyHost.equals("NONE")) { |
| System.setProperty("https.proxyHost", proxyHost); |
| } |
| if (proxyPort != null && !proxyPort.equals("NONE")) { |
| System.setProperty("https.proxyPort", proxyPort); |
| } |
| if (cypher != null && !cypher.equals("NONE")) { |
| System.setProperty("https.cipherSuites", cypher); |
| } |
| |
| if (debug) { |
| System.setProperty("javax.net.debug","ssl:handshake"); |
| } |
| loadedProps = true; |
| } |
| } |
| |
| static class TrustAnyManager implements X509TrustManager { |
| |
| public void checkClientTrusted(X509Certificate[] certs, String string) throws CertificateException { |
| Debug.logImportant("Trusting (un-trusted) client certificate chain:", module); |
| for (X509Certificate cert: certs) { |
| Debug.logImportant("---- " + cert.getSubjectX500Principal().getName() + " valid: " + cert.getNotAfter(), module); |
| |
| } |
| } |
| |
| public void checkServerTrusted(X509Certificate[] certs, String string) throws CertificateException { |
| Debug.logImportant("Trusting (un-trusted) server certificate chain:", module); |
| for (X509Certificate cert: certs) { |
| Debug.logImportant("---- " + cert.getSubjectX500Principal().getName() + " valid: " + cert.getNotAfter(), module); |
| } |
| } |
| |
| public X509Certificate[] getAcceptedIssuers() { |
| return new X509Certificate[0]; |
| } |
| } |
| } |