/*
* Copyright (c) 2011-2012 ICM Uniwersytet Warszawski All rights reserved.
* See LICENCE file for licensing information.
*/
package eu.emi.security.authn.x509.impl;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.PrivateKey;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import eu.emi.security.authn.x509.helpers.AbstractDelegatingX509Credential;
import eu.emi.security.authn.x509.helpers.AbstractX509Credential;
import eu.emi.security.authn.x509.helpers.PasswordSupplier;
import eu.emi.security.authn.x509.helpers.ReaderInputStream;
import eu.emi.security.authn.x509.impl.CertificateUtils.Encoding;
/**
* Wraps certificate and private key stored in PEM format.
* @author K. Benedyczak
*/
public class PEMCredential extends AbstractDelegatingX509Credential
{
static
{
CertificateUtils.configureSecProvider();
}
/**
* Constructs the object from {@link InputStream} which can be used to read
* a private key and certificate in PEM keystore format, i.e. the file must contain
* both certificates and a private key. See
* {@link CertificateUtils#loadPEMKeystore(InputStream, char[], char[])}
* for details.
*
* @param keystorePath file path with the PEM keystore
* @param keyPasswd Password used to decrypt the key. May be null if the key
* is not encrypted.
* @throws IOException if the stream can not be read
* @throws KeyStoreException if private key can not be parsed or decrypted
* @throws CertificateException if certificate can not be parsed
*/
public PEMCredential(String keystorePath, char[] keyPasswd)
throws IOException, KeyStoreException, CertificateException
{
this(new BufferedInputStream(new FileInputStream(keystorePath)), keyPasswd);
}
/**
* As {@link #PEMCredential(String, char[])} but this version allows for providing
* decryption key only when needed.
* @param keystorePath file path with the PEM keystore
* @param pf object to retrieve password on demand.
* @throws IOException if the stream can not be read
* @throws KeyStoreException if private key can not be parsed or decrypted
* @throws CertificateException if certificate can not be parsed
* @since 1.1.0
*/
public PEMCredential(String keystorePath, PasswordSupplier pf)
throws IOException, KeyStoreException, CertificateException
{
this(new BufferedInputStream(new FileInputStream(keystorePath)), pf);
}
/**
* Constructs the object from {@link InputStream} which can be used to read
* a private key and certificate in PEM keystore format, i.e. the file must contain
* both certificates and a private key. See
* {@link CertificateUtils#loadPEMKeystore(InputStream, char[], char[])}
* for details.
* <p>
* The stream is closed after constructing the object.
* </p>
*
* @param keystoreStream InputStream which can be used to read the PEM keystore
* @param keyPasswd Password used to decrypt the key. May be null if the key
* is not encrypted.
* @throws IOException if the stream can not be read
* @throws KeyStoreException if private key can not be parsed or decrypted
* @throws CertificateException if certificate can not be parsed
*/
public PEMCredential(InputStream keystoreStream, char[] keyPasswd)
throws IOException, KeyStoreException, CertificateException
{
this(keystoreStream, CertificateUtils.getPF(keyPasswd));
}
/**
* As {@link #PEMCredential(InputStream, char[])} but this version allows for providing
* decryption key only when needed.
*
* @param keystoreStream InputStream which can be used to read the PEM keystore
* @param pf object to retrieve password on demand.
* @throws IOException if the stream can not be read
* @throws KeyStoreException if private key can not be parsed or decrypted
* @throws CertificateException if certificate can not be parsed
* @since 1.1.0
*/
public PEMCredential(InputStream keystoreStream, PasswordSupplier pf)
throws IOException, KeyStoreException, CertificateException
{
KeyStore ks = CertificateUtils.loadPEMKeystore(keystoreStream, pf,
AbstractX509Credential.KEY_PASSWD);
X509Certificate[] certChain = CertificateUtils.convertToX509Chain(
ks.getCertificateChain(CertificateUtils.DEFAULT_KEYSTORE_ALIAS));
PrivateKey pk;
try
{
pk = (PrivateKey)ks.getKey(CertificateUtils.DEFAULT_KEYSTORE_ALIAS,
AbstractX509Credential.KEY_PASSWD);
} catch (Exception e)
{
throw new RuntimeException("Can't get key from the generated keystore, bug?", e);
}
delegate = new KeyAndCertCredential(pk, certChain);
}
/**
* Constructs the object from two {@link InputStream}s which can be used to read
* a private key and certificate in PEM format.
* <p>
* The streams are closed after constructing the object.
* </p>
*
* @param privateKeyStream InputStream which can be used to read the private key in PEM format
* @param certificateStream certificate in PEM format InputStream
* @param keyPasswd Password used to decrypt the key. May be null if the key
* is not encrypted.
* @throws IOException if any of the streams can not be read
* @throws KeyStoreException if private key can not be parsed or decrypted
* @throws CertificateException if certificate can not be parsed
*/
public PEMCredential(InputStream privateKeyStream, InputStream certificateStream, char[] keyPasswd)
throws IOException, KeyStoreException, CertificateException
{
this(privateKeyStream, certificateStream, CertificateUtils.getPF(keyPasswd));
}
/**
* As {@link #PEMCredential(InputStream, InputStream, char[])} but password is retrieved on demand.
*
* @param privateKeyStream InputStream which can be used to read the private key in PEM format
* @param certificateStream certificate in PEM format InputStream
* @param pf object to retrieve password on demand.
* @throws IOException if any of the streams can not be read
* @throws KeyStoreException if private key can not be parsed or decrypted
* @throws CertificateException if certificate can not be parsed
* @since 1.1.0
*/
public PEMCredential(InputStream privateKeyStream, InputStream certificateStream, PasswordSupplier pf)
throws IOException, KeyStoreException, CertificateException
{
init(privateKeyStream, certificateStream, pf);
}
/**
* Constructs the object from two {@link Reader}s which can be used to read
* a private key and certificate in PEM format.
* <p>
* The streams are closed after constructing the object.
* </p>
* @param privateKeyReader Reader which can be used to read the PEM private key
* @param certificateReader certificate file Reader
* @param keyPasswd Password used to decrypt the key. May be null if the key
* is not encrypted.
* @throws IOException if any of files can not be read
* @throws KeyStoreException if private key can not be parsed or decrypted
* @throws CertificateException if certificate can not be parsed
*/
public PEMCredential(Reader privateKeyReader, Reader certificateReader, char[] keyPasswd)
throws IOException, KeyStoreException, CertificateException
{
this(privateKeyReader, certificateReader, CertificateUtils.getPF(keyPasswd));
}
/**
* As {@link #PEMCredential(Reader, Reader, char[])} but password is retrieved on demand.
*
* @param privateKeyReader Reader which can be used to read the PEM private key
* @param certificateReader certificate file Reader
* @param pf object to retrieve password on demand.
* @throws IOException if any of files can not be read
* @throws KeyStoreException if private key can not be parsed or decrypted
* @throws CertificateException if certificate can not be parsed
* @since 1.1.0
*/
public PEMCredential(Reader privateKeyReader, Reader certificateReader, PasswordSupplier pf)
throws IOException, KeyStoreException, CertificateException
{
InputStream pkIs = new ReaderInputStream(privateKeyReader, CertificateUtils.ASCII);
InputStream ccIs = new ReaderInputStream(certificateReader, CertificateUtils.ASCII);
init(pkIs, ccIs, pf);
}
/**
* Constructs the object from two files containing private key and certificate in
* PEM format.
* <p>
* The streams are closed after constructing the object.
* </p>
*
* @param keyPath private key file path
* @param certificatePath certificate file path
* @param keyPasswd Password used to decrypt the key. May be null if the key
* is not encrypted.
* @throws IOException if any of files can not be read
* @throws KeyStoreException if private key can not be parsed or decrypted
* @throws CertificateException if certificate can not be parsed
*/
public PEMCredential(String keyPath, String certificatePath, char[] keyPasswd)
throws IOException, KeyStoreException, CertificateException
{
this(new FileInputStream(keyPath), new FileInputStream(certificatePath), keyPasswd);
}
private void init(InputStream privateKeyStream, InputStream certificateStream,
PasswordSupplier pf) throws IOException, KeyStoreException, CertificateException
{
X509Certificate []chain = CertificateUtils.loadCertificateChain(
certificateStream, Encoding.PEM);
PrivateKey pk = CertificateUtils.loadPEMPrivateKey(privateKeyStream, pf);
privateKeyStream.close();
delegate = new KeyAndCertCredential(pk, chain);
}
}