339150 Validate client certificate when it is used for authentication
git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk@2882 7e9141cc-0065-0410-87d8-b60c137991c4
This commit is contained in:
parent
31d8e8b3dc
commit
626ef8271b
|
@ -1,8 +1,10 @@
|
|||
jetty-7.3.2-SNAPSHOT
|
||||
+ 338819 Externally control Deployment Manager application lifecycle
|
||||
+ Ensure generated fragment names are unique
|
||||
+ 339187 In the OSGi manifest of the jetty-all-server aggregate, mark javax.annotation as optional
|
||||
+ 337685 Update websocket API in preparation for draft -07
|
||||
+ 338819 Externally control Deployment Manager application lifecycle
|
||||
+ 339150 Validate client certificate when it is used for authentication
|
||||
+ 339187 In the OSGi manifest of the jetty-all-server aggregate, mark javax.annotation as optional
|
||||
+ 339543 Add configuration options for Certificate Revocation checking
|
||||
+ Ensure generated fragment names are unique
|
||||
|
||||
jetty-7.3.1.v20110307 7 March 2011
|
||||
+ 316382 Support a more strict SSL option with certificates
|
||||
|
|
|
@ -0,0 +1,171 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2009-2009 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.client;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.security.auth.Subject;
|
||||
|
||||
import org.eclipse.jetty.http.security.Constraint;
|
||||
import org.eclipse.jetty.http.security.Credential;
|
||||
import org.eclipse.jetty.http.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.security.Authenticator;
|
||||
import org.eclipse.jetty.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.security.ConstraintSecurityHandler;
|
||||
import org.eclipse.jetty.security.IdentityService;
|
||||
import org.eclipse.jetty.security.LoginService;
|
||||
import org.eclipse.jetty.security.MappedLoginService.KnownUser;
|
||||
import org.eclipse.jetty.security.authentication.ClientCertAuthenticator;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.UserIdentity;
|
||||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||
import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
|
||||
import org.eclipse.jetty.servlet.DefaultServlet;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
|
||||
public class SslCertSecuredExchangeTest extends ContentExchangeTest
|
||||
{
|
||||
// certificate is valid until Jan 1, 2050
|
||||
private String _keypath = MavenTestingUtils.getTargetFile("test-policy/validation/jetty-valid.keystore").getAbsolutePath();
|
||||
private String _trustpath = MavenTestingUtils.getTargetFile("test-policy/validation/jetty-trust.keystore").getAbsolutePath();
|
||||
private String _clientpath = MavenTestingUtils.getTargetFile("test-policy/validation/jetty-client.keystore").getAbsolutePath();
|
||||
private String _crlpath = MavenTestingUtils.getTargetFile("test-policy/validation/crlfile.pem").getAbsolutePath();
|
||||
private String _password = "OBF:1wnl1sw01ta01z0f1tae1svy1wml";
|
||||
|
||||
protected void configureServer(Server server)
|
||||
throws Exception
|
||||
{
|
||||
setProtocol("https");
|
||||
|
||||
SslSelectChannelConnector connector = new SslSelectChannelConnector();
|
||||
SslContextFactory cf = connector.getSslContextFactory();
|
||||
cf.setValidateCerts(true);
|
||||
cf.setCrlPath(_crlpath);
|
||||
cf.setNeedClientAuth(true);
|
||||
cf.setKeyStore(_keypath);
|
||||
cf.setKeyStorePassword(_password);
|
||||
cf.setKeyManagerPassword(_password);
|
||||
cf.setTrustStore(_trustpath);
|
||||
cf.setTrustStorePassword(_password);
|
||||
server.addConnector(connector);
|
||||
|
||||
LoginService loginService = new LoginService() {
|
||||
public String getName()
|
||||
{
|
||||
return "MyLoginService";
|
||||
}
|
||||
|
||||
public UserIdentity login(String username, Object credentials)
|
||||
{
|
||||
return new UserIdentity() {
|
||||
public Subject getSubject()
|
||||
{
|
||||
Subject subject = new Subject();
|
||||
subject.getPrincipals().add(getUserPrincipal());
|
||||
subject.setReadOnly();
|
||||
return subject;
|
||||
}
|
||||
|
||||
public Principal getUserPrincipal()
|
||||
{
|
||||
return new KnownUser("client", new Credential() {
|
||||
@Override
|
||||
public boolean check(Object credentials)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean isUserInRole(String role, Scope scope) { return true; }
|
||||
};
|
||||
}
|
||||
|
||||
public boolean validate(UserIdentity user) { return true; }
|
||||
|
||||
public IdentityService getIdentityService() { return null; }
|
||||
|
||||
public void setIdentityService(IdentityService service) {}
|
||||
|
||||
public void logout(UserIdentity user) {}
|
||||
|
||||
};
|
||||
server.addBean(loginService);
|
||||
|
||||
ConstraintSecurityHandler security = new ConstraintSecurityHandler();
|
||||
server.setHandler(security);
|
||||
|
||||
Constraint constraint = new Constraint();
|
||||
constraint.setName("auth");
|
||||
constraint.setAuthenticate( true );
|
||||
constraint.setRoles(new String[]{"user", "admin"});
|
||||
|
||||
ConstraintMapping mapping = new ConstraintMapping();
|
||||
mapping.setPathSpec( "/*" );
|
||||
mapping.setConstraint( constraint );
|
||||
|
||||
Set<String> knownRoles = new HashSet<String>();
|
||||
knownRoles.add("user");
|
||||
knownRoles.add("admin");
|
||||
|
||||
security.setConstraintMappings(Collections.singletonList(mapping), knownRoles);
|
||||
security.setLoginService(loginService);
|
||||
|
||||
ClientCertAuthenticator auth = new ClientCertAuthenticator();
|
||||
auth.setValidateCerts(true);
|
||||
auth.setCrlPath(_crlpath);
|
||||
auth.setTrustStore(_trustpath);
|
||||
auth.setTrustStorePassword(_password);
|
||||
security.setAuthenticator(auth);
|
||||
security.setAuthMethod(auth.getAuthMethod());
|
||||
security.setRealmName("MyRealm");
|
||||
security.setStrict(true);
|
||||
|
||||
ServletContextHandler root = new ServletContextHandler();
|
||||
root.setContextPath("/");
|
||||
root.setResourceBase(getBasePath());
|
||||
ServletHolder servletHolder = new ServletHolder( new DefaultServlet() );
|
||||
servletHolder.setInitParameter( "gzip", "true" );
|
||||
root.addServlet( servletHolder, "/*" );
|
||||
|
||||
Handler handler = new TestHandler(getBasePath());
|
||||
|
||||
HandlerCollection handlers = new HandlerCollection();
|
||||
handlers.setHandlers(new Handler[]{handler, root});
|
||||
security.setHandler(handlers);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureClient(HttpClient client) throws Exception
|
||||
{
|
||||
SslContextFactory cf = client.getSslContextFactory();
|
||||
cf.setValidateCerts(true);
|
||||
cf.setCrlPath(_crlpath);
|
||||
|
||||
cf.setCertAlias("client");
|
||||
cf.setKeyStore(_clientpath);
|
||||
cf.setKeyStorePassword(_password);
|
||||
cf.setKeyManagerPassword(_password);
|
||||
|
||||
cf.setTrustStore(_trustpath);
|
||||
cf.setTrustStorePassword(_password);
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@ import org.eclipse.jetty.servlet.ServletContextHandler;
|
|||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
|
||||
public abstract class SslValidationTestBase extends SslContentExchangeTest
|
||||
public abstract class SslValidationTestBase extends ContentExchangeTest
|
||||
{
|
||||
protected static Class<? extends SslConnector> __klass;
|
||||
protected static int __konnector;
|
||||
|
@ -20,6 +20,7 @@ public abstract class SslValidationTestBase extends SslContentExchangeTest
|
|||
// certificate is valid until Jan 1, 2050
|
||||
private String _keypath = MavenTestingUtils.getTargetFile("test-policy/validation/jetty-valid.keystore").getAbsolutePath();
|
||||
private String _trustpath = MavenTestingUtils.getTargetFile("test-policy/validation/jetty-trust.keystore").getAbsolutePath();
|
||||
private String _clientpath = MavenTestingUtils.getTargetFile("test-policy/validation/jetty-client.keystore").getAbsolutePath();
|
||||
private String _crlpath = MavenTestingUtils.getTargetFile("test-policy/validation/crlfile.pem").getAbsolutePath();
|
||||
private String _password = "OBF:1wnl1sw01ta01z0f1tae1svy1wml";
|
||||
|
||||
|
@ -31,12 +32,15 @@ public abstract class SslValidationTestBase extends SslContentExchangeTest
|
|||
|
||||
SslContextFactory srvFactory = new SslContextFactory();
|
||||
srvFactory.setValidateCerts(true);
|
||||
srvFactory.setCrlPath(_crlpath);
|
||||
srvFactory.setNeedClientAuth(true);
|
||||
|
||||
srvFactory.setKeyStore(_keypath);
|
||||
srvFactory.setKeyStorePassword(_password);
|
||||
srvFactory.setKeyManagerPassword(_password);
|
||||
|
||||
srvFactory.setTrustStore(_trustpath);
|
||||
srvFactory.setTrustStorePassword(_password);
|
||||
srvFactory.setCrlPath(_crlpath);
|
||||
|
||||
Constructor<? extends SslConnector> constructor = __klass.getConstructor(SslContextFactory.class);
|
||||
SslConnector connector = constructor.newInstance(srvFactory);
|
||||
|
@ -64,6 +68,13 @@ public abstract class SslValidationTestBase extends SslContentExchangeTest
|
|||
client.setConnectorType(__konnector);
|
||||
|
||||
SslContextFactory cf = client.getSslContextFactory();
|
||||
cf.setValidateCerts(true);
|
||||
cf.setCrlPath(_crlpath);
|
||||
|
||||
cf.setKeyStore(_clientpath);
|
||||
cf.setKeyStorePassword(_password);
|
||||
cf.setKeyManagerPassword(_password);
|
||||
|
||||
cf.setTrustStore(_trustpath);
|
||||
cf.setTrustStorePassword(_password);
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ import java.security.Security;
|
|||
import java.security.cert.CRL;
|
||||
import java.security.cert.CertStore;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.CollectionCertStoreParameters;
|
||||
import java.security.cert.PKIXBuilderParameters;
|
||||
import java.security.cert.X509CertSelector;
|
||||
|
@ -50,7 +49,7 @@ import javax.net.ssl.X509TrustManager;
|
|||
import org.eclipse.jetty.http.security.Password;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.security.CertificateUtils;
|
||||
import org.eclipse.jetty.util.security.CertificateValidator;
|
||||
|
||||
|
||||
|
@ -110,8 +109,6 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
private boolean _needClientAuth = false;
|
||||
/** Set to true if client certificate authentication is desired */
|
||||
private boolean _wantClientAuth = false;
|
||||
/** Set to true if SSL certificate validation is required */
|
||||
private boolean _validateCerts;
|
||||
/** Set to true if renegotiation is allowed */
|
||||
private boolean _allowRenegotiate = false;
|
||||
|
||||
|
@ -134,11 +131,19 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
/** TrustManager factory algorithm */
|
||||
private String _trustManagerFactoryAlgorithm = DEFAULT_TRUSTMANAGERFACTORY_ALGORITHM;
|
||||
|
||||
/** Path to file that contains Certificate Revocation List */
|
||||
private String _crlPath;
|
||||
/** Set to true if SSL certificate validation is required */
|
||||
private boolean _validateCerts;
|
||||
/** Maximum certification path length (n - number of intermediate certs, -1 for unlimited) */
|
||||
private int _maxCertPathLength = -1;
|
||||
|
||||
/** Path to file that contains Certificate Revocation List */
|
||||
private String _crlPath;
|
||||
/** Set to true to enable CRL Distribution Points (CRLDP) support */
|
||||
private boolean _enableCRLDP = false;
|
||||
/** Set to true to enable On-Line Certificate Status Protocol (OCSP) support */
|
||||
private boolean _enableOCSP = false;
|
||||
/** Location of OCSP Responder */
|
||||
private String _ocspResponderURL;
|
||||
|
||||
/** SSL context */
|
||||
private SSLContext _context;
|
||||
|
||||
|
@ -154,11 +159,11 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Construct an instance of SslContextFactory
|
||||
* @param keystorePath default keystore location
|
||||
* @param keyStorePath default keystore location
|
||||
*/
|
||||
public SslContextFactory(String keystorePath)
|
||||
public SslContextFactory(String keyStorePath)
|
||||
{
|
||||
_keyStorePath = keystorePath;
|
||||
_keyStorePath = keyStorePath;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -258,14 +263,14 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param keystore
|
||||
* @param keyStorePath
|
||||
* The file or URL of the SSL Key store.
|
||||
*/
|
||||
public void setKeyStore(String keystore)
|
||||
public void setKeyStore(String keyStorePath)
|
||||
{
|
||||
checkStarted();
|
||||
|
||||
_keyStorePath = keystore;
|
||||
_keyStorePath = keyStorePath;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -279,14 +284,14 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param keystoreProvider
|
||||
* @param keyStoreProvider
|
||||
* The provider of the key store
|
||||
*/
|
||||
public void setKeyStoreProvider(String keystoreProvider)
|
||||
public void setKeyStoreProvider(String keyStoreProvider)
|
||||
{
|
||||
checkStarted();
|
||||
|
||||
_keyStoreProvider = keystoreProvider;
|
||||
_keyStoreProvider = keyStoreProvider;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -300,14 +305,14 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param keystoreType
|
||||
* @param keyStoreType
|
||||
* The type of the key store (default "JKS")
|
||||
*/
|
||||
public void setKeyStoreType(String keystoreType)
|
||||
public void setKeyStoreType(String keyStoreType)
|
||||
{
|
||||
checkStarted();
|
||||
|
||||
_keyStoreType = keystoreType;
|
||||
_keyStoreType = keyStoreType;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -323,13 +328,13 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Set the keyStoreInputStream.
|
||||
* @param keystoreInputStream the InputStream to the KeyStore
|
||||
* @param keyStoreInputStream the InputStream to the KeyStore
|
||||
*/
|
||||
public void setKeyStoreInputStream(InputStream keystoreInputStream)
|
||||
public void setKeyStoreInputStream(InputStream keyStoreInputStream)
|
||||
{
|
||||
checkStarted();
|
||||
|
||||
_keyStoreInputStream = keystoreInputStream;
|
||||
_keyStoreInputStream = keyStoreInputStream;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -364,14 +369,14 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param truststore
|
||||
* @param trustStorePath
|
||||
* The file name or URL of the trust store location
|
||||
*/
|
||||
public void setTrustStore(String truststore)
|
||||
public void setTrustStore(String trustStorePath)
|
||||
{
|
||||
checkStarted();
|
||||
|
||||
_trustStorePath = truststore;
|
||||
_trustStorePath = trustStorePath;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -385,14 +390,14 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param truststoreProvider
|
||||
* @param trustStoreProvider
|
||||
* The provider of the trust store
|
||||
*/
|
||||
public void setTrustStoreProvider(String truststoreProvider)
|
||||
public void setTrustStoreProvider(String trustStoreProvider)
|
||||
{
|
||||
checkStarted();
|
||||
|
||||
_trustStoreProvider = truststoreProvider;
|
||||
_trustStoreProvider = trustStoreProvider;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -406,14 +411,14 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param truststoreType
|
||||
* @param trustStoreType
|
||||
* The type of the trust store (default "JKS")
|
||||
*/
|
||||
public void setTrustStoreType(String truststoreType)
|
||||
public void setTrustStoreType(String trustStoreType)
|
||||
{
|
||||
checkStarted();
|
||||
|
||||
_trustStoreType = truststoreType;
|
||||
_trustStoreType = trustStoreType;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -429,13 +434,13 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Set the _trustStoreInputStream.
|
||||
* @param truststoreInputStream the InputStream to the TrustStore
|
||||
* @param trustStoreInputStream the InputStream to the TrustStore
|
||||
*/
|
||||
public void setTrustStoreInputStream(InputStream truststoreInputStream)
|
||||
public void setTrustStoreInputStream(InputStream trustStoreInputStream)
|
||||
{
|
||||
checkStarted();
|
||||
|
||||
_trustStoreInputStream = truststoreInputStream;
|
||||
_trustStoreInputStream = trustStoreInputStream;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -487,12 +492,23 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return true if SSL certificate has to be validated
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean getValidateCerts()
|
||||
{
|
||||
return _validateCerts;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return true if SSL certificate has to be validated
|
||||
*/
|
||||
public boolean isValidateCerts()
|
||||
{
|
||||
return _validateCerts;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param validateCerts
|
||||
|
@ -754,11 +770,11 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
// parameters are set up correctly
|
||||
checkConfig();
|
||||
|
||||
KeyStore keyStore = getKeyStore(_keyStoreInputStream, _keyStorePath, _keyStoreType,
|
||||
KeyStore keyStore = CertificateUtils.getKeyStore(_keyStoreInputStream, _keyStorePath, _keyStoreType,
|
||||
_keyStoreProvider, _keyStorePassword==null? null: _keyStorePassword.toString());
|
||||
KeyStore trustStore = getKeyStore(_trustStoreInputStream, _trustStorePath, _trustStoreType,
|
||||
KeyStore trustStore = CertificateUtils.getKeyStore(_trustStoreInputStream, _trustStorePath, _trustStoreType,
|
||||
_trustStoreProvider, _trustStorePassword==null? null: _trustStorePassword.toString());
|
||||
Collection<? extends CRL> crls = loadCRL(_crlPath);
|
||||
Collection<? extends CRL> crls = CertificateUtils.loadCRL(_crlPath);
|
||||
|
||||
if (_validateCerts && keyStore != null)
|
||||
{
|
||||
|
@ -774,7 +790,11 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
throw new Exception("No certificate found in the keystore" + (_certAlias==null ? "":" for alias " + _certAlias));
|
||||
}
|
||||
|
||||
CertificateValidator validator = new CertificateValidator(trustStore,crls);
|
||||
CertificateValidator validator = new CertificateValidator(trustStore, crls);
|
||||
validator.setMaxCertPathLength(_maxCertPathLength);
|
||||
validator.setEnableCRLDP(_enableCRLDP);
|
||||
validator.setEnableOCSP(_enableOCSP);
|
||||
validator.setOcspResponderURL(_ocspResponderURL);
|
||||
validator.validate(keyStore, cert);
|
||||
}
|
||||
|
||||
|
@ -823,22 +843,34 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
{
|
||||
PKIXBuilderParameters pbParams = new PKIXBuilderParameters(trustStore,new X509CertSelector());
|
||||
|
||||
// Enable revocation checking
|
||||
pbParams.setRevocationEnabled(true);
|
||||
|
||||
// Set maximum certification path length
|
||||
pbParams.setMaxPathLength(_maxCertPathLength);
|
||||
|
||||
// Make sure revocation checking is enabled
|
||||
pbParams.setRevocationEnabled(true);
|
||||
|
||||
if (crls != null && !crls.isEmpty())
|
||||
{
|
||||
pbParams.addCertStore(CertStore.getInstance("Collection",new CollectionCertStoreParameters(crls)));
|
||||
}
|
||||
|
||||
// Enable On-Line Certificate Status Protocol (OCSP) support
|
||||
Security.setProperty("ocsp.enable","true");
|
||||
if (_enableCRLDP)
|
||||
{
|
||||
// Enable Certificate Revocation List Distribution Points (CRLDP) support
|
||||
System.setProperty("com.sun.security.enableCRLDP","true");
|
||||
}
|
||||
|
||||
// Enable Certificate Revocation List Distribution Points (CRLDP) support
|
||||
System.setProperty("com.sun.security.enableCRLDP","true");
|
||||
if (_enableOCSP)
|
||||
{
|
||||
// Enable On-Line Certificate Status Protocol (OCSP) support
|
||||
Security.setProperty("ocsp.enable","true");
|
||||
|
||||
if (_ocspResponderURL != null)
|
||||
{
|
||||
// Override location of OCSP Responder
|
||||
Security.setProperty("ocsp.responderURL", _ocspResponderURL);
|
||||
}
|
||||
}
|
||||
|
||||
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(_trustManagerFactoryAlgorithm);
|
||||
trustManagerFactory.init(new CertPathTrustManagerParameters(pbParams));
|
||||
|
@ -857,69 +889,6 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
return managers;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected KeyStore getKeyStore(InputStream storeStream, String storePath, String storeType, String storeProvider, String storePassword) throws Exception
|
||||
{
|
||||
KeyStore keystore = null;
|
||||
|
||||
if (storeStream != null || storePath != null)
|
||||
{
|
||||
InputStream inStream = storeStream;
|
||||
try
|
||||
{
|
||||
if (inStream == null)
|
||||
{
|
||||
inStream = Resource.newResource(storePath).getInputStream();
|
||||
}
|
||||
|
||||
if (storeProvider != null)
|
||||
{
|
||||
keystore = KeyStore.getInstance(storeType, storeProvider);
|
||||
}
|
||||
else
|
||||
{
|
||||
keystore = KeyStore.getInstance(storeType);
|
||||
}
|
||||
|
||||
keystore.load(inStream, storePassword == null ? null : storePassword.toCharArray());
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (inStream != null)
|
||||
{
|
||||
inStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return keystore;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected Collection<? extends CRL> loadCRL(String crlPath) throws Exception
|
||||
{
|
||||
Collection<? extends CRL> crlList = null;
|
||||
|
||||
if (crlPath != null)
|
||||
{
|
||||
InputStream in = null;
|
||||
try
|
||||
{
|
||||
in = Resource.newResource(crlPath).getInputStream();
|
||||
crlList = CertificateFactory.getInstance("X.509").generateCRLs(in);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (in != null)
|
||||
{
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return crlList;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Check configuration. Ensures that if keystore has been
|
||||
|
@ -1032,4 +1001,58 @@ public class SslContextFactory extends AbstractLifeCycle
|
|||
throw new IllegalStateException("Cannot modify configuration after SslContextFactory was started");
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,9 +13,11 @@
|
|||
|
||||
package org.eclipse.jetty.security.authentication;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.Principal;
|
||||
import java.security.cert.CRL;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
@ -23,18 +25,46 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.security.Constraint;
|
||||
import org.eclipse.jetty.http.security.Password;
|
||||
import org.eclipse.jetty.security.ServerAuthException;
|
||||
import org.eclipse.jetty.security.UserAuthentication;
|
||||
import org.eclipse.jetty.server.Authentication;
|
||||
import org.eclipse.jetty.server.UserIdentity;
|
||||
import org.eclipse.jetty.server.Authentication.User;
|
||||
import org.eclipse.jetty.server.UserIdentity;
|
||||
import org.eclipse.jetty.util.B64Code;
|
||||
import org.eclipse.jetty.util.security.CertificateUtils;
|
||||
import org.eclipse.jetty.util.security.CertificateValidator;
|
||||
|
||||
/**
|
||||
* @version $Rev: 4793 $ $Date: 2009-03-19 00:00:01 +0100 (Thu, 19 Mar 2009) $
|
||||
*/
|
||||
public class ClientCertAuthenticator extends LoginAuthenticator
|
||||
{
|
||||
/** String name of keystore password property. */
|
||||
private static final String PASSWORD_PROPERTY = "org.eclipse.jetty.ssl.password";
|
||||
|
||||
/** Truststore path */
|
||||
private String _trustStorePath;
|
||||
/** Truststore provider name */
|
||||
private String _trustStoreProvider;
|
||||
/** Truststore type */
|
||||
private String _trustStoreType = "JKS";
|
||||
/** Truststore password */
|
||||
private transient Password _trustStorePassword;
|
||||
|
||||
/** Set to true if SSL certificate validation is required */
|
||||
private boolean _validateCerts;
|
||||
/** Path to file that contains Certificate Revocation List */
|
||||
private String _crlPath;
|
||||
/** 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;
|
||||
|
||||
public ClientCertAuthenticator()
|
||||
{
|
||||
super();
|
||||
|
@ -63,10 +93,22 @@ public class ClientCertAuthenticator extends LoginAuthenticator
|
|||
// Need certificates.
|
||||
if (certs != null && certs.length > 0)
|
||||
{
|
||||
|
||||
if (_validateCerts)
|
||||
{
|
||||
KeyStore trustStore = CertificateUtils.getKeyStore(null,
|
||||
_trustStorePath, _trustStoreType, _trustStoreProvider,
|
||||
_trustStorePassword == null ? null :_trustStorePassword.toString());
|
||||
Collection<? extends CRL> crls = CertificateUtils.loadCRL(_crlPath);
|
||||
CertificateValidator validator = new CertificateValidator(trustStore, crls);
|
||||
validator.validate(certs);
|
||||
}
|
||||
|
||||
for (X509Certificate cert: certs)
|
||||
{
|
||||
if (cert==null)
|
||||
continue;
|
||||
|
||||
Principal principal = cert.getSubjectDN();
|
||||
if (principal == null) principal = cert.getIssuerDN();
|
||||
final String username = principal == null ? "clientcert" : principal.getName();
|
||||
|
@ -90,7 +132,7 @@ public class ClientCertAuthenticator extends LoginAuthenticator
|
|||
|
||||
return Authentication.UNAUTHENTICATED;
|
||||
}
|
||||
catch (IOException e)
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ServerAuthException(e.getMessage());
|
||||
}
|
||||
|
@ -100,4 +142,182 @@ public class ClientCertAuthenticator extends LoginAuthenticator
|
|||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return true if SSL certificate has to be validated
|
||||
*/
|
||||
public boolean isValidateCerts()
|
||||
{
|
||||
return _validateCerts;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param validateCerts
|
||||
* true if SSL certificates have to be validated
|
||||
*/
|
||||
public void setValidateCerts(boolean validateCerts)
|
||||
{
|
||||
_validateCerts = validateCerts;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return The file name or URL of the trust store location
|
||||
*/
|
||||
public String getTrustStore()
|
||||
{
|
||||
return _trustStorePath;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param trustStorePath
|
||||
* The file name or URL of the trust store location
|
||||
*/
|
||||
public void setTrustStore(String trustStorePath)
|
||||
{
|
||||
_trustStorePath = trustStorePath;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return The provider of the trust store
|
||||
*/
|
||||
public String getTrustStoreProvider()
|
||||
{
|
||||
return _trustStoreProvider;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param trustStoreProvider
|
||||
* The provider of the trust store
|
||||
*/
|
||||
public void setTrustStoreProvider(String trustStoreProvider)
|
||||
{
|
||||
_trustStoreProvider = trustStoreProvider;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return The type of the trust store (default "JKS")
|
||||
*/
|
||||
public String getTrustStoreType()
|
||||
{
|
||||
return _trustStoreType;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param trustStoreType
|
||||
* The type of the trust store (default "JKS")
|
||||
*/
|
||||
public void setTrustStoreType(String trustStoreType)
|
||||
{
|
||||
_trustStoreType = trustStoreType;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param password
|
||||
* The password for the trust store
|
||||
*/
|
||||
public void setTrustStorePassword(String password)
|
||||
{
|
||||
_trustStorePassword = Password.getPassword(PASSWORD_PROPERTY,password,null);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the crlPath.
|
||||
* @return the crlPath
|
||||
*/
|
||||
public String getCrlPath()
|
||||
{
|
||||
return _crlPath;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Set the crlPath.
|
||||
* @param crlPath the crlPath to set
|
||||
*/
|
||||
public void setCrlPath(String crlPath)
|
||||
{
|
||||
_crlPath = crlPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
//========================================================================
|
||||
//Copyright (c) Webtide LLC
|
||||
//------------------------------------------------------------------------
|
||||
//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.apache.org/licenses/LICENSE-2.0.txt
|
||||
//
|
||||
//You may elect to redistribute this code under either of these licenses.
|
||||
//========================================================================
|
||||
|
||||
package org.eclipse.jetty.util.security;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.security.KeyStore;
|
||||
import java.security.cert.CRL;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
|
||||
public class CertificateUtils
|
||||
{
|
||||
/* ------------------------------------------------------------ */
|
||||
public static KeyStore getKeyStore(InputStream storeStream, String storePath, String storeType, String storeProvider, String storePassword) throws Exception
|
||||
{
|
||||
KeyStore keystore = null;
|
||||
|
||||
if (storeStream != null || storePath != null)
|
||||
{
|
||||
InputStream inStream = storeStream;
|
||||
try
|
||||
{
|
||||
if (inStream == null)
|
||||
{
|
||||
inStream = Resource.newResource(storePath).getInputStream();
|
||||
}
|
||||
|
||||
if (storeProvider != null)
|
||||
{
|
||||
keystore = KeyStore.getInstance(storeType, storeProvider);
|
||||
}
|
||||
else
|
||||
{
|
||||
keystore = KeyStore.getInstance(storeType);
|
||||
}
|
||||
|
||||
keystore.load(inStream, storePassword == null ? null : storePassword.toCharArray());
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (inStream != null)
|
||||
{
|
||||
inStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return keystore;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public static Collection<? extends CRL> loadCRL(String crlPath) throws Exception
|
||||
{
|
||||
Collection<? extends CRL> crlList = null;
|
||||
|
||||
if (crlPath != null)
|
||||
{
|
||||
InputStream in = null;
|
||||
try
|
||||
{
|
||||
in = Resource.newResource(crlPath).getInputStream();
|
||||
crlList = CertificateFactory.getInstance("X.509").generateCRLs(in);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (in != null)
|
||||
{
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return crlList;
|
||||
}
|
||||
|
||||
}
|
|
@ -16,8 +16,11 @@ package org.eclipse.jetty.util.security;
|
|||
//You may elect to redistribute this code under either of these licenses.
|
||||
//========================================================================
|
||||
|
||||
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;
|
||||
|
@ -32,22 +35,35 @@ 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;
|
||||
|
||||
/**
|
||||
* Convenience class to handle validation of certificates, aliases and keystores
|
||||
*
|
||||
* Currently handles certificate revocation lists, should evolve to handle ocsp as well
|
||||
* 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.
|
||||
*
|
||||
* TODO: consider the case of a null trust store, is that important?
|
||||
* TODO: add what support for ocsp is needed, if any
|
||||
* IMPORTANT: at least one of the above mechanisms *MUST* be configured and
|
||||
* operational, otherwise certificate validation *WILL FAIL* unconditionally.
|
||||
*/
|
||||
public class CertificateValidator
|
||||
{
|
||||
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
|
||||
|
@ -57,6 +73,11 @@ public class CertificateValidator
|
|||
*/
|
||||
public CertificateValidator(KeyStore trustStore, Collection<? extends CRL> crls)
|
||||
{
|
||||
if (trustStore == null)
|
||||
{
|
||||
throw new InvalidParameterException("TrustStore must be specified for CertificateValidator.");
|
||||
}
|
||||
|
||||
_trustStore = trustStore;
|
||||
_crls = crls;
|
||||
}
|
||||
|
@ -83,7 +104,7 @@ public class CertificateValidator
|
|||
}
|
||||
catch ( KeyStoreException kse )
|
||||
{
|
||||
throw new CertificateException("error obtaining aliases", kse);
|
||||
throw new CertificateException("Unable to retrieve aliases from keystore", kse);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,11 +127,11 @@ public class CertificateValidator
|
|||
{
|
||||
validate(keyStore, keyStore.getCertificate(keyAlias));
|
||||
}
|
||||
catch (KeyStoreException ex)
|
||||
catch (KeyStoreException kse)
|
||||
{
|
||||
Log.debug(ex);
|
||||
throw new CertificateException("Unable to validate certificate for alias [" +
|
||||
keyAlias + "]: " + ex.getMessage());
|
||||
Log.debug(kse);
|
||||
throw new CertificateException("Unable to validate certificate" +
|
||||
" for alias [" + keyAlias + "]: " + kse.getMessage(), kse);
|
||||
}
|
||||
result = keyAlias;
|
||||
}
|
||||
|
@ -127,74 +148,104 @@ public class CertificateValidator
|
|||
*/
|
||||
public void validate(KeyStore keyStore, Certificate cert) throws CertificateException
|
||||
{
|
||||
Certificate[] certChain = null;
|
||||
|
||||
if (cert != null && cert instanceof X509Certificate)
|
||||
{
|
||||
((X509Certificate)cert).checkValidity();
|
||||
|
||||
String certAlias = "[none]";
|
||||
String certAlias = null;
|
||||
try
|
||||
{
|
||||
if (keyStore == null)
|
||||
{
|
||||
throw new InvalidParameterException("Keystore cannot be null");
|
||||
}
|
||||
|
||||
certAlias = keyStore.getCertificateAlias((X509Certificate)cert);
|
||||
Certificate[] certChain = keyStore.getCertificateChain(certAlias);
|
||||
|
||||
ArrayList<X509Certificate> certList = new ArrayList<X509Certificate>();
|
||||
for (Certificate item : certChain)
|
||||
if (certAlias == null)
|
||||
{
|
||||
if (!(item instanceof X509Certificate))
|
||||
{
|
||||
throw new CertificateException("Invalid certificate type in chain");
|
||||
}
|
||||
certList.add((X509Certificate)item);
|
||||
certAlias = "JETTY" + String.format("%016X",__aliasCount.incrementAndGet());
|
||||
keyStore.setCertificateEntry(certAlias, cert);
|
||||
}
|
||||
|
||||
if (certList.isEmpty())
|
||||
{
|
||||
throw new CertificateException("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 static Certificate Revocation List
|
||||
if (_crls != null && !_crls.isEmpty())
|
||||
certChain = keyStore.getCertificateChain(certAlias);
|
||||
if (certChain == null || certChain.length == 0)
|
||||
{
|
||||
pbParams.addCertStore(CertStore.getInstance("Collection", new CollectionCertStoreParameters(_crls)));
|
||||
throw new IllegalStateException("Unable to retrieve certificate chain");
|
||||
}
|
||||
|
||||
// Enable revocation checking
|
||||
pbParams.setRevocationEnabled(true);
|
||||
|
||||
// Set maximum certification path length
|
||||
pbParams.setMaxPathLength(_maxCertPathLength);
|
||||
|
||||
// Build certification path
|
||||
CertPathBuilderResult buildResult = CertPathBuilder.getInstance("PKIX").build(pbParams);
|
||||
|
||||
// Validate certification path
|
||||
CertPathValidator.getInstance("PKIX").validate(buildResult.getCertPath(),pbParams);
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (KeyStoreException kse)
|
||||
{
|
||||
Log.debug(ex);
|
||||
throw new CertificateException("Unable to validate certificate for alias [" +
|
||||
certAlias + "]: " + ex.getMessage());
|
||||
Log.debug(kse);
|
||||
throw new CertificateException("Unable to validate certificate" +
|
||||
(certAlias == null ? "":" for alias [" +certAlias + "]") + ": " + kse.getMessage(), kse);
|
||||
}
|
||||
|
||||
validate(certChain);
|
||||
}
|
||||
}
|
||||
|
||||
public int getMaxCertPathLength()
|
||||
|
||||
public void validate(Certificate[] certChain) throws CertificateException
|
||||
{
|
||||
return _maxCertPathLength;
|
||||
}
|
||||
|
||||
public void setMaxCertPathLength(int maxCertPathLength)
|
||||
{
|
||||
_maxCertPathLength = maxCertPathLength;
|
||||
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
|
||||
Security.setProperty("ocsp.enable","true");
|
||||
|
||||
// Enable Certificate Revocation List Distribution Points (CRLDP) support
|
||||
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()
|
||||
|
@ -206,4 +257,78 @@ public class CertificateValidator
|
|||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue