/*
* Copyright (C) 2014 Intel Corporation
* All rights reserved.
*/
package com.intel.mtwilson.tls.policy.factory;
import com.intel.dcsg.cpg.codec.Base64Codec;
import com.intel.dcsg.cpg.codec.Base64Util;
import com.intel.dcsg.cpg.codec.ByteArrayCodec;
import com.intel.dcsg.cpg.codec.HexCodec;
import com.intel.dcsg.cpg.codec.HexUtil;
import com.intel.dcsg.cpg.crypto.SimpleKeystore;
import com.intel.dcsg.cpg.io.Resource;
import com.intel.mtwilson.My;
import com.intel.mtwilson.tls.policy.TlsPolicyDescriptor;
import com.intel.mtwilson.tls.policy.TlsProtection;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableEntryException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.codec.binary.Base64;
/**
*
* @author jbuhacoff
*/
public class TlsPolicyFactoryUtil {
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TlsPolicyFactoryUtil.class);
/**
* Utility function to detect if the sample is base64-encoded or hex-encoded
* and return a new instance of the appropriate codec. If the sample
* encoding cannot be detected, this method will return null.
*
* @param sample of data either base64-encoded or hex-encoded
* @return a new codec instance or null if the encoding is not recognized
*/
public static String guessEncodingForData(String sample) {
log.debug("guessEncodingForData: {}", sample);
if( sample == null ) { return null; }
// String printable = sample.replaceAll("[^\\p{Print}]", "");
String printable = sample.replaceAll("["+HexUtil.NON_HEX+"&&"+Base64Util.NON_BASE64+"]", "");
log.debug("guessEncodingForData printable: {}", printable);
String hex = HexUtil.trim(printable);
if (HexUtil.isHex(hex)) {
log.debug("guessEncodingForData hex: {}", hex);
return "hex";
}
String base64 = Base64Util.trim(printable);
if (Base64Util.isBase64(base64)) {
log.debug("guessEncodingForData base64: {}", base64);
return "base64";
}
log.debug("guessEncodingForData failed");
return null;
}
/**
* Utility function to instantiate a codec by name
*
* @param encoding "base64" or "hex" or null
* @return new codec instance or null if the encoding name is null or is not
* recognized
*/
public static ByteArrayCodec getCodecByName(String encoding) {
if (encoding == null) {
return null;
}
switch (encoding) {
case "base64": {
Base64Codec codec = new Base64Codec();
codec.setNormalizeInput(true);
return codec;
}
case "hex": {
HexCodec codec = new HexCodec();
codec.setNormalizeInput(true);
return codec;
}
default:
return null;
}
}
public static String guessAlgorithmForDigest(byte[] hash) {
if (hash.length == 16) {
return "MD5";
}
if (hash.length == 20) {
return "SHA-1";
}
if (hash.length == 32) {
return "SHA-256";
}
if (hash.length == 48) {
return "SHA-384";
}
if (hash.length == 64) {
return "SHA-512";
}
return null;
}
/**
* Utility function to get a sample item from a collection
*
* @param collection
* @return the first item from the collection, or null if the collection is
* empty
*/
public static String getFirst(Collection<String> collection) {
Iterator<String> it = collection.iterator();
if (it.hasNext()) {
return it.next();
}
return null;
}
public static TlsPolicyDescriptor getTlsPolicyDescriptorFromResource(Resource resource) {
return getTlsPolicyDescriptorFromResource(resource, My.configuration().getTlsKeystorePassword());
}
public static TlsPolicyDescriptor getTlsPolicyDescriptorFromResource(Resource resource, String password) {
try {
SimpleKeystore tlsKeystore = new SimpleKeystore(resource, password);
TlsPolicyDescriptor tlsPolicyDescriptor = createTlsPolicyDescriptorFromKeystore(tlsKeystore);
return tlsPolicyDescriptor;
} catch (KeyManagementException e) {
log.warn("Cannot load tls policy descriptor", e);
return null;
}
}
public static TlsPolicyDescriptor createTlsPolicyDescriptorFromKeystore(SimpleKeystore tlsKeystore) {
TlsPolicyDescriptor tlsPolicyDescriptor = new TlsPolicyDescriptor();
tlsPolicyDescriptor.setPolicyType("certificate");
tlsPolicyDescriptor.setProtection(getAllTlsProtection());
ArrayList<String> encodedCertificates = new ArrayList<>();
tlsPolicyDescriptor.setData(encodedCertificates);
ArrayList<X509Certificate> certificates = new ArrayList<>();
certificates.addAll(V1TlsPolicyFactory.getMtWilsonTrustedTlsCertificates());
certificates.addAll(getTrustedTlsCertificatesFromSimpleKeystore(tlsKeystore));
for (X509Certificate cert : certificates) {
log.debug("Adding trusted TLS certs and cacerts: {}", cert.getSubjectX500Principal().getName());
try {
encodedCertificates.add(Base64.encodeBase64String(cert.getEncoded()));
} catch (CertificateEncodingException e) {
throw new IllegalArgumentException("Invalid certificate", e);
}
}
return tlsPolicyDescriptor;
}
public static TlsProtection getAllTlsProtection() {
TlsProtection tlsProtection = new TlsProtection();
tlsProtection.integrity = true;
tlsProtection.encryption = true;
tlsProtection.authentication = true;
tlsProtection.forwardSecrecy = true;
return tlsProtection;
}
public static List<X509Certificate> getTrustedTlsCertificatesFromSimpleKeystore(SimpleKeystore tlsKeystore) {
ArrayList<X509Certificate> list = new ArrayList<>();
if (tlsKeystore != null) {
try {
X509Certificate[] cacerts = tlsKeystore.getTrustedCertificates(SimpleKeystore.CA);
list.addAll(Arrays.asList(cacerts));
X509Certificate[] sslcerts = tlsKeystore.getTrustedCertificates(SimpleKeystore.SSL);
list.addAll(Arrays.asList(sslcerts));
} catch (KeyStoreException | NoSuchAlgorithmException | UnrecoverableEntryException | CertificateEncodingException e) {
log.warn("Cannot load trusted TLS certificates from Mt Wilson 1.x keystore", e);
}
}
return list;
}
}