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 String str = access.getProperty(Config.CADI_ALIAS, null);
95 if(str==null || str.isEmpty()) {
101 str = access.getProperty(Config.CADI_CLIENT_ALIAS, null);
103 defaultClientAlias = defaultAlias;
104 } else if(str.isEmpty()) {
105 // intentionally off, i.e. cadi_client_alias=
106 defaultClientAlias = null;
108 defaultClientAlias = str;
111 msgHelp = String.format(INITIALIZING_ERR_FMT,"Keystore", access.getProperty(Config.CADI_KEYSTORE, ""));
112 initializeKeyManager();
114 msgHelp = String.format(INITIALIZING_ERR_FMT,"Truststore", access.getProperty(Config.CADI_TRUSTSTORE, ""));
115 initializeTrustManager();
118 msgHelp = String.format(INITIALIZING_ERR_FMT,"Trustmasks", access.getProperty(Config.CADI_TRUST_MASKS, ""));
119 initializeTrustMasks();
121 msgHelp = String.format(INITIALIZING_ERR_FMT,"HTTP Protocols", "access properties");
122 setHTTPProtocols(access);
124 msgHelp = String.format(INITIALIZING_ERR_FMT,"Context", "TLS");
125 context = SSLContext.getInstance("TLS");
126 context.init(x509KeyManager, x509TrustManager, null);
127 SSLContext.setDefault(context);
128 socketFactory = context.getSocketFactory();
129 } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException | CertificateException | UnrecoverableKeyException | IOException e) {
130 throw new CadiException(msgHelp,e);
134 public static void setHTTPProtocols(Access access) {
135 String httpsProtocols = System.getProperty(Config.HTTPS_PROTOCOLS);
136 if(httpsProtocols!=null) {
137 access.printf(Level.INIT, LOADED_FROM_SYSTEM_PROPERTIES, HTTPS_PROTOCOLS);
139 httpsProtocols = access.getProperty(Config.HTTPS_PROTOCOLS,null);
140 if(httpsProtocols!=null) {
141 access.printf(Level.INIT, LOADED_FROM_CADI_PROPERTIES, HTTPS_PROTOCOLS);
143 httpsProtocols = access.getProperty(HTTPS_PROTOCOLS, Config.HTTPS_PROTOCOLS_DEFAULT);
144 access.printf(Level.INIT, "%s set by %s in CADI Properties",Config.HTTPS_PROTOCOLS,Config.CADI_PROTOCOLS);
146 // This needs to be set when people do not.
147 System.setProperty(HTTPS_PROTOCOLS, httpsProtocols);
149 String httpsClientProtocols = System.getProperty(JDK_TLS_CLIENT_PROTOCOLS,null);
150 if(httpsClientProtocols!=null) {
151 access.printf(Level.INIT, LOADED_FROM_SYSTEM_PROPERTIES, JDK_TLS_CLIENT_PROTOCOLS);
153 httpsClientProtocols = access.getProperty(Config.HTTPS_CLIENT_PROTOCOLS, null);
154 if(httpsClientProtocols!=null) {
155 access.printf(Level.INIT, LOADED_FROM_CADI_PROPERTIES, Config.HTTPS_CLIENT_PROTOCOLS);
157 httpsClientProtocols = Config.HTTPS_PROTOCOLS_DEFAULT;
158 access.printf(Level.INIT, "%s set from %s",Config.HTTPS_CLIENT_PROTOCOLS, "Default Protocols");
160 System.setProperty(JDK_TLS_CLIENT_PROTOCOLS, httpsClientProtocols);
167 public SSLSocketFactory getSSLSocketFactory() {
168 return socketFactory;
171 public SSLContext getSSLContext() {
178 public X509KeyManager[] getKeyManagers() {
179 return x509KeyManager;
182 public void checkClientTrusted(X509Certificate[] certarr) throws CertificateException {
183 for (X509TrustManager xtm : x509TrustManager) {
184 xtm.checkClientTrusted(certarr, SECURITY_ALGO);
188 public void checkServerTrusted(X509Certificate[] certarr) throws CertificateException {
189 for (X509TrustManager xtm : x509TrustManager) {
190 xtm.checkServerTrusted(certarr, SECURITY_ALGO);
194 public void setSocketFactoryOn(HttpsURLConnection hsuc) {
195 hsuc.setSSLSocketFactory(socketFactory);
196 if (maskHV != null && !maskHV.equals(hsuc.getHostnameVerifier())) {
197 hsuc.setHostnameVerifier(maskHV);
201 protected void initializeKeyManager() throws CadiException, IOException, NoSuchAlgorithmException, KeyStoreException, CertificateException, UnrecoverableKeyException {
202 String keyStore = access.getProperty(Config.CADI_KEYSTORE, null);
205 } else if (!new File(keyStore).exists()) {
206 throw new CadiException(keyStore + " does not exist");
209 String keyStorePasswd = access.getProperty(Config.CADI_KEYSTORE_PASSWORD, null);
210 keyStorePasswd = (keyStorePasswd == null) ? null : access.decrypt(keyStorePasswd, false);
211 if (keyStore == null || keyStorePasswd == null) {
212 x509KeyManager = new X509KeyManager[0];
216 String keyPasswd = access.getProperty(Config.CADI_KEY_PASSWORD, null);
217 keyPasswd = (keyPasswd == null) ? keyStorePasswd : access.decrypt(keyPasswd, false);
219 KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(SSL_KEY_MANAGER_FACTORY_ALGORITHM);
221 ArrayList<X509KeyManager> keyManagers = new ArrayList<>();
223 for (String ksname : Split.splitTrim(',', keyStore)) {
224 String keystoreFormat;
225 if (ksname.endsWith(".p12") || ksname.endsWith(".pkcs12")) {
226 keystoreFormat = "PKCS12";
228 keystoreFormat = "JKS";
231 file = new File(ksname);
233 FileInputStream fis = new FileInputStream(file);
235 KeyStore ks = KeyStore.getInstance(keystoreFormat);
236 ks.load(fis, keyStorePasswd.toCharArray());
237 keyManagerFactory.init(ks, keyPasswd.toCharArray());
244 StringBuilder sb = null;
245 for (KeyManager keyManager : keyManagerFactory.getKeyManagers()) {
246 if (keyManager instanceof X509KeyManager) {
247 X509KeyManager xkm = (X509KeyManager)keyManager;
248 keyManagers.add(xkm);
249 if(defaultAlias!=null) {
250 sb=new StringBuilder("X509 Chain\n");
251 x509Info(sb,xkm.getCertificateChain(defaultAlias));
253 if(defaultClientAlias!=null && !defaultClientAlias.equals(defaultAlias)) {
255 sb = new StringBuilder();
259 sb.append("X509 Client Chain\n");
260 x509Info(sb,xkm.getCertificateChain(defaultAlias));
264 x509KeyManager = new X509KeyManager[keyManagers.size()];
265 keyManagers.toArray(x509KeyManager);
268 access.log(Level.INIT, sb);
272 private void x509Info(StringBuilder sb, X509Certificate[] chain) {
275 for(X509Certificate x : chain) {
279 sb.append("\n Subject: ");
280 sb.append(x.getSubjectDN());
281 sb.append("\n Issuer : ");
282 sb.append(x.getIssuerDN());
283 sb.append("\n Expires: ");
284 sb.append(x.getNotAfter());
290 protected void initializeTrustManager() throws NoSuchAlgorithmException, CertificateException, IOException, KeyStoreException, CadiException {
291 String trustStore = access.getProperty(Config.CADI_TRUSTSTORE, null);
292 if(trustStore==null) {
294 } else if(!new File(trustStore).exists()) {
295 throw new CadiException(trustStore + " does not exist");
298 String trustStorePasswd = access.getProperty(Config.CADI_TRUSTSTORE_PASSWORD, null);
299 trustStorePasswd = (trustStorePasswd == null ) ? "changeit"/*defacto Java Trust Pass*/ : access.decrypt(trustStorePasswd, false);
301 TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(SSL_KEY_MANAGER_FACTORY_ALGORITHM);
303 for (String trustStoreName : Split.splitTrim(',',trustStore)) {
304 file = new File(trustStoreName);
306 FileInputStream fis = new FileInputStream(file);
308 KeyStore ts = KeyStore.getInstance("JKS");
309 ts.load(fis, trustStorePasswd.toCharArray());
310 trustManagerFactory.init(ts);
317 TrustManager trustManagers[] = trustManagerFactory.getTrustManagers();
318 if (trustManagers == null || trustManagers.length == 0) {
322 x509TrustManager = new X509TrustManager[trustManagers.length];
323 for (int i = 0; i < trustManagers.length; ++i) {
325 x509TrustManager[i] = (X509TrustManager)trustManagers[i];
326 } catch (ClassCastException e) {
327 access.log(Level.WARN, "Non X509 TrustManager", x509TrustManager[i].getClass().getName(), "skipped in SecurityInfo");
332 protected void initializeTrustMasks() throws AccessException {
333 String tips = access.getProperty(Config.CADI_TRUST_MASKS, null);
338 access.log(Level.INIT, "Explicitly accepting valid X509s from", tips);
339 String[] ipsplit = Split.splitTrim(',', tips);
340 trustMasks = new NetMask[ipsplit.length];
341 for (int i = 0; i < ipsplit.length; ++i) {
343 trustMasks[i] = new NetMask(ipsplit[i]);
344 } catch (MaskFormatException e) {
345 throw new AccessException("Invalid IP Mask in " + Config.CADI_TRUST_MASKS, e);
349 final HostnameVerifier origHV = HttpsURLConnection.getDefaultHostnameVerifier();
350 maskHV = new HostnameVerifier() {
352 public boolean verify(final String urlHostName, final SSLSession session) {
354 // This will pick up /etc/host entries as well as DNS
355 InetAddress ia = InetAddress.getByName(session.getPeerHost());
356 for (NetMask tmask : trustMasks) {
357 if (tmask.isInNet(ia.getHostAddress())) {
361 } catch (UnknownHostException e) {
362 // It's ok. do normal Verify
364 return origHV.verify(urlHostName, session);
367 HttpsURLConnection.setDefaultHostnameVerifier(maskHV);