diff src/org/eclipse/jetty/util/security/CertificateValidator.java @ 802:3428c60d7cfc

replace jetty jars with source
author Franklin Schmidt <fschmidt@gmail.com>
date Wed, 07 Sep 2016 21:15:48 -0600
parents
children 8e9db0bbf4f9
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/eclipse/jetty/util/security/CertificateValidator.java	Wed Sep 07 21:15:48 2016 -0600
@@ -0,0 +1,343 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.util.security;
+
+import java.security.GeneralSecurityException;
+import java.security.InvalidParameterException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.Security;
+import java.security.cert.CRL;
+import java.security.cert.CertPathBuilder;
+import java.security.cert.CertPathBuilderResult;
+import java.security.cert.CertPathValidator;
+import java.security.cert.CertStore;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CollectionCertStoreParameters;
+import java.security.cert.PKIXBuilderParameters;
+import java.security.cert.X509CertSelector;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+/**
+ * Convenience class to handle validation of certificates, aliases and keystores
+ *
+ * Allows specifying Certificate Revocation List (CRL), as well as enabling
+ * CRL Distribution Points Protocol (CRLDP) certificate extension support,
+ * and also enabling On-Line Certificate Status Protocol (OCSP) support.
+ * 
+ * IMPORTANT: at least one of the above mechanisms *MUST* be configured and
+ * operational, otherwise certificate validation *WILL FAIL* unconditionally.
+ */
+public class CertificateValidator
+{
+    private static final Logger LOG = Log.getLogger(CertificateValidator.class);
+    private static AtomicLong __aliasCount = new AtomicLong();
+    
+    private KeyStore _trustStore;
+    private Collection<? extends CRL> _crls;
+
+    /** Maximum certification path length (n - number of intermediate certs, -1 for unlimited) */
+    private int _maxCertPathLength = -1;
+    /** CRL Distribution Points (CRLDP) support */
+    private boolean _enableCRLDP = false;
+    /** On-Line Certificate Status Protocol (OCSP) support */
+    private boolean _enableOCSP = false;
+    /** Location of OCSP Responder */
+    private String _ocspResponderURL;
+    
+    /**
+     * creates an instance of the certificate validator 
+     *
+     * @param trustStore 
+     * @param crls
+     */
+    public CertificateValidator(KeyStore trustStore, Collection<? extends CRL> crls)
+    {
+        if (trustStore == null)
+        {
+            throw new InvalidParameterException("TrustStore must be specified for CertificateValidator.");
+        }
+        
+        _trustStore = trustStore;
+        _crls = crls;
+    }
+    
+    /**
+     * validates all aliases inside of a given keystore
+     * 
+     * @param keyStore
+     * @throws CertificateException
+     */
+    public void validate( KeyStore keyStore ) throws CertificateException
+    {
+        try
+        {
+            Enumeration<String> aliases = keyStore.aliases();
+            
+            for ( ; aliases.hasMoreElements(); )
+            {
+                String alias = aliases.nextElement();
+                
+                validate(keyStore,alias);
+            }
+            
+        }
+        catch ( KeyStoreException kse )
+        {
+            throw new CertificateException("Unable to retrieve aliases from keystore", kse);
+        }
+    }
+    
+
+    /**
+     * validates a specific alias inside of the keystore being passed in
+     * 
+     * @param keyStore
+     * @param keyAlias
+     * @return the keyAlias if valid
+     * @throws CertificateException
+     */
+    public String validate(KeyStore keyStore, String keyAlias) throws CertificateException
+    {
+        String result = null;
+
+        if (keyAlias != null)
+        {
+            try
+            {
+                validate(keyStore, keyStore.getCertificate(keyAlias));
+            }
+            catch (KeyStoreException kse)
+            {
+                LOG.debug(kse);
+                throw new CertificateException("Unable to validate certificate" +
+                        " for alias [" + keyAlias + "]: " + kse.getMessage(), kse);
+            }
+            result = keyAlias;            
+        }
+        
+        return result;
+    }
+    
+    /**
+     * validates a specific certificate inside of the keystore being passed in
+     * 
+     * @param keyStore
+     * @param cert
+     * @throws CertificateException
+     */
+    public void validate(KeyStore keyStore, Certificate cert) throws CertificateException
+    {
+        Certificate[] certChain = null;
+        
+        if (cert != null && cert instanceof X509Certificate)
+        {
+            ((X509Certificate)cert).checkValidity();
+            
+            String certAlias = null;
+            try
+            {
+                if (keyStore == null)
+                {
+                    throw new InvalidParameterException("Keystore cannot be null");
+                }
+
+                certAlias = keyStore.getCertificateAlias((X509Certificate)cert);
+                if (certAlias == null)
+                {
+                    certAlias = "JETTY" + String.format("%016X",__aliasCount.incrementAndGet());
+                    keyStore.setCertificateEntry(certAlias, cert);
+                }
+                
+                certChain = keyStore.getCertificateChain(certAlias);
+                if (certChain == null || certChain.length == 0)
+                {
+                    throw new IllegalStateException("Unable to retrieve certificate chain");
+                }
+            }
+            catch (KeyStoreException kse)
+            {
+                LOG.debug(kse);
+                throw new CertificateException("Unable to validate certificate" +
+                        (certAlias == null ? "":" for alias [" +certAlias + "]") + ": " + kse.getMessage(), kse);
+            }
+            
+            validate(certChain);
+        } 
+    }
+    
+    public void validate(Certificate[] certChain) throws CertificateException
+    {
+        try
+        {
+            ArrayList<X509Certificate> certList = new ArrayList<X509Certificate>();
+            for (Certificate item : certChain)
+            {
+                if (item == null)
+                    continue;
+                
+                if (!(item instanceof X509Certificate))
+                {
+                    throw new IllegalStateException("Invalid certificate type in chain");
+                }
+                
+                certList.add((X509Certificate)item);
+            }
+    
+            if (certList.isEmpty())
+            {
+                throw new IllegalStateException("Invalid certificate chain");
+                
+            }
+    
+            X509CertSelector certSelect = new X509CertSelector();
+            certSelect.setCertificate(certList.get(0));
+            
+            // Configure certification path builder parameters
+            PKIXBuilderParameters pbParams = new PKIXBuilderParameters(_trustStore, certSelect);
+            pbParams.addCertStore(CertStore.getInstance("Collection", new CollectionCertStoreParameters(certList)));
+    
+            // Set maximum certification path length
+            pbParams.setMaxPathLength(_maxCertPathLength);
+    
+            // Enable revocation checking
+            pbParams.setRevocationEnabled(true);
+    
+            // Set static Certificate Revocation List
+            if (_crls != null && !_crls.isEmpty())
+            {
+                pbParams.addCertStore(CertStore.getInstance("Collection", new CollectionCertStoreParameters(_crls)));
+            }
+    
+            // Enable On-Line Certificate Status Protocol (OCSP) support
+            if (_enableOCSP)
+            {
+                Security.setProperty("ocsp.enable","true");
+            }
+            // Enable Certificate Revocation List Distribution Points (CRLDP) support
+            if (_enableCRLDP)
+            {
+                System.setProperty("com.sun.security.enableCRLDP","true");
+            }
+    
+            // Build certification path
+            CertPathBuilderResult buildResult = CertPathBuilder.getInstance("PKIX").build(pbParams);               
+            
+            // Validate certification path
+            CertPathValidator.getInstance("PKIX").validate(buildResult.getCertPath(),pbParams);
+        }
+        catch (GeneralSecurityException gse)
+        {
+            LOG.debug(gse);
+            throw new CertificateException("Unable to validate certificate: " + gse.getMessage(), gse);
+        }
+    }
+
+    public KeyStore getTrustStore()
+    {
+        return _trustStore;
+    }
+
+    public Collection<? extends CRL> getCrls()
+    {
+        return _crls;
+    }
+
+    /**
+     * @return Maximum number of intermediate certificates in
+     * the certification path (-1 for unlimited)
+     */
+    public int getMaxCertPathLength()
+    {
+        return _maxCertPathLength;
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @param maxCertPathLength
+     *            maximum number of intermediate certificates in
+     *            the certification path (-1 for unlimited)
+     */
+    public void setMaxCertPathLength(int maxCertPathLength)
+    {
+        _maxCertPathLength = maxCertPathLength;
+    }
+    
+    /* ------------------------------------------------------------ */
+    /** 
+     * @return true if CRL Distribution Points support is enabled
+     */
+    public boolean isEnableCRLDP()
+    {
+        return _enableCRLDP;
+    }
+
+    /* ------------------------------------------------------------ */
+    /** Enables CRL Distribution Points Support
+     * @param enableCRLDP true - turn on, false - turns off
+     */
+    public void setEnableCRLDP(boolean enableCRLDP)
+    {
+        _enableCRLDP = enableCRLDP;
+    }
+
+    /* ------------------------------------------------------------ */
+    /** 
+     * @return true if On-Line Certificate Status Protocol support is enabled
+     */
+    public boolean isEnableOCSP()
+    {
+        return _enableOCSP;
+    }
+
+    /* ------------------------------------------------------------ */
+    /** Enables On-Line Certificate Status Protocol support
+     * @param enableOCSP true - turn on, false - turn off
+     */
+    public void setEnableOCSP(boolean enableOCSP)
+    {
+        _enableOCSP = enableOCSP;
+    }
+
+    /* ------------------------------------------------------------ */
+    /** 
+     * @return Location of the OCSP Responder
+     */
+    public String getOcspResponderURL()
+    {
+        return _ocspResponderURL;
+    }
+
+    /* ------------------------------------------------------------ */
+    /** Set the location of the OCSP Responder.
+     * @param ocspResponderURL location of the OCSP Responder
+     */
+    public void setOcspResponderURL(String ocspResponderURL)
+    {
+        _ocspResponderURL = ocspResponderURL;
+    }
+}