/******************************************************************************* * Copyright 2020 Graz University of Technology * MOA ZS has been developed in a cooperation between EGIZ * and Graz University of Technology. * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * * Unless required by applicable law or agreed to in writing, software * distributed under the Licence is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and * limitations under the Licence. * * This product combines work with different licenses. See the "NOTICE" text * file for details on the various modules and licenses. * The "NOTICE" text file is part of the distribution. Any derivative works * that you distribute must include a readable copy of the "NOTICE" text file. *******************************************************************************/ package at.gv.egiz.moazs.client; import at.gv.egiz.eaaf.core.impl.utils.KeyStoreUtils; import at.gv.zustellung.app2mzs.xsd.KeyStoreType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.lang.Nullable; import org.springframework.stereotype.Component; import javax.net.ssl.*; import java.io.IOException; import java.security.*; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import static at.gv.egiz.moazs.MoaZSException.moaZSException; import static java.lang.String.format; /** * Adapted from at.asitplus.eidas.specific.modules.authmodule_eIDASv2.szr.SZRClient * @author Christof Rabensteiner */ @Component public class SSLContextCreator { private static final Logger log = LoggerFactory.getLogger(SSLContextCreator.class); private static final String SSL_WARN_MAN_IN_THE_MIDDLE_MSG = "HTTP Client trusts ANY server certificate and is therefore vulnerable to Man-In-The-Middle attacks. " + "Use this configuration for testing purposes only and NOT IN PRODUCTION. "; /** * Creates an SSL Context. * * @param keystore (if null, use no key store) * @param truststore (if null, use default trust store) * @throws at.gv.egiz.moazs.MoaZSException */ public SSLContext createSSLContext(@Nullable KeyStoreType keystore, @Nullable KeyStoreType truststore) { return createSSLContext(keystore, false, truststore); } /** * Creates an SSL Context that trusts all certificates. Don't use in production. * * @param keystore (if null, use no key store) * @throws at.gv.egiz.moazs.MoaZSException */ public SSLContext createUnsafeSSLContext(@Nullable KeyStoreType keystore) { log.warn(SSL_WARN_MAN_IN_THE_MIDDLE_MSG); return createSSLContext(keystore, true, null); } private SSLContext createSSLContext(@Nullable KeyStoreType keystore, boolean trustAll, @Nullable KeyStoreType truststore) { try { SSLContext context = SSLContext.getInstance("TLS"); KeyManager[] keyManager = initKeyManager(keystore); TrustManager[] trustManager = trustAll ? new TrustManager[]{new TrustAllManager()} : initTrustManager(truststore); context.init(keyManager, trustManager, new SecureRandom()); return context; } catch (NoSuchAlgorithmException | KeyManagementException e) { throw moaZSException("SSLContext initialization FAILED.", e); } } private KeyManager[] initKeyManager(KeyStoreType keystore) { if (keystore == null) { log.trace("No keystore path provided. NOT using SSL client authentication. "); return null; } else { log.trace("Find keystore path: {}. Injecting SSL client certificate... ", keystore.getFileName()); try { KeyStore keyStore = KeyStoreUtils.loadKeyStore( keystore.getFileType(), keystore.getFileName(), keystore.getPassword()); KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); kmf.init(keyStore, keystore.getPassword().toCharArray()); log.trace("SSL client certificate injected."); return kmf.getKeyManagers(); } catch (IOException | GeneralSecurityException e) { throw moaZSException(format("Can NOT load SSL client certificate from path: %s.", keystore.getFileName()), e); } } } private TrustManager[] initTrustManager(KeyStoreType truststore) { if (truststore == null) { log.trace("Using default truststore. "); return null; } else { log.trace("Find truststore path: {}. Injecting SSL truststore... ", truststore.getFileName()); try { KeyStore trustStore = KeyStoreUtils.loadKeyStore( truststore.getFileType(), truststore.getFileName(), truststore.getPassword()); TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); tmf.init(trustStore); log.trace("SSL TrustStore injected to client. "); return tmf.getTrustManagers(); } catch (GeneralSecurityException | IOException e) { throw moaZSException(format("Can NOT open SSL TrustStore from path: %s.", truststore.getFileName()), e); } } } /** * Class implementing a trust manager that trusts all certificates. * * @author Arne Tauber */ public static class TrustAllManager implements X509TrustManager { private static Logger log = LoggerFactory.getLogger(TrustAllManager.class); public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { log.debug("Automatically accepting client certificate as trusted."); } public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { log.debug("Automatically accepting server certificate as trusted."); } } }