/*********************************************************************************** * * Copyright (c) 2015 Kamil Baczkowicz * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Eclipse Distribution License v1.0 which accompany this distribution. * * The Eclipse Public License is available at * http://www.eclipse.org/legal/epl-v10.html * * The Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * * Kamil Baczkowicz - initial API and implementation and/or initial documentation * */ package pl.baczkowicz.spy.security; import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.security.KeyFactory; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.Provider; import java.security.UnrecoverableKeyException; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.TrustManagerFactory; import org.bouncycastle.util.io.pem.PemReader; import pl.baczkowicz.spy.common.generated.KeyStoreTypeEnum; import pl.baczkowicz.spy.files.FileUtils; /** * Utility class for handling SSL/TLS connections. */ public class SecureSocketUtils { private final static String ALGORITHM = "RSA"; /** * Loads a PEM file from the specified location. * * @param file Location of the file to load * * @return Content of the PEM file * * @throws IOException Thrown when cannot read the file */ public static byte[] loadPemFile(final String file) throws IOException { final PemReader pemReader = new PemReader(new FileReader(file)); final byte[] content = pemReader.readPemObject().getContent(); pemReader.close(); return content; } /** * Loads a key file from the specified location. * * @param file Location of the file to load * * @return Content of the key file * * @throws IOException Thrown when cannot read the file */ public static byte[] loadBinaryFile(final String file) throws IOException { final FileInputStream inputStream = new FileInputStream(file); final byte[] data = new byte[inputStream.available()]; inputStream.read(data); inputStream.close(); return data; } /** * Loads a private key from the specified location. */ public static PrivateKey loadPrivateKeyFromPemFile(final String keyFile) throws IOException, InvalidKeySpecException, NoSuchAlgorithmException { final PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(loadPemFile(keyFile)); final PrivateKey privateKey = KeyFactory.getInstance(ALGORITHM).generatePrivate(privateKeySpec); return privateKey; } /** * Loads a private key from the specified location. */ public static PrivateKey loadPrivateKeyFromBinaryFile(final String keyFile) throws IOException, InvalidKeySpecException, NoSuchAlgorithmException { final PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(loadBinaryFile(keyFile)); final PrivateKey privateKey = KeyFactory.getInstance(ALGORITHM).generatePrivate(privateKeySpec); return privateKey; } /** * Loads an X509 certificate from the given location. */ public static X509Certificate loadX509Certificate(final String certificateFile) throws IOException, CertificateException { final CertificateFactory cf = CertificateFactory.getInstance("X.509"); final InputStream inputStream = FileUtils.loadFileByName(certificateFile); final X509Certificate certificate = (X509Certificate) cf.generateCertificate(inputStream); inputStream.close(); return certificate; } /** * Creates a trust manager factory. */ public static TrustManagerFactory getTrustManagerFactory(final String caCertificateFile) throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException { // Load CA certificate final X509Certificate caCertificate = (X509Certificate) loadX509Certificate(caCertificateFile); // CA certificate is used to authenticate server final KeyStore keyStore = getKeyStoreInstance(KeyStoreTypeEnum.DEFAULT); keyStore.load(null, null); keyStore.setCertificateEntry("ca-certificate", caCertificate); final TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(keyStore); return tmf; } /** * Creates a trust manager factory. */ public static TrustManagerFactory getTrustManagerFactory(final String keyStoreFile, final String keyStorePassword, final KeyStoreTypeEnum keyStoreType) throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException { // Load key store final KeyStore keyStore = loadKeystore(keyStoreFile, keyStorePassword, keyStoreType); final TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(keyStore); return tmf; } /** * Creates a key manager factory using a key store. */ public static KeyManagerFactory getKeyManagerFactory(final String keyStoreFile, final String keyStorePassword, final String keyPassword, final KeyStoreTypeEnum keyStoreType) throws IOException, NoSuchAlgorithmException, KeyStoreException, CertificateException, UnrecoverableKeyException, InvalidKeySpecException { // Load key store final KeyStore keyStore = loadKeystore(keyStoreFile, keyStorePassword, keyStoreType); final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(keyStore, keyPassword.toCharArray()); return kmf; } /** * Creates a key manager factory. */ public static KeyManagerFactory getKeyManagerFactory( final String clientCertificateFile, final String clientKeyFile, final String clientKeyPassword, final boolean pemFormat) throws IOException, NoSuchAlgorithmException, KeyStoreException, CertificateException, UnrecoverableKeyException, InvalidKeySpecException { // Load client certificate final X509Certificate clientCertificate = loadX509Certificate(clientCertificateFile); // Load private client key final PrivateKey privateKey = pemFormat ? loadPrivateKeyFromPemFile(clientKeyFile) : loadPrivateKeyFromBinaryFile(clientKeyFile); // Client key and certificate are sent to server final KeyStore keyStore = getKeyStoreInstance(KeyStoreTypeEnum.DEFAULT); keyStore.load(null, null); keyStore.setCertificateEntry("certificate", clientCertificate); keyStore.setKeyEntry("private-key", privateKey, clientKeyPassword.toCharArray(), new Certificate[] { clientCertificate }); final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(keyStore, clientKeyPassword.toCharArray()); return kmf; } /** * Loads a key store from the specified location and using the given password. */ public static KeyStore loadKeystore(final String keyStoreFile, final String keyStorePassword, final KeyStoreTypeEnum keyStoreType) throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException { final FileInputStream inputStream = new FileInputStream(keyStoreFile); KeyStore keyStore; try { keyStore = getKeyStoreInstance(keyStoreType); keyStore.load(inputStream, keyStorePassword.toCharArray()); } finally { if (inputStream != null) { inputStream.close(); } } return keyStore; } public static KeyStore getKeyStoreInstance(final KeyStoreTypeEnum type) throws KeyStoreException { if (type == null || KeyStoreTypeEnum.DEFAULT.equals(type)) { return KeyStore.getInstance(KeyStore.getDefaultType()); } return KeyStore.getInstance(type.value()); } public static KeyStore getKeyStoreInstance(final KeyStoreTypeEnum type, final Provider provider) throws KeyStoreException { if (type == null || KeyStoreTypeEnum.DEFAULT.equals(type)) { return KeyStore.getInstance(KeyStore.getDefaultType()); } return KeyStore.getInstance(type.value(), provider); } public static KeyStoreTypeEnum getTypeFromFilename(final String filename) { if (filename == null || filename.isEmpty()) { return KeyStoreTypeEnum.DEFAULT; } else if (filename.toLowerCase().endsWith("jks")) { return KeyStoreTypeEnum.JKS; } else if (filename.toLowerCase().endsWith("jceks")) { return KeyStoreTypeEnum.JCEKS; } else if (filename.toLowerCase().endsWith("p12")) { return KeyStoreTypeEnum.PKCS_12; } else if (filename.toLowerCase().endsWith("pfx")) { return KeyStoreTypeEnum.PKCS_12; } else if (filename.toLowerCase().endsWith("bks")) { return KeyStoreTypeEnum.BKS; } else { return KeyStoreTypeEnum.DEFAULT; } } }