2 * ============LICENSE_START====================================================
4 * ===========================================================================
5 * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
6 * ===========================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END====================================================
22 package org.onap.aaf.cadi.config;
25 import java.io.FileInputStream;
26 import java.io.IOException;
27 import java.net.InetAddress;
28 import java.net.UnknownHostException;
29 import java.rmi.AccessException;
30 import java.security.KeyManagementException;
31 import java.security.KeyStore;
32 import java.security.KeyStoreException;
33 import java.security.NoSuchAlgorithmException;
34 import java.security.UnrecoverableKeyException;
35 import java.security.cert.CertificateException;
36 import java.security.cert.X509Certificate;
37 import java.util.ArrayList;
39 import javax.net.ssl.HostnameVerifier;
40 import javax.net.ssl.HttpsURLConnection;
41 import javax.net.ssl.KeyManager;
42 import javax.net.ssl.KeyManagerFactory;
43 import javax.net.ssl.SSLContext;
44 import javax.net.ssl.SSLSession;
45 import javax.net.ssl.SSLSocketFactory;
46 import javax.net.ssl.TrustManager;
47 import javax.net.ssl.TrustManagerFactory;
48 import javax.net.ssl.X509KeyManager;
49 import javax.net.ssl.X509TrustManager;
51 import org.onap.aaf.cadi.Access;
52 import org.onap.aaf.cadi.CadiException;
53 import org.onap.aaf.cadi.Access.Level;
54 import org.onap.aaf.cadi.util.MaskFormatException;
55 import org.onap.aaf.cadi.util.NetMask;
56 import org.onap.aaf.cadi.util.Split;
58 public class SecurityInfo {
59 private static final String SECURITY_ALGO = "RSA";
60 private static final String HTTPS_PROTOCOLS = "https.protocols";
61 private static final String JDK_TLS_CLIENT_PROTOCOLS = "jdk.tls.client.protocols";
62 private static final String INITIALIZING_ERR_FMT = "Error initializing %s: %s";
63 private static final String LOADED_FROM_CADI_PROPERTIES = "%s loaded from CADI Properties";
64 private static final String LOADED_FROM_SYSTEM_PROPERTIES = "%s loaded from System Properties";
66 public static final String SSL_KEY_MANAGER_FACTORY_ALGORITHM;
68 private SSLSocketFactory socketFactory;
69 private X509KeyManager[] x509KeyManager;
70 private X509TrustManager[] x509TrustManager;
71 public final String defaultAlias;
72 public final String defaultClientAlias;
73 private NetMask[] trustMasks;
74 private SSLContext context;
75 private HostnameVerifier maskHV;
76 public final Access access;
78 // Change Key Algorithms for IBM's VM. Could put in others, if needed.
80 if ("IBM Corporation".equalsIgnoreCase(System.getProperty("java.vm.vendor"))) {
81 SSL_KEY_MANAGER_FACTORY_ALGORITHM = "IbmX509";
83 SSL_KEY_MANAGER_FACTORY_ALGORITHM = "SunX509";
88 public SecurityInfo(final Access access) throws CadiException {
92 // reuse DME2 Properties for convenience if specific Properties don't exist
94 msgHelp = String.format(INITIALIZING_ERR_FMT,"Keystore", access.getProperty(Config.CADI_KEYSTORE, ""));
95 initializeKeyManager();
97 msgHelp = String.format(INITIALIZING_ERR_FMT,"Truststore", access.getProperty(Config.CADI_TRUSTSTORE, ""));
98 initializeTrustManager();
100 String str = access.getProperty(Config.CADI_ALIAS, null);
101 if(str==null || str.isEmpty()) {
107 str = access.getProperty(Config.CADI_CLIENT_ALIAS, null);
109 defaultClientAlias = defaultAlias;
110 } else if(str.isEmpty()) {
111 // intentionally off, i.e. cadi_client_alias=
112 defaultClientAlias = null;
114 defaultClientAlias = str;
117 msgHelp = String.format(INITIALIZING_ERR_FMT,"Trustmasks", access.getProperty(Config.CADI_TRUST_MASKS, ""));
118 initializeTrustMasks();
120 msgHelp = String.format(INITIALIZING_ERR_FMT,"HTTP Protocols", "access properties");
121 setHTTPProtocols(access);
123 msgHelp = String.format(INITIALIZING_ERR_FMT,"Context", "TLS");
124 context = SSLContext.getInstance("TLS");
125 context.init(x509KeyManager, x509TrustManager, null);
126 SSLContext.setDefault(context);
127 socketFactory = context.getSocketFactory();
128 } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException | CertificateException | UnrecoverableKeyException | IOException e) {
129 throw new CadiException(msgHelp,e);
133 public static void setHTTPProtocols(Access access) {
134 String httpsProtocols = System.getProperty(Config.HTTPS_PROTOCOLS);
135 if(httpsProtocols!=null) {
136 access.printf(Level.INIT, LOADED_FROM_SYSTEM_PROPERTIES, HTTPS_PROTOCOLS);
138 httpsProtocols = access.getProperty(Config.HTTPS_PROTOCOLS,null);
139 if(httpsProtocols!=null) {
140 access.printf(Level.INIT, LOADED_FROM_CADI_PROPERTIES, HTTPS_PROTOCOLS);
142 httpsProtocols = access.getProperty(HTTPS_PROTOCOLS, Config.HTTPS_PROTOCOLS_DEFAULT);
143 access.printf(Level.INIT, "%s set by %s in CADI Properties",Config.HTTPS_PROTOCOLS,Config.CADI_PROTOCOLS);
145 // This needs to be set when people do not.
146 System.setProperty(HTTPS_PROTOCOLS, httpsProtocols);
148 String httpsClientProtocols = System.getProperty(JDK_TLS_CLIENT_PROTOCOLS,null);
149 if(httpsClientProtocols!=null) {
150 access.printf(Level.INIT, LOADED_FROM_SYSTEM_PROPERTIES, JDK_TLS_CLIENT_PROTOCOLS);
152 httpsClientProtocols = access.getProperty(Config.HTTPS_CLIENT_PROTOCOLS, null);
153 if(httpsClientProtocols!=null) {
154 access.printf(Level.INIT, LOADED_FROM_CADI_PROPERTIES, Config.HTTPS_CLIENT_PROTOCOLS);
156 httpsClientProtocols = Config.HTTPS_PROTOCOLS_DEFAULT;
157 access.printf(Level.INIT, "%s set from %s",Config.HTTPS_CLIENT_PROTOCOLS, "Default Protocols");
159 System.setProperty(JDK_TLS_CLIENT_PROTOCOLS, httpsClientProtocols);
166 public SSLSocketFactory getSSLSocketFactory() {
167 return socketFactory;
170 public SSLContext getSSLContext() {
177 public X509KeyManager[] getKeyManagers() {
178 return x509KeyManager;
181 public void checkClientTrusted(X509Certificate[] certarr) throws CertificateException {
182 for (X509TrustManager xtm : x509TrustManager) {
183 xtm.checkClientTrusted(certarr, SECURITY_ALGO);
187 public void checkServerTrusted(X509Certificate[] certarr) throws CertificateException {
188 for (X509TrustManager xtm : x509TrustManager) {
189 xtm.checkServerTrusted(certarr, SECURITY_ALGO);
193 public void setSocketFactoryOn(HttpsURLConnection hsuc) {
194 hsuc.setSSLSocketFactory(socketFactory);
195 if (maskHV != null && !maskHV.equals(hsuc.getHostnameVerifier())) {
196 hsuc.setHostnameVerifier(maskHV);
200 protected void initializeKeyManager() throws CadiException, IOException, NoSuchAlgorithmException, KeyStoreException, CertificateException, UnrecoverableKeyException {
201 String keyStore = access.getProperty(Config.CADI_KEYSTORE, null);
204 } else if (!new File(keyStore).exists()) {
205 throw new CadiException(keyStore + " does not exist");
208 String keyStorePasswd = access.getProperty(Config.CADI_KEYSTORE_PASSWORD, null);
209 keyStorePasswd = (keyStorePasswd == null) ? null : access.decrypt(keyStorePasswd, false);
210 if (keyStore == null || keyStorePasswd == null) {
211 x509KeyManager = new X509KeyManager[0];
215 String keyPasswd = access.getProperty(Config.CADI_KEY_PASSWORD, null);
216 keyPasswd = (keyPasswd == null) ? keyStorePasswd : access.decrypt(keyPasswd, false);
218 KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(SSL_KEY_MANAGER_FACTORY_ALGORITHM);
220 ArrayList<X509KeyManager> keyManagers = new ArrayList<>();
222 for (String ksname : Split.splitTrim(',', keyStore)) {
223 String keystoreFormat;
224 if (ksname.endsWith(".p12") || ksname.endsWith(".pkcs12")) {
225 keystoreFormat = "PKCS12";
227 keystoreFormat = "JKS";
230 file = new File(ksname);
232 FileInputStream fis = new FileInputStream(file);
234 KeyStore ks = KeyStore.getInstance(keystoreFormat);
235 ks.load(fis, keyStorePasswd.toCharArray());
236 keyManagerFactory.init(ks, keyPasswd.toCharArray());
242 for (KeyManager keyManager : keyManagerFactory.getKeyManagers()) {
243 if (keyManager instanceof X509KeyManager) {
244 keyManagers.add((X509KeyManager)keyManager);
247 x509KeyManager = new X509KeyManager[keyManagers.size()];
248 keyManagers.toArray(x509KeyManager);
251 protected void initializeTrustManager() throws NoSuchAlgorithmException, CertificateException, IOException, KeyStoreException, CadiException {
252 String trustStore = access.getProperty(Config.CADI_TRUSTSTORE, null);
253 if(trustStore==null) {
255 } else if(!new File(trustStore).exists()) {
256 throw new CadiException(trustStore + " does not exist");
259 String trustStorePasswd = access.getProperty(Config.CADI_TRUSTSTORE_PASSWORD, null);
260 trustStorePasswd = (trustStorePasswd == null ) ? "changeit"/*defacto Java Trust Pass*/ : access.decrypt(trustStorePasswd, false);
262 TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(SSL_KEY_MANAGER_FACTORY_ALGORITHM);
264 for (String trustStoreName : Split.splitTrim(',',trustStore)) {
265 file = new File(trustStoreName);
267 FileInputStream fis = new FileInputStream(file);
269 KeyStore ts = KeyStore.getInstance("JKS");
270 ts.load(fis, trustStorePasswd.toCharArray());
271 trustManagerFactory.init(ts);
278 TrustManager trustManagers[] = trustManagerFactory.getTrustManagers();
279 if (trustManagers == null || trustManagers.length == 0) {
283 x509TrustManager = new X509TrustManager[trustManagers.length];
284 for (int i = 0; i < trustManagers.length; ++i) {
286 x509TrustManager[i] = (X509TrustManager)trustManagers[i];
287 } catch (ClassCastException e) {
288 access.log(Level.WARN, "Non X509 TrustManager", x509TrustManager[i].getClass().getName(), "skipped in SecurityInfo");
293 protected void initializeTrustMasks() throws AccessException {
294 String tips = access.getProperty(Config.CADI_TRUST_MASKS, null);
299 access.log(Level.INIT, "Explicitly accepting valid X509s from", tips);
300 String[] ipsplit = Split.splitTrim(',', tips);
301 trustMasks = new NetMask[ipsplit.length];
302 for (int i = 0; i < ipsplit.length; ++i) {
304 trustMasks[i] = new NetMask(ipsplit[i]);
305 } catch (MaskFormatException e) {
306 throw new AccessException("Invalid IP Mask in " + Config.CADI_TRUST_MASKS, e);
310 final HostnameVerifier origHV = HttpsURLConnection.getDefaultHostnameVerifier();
311 maskHV = new HostnameVerifier() {
313 public boolean verify(final String urlHostName, final SSLSession session) {
315 // This will pick up /etc/host entries as well as DNS
316 InetAddress ia = InetAddress.getByName(session.getPeerHost());
317 for (NetMask tmask : trustMasks) {
318 if (tmask.isInNet(ia.getHostAddress())) {
322 } catch (UnknownHostException e) {
323 // It's ok. do normal Verify
325 return origHV.verify(urlHostName, session);
328 HttpsURLConnection.setDefaultHostnameVerifier(maskHV);