/* * Copyright (c) 2011 ICM Uniwersytet Warszawski All rights reserved. * See LICENCE file for licensing information. */ package eu.emi.security.authn.x509.helpers.ssl; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import eu.emi.security.authn.x509.ValidationResult; import eu.emi.security.authn.x509.X509CertChainValidator; /** * Implementation of {@link TrustManager} which uses a configured {@link X509CertChainValidator} * to validate certificates. * * <p> * Note that if the client's certificate is not trusted the server will send an alert and close the connection. * Unfortunately, TLS is build in such a way, that in the same time, the client might still be busy * with sending the rest of handshake data (the client's certificate is sent first, then other records). * This alone would be no problem but Java SSL implementation, when trustmanager throws an exception, * first closes the input half of the socket and only then sends the alert. * All this is done without waiting for the client to finish sending its portion of handshake data. * This can cause a race condition: client will try to send data on a closed channel * of the socket, before it receives an alert about its certificate. The only known solution is to introduce * a sleep before throwing an exception by checkClientTrusted(). But it is hard to provide a good value, and what is * more this timeout is obviously slowing the invalid connection dropping, what might be used to perform DoS attacs. * Therefore there is no solution implemented. * * @author K. Benedyczak */ public class SSLTrustManager implements X509TrustManager { protected X509CertChainValidator validator; public SSLTrustManager(X509CertChainValidator validator) { this.validator = validator; } /** * {@inheritDoc} */ @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { checkIfTrusted(chain); } /** * {@inheritDoc} */ @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { checkIfTrusted(chain); } protected void checkIfTrusted(X509Certificate[] certChain) throws CertificateException { ValidationResult result = validator.validate(certChain); if (!result.isValid()) { result.toString(); String subject = ""; if (certChain != null && certChain.length > 0) subject = certChain[0].getSubjectX500Principal().getName(); throw new CertificateException("The peer's certificate with subject's DN " + subject + " was rejected. The peer's certificate status is: " + result.toString()); } } /** * {@inheritDoc} */ @Override public X509Certificate[] getAcceptedIssuers() { return validator.getTrustedIssuers(); } }