| package org.apache.synapse.securevault.keystore; |
| |
| import org.apache.commons.codec.binary.Base64; |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| import org.apache.synapse.securevault.IKeyStoreLoader; |
| import org.apache.synapse.securevault.SecureVaultException; |
| |
| import java.io.*; |
| import java.security.*; |
| import java.security.cert.Certificate; |
| import java.security.cert.CertificateException; |
| import java.security.cert.CertificateFactory; |
| import java.security.spec.InvalidKeySpecException; |
| import java.security.spec.PKCS8EncodedKeySpec; |
| |
| /** |
| * Constructs a KeyStore instance of type JKS from a pkcs8 private key and certificate. |
| */ |
| public class PKCS8KeyStoreLoader implements IKeyStoreLoader { |
| |
| private static Log log = LogFactory.getLog(PKCS8KeyStoreLoader.class); |
| private String pkPath; |
| private String certPath; |
| private String keyPassword; |
| private String entryAlias; |
| |
| private static final String HEADER = "-----BEGIN PRIVATE KEY-----\n"; |
| private static final String FOOTER = "-----END PRIVATE KEY-----"; |
| |
| /** |
| * constructs an instance of KeyStoreLoader |
| * |
| * @param pkcs8PrivateKeyPath - path to a private key file. Key must be in PKCS8 format, |
| * PEM encoded and unencrypted. |
| * @param certFilePath - path to certificate file. File must be PEM encoded. |
| * @param keyPass - password to secure the private key within the keystore. |
| * This will be required later to retrieve the private key |
| * back from the keystore. |
| * @param entryAlias - alias for the given entry within the keystore. |
| */ |
| public PKCS8KeyStoreLoader(String pkcs8PrivateKeyPath, String certFilePath, |
| String keyPass, |
| String entryAlias) { |
| pkPath = pkcs8PrivateKeyPath; |
| certPath = certFilePath; |
| keyPassword = keyPass; |
| this.entryAlias = entryAlias; |
| } |
| |
| /** |
| * Returns a JKS keyStore from the given private key, certificate path, key password and alias. |
| */ |
| public KeyStore getKeyStore() { |
| |
| File file = new File(pkPath); |
| if (!file.exists()) { |
| if (log.isDebugEnabled()) { |
| log.debug("There is no private key in the given path : " + pkPath); |
| } |
| return null; |
| } |
| |
| File certFile = new File(certPath); |
| if (!certFile.exists()) { |
| if (log.isDebugEnabled()) { |
| log.debug("There is no certificate in the given path : " + certPath); |
| } |
| return null; |
| } |
| |
| try { |
| |
| if (log.isDebugEnabled()) { |
| log.debug("Reading a private key(unencrypted) from given path : " + pkPath); |
| } |
| |
| FileInputStream fileInputStream = new FileInputStream(file); |
| BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream); |
| ByteArrayOutputStream outStream = new ByteArrayOutputStream(); |
| |
| byte[] buffer = new byte[1024]; |
| int length; |
| try { |
| while ((length = bufferedInputStream.read(buffer)) != -1) { |
| outStream.write(buffer, 0, length); |
| } |
| } catch (IOException e) { |
| handleException("IOError reading from file : " + pkPath, e); |
| } finally { |
| try { |
| bufferedInputStream.close(); |
| fileInputStream.close(); |
| outStream.close(); |
| } catch (IOException ignored) { |
| |
| } |
| } |
| |
| if (log.isDebugEnabled()) { |
| log.debug("Creating a private key in PKCS8Encoded using given" + |
| " (unencrypted) RSA private key "); |
| } |
| PrivateKey key = createPrivateKey(outStream.toByteArray()); |
| |
| if (log.isDebugEnabled()) { |
| log.debug("Generating a X509 certificate form given certificate file"); |
| } |
| |
| FileInputStream certInputStream = new FileInputStream(certFile); |
| BufferedInputStream certBufferedInputStream = new BufferedInputStream(certInputStream); |
| |
| CertificateFactory certFactory = CertificateFactory.getInstance("X509"); |
| Certificate cert = certFactory.generateCertificate(certBufferedInputStream); |
| |
| certBufferedInputStream.close(); |
| certInputStream.close(); |
| |
| |
| if (log.isDebugEnabled()) { |
| log.debug("Creating a KeyStore instance of type JKS from a" + |
| " PKCS8 private key and X509 certificate"); |
| } |
| |
| KeyStore newKeyStore = KeyStore.getInstance("JKS"); |
| newKeyStore.load(null, null); |
| |
| newKeyStore.setCertificateEntry("server Cert", cert); |
| |
| Certificate[] certChain = new Certificate[1]; |
| certChain[0] = cert; |
| |
| newKeyStore.setKeyEntry(entryAlias, key, keyPassword.toCharArray(), certChain); |
| |
| return newKeyStore; |
| } catch (FileNotFoundException e) { |
| handleException("IOError", e); |
| } catch (IOException e) { |
| handleException("IOError", e); |
| } catch (NoSuchAlgorithmException e) { |
| handleException("Error creating KeyStore", e); |
| } catch (KeyStoreException e) { |
| handleException("Error creating KeyStore", e); |
| } catch (CertificateException e) { |
| handleException("Error creating KeyStore", e); |
| } |
| return null; |
| |
| |
| } |
| |
| |
| /** |
| * Takes the (unencrypted) RSA private key in pkcs8 format, and creates a private key out of it |
| * |
| * @param keyBytes Byte Array of the private key |
| * @return PKCS8Encoded PrivateKey |
| */ |
| private PrivateKey createPrivateKey(byte[] keyBytes) { |
| |
| int dataStart = HEADER.length(); |
| int dataEnd = keyBytes.length - FOOTER.length() - 1; |
| int dataLength = dataEnd - dataStart; |
| byte[] keyContent = new byte[dataLength]; |
| |
| System.arraycopy(keyBytes, dataStart, keyContent, 0, dataLength); |
| |
| PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec( |
| new Base64().decode(keyContent)); |
| try { |
| KeyFactory keyFactory = KeyFactory.getInstance("RSA"); |
| return keyFactory.generatePrivate(pkcs8EncodedKeySpec); |
| } catch (NoSuchAlgorithmException e) { |
| handleException("Error getting a KeyFactory instance", e); |
| } catch (InvalidKeySpecException e) { |
| handleException("Error generating a private key", e); |
| } |
| return null; |
| } |
| |
| private void handleException(String msg, Exception e) { |
| log.error(msg, e); |
| throw new SecureVaultException(msg, e); |
| } |
| } |