/*
* X509SecurityInfo.java
*
* Created on Mar 1, 2010, 11:52:56 AM
*
* Description: Provides a container for X509 security information.
*
* Copyright (C) Mar 1, 2010 reed.
*
* This program is free software; you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.texai.x509;
import java.security.KeyStore;
import java.security.KeyStore.PasswordProtection;
import java.security.KeyStore.PrivateKeyEntry;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.UnrecoverableEntryException;
import java.security.cert.CertPath;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.X509KeyManager;
import net.jcip.annotations.Immutable;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.texai.util.TexaiException;
/** Provides a container for X509 security information.
*
* @author reed
*/
@Immutable
public final class X509SecurityInfo {
/** the key store containing the trusted Texai X.509 certificate */
private final KeyStore trustStore;
/** the key manager factory */
private final KeyManagerFactory keyManagerFactory;
/** the key store */
private final KeyStore keyStore;
/** the private key entry for a certain alias id that contains the X.509 certificate and private key for that id */
private final PrivateKeyEntry privateKeyEntry;
/** Constructs a new X509SecurityInfo instance.
*
* @param trustStore the key store containing the trusted Texai X.509 certificate
* @param keyStore the key store containing the peer's X.509 certificate chain
* @param keyStorePassword the password to the key store
* @param alias the private key entry alias
*/
public X509SecurityInfo(
final KeyStore trustStore,
final KeyStore keyStore,
final char[] keyStorePassword,
final String alias) {
//Preconditions
assert trustStore != null : "trustStore must not be null";
assert keyStore != null : "keyStore must not be null";
assert keyStorePassword != null : "keyStorePassword must not be null";
this.trustStore = trustStore;
this.keyStore = keyStore;
try {
keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
keyManagerFactory.init(keyStore, keyStorePassword);
if (alias == null) {
privateKeyEntry = null;
} else {
privateKeyEntry = (PrivateKeyEntry) keyStore.getEntry(alias, new PasswordProtection(keyStorePassword));
assert privateKeyEntry != null : "privateKeyEntry not found for alias " + alias;
}
} catch (NoSuchAlgorithmException | KeyStoreException | UnrecoverableEntryException ex) {
throw new TexaiException(ex);
}
}
/** Gets the key store containing the trusted Texai X.509 certificate.
*
* @return the trustStore
*/
public KeyStore getTrustStore() {
return trustStore;
}
/** Gets the key store.
*
* @return the key store
*/
public KeyStore getKeyStore() {
return keyStore;
}
/** Returns one key manager for each type of key material.
*
* @return the key managers
*/
public KeyManager[] getKeyManagers() {
return keyManagerFactory.getKeyManagers();
}
/** Returns the private key.
*
* @return the private key
*/
public PrivateKey getPrivateKey() {
if (privateKeyEntry == null) {
// for unit tests
final X509KeyManager x509KeyManager = (X509KeyManager) getKeyManagers()[0];
return x509KeyManager.getPrivateKey(X509Utils.ENTRY_ALIAS);
} else {
return privateKeyEntry.getPrivateKey();
}
}
/** Returns the certificate chain.
*
* @return the certificate chain
*/
public X509Certificate[] getCertificateChain() {
final X509Certificate[] certificateChain;
if (privateKeyEntry == null) {
// for unit tests
final X509KeyManager x509KeyManager = (X509KeyManager) getKeyManagers()[0];
certificateChain = x509KeyManager.getCertificateChain(X509Utils.ENTRY_ALIAS);
} else {
certificateChain = (X509Certificate[]) privateKeyEntry.getCertificateChain();
}
//Postconditions
assert certificateChain != null;
assert certificateChain.length >= 2;
return certificateChain;
}
/** Returns the X.509 certificate.
*
* @return the X.509 certificate
*/
public X509Certificate getX509Certificate() {
return getCertificateChain()[0];
}
/** Returns the certificate path.
*
* @return the certificate path
*/
public CertPath getCertPath() {
final X509Certificate[] certificateChain = getCertificateChain();
final CertificateFactory certificateFactory;
try {
certificateFactory = CertificateFactory.getInstance("X.509", X509Utils.BOUNCY_CASTLE_PROVIDER);
final List<Certificate> certificateList = new ArrayList<>();
// the certificate path does not include the trust anchor which terminates the certificate chain
for (int i = 0; i < certificateChain.length - 1; i++) {
certificateList.add(certificateChain[i]);
}
return certificateFactory.generateCertPath(certificateList);
} catch (CertificateException | NoSuchProviderException ex) {
throw new TexaiException(ex);
}
}
/** Returns a string representation of this object.
*
* @return a string representation of this object
*/
@Override
public String toString() {
return "[X509 certificate information for ...\n" + getX509Certificate().toString() + "]";
}
/** Returns whether the X509 certificate can be used for digital signing.
*
* @return the X509 certificate can be used for digital signing
*/
public boolean isDigitialSigniatureCertificate() {
return X509Utils.hasKeyUsage(getCertificateChain()[0], KeyUsage.digitalSignature);
}
}