001/**
002 *
003 * Copyright 2014 the original author or authors
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.jivesoftware.smack.java7;
019
020import java.security.Principal;
021import java.security.cert.Certificate;
022import java.security.cert.CertificateException;
023import java.security.cert.X509Certificate;
024
025import javax.net.ssl.HostnameVerifier;
026import javax.net.ssl.SSLPeerUnverifiedException;
027import javax.net.ssl.SSLSession;
028import javax.security.auth.kerberos.KerberosPrincipal;
029
030import sun.security.util.HostnameChecker;
031
032/**
033 * <p>
034 * HostnameVerifier implementation which implements the same policy as the Java built-in
035 * pre-HostnameVerifier policy.
036 * </p>
037 * <p>
038 * Based on the <a href="found at http://kevinlocke.name/bits
039 * /2012/10/03/ssl-certificate-verification-in-dispatch-and-asynchttpclient/">work by Kevin
040 * Locke</a> (released under CC0 1.0 Universal / Public Domain Dedication).
041 * </p>
042 */
043public class Java7HostnameVerifier implements HostnameVerifier {
044
045    @Override
046    public boolean verify(String hostname, SSLSession session) {
047        HostnameChecker checker = HostnameChecker.getInstance(HostnameChecker.TYPE_TLS);
048
049        boolean validCertificate = false, validPrincipal = false;
050        try {
051            Certificate[] peerCertificates = session.getPeerCertificates();
052
053            if (peerCertificates.length > 0 && peerCertificates[0] instanceof X509Certificate) {
054                X509Certificate peerCertificate = (X509Certificate) peerCertificates[0];
055
056                try {
057                    checker.match(hostname, peerCertificate);
058                    // Certificate matches hostname
059                    validCertificate = true;
060                }
061                catch (CertificateException ex) {
062                    // Certificate does not match hostname
063                }
064            }
065            else {
066                // Peer does not have any certificates or they aren't X.509
067            }
068        }
069        catch (SSLPeerUnverifiedException ex) {
070            // Not using certificates for peers, try verifying the principal
071            try {
072                Principal peerPrincipal = session.getPeerPrincipal();
073                if (peerPrincipal instanceof KerberosPrincipal) {
074                    validPrincipal = HostnameChecker.match(hostname,
075                                    (KerberosPrincipal) peerPrincipal);
076                }
077                else {
078                    // Can't verify principal, not Kerberos
079                }
080            }
081            catch (SSLPeerUnverifiedException ex2) {
082                // Can't verify principal, no principal
083            }
084        }
085
086        return validCertificate || validPrincipal;
087    }
088}