package org.limewire.security.certificate; import java.io.IOException; import java.security.GeneralSecurityException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.cert.CertPath; import java.security.cert.CertPathValidator; import java.security.cert.CertPathValidatorException; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.security.cert.PKIXParameters; import java.security.cert.TrustAnchor; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.google.inject.Inject; import com.google.inject.Singleton; @Singleton public class CertificateVerifierImpl implements CertificateVerifier { private static final Log LOG = LogFactory.getLog(CertificateVerifierImpl.class); private KeyStoreProvider keyStoreProvider; private RootCAProvider rootCAProvider; @Inject public CertificateVerifierImpl(KeyStoreProvider keyStoreProvider, RootCAProvider rootCAProvider) { this.keyStoreProvider = keyStoreProvider; this.rootCAProvider = rootCAProvider; } public boolean isValid(Certificate certificate) { KeyStore ks; try { ks = keyStoreProvider.getKeyStore(); } catch (IOException ex) { LOG.error("IOException getting keyStore", ex); return false; } try { CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); CertPathValidator certPathValidator = CertPathValidator.getInstance("PKIX"); List<Certificate> certList = new ArrayList<Certificate>(); certList.add(certificate); populateCertList(ks, certificate, certList); CertPath certPath = certFactory.generateCertPath(certList); // Set the Trust anchor TrustAnchor anchor = new TrustAnchor(rootCAProvider.getCertificate(), null); // Set the PKIX parameters PKIXParameters params = new PKIXParameters(Collections.singleton(anchor)); params.setRevocationEnabled(false); // Validate and obtain results try { certPathValidator.validate(certPath, params); } catch (CertPathValidatorException ex) { LOG.error("Validation failure, cert[" + ex.getIndex() + "] :", ex); return false; } } catch (GeneralSecurityException ex) { LOG.error("CertificateException caught.", ex); return false; } return true; } /** * Looks at the certificate, looks up the issuer, and tries to find it in * the key store. When found, adds it to the end of the list. Then calls * itself recursively until it reaches the top of the signing chain. */ private void populateCertList(KeyStore keyStore, Certificate certificate, List<Certificate> certs) { // We expect these to be x.509, otherwise we just return if (certificate instanceof X509Certificate) { X509Certificate x509 = (X509Certificate) certificate; String dn = x509.getIssuerDN().getName(); // Find the 'CN=' String cn = ""; for (String token : dn.split(",")) { if (token.trim().startsWith("CN=")) { cn = token.trim().substring(3); break; } } // Break if this cert is self-signed, indicates it's the top of the // chain if (x509.getIssuerDN().getName().equals(x509.getSubjectDN().getName())) return; // System.out.println(cn); try { Certificate issuerCert = keyStore.getCertificate(cn); if (issuerCert == null) { LOG.error("Could not find certificate alias '" + cn + "'"); return; } certs.add(issuerCert); populateCertList(keyStore, issuerCert, certs); } catch (KeyStoreException ex) { LOG.error("KeyStoreException caught while walking chain.", ex); } } } }