Java tutorial
/* * Copyright (c) Stichting SURF. All rights reserved. * * A-Select is a trademark registered by SURFnet bv. * * This program is distributed under the A-Select license. * See the included LICENSE file for details. * * If you did not receive a copy of the LICENSE * please contact SURFnet bv. (http://www.surfnet.nl) */ /* * $Id: PKIManager.java,v 1.3 2006/05/03 10:07:31 tom Exp $ * * Changelog: * $log$ * */ package org.aselect.authspserver.authsp.pki; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.UnknownHostException; import java.security.InvalidKeyException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.PublicKey; import java.security.SignatureException; import java.security.cert.CRLException; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CertificateExpiredException; import java.security.cert.CertificateNotYetValidException; import java.security.cert.X509CRL; import java.security.cert.X509Certificate; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; import java.util.Set; import java.util.Vector; import java.util.logging.Level; import org.aselect.authspserver.authsp.pki.crl.handler.ICRLHandler; import org.aselect.authspserver.authsp.pki.crl.handler.file.FileCRLHandler; import org.aselect.authspserver.authsp.pki.crl.handler.html.HttpCRLHandler; import org.aselect.authspserver.authsp.pki.crl.handler.ldap.LDAPCRLHandler; import org.aselect.authspserver.config.AuthSPConfigManager; import org.aselect.authspserver.log.AuthSPSystemLogger; import org.aselect.system.exception.ASelectConfigException; import org.aselect.system.exception.ASelectException; import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.DERObject; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.DERTaggedObject; /** * The PKI Manager. <br> * <br> * <b>Description:</b><br> * Handles all the PKI functionality of the PKI AuthSP <br> * <br> * <b>Concurrency issues:</b> <br> * None <br> * * @author Alfa & Ariss */ public class PKIManager { /** The name of this module, that is used in the system logging. */ public static final String MODULE = "PKIManager"; private AuthSPConfigManager _oConfigManager; private Object _oConfig; private KeyStore _oCaKeystore; private String _sCaKeyStorePassword; private String _sCaKeyStoreLocation; private HashMap _htCRLs; private HashMap _htFailedCRLs; private Thread _tAutoCrlUpdater; private AutoCRLUpdater _oAutoCrlUpdater; private Thread _tCrlRecoverer; private CRLRecoverer _oCrlRecoverer; private Thread _tPkiAdminServer; private PKIAdminServer _oPkiAdminServer; /** The logger that logs system information. */ private AuthSPSystemLogger _systemLogger; private final String _sCrlDistributionPointOid = "2.5.29.31"; /** * Initializes the PKI Manager. * * @param oConfig * necessary configuration * @param oSystemLogger * the systemlogger * @throws ASelectException * if something goes wrong during init. */ public void init(Object oConfig, AuthSPSystemLogger oSystemLogger) throws ASelectException { String sMethod = "init"; _oConfig = oConfig; _systemLogger = oSystemLogger; _htCRLs = new HashMap(); _htFailedCRLs = new HashMap(); Integer intTmp; _oConfigManager = AuthSPConfigManager.getHandle(); _systemLogger.log(Level.INFO, MODULE, sMethod, "PKI mgr init"); try { String sCaValidationCheck = _oConfigManager.getParam(oConfig, "enabled"); if (!sCaValidationCheck.equalsIgnoreCase("false")) { _oConfigManager = AuthSPConfigManager.getHandle(); Object oKeystoreConfig = _oConfigManager.getSection(oConfig, "ca_keystore"); _sCaKeyStoreLocation = _oConfigManager.getParam(oKeystoreConfig, "location"); _sCaKeyStorePassword = _oConfigManager.getParam(oKeystoreConfig, "password"); // Load CA KeyStore loadCaKeyStoreFromPFXFile(_sCaKeyStoreLocation, _sCaKeyStorePassword); // Load CRL's in HashMap loadCRLs(); // init and start auto CRL updater Thread intTmp = new Integer(_oConfigManager.getParam(oConfig, "crl_update_timer")); _oAutoCrlUpdater = new AutoCRLUpdater(intTmp.intValue()); _tAutoCrlUpdater = new Thread(_oAutoCrlUpdater); _tAutoCrlUpdater.start(); // init and start auto CRL Recoverer Thread intTmp = new Integer(_oConfigManager.getParam(oConfig, "crl_recover_timer")); _oCrlRecoverer = new CRLRecoverer(intTmp.intValue()); _tCrlRecoverer = new Thread(_oCrlRecoverer); _tCrlRecoverer.start(); // init and start Admin Server Thread intTmp = new Integer(_oConfigManager.getParam(oConfig, "pki_admin_port")); _oPkiAdminServer = new PKIAdminServer(intTmp.intValue()); _tPkiAdminServer = new Thread(_oPkiAdminServer); _tPkiAdminServer.start(); } } catch (ASelectException e) { _systemLogger.log(Level.SEVERE, MODULE, sMethod, "Failed to initialize " + MODULE, e); throw e; } } /** * Destroy all running threads. */ public void destroy() { String sMethod = "destroy"; _systemLogger.log(Level.INFO, MODULE, sMethod, "Destroy running PKI mgr threads"); if (_oAutoCrlUpdater != null) _oAutoCrlUpdater.destroy(); if (_oCrlRecoverer != null) _oCrlRecoverer.destroy(); if (_oPkiAdminServer != null) _oPkiAdminServer.destroy(); _systemLogger.log(Level.INFO, MODULE, sMethod, "Running PKI mgr threads destroyed"); } /** * Load the CRL's for all the CA's where CRL Checking is enabled. * * @throws ASelectException * the a select exception */ private void loadCRLs() throws ASelectException { _htCRLs = new HashMap(); String sMethod = "loadCRLs"; Enumeration oCaAliases; try { oCaAliases = _oCaKeystore.aliases(); while (oCaAliases.hasMoreElements()) { String sCaAlias = (String) oCaAliases.nextElement(); try { loadCRLForCA(sCaAlias); } catch (ASelectException e) { _htFailedCRLs.put(sCaAlias, e); } } } catch (KeyStoreException e) { _systemLogger.log(Level.SEVERE, MODULE, sMethod, "Unable to read keystore aliases", e); throw new ASelectException(Errors.PKI_INTERNAL_SERVER_ERROR, e); } } /** * Loads the CRL for a particular CA. <br> * <br> * <b>Description:</b> <br> * Loads the CRL for a particular CA. <br> * <br> * <b>Concurrency issues:</b> <br> * None <br> * <br> * <b>Preconditions:</b> <br> * sAlias may not be null. <br> * <br> * <b>Postconditions:</b> <br> * none <br> * * @param sCaAlias * The alias of the CA. * @throws ASelectException * the a select exception */ private void loadCRLForCA(String sCaAlias) throws ASelectException { String sMethod = "loadCRLForCA"; Object oCaConfig; Object oCrlConfig; String sCrlCheck; try { oCaConfig = _oConfigManager.getSection(_oConfig, "ca", "alias=" + sCaAlias); oCrlConfig = _oConfigManager.getSection(oCaConfig, "crl_check"); sCrlCheck = _oConfigManager.getParam(oCrlConfig, "enabled"); } catch (ASelectConfigException e) { _systemLogger.log(Level.SEVERE, MODULE, sMethod, "No config found for CA: " + sCaAlias, e); throw e; } if (!sCrlCheck.equalsIgnoreCase("false")) { X509CRL oCrl = null; X509Certificate oCaCert = null; boolean bFoundCrl = false; int i = 0; try { oCaCert = getCA(sCaAlias); } catch (KeyStoreException e) { _systemLogger.log(Level.WARNING, MODULE, sMethod, "Keystore does not contain CA Certificate: " + sCaAlias, e); throw new ASelectException(Errors.PKI_NO_CA_FOUND); } Vector vCrlUrls = getCRLUrls(oCrlConfig, sCaAlias); while (i < vCrlUrls.size() && !bFoundCrl) { String sUrl = (String) vCrlUrls.get(i); X509CRL oTmpCrl = getCRL((sUrl)); if (oTmpCrl != null) { if (validateCrl(oTmpCrl, oCaCert)) { oCrl = oTmpCrl; bFoundCrl = true; } } i++; if (!bFoundCrl) { _systemLogger.log(Level.INFO, MODULE, sMethod, "CA '" + sCaAlias + "' CRL distribution point '" + sUrl + "' failed, trying next distributionpoint."); } } if (!bFoundCrl) { _systemLogger.log(Level.WARNING, MODULE, sMethod, "No CRL Found which is signed by CA: " + sCaAlias); throw new ASelectException(Errors.PKI_NO_CRL_FOUND_FOR_CA); } _htCRLs.put(sCaAlias, oCrl); } } /** * Looks up the certifcate and alias of the CA for a client certificate. <br> * <br> * <b>Description:</b> <br> * Looks up the certifcate of the CA which have signed the client certificate. <br> * <br> * <b>Concurrency issues:</b> <br> * None <br> * <br> * <b>Preconditions:</b> <br> * oCert may not be null <br> * <br> * <b>Postconditions:</b> <br> * None <br> * * @param oCert * the client certificate * @return HashMap containing alias and certificate of CA which signed the client cert. * @throws ASelectException * the a select exception */ public HashMap getTrustedCACertificate(X509Certificate oCert) throws ASelectException { String sMethod = "getTrustedCACertificate"; HashMap htResult = new HashMap(); Certificate oCaCert = null; String sCaAlias = null; Enumeration oKeyAliases = null; boolean bCaCertFound = false; try { oKeyAliases = _oCaKeystore.aliases(); while (oKeyAliases.hasMoreElements() && !bCaCertFound) { sCaAlias = (String) oKeyAliases.nextElement(); oCaCert = _oCaKeystore.getCertificate(sCaAlias); bCaCertFound = validateCertificateIsSignedByCA(oCert, oCaCert); } } catch (KeyStoreException e) { _systemLogger.log(Level.SEVERE, MODULE, sMethod, "Keystore does not contain CA Certificate: " + sCaAlias, e); throw new ASelectException(Errors.PKI_INTERNAL_SERVER_ERROR, e); } if (!bCaCertFound) { _systemLogger.log(Level.WARNING, MODULE, sMethod, "Client Certificate is not signed by a Trusted CA: " + sCaAlias); throw new ASelectException(Errors.PKI_CLIENT_CERT_NOT_NOT_SIGNED_BY_TRUSTED_CA); } htResult.put("caCert", oCaCert); htResult.put("caAlias", sCaAlias); return htResult; } /** * Validates if the provided client certificate is signed by the provided CA cert. <br> * <br> * <b>Description:</b> <br> * Validates if the provided client certificate is signed by the provided CA cert. <br> * <br> * <b>Concurrency issues:</b> <br> * None <br> * <br> * <b>Preconditions:</b> <br> * oClientCert, oCaCert may not be null <br> * <br> * <b>Postconditions:</b> <br> * none <br> * * @param oClientCert * Client certificate * @param oCaCert * CA certificate * @return true if client cert is signed by CA and false otherwise. */ public boolean validateCertificateIsSignedByCA(Certificate oClientCert, Certificate oCaCert) { String sMethod = "validateCertificateIsSignedByCA"; boolean isSignedByCA = true; PublicKey caPublicKey = oCaCert.getPublicKey(); try { oClientCert.verify(caPublicKey); } catch (InvalidKeyException e) { isSignedByCA = false; _systemLogger.log(Level.FINE, MODULE, sMethod, e.getMessage(), e); } catch (CertificateException e) { isSignedByCA = false; _systemLogger.log(Level.FINE, MODULE, sMethod, e.getMessage(), e); } catch (NoSuchAlgorithmException e) { isSignedByCA = false; _systemLogger.log(Level.FINE, MODULE, sMethod, e.getMessage(), e); } catch (NoSuchProviderException e) { isSignedByCA = false; _systemLogger.log(Level.FINE, MODULE, sMethod, e.getMessage(), e); } catch (SignatureException e) { isSignedByCA = false; _systemLogger.log(Level.FINE, MODULE, sMethod, e.getMessage(), e); } return isSignedByCA; } /** * Gets the cA. * * @param sCaAlias * the s ca alias * @return the cA * @throws KeyStoreException * the key store exception */ private X509Certificate getCA(String sCaAlias) throws KeyStoreException { return (X509Certificate) _oCaKeystore.getCertificate(sCaAlias); } /** * Checks if the provided certificate is valid. <br> * <br> * <b>Description:</b> <br> * Checks if the provided certificate is valid yet and not expired. <br> * <br> * <b>Concurrency issues:</b> <br> * None <br> * <br> * <b>Preconditions:</b> <br> * oCert may not be null. <br> * <br> * <b>Postconditions:</b> <br> * None <br> * * @param oCert * the o cert * @throws ASelectException * if cert is not yet valid or expired. */ public void validateCertificateDate(X509Certificate oCert) throws ASelectException { String sMethod = "validateCertificateDate"; try { oCert.checkValidity(); } catch (CertificateExpiredException e) { _systemLogger.log(Level.FINE, MODULE, sMethod, "Certificate expired", e); throw new ASelectException(Errors.PKI_CLIENT_CERT_EXPIRED, e); } catch (CertificateNotYetValidException e) { _systemLogger.log(Level.FINE, MODULE, sMethod, "Certificate not yet valid", e); throw new ASelectException(Errors.PKI_CLIENT_CERT_NOT_YET_VALID, e); } } /** * Validates if the provided CRL is signed by the provided Issuer. <br> * <br> * <b>Description:</b> <br> * Validates if the provided CRL is signed by the provided Issuer. <br> * <br> * <b>Concurrency issues:</b> <br> * None <br> * <br> * <b>Preconditions:</b> <br> * crl and crlIssuerCert may not be null <br> * <br> * <b>Postconditions:</b> <br> * none <br> * * @param crl * The Certificate Revocation List * @param crlIssuerCert * the CRL Issuer * @return true if crl is valid and false otherwise */ public boolean validateCrl(X509CRL crl, X509Certificate crlIssuerCert) { String sMethod = "getValidCrl"; boolean bValidCRL = true; PublicKey oPublicKey = crlIssuerCert.getPublicKey(); try { crl.verify(oPublicKey); } catch (InvalidKeyException e) { _systemLogger.log(Level.FINE, MODULE, sMethod, e.getMessage(), e); bValidCRL = false; } catch (CRLException e) { _systemLogger.log(Level.FINE, MODULE, sMethod, e.getMessage(), e); bValidCRL = false; } catch (NoSuchAlgorithmException e) { _systemLogger.log(Level.FINE, MODULE, sMethod, e.getMessage(), e); bValidCRL = false; } catch (NoSuchProviderException e) { _systemLogger.log(Level.FINE, MODULE, sMethod, e.getMessage(), e); bValidCRL = false; } catch (SignatureException e) { _systemLogger.log(Level.FINE, MODULE, sMethod, e.getMessage(), e); bValidCRL = false; } return bValidCRL; } /** * Checks if a certificate is revoked. <br> * <br> * <b>Description:</b> <br> * Checks if a certificate stands on the CRL <br> * <br> * <b>Concurrency issues:</b> <br> * None <br> * <br> * <b>Preconditions:</b> <br> * sCaAlias and oClientCert may not be null <br> * <br> * <b>Postconditions:</b> <br> * None <br> * * @param sCaAlias * The Alias of the CA. * @param oClientCert * The certificate to be checked * @return true if the certicate is listed on the CRL and false otherwise. * @throws ASelectException * the a select exception */ public boolean isClientCertRevoked(String sCaAlias, X509Certificate oClientCert) throws ASelectException { String sMethod = "isCRLisSignedByCA"; X509CRL oCrl = null; if (!_htCRLs.containsKey(sCaAlias)) { _systemLogger.log(Level.WARNING, MODULE, sMethod, "No Valid CRL Found for CA: " + sCaAlias); throw new ASelectException(Errors.PKI_NO_CRL_FOUND_FOR_CA); } oCrl = (X509CRL) _htCRLs.get(sCaAlias); return oCrl.isRevoked(oClientCert); } /** * Get all defined CRLs for a corresponding CA. <br> * <br> * <b>Description:</b> <br> * Get all defined CRLs for a corresponding CA can be from confiration or from the CA certificate. <br> * <br> * <b>Concurrency issues:</b> <br> * None <br> * <br> * <b>Preconditions:</b> <br> * None <br> * <br> * <b>Postconditions:</b> <br> * None <br> * * @param oCrlConfig * necessary configuration * @param sCaAlias * the ca alias * @return a vector containing URL to CRL files. * @throws ASelectException * the a select exception */ private Vector getCRLUrls(Object oCrlConfig, String sCaAlias) throws ASelectException { String sMethod = "getCRLUrls"; Vector oCrlUrls = null; String sCRLDistrPointLocation; try { Object oCrlDistributionPoints = _oConfigManager.getSection(oCrlConfig, "crl_distributionpoints"); sCRLDistrPointLocation = _oConfigManager.getParam(oCrlDistributionPoints, "location"); if (sCRLDistrPointLocation.equalsIgnoreCase("cacert")) { X509Certificate oCaCert = (X509Certificate) _oCaKeystore.getCertificate(sCaAlias); oCrlUrls = getCrlUrls(oCaCert); } else if (sCRLDistrPointLocation.equalsIgnoreCase("config")) { oCrlUrls = new Vector(); Object oCrlDistributionPoint = _oConfigManager.getSection(oCrlDistributionPoints, "distributionpoint"); while (oCrlDistributionPoint != null) { String sCrlDistributionlocation = _oConfigManager.getParam(oCrlDistributionPoint, "location"); oCrlUrls.add(sCrlDistributionlocation); oCrlDistributionPoint = _oConfigManager.getNextSection(oCrlDistributionPoint); } } else { _systemLogger.log(Level.WARNING, MODULE, sMethod, "Config Error: Invalid location specified for CRL distribution points: " + sCaAlias); throw new ASelectConfigException(Errors.PKI_CONFIG_ERROR); } } catch (KeyStoreException e) { _systemLogger.log(Level.WARNING, MODULE, sMethod, "No Certificate found in Keystore for: " + sCaAlias, e); throw new ASelectException(Errors.PKI_INTERNAL_SERVER_ERROR, e); } return oCrlUrls; } /** * Get the CRL File for the given URI. <br> * <br> * <b>Description:</b> <br> * Get the CRL File for the given URI. <br> * <br> * <b>Concurrency issues:</b> <br> * <br> * <br> * <b>Preconditions:</b> <br> * sUri != null <br> * <br> * <b>Postconditions:</b> <br> * None <br> * * @param sUri * the location of the CRL file * @return a CRL */ private X509CRL getCRL(String sUri) { String sMethod = "getCRL"; ICRLHandler oCrlHandler = null; X509CRL oCrl = null; if (sUri.indexOf("http://") >= 0) { oCrlHandler = new HttpCRLHandler(); oCrlHandler.init(_systemLogger); } else if (sUri.indexOf("ldap://") >= 0) { oCrlHandler = new LDAPCRLHandler(); oCrlHandler.init(_systemLogger); } else if (sUri.indexOf("file://") >= 0) { oCrlHandler = new FileCRLHandler(); oCrlHandler.init(_systemLogger); } else { _systemLogger.log(Level.WARNING, MODULE, sMethod, "can't handle supplied CRL uri: " + sUri); } try { oCrl = (X509CRL) oCrlHandler.getCRL(sUri); } catch (ASelectException e) { _systemLogger.log(Level.WARNING, MODULE, sMethod, "sUri: " + e.getMessage()); } return oCrl; } /** * loads the CA certificate from the CA Keystore. <br> * <br> * <b>Description:</b> <br> * loads the CA certificate from the CA Keystore. <br> * <br> * <b>Concurrency issues:</b> <br> * None <br> * <br> * <b>Preconditions:</b> <br> * None <br> * <br> * <b>Postconditions:</b> <br> * None <br> * * @param aFileName * Filename of ca keystore * @param aKeyStorePassword * password for keystore * @throws ASelectException * the a select exception */ private void loadCaKeyStoreFromPFXFile(String aFileName, String aKeyStorePassword) throws ASelectException { String sMethod = "loadCaKeyStoreFromPFXFile"; try { KeyStore oKeyStore = KeyStore.getInstance("JKS"); FileInputStream keyStoreStream = new FileInputStream(aFileName); char[] password = aKeyStorePassword.toCharArray(); oKeyStore.load(keyStoreStream, password); _oCaKeystore = oKeyStore; } catch (KeyStoreException e) { _systemLogger.log(Level.WARNING, MODULE, sMethod, "Failed to initialize JKS Keystore", e); throw new ASelectException(Errors.PKI_INTERNAL_SERVER_ERROR, e); } catch (FileNotFoundException e) { _systemLogger.log(Level.WARNING, MODULE, sMethod, aFileName, e); throw new ASelectException(Errors.PKI_INTERNAL_SERVER_ERROR, e); } catch (IOException e) { _systemLogger.log(Level.WARNING, MODULE, sMethod, aFileName, e); throw new ASelectException(Errors.PKI_INTERNAL_SERVER_ERROR, e); } catch (NoSuchAlgorithmException e) { _systemLogger.log(Level.WARNING, MODULE, sMethod, aFileName, e); throw new ASelectException(Errors.PKI_INTERNAL_SERVER_ERROR, e); } catch (CertificateException e) { _systemLogger.log(Level.WARNING, MODULE, sMethod, aFileName, e); throw new ASelectException(Errors.PKI_INTERNAL_SERVER_ERROR, e); } } /** * Returns the CRL Url located in the (CA) Certificate. <br> * <br> * <b>Description:</b> <br> * Returns the CRL Distribution Points located in the CA Cert. <br> * <br> * <b>Concurrency issues:</b> <br> * None. <br> * <br> * <b>Preconditions:</b> <br> * oCertificate may not be null. <br> * <br> * <b>Postconditions:</b> <br> * None <br> * * @param oCertificate * the Certificate to get the CRL distribution points from. * @return a Vector with CRL urls. * @throws ASelectException * the a select exception */ private Vector getCrlUrls(X509Certificate oCertificate) throws ASelectException { String sMethod = "getCRLUrls"; Vector vOctetValues = new Vector(); Vector vCrlUrls = new Vector(); byte[] baCrlDistributionPoints = oCertificate.getExtensionValue(_sCrlDistributionPointOid); if (baCrlDistributionPoints == null) { _systemLogger.log(Level.WARNING, MODULE, sMethod, "No CRL Distribution Points in Ca Certificate"); throw new ASelectException(Errors.PKI_NO_CRL_DISTR_POINT_IN_CA_CERT); } vOctetValues = getOctetValues(baCrlDistributionPoints); for (int i = 0; i < vOctetValues.size(); i++) { String sUrl = new String((byte[]) vOctetValues.get(i)); vCrlUrls.add(sUrl); } return vCrlUrls; } /** * Return a vector with the octet Values for the binary input. <br> * <br> * <b>Description:</b> <br> * Return a vector with the octet Values for the binary input. <br> * <br> * <b>Concurrency issues:</b> <br> * None <br> * <br> * <b>Preconditions:</b> <br> * None <br> * <br> * <b>Postconditions:</b> <br> * None <br> * * @param baExtensionValue * DER encoded binary input * @return a vector with octet values. * @throws ASelectException * the a select exception */ private Vector getOctetValues(byte[] baExtensionValue) throws ASelectException { return getOctetValues(getDERObject(baExtensionValue)); } /** * private Helper function for DER Decoding. <br> * <br> * * @param baExtensionValue * the ba extension value * @return a DER object * @throws ASelectException * the a select exception */ private DERObject getDERObject(byte[] baExtensionValue) throws ASelectException { String sMethod = "getDERObject"; try { ASN1InputStream oInputStream = new ASN1InputStream(new ByteArrayInputStream(baExtensionValue)); byte[] baExtOctets = ((ASN1OctetString) oInputStream.readObject()).getOctets(); oInputStream = new ASN1InputStream(new ByteArrayInputStream(baExtOctets)); return oInputStream.readObject(); } catch (IOException e) { _systemLogger.log(Level.WARNING, MODULE, sMethod, e.getMessage(), e); throw new ASelectException(Errors.PKI_INTERNAL_SERVER_ERROR, e); } } /** * private Helper function for DER Decoding. <br> * <br> * * @param derObject * the der object * @return a DER object * @throws ASelectException * the a select exception */ private Vector getOctetValues(DERObject derObject) throws ASelectException { String sMethod = "getOctetValues(DERObject derObject)"; Vector vDerValues = new Vector(); if (derObject == null) { _systemLogger.log(Level.WARNING, MODULE, sMethod, "Supplied derObject is null"); throw new ASelectException(Errors.PKI_INTERNAL_SERVER_ERROR); } else if (derObject instanceof DERSequence) { Enumeration enumDerObjects = ((DERSequence) derObject).getObjects(); while (enumDerObjects.hasMoreElements()) { DERObject nestedDerObject = (DERObject) enumDerObjects.nextElement(); vDerValues.addAll(getOctetValues(nestedDerObject)); } } else if (derObject instanceof DERTaggedObject) { DERTaggedObject derTaggedObject = (DERTaggedObject) derObject; if (derTaggedObject.isExplicit() && !derTaggedObject.isEmpty()) { DERObject nestedDerObject = derTaggedObject.getObject(); vDerValues = getOctetValues(nestedDerObject); } else { DEROctetString derOctetString = (DEROctetString) derTaggedObject.getObject(); byte[] octetValue = derOctetString.getOctets(); vDerValues = new Vector(); vDerValues.add(octetValue); } } return vDerValues; } class AutoCRLUpdater implements Runnable { private boolean _bActive; private long _lMilliSeconds; /** * Thread that keeps track of the latest CRLs <br> * <br> * <b>Description:</b> <br> * Thread that runs with a configurable interval. Every CRL is checked on its 'NextUpdate' time. If the * 'NextUpdate' time was in the history, a new CRL will be retrieved from one of the CRL distibution points * configured for that particular CA.<br> * If retrieval of the CRL fails, the CA will be added to a 'failed_CRL' list that will be processed by the * <code>CRLRecoverer</code> <br> * <br> * <b>Concurrency issues:</b> <br> * - <br> * <br> * <b>Preconditions:</b> <br> * - <br> * <br> * <b>Postconditions:</b> <br> * - <br> * * @param lSeconds * the interval between the checks. */ public AutoCRLUpdater(long lSeconds) { _lMilliSeconds = lSeconds * 1000; _bActive = true; } /** * tries to auto update the CRL's when they are expired. <br> * <br> * * @see java.lang.Runnable#run() */ public void run() { String sMethod = "AutoCRLUpdater.run"; _systemLogger.log(Level.INFO, MODULE, sMethod, "Run " + _bActive); while (_bActive) { try { _systemLogger.log(Level.FINEST, MODULE, sMethod, "Sleep " + _lMilliSeconds); Thread.sleep(_lMilliSeconds); _systemLogger.log(Level.FINEST, MODULE, sMethod, "Slept " + _lMilliSeconds); Set keys = _htCRLs.keySet(); for (Object oCrlKey : keys) { // Enumeration oCrlKeys = _htCRLs.keys(); // while(oCrlKeys.hasMoreElements()) // { // Object oCrlKey = oCrlKeys.nextElement(); X509CRL oCrl = (X509CRL) _htCRLs.get(oCrlKey); Date oCrlExpirtationDate = oCrl.getNextUpdate(); Date oCurrentDate = new Date(System.currentTimeMillis()); if (oCurrentDate.after(oCrlExpirtationDate)) { try { loadCRLForCA((String) oCrlKey); } catch (ASelectException e) { _htFailedCRLs.put(oCrlKey, e); _htCRLs.remove(oCrlKey); _systemLogger.log(Level.WARNING, MODULE, sMethod, "Reloading CRL for CA with alias: " + oCrlKey.toString() + " failed"); } } } } catch (InterruptedException e) { _systemLogger.log(Level.INFO, MODULE, sMethod, "InterruptedException" + e); } _systemLogger.log(Level.INFO, MODULE, sMethod, "Stopped"); } } /** * Destroys the AutoUpdater. <br> * <br> * <b>Description: </b> <br> * Stop the thread from running. <br> * <br> * <b>Concurrency issues: </b> <br> * -<br> * <br> * <b>Preconditions: </b> <br> * <br> * <br> * <b>Postconditions: </b> <br> * - * * @see java.lang.Thread#destroy() */ public void destroy() { String sMethod = "AutoCRLUpdater.destroy"; _systemLogger.log(Level.INFO, MODULE, sMethod, "---"); _bActive = false; try { // interrupt if sleeping _tAutoCrlUpdater.interrupt(); //Thread.currentThread().interrupt(); } catch (Exception e) { // no logging } } } class CRLRecoverer implements Runnable { private boolean _bActive; private long _lMilliSeconds; /** * Thread that keeps tries to recover failed CRL updates. <br> * <br> * <b>Description:</b> <br> * Thread that runs with a configurable interval. Every expired CRL that could not be updated is put in a list. * This thread runs through the list of failed CRL updates and will keep trying to recover the CRL. <br> * <br> * <b>Concurrency issues:</b> <br> * - <br> * <br> * <b>Preconditions:</b> <br> * - <br> * <br> * <b>Postconditions:</b> <br> * - <br> * * @param lSeconds * the interval between the checks. */ public CRLRecoverer(long lSeconds) { _lMilliSeconds = lSeconds * 1000; _bActive = true; } /** * tries to auto update the CRL's when retrieval failed. <br> * <br> * * @see java.lang.Runnable#run() */ public void run() { String sMethod = "CRLRecoverer.run"; _systemLogger.log(Level.INFO, MODULE, sMethod, "Run " + _bActive); while (_bActive) { try { _systemLogger.log(Level.FINEST, MODULE, sMethod, "Sleep " + _lMilliSeconds); Thread.sleep(_lMilliSeconds); //_systemLogger.log(Level.INFO, MODULE, sMethod, "Slept "+_lMilliSeconds); Set keys = _htFailedCRLs.keySet(); for (Object oFailedCrlKey : keys) { try { loadCRLForCA((String) oFailedCrlKey); _htFailedCRLs.remove(oFailedCrlKey); } catch (ASelectException e) { _systemLogger.log(Level.WARNING, MODULE, sMethod, "Reloading CRL for CA with alias: " + oFailedCrlKey.toString() + " failed"); } } } catch (InterruptedException e) { _systemLogger.log(Level.INFO, MODULE, sMethod, "InterruptedException " + e); } } _systemLogger.log(Level.INFO, MODULE, sMethod, "Stopped"); } /** * Destroys the CRLRecoverer. <br> * <br> * <b>Description: </b> <br> * Stop the thread from running. <br> * <br> * <b>Concurrency issues: </b> <br> * -<br> * <br> * <b>Preconditions: </b> <br> * <br> * <br> * <b>Postconditions: </b> <br> * - * * @see java.lang.Thread#destroy() */ public void destroy() { String sMethod = "CRLRecoverer.destroy"; _systemLogger.log(Level.INFO, MODULE, sMethod, "---"); _bActive = false; try { // interrupt if sleeping _tCrlRecoverer.interrupt(); //Thread.currentThread().interrupt(); } catch (Exception e) { _systemLogger.log(Level.INFO, MODULE, sMethod, "Interrupt failed"); } } } class PKIAdminServer implements Runnable { private ServerSocket oSocket; private boolean _bActive; /** * Thread that handles incoming requests from the admin tool. <br> * <br> * <b>Description:</b> <br> * Thread that creates a new <code>PKIAdminRequestDispatcher</code> thread to interact with the client. <br> * <br> * <b>Concurrency issues:</b> <br> * - <br> * <br> * <b>Preconditions:</b> <br> * - <br> * <br> * <b>Postconditions:</b> <br> * - <br> * * @param iPort * the i port * @throws ASelectException * the a select exception */ public PKIAdminServer(int iPort) throws ASelectException { try { oSocket = new ServerSocket(iPort, 0, InetAddress.getByName("localhost")); } catch (UnknownHostException e) { _systemLogger.log(Level.SEVERE, MODULE, "PKIAdminServer", "localhost", e); throw new ASelectException(Errors.PKI_INTERNAL_SERVER_ERROR, e); } catch (IOException e) { _systemLogger.log(Level.SEVERE, MODULE, "PKIAdminServer", "localhost", e); throw new ASelectException(Errors.PKI_INTERNAL_SERVER_ERROR, e); } _bActive = true; } /** * Listen for incoming requests. <br> * <br> * * @see java.lang.Runnable#run() */ public void run() { String sMethod = "PKIAdminServer.run"; _systemLogger.log(Level.INFO, MODULE, sMethod, "Run " + _bActive); PKIAdminRequestDispatcher oRequestDispatcher; Thread oRequestThread; while (_bActive) { try { _systemLogger.log(Level.FINEST, MODULE, sMethod, "Accept"); Socket clientSocket = oSocket.accept(); _systemLogger.log(Level.FINEST, MODULE, sMethod, "Accepted"); oRequestDispatcher = new PKIAdminRequestDispatcher(clientSocket); oRequestThread = new Thread(oRequestDispatcher); oRequestThread.setDaemon(true); _systemLogger.log(Level.FINEST, MODULE, sMethod, "Start Thread"); oRequestThread.start(); _systemLogger.log(Level.FINEST, MODULE, sMethod, "Started Thread"); } catch (Exception e) { _systemLogger.log(Level.WARNING, MODULE, sMethod, e.getMessage(), e); } } _systemLogger.log(Level.INFO, MODULE, sMethod, "Stopped"); } /** * Destroys the PKIAdminServer. <br> * <br> * <b>Description: </b> <br> * Stop the thread from running. <br> * <br> * <b>Concurrency issues: </b> <br> * -<br> * <br> * <b>Preconditions: </b> <br> * <br> * <br> * <b>Postconditions: </b> <br> * - * * @see java.lang.Thread#destroy() */ public void destroy() { String sMethod = "PKIAdminServer.destroy"; _systemLogger.log(Level.INFO, MODULE, sMethod, "---"); _bActive = false; try { // interrupt if sleeping _tPkiAdminServer.interrupt(); //Thread.currentThread().interrupt(); oSocket.close(); } catch (Exception e) { // no logging } } } class PKIAdminRequestDispatcher implements Runnable { private Socket _oClientSocket; private boolean _bActive; private BufferedReader _oInputReader; private PrintWriter _pwOutput; /** * Thread that offers admin functionality. <br> * <br> * <b>Description:</b> <br> * Thread created by the <code>PKIAdminServer</code>. Offers functionality to reload CA keystores and/or CRL * files. <br> * <br> * <b>Concurrency issues:</b> <br> * - <br> * <br> * <b>Preconditions:</b> <br> * - <br> * <br> * <b>Postconditions:</b> <br> * - <br> * * @param oClientSocket * the o client socket */ public PKIAdminRequestDispatcher(Socket oClientSocket) { _bActive = true; _oClientSocket = oClientSocket; } /** * Reads input from admin client to proces desired functionality. <br> * <br> * * @see java.lang.Runnable#run() */ public void run() { String sMethod = "PKIAdminRequestDispatcher.run"; _systemLogger.log(Level.INFO, MODULE, sMethod, "Run " + _bActive); try { _oInputReader = new BufferedReader(new InputStreamReader(_oClientSocket.getInputStream())); _pwOutput = new PrintWriter(_oClientSocket.getOutputStream(), true); while (_bActive) { handleRequest("menu"); String sRequest = _oInputReader.readLine(); if (sRequest == null) { _bActive = false; } else { handleRequest(sRequest); } } _oClientSocket.close(); } catch (IOException e) { _systemLogger.log(Level.WARNING, MODULE, sMethod, e.getMessage(), e); } _systemLogger.log(Level.INFO, MODULE, sMethod, "Stopped"); } /** * Provides an ASCII menu and reads input from admin client. * * @param sRequest * the s request */ public void handleRequest(String sRequest) { if (sRequest.equalsIgnoreCase("menu")) { _pwOutput.println("1 ) Reload All (CA Keystore and CRL's)"); _pwOutput.println("2 ) Reload CRL's only "); _pwOutput.println("3 ) Reload CRL for CA (usage: 3 <CA alias>)"); _pwOutput.println("Type \"quit\" to stop and \"menu\" for this menu."); _pwOutput.flush(); } else if (sRequest.equalsIgnoreCase("1")) { try { loadCaKeyStoreFromPFXFile(_sCaKeyStoreLocation, _sCaKeyStorePassword); loadCRLs(); _pwOutput.println("Successfully Reloaded CA Keystore and CRL's"); } catch (ASelectException e) { _pwOutput.println("The Following exception occured: " + e.getMessage()); _systemLogger.log(Level.WARNING, MODULE, "PKIAdminRequestDispatcher->handleRequest", e.getMessage(), e); } } else if (sRequest.equalsIgnoreCase("2")) { try { loadCRLs(); } catch (ASelectException e) { _pwOutput.println("The Following exception occured: " + e.getMessage()); _systemLogger.log(Level.WARNING, MODULE, "PKIAdminRequestDispatcher->handleRequest", e.getMessage(), e); } _pwOutput.println("Successfully Reloaded CRL's"); } else if (sRequest.equalsIgnoreCase("3")) { try { _pwOutput.println("CA alias: "); _pwOutput.flush(); String sAlias = _oInputReader.readLine(); if (_oCaKeystore.containsAlias(sAlias)) { try { loadCRLForCA(sAlias); _pwOutput.println("Successfully Reloaded CRL for CA with Alias: " + sAlias); } catch (ASelectException e) { _htCRLs.remove(sAlias); _htFailedCRLs.put(sAlias, e); _pwOutput.println("Failed to reload CRL for CA with Alias: " + sAlias); _pwOutput.println("CRL is added to the auto recovery list"); } } else { _pwOutput.println("\nNo Such CA Alias found in CA Keystore."); } } catch (IOException e) { _pwOutput.println("The Following exception occured: " + e.getMessage()); _systemLogger.log(Level.WARNING, MODULE, "PKIAdminRequestDispatcher->handleRequest", e.getMessage(), e); } catch (KeyStoreException e) { _pwOutput.println("The Following exception occured: " + e.getMessage()); _systemLogger.log(Level.WARNING, MODULE, "PKIAdminRequestDispatcher->handleRequest", e.getMessage(), e); } } else if (sRequest.equalsIgnoreCase("quit")) { _bActive = false; _pwOutput.println("Connection Closed"); } else { _pwOutput.println("Unknown Command"); } } /** * Destroys the PKIAdminRequestDispatcher. <br> * <br> * <b>Description: </b> <br> * Stop the thread from running. <br> * <br> * <b>Concurrency issues: </b> <br> * -<br> * <br> * <b>Preconditions: </b> <br> * <br> * <br> * <b>Postconditions: </b> <br> * - * * @see java.lang.Thread#destroy() */ public void destroy() { String sMethod = "PKIAdminRequestDispatcher.destroy"; _systemLogger.log(Level.INFO, MODULE, sMethod, "---"); _bActive = false; try { // interrupt if sleeping Thread.currentThread().interrupt(); } catch (Exception e) { // no logging } } } }