/* * 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); } }