/* * Copyright (c) 2011-2012 ICM Uniwersytet Warszawski All rights reserved. * See LICENCE file for licensing information. * * Derived from the code copyrighted and licensed as follows: * * Copyright (c) Members of the EGEE Collaboration. 2004. * See http://www.eu-egee.org/partners/ for details on the copyright * holders. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package eu.emi.security.authn.x509.impl; import java.security.cert.Certificate; import java.security.cert.X509Certificate; import javax.net.ssl.HandshakeCompletedEvent; import javax.net.ssl.HandshakeCompletedListener; import javax.net.ssl.SSLException; import javax.net.ssl.SSLPeerUnverifiedException; import javax.net.ssl.SSLSocket; import eu.emi.security.authn.x509.helpers.ssl.HostnameToCertificateChecker; /** * Abstract implementation of the JSSE {@link HandshakeCompletedListener} * which can be registered on a {@link SSLSocket} to verify if a peer's * host name matches a DN of its certificate. It is useful on client side * when connecting to a server. * <p> * By default the implementation checks the certificate's Subject Alternative Name * and Common Name, following the server identity part of RFC 2818. Additionally the * 'service/hostname' syntax is supported (the service prefix is simply ignored). * <p> * If there is a name mismatch the nameMismatch() method is called. * User of this class must extend it and provide the application specific reaction * in this method. * <p> * Note that this class should be used only on SSL connections which are * authenticated with X.509 certificates. * * @deprecated Use {@link SocketFactoryCreator#connectWithHostnameChecking(SSLSocket, HostnameMismatchCallback)} * instead. This class is not perfect as the {@link HandshakeCompletedListener} is invoked (at least in reference JDK) * in a separate thread, what can easily lead to a situation when the connection is opened and made available, * before this implementation finishes checking. * @author Joni Hahkala * @author K. Benedyczak * */ @Deprecated public abstract class AbstractHostnameToCertificateChecker implements HandshakeCompletedListener { static { CertificateUtils.configureSecProvider(); } public void handshakeCompleted(HandshakeCompletedEvent hce) { X509Certificate cert; try { Certificate[] serverChain = hce.getPeerCertificates(); if (serverChain == null || serverChain.length == 0) { processingError(hce, new Exception("JDK BUG? Got null or empty peer certificate array")); return; } if (!(serverChain[0] instanceof X509Certificate)) { processingError(hce, new ClassCastException("Peer certificate should be " + "an X.509 certificate, but is " + serverChain[0].getClass().getName())); return; } cert = (X509Certificate) serverChain[0]; } catch (SSLPeerUnverifiedException e) { processingError(hce, new Exception("Peer is unverified " + "when handshake is completed - is it really an X.509-authenticated connection?", e)); return; } String hostname = hce.getSocket().getInetAddress().getHostName(); try { HostnameToCertificateChecker checker = new HostnameToCertificateChecker(); if (!checker.checkMatching(hostname, cert)) nameMismatch(hce, cert, hostname); } catch (Exception e) { processingError(hce, e); return; } } /** * This method is called whenever peer's host name is not matching the peer's * certificate DN. Note that throwing exceptions from this method doesn't make any sense. * @param hce the original event object * @param peerCertificate peer's certificate (for convenience) * @param hostName peer's host name (for convenience) * @throws SSLException SSL exception */ protected abstract void nameMismatch(HandshakeCompletedEvent hce, X509Certificate peerCertificate, String hostName) throws SSLException; /** * This method is called whenever there is an error when processing the peer's certificate * and hostname. Generally it should never happen, and the implementation should simply * close the socket and report the error. The default implementation simply throws an * {@link IllegalStateException}. * @param hce the original event object * @param e error */ protected void processingError(HandshakeCompletedEvent hce, Exception e) { throw new IllegalStateException("Error occured when verifying if the SSL peer's " + "hostname matches its certificate", e); } }