All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.aoju.bus.http.secure.OkHostnameVerifier Maven / Gradle / Ivy

/*
 * The MIT License
 *
 * Copyright (c) 2015-2020 aoju.org All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.aoju.bus.http.secure;

import org.aoju.bus.core.lang.Symbol;
import org.aoju.bus.http.Builder;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import java.security.cert.Certificate;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.util.*;

/**
 * 一个与RFC 2818一致的HostnameVerifier
 *
 * @author Kimi Liu
 * @version 5.6.5
 * @since JDK 1.8+
 */
public final class OkHostnameVerifier implements HostnameVerifier {

    public static final OkHostnameVerifier INSTANCE = new OkHostnameVerifier();

    private static final int ALT_DNS_NAME = 2;
    private static final int ALT_IPA_NAME = 7;

    private OkHostnameVerifier() {
    }

    public static List allSubjectAltNames(X509Certificate certificate) {
        List altIpaNames = getSubjectAltNames(certificate, ALT_IPA_NAME);
        List altDnsNames = getSubjectAltNames(certificate, ALT_DNS_NAME);
        List result = new ArrayList<>(altIpaNames.size() + altDnsNames.size());
        result.addAll(altIpaNames);
        result.addAll(altDnsNames);
        return result;
    }

    private static List getSubjectAltNames(X509Certificate certificate, int type) {
        List result = new ArrayList<>();
        try {
            Collection subjectAltNames = certificate.getSubjectAlternativeNames();
            if (subjectAltNames == null) {
                return Collections.emptyList();
            }
            for (Object subjectAltName : subjectAltNames) {
                List entry = (List) subjectAltName;
                if (entry == null || entry.size() < 2) {
                    continue;
                }
                Integer altNameType = (Integer) entry.get(0);
                if (altNameType == null) {
                    continue;
                }
                if (altNameType == type) {
                    String altName = (String) entry.get(1);
                    if (altName != null) {
                        result.add(altName);
                    }
                }
            }
            return result;
        } catch (CertificateParsingException e) {
            return Collections.emptyList();
        }
    }

    @Override
    public boolean verify(String host, SSLSession session) {
        try {
            Certificate[] certificates = session.getPeerCertificates();
            return verify(host, (X509Certificate) certificates[0]);
        } catch (SSLException e) {
            return false;
        }
    }

    public boolean verify(String host, X509Certificate certificate) {
        return Builder.verifyAsIpAddress(host)
                ? verifyIpAddress(host, certificate)
                : verifyHostname(host, certificate);
    }

    private boolean verifyIpAddress(String ipAddress, X509Certificate certificate) {
        List altNames = getSubjectAltNames(certificate, ALT_IPA_NAME);
        for (int i = 0, size = altNames.size(); i < size; i++) {
            if (ipAddress.equalsIgnoreCase(altNames.get(i))) {
                return true;
            }
        }
        return false;
    }

    private boolean verifyHostname(String hostname, X509Certificate certificate) {
        hostname = hostname.toLowerCase(Locale.US);
        List altNames = getSubjectAltNames(certificate, ALT_DNS_NAME);
        for (String altName : altNames) {
            if (verifyHostname(hostname, altName)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 返回{@code true} iff {@code hostname}匹配域名{@code pattern}.
     *
     * @param hostname 小写字母的主机名.
     * @param pattern  从证书的域名模式。可能是一个通配符模式,如{@code *.android.com}
     * @return the true/false
     */
    public boolean verifyHostname(String hostname, String pattern) {
        // 基本健康检查
        if ((hostname == null) || (hostname.length() == 0) || (hostname.startsWith(Symbol.DOT))
                || (hostname.endsWith(Symbol.DOUBLE_DOT))) {
            return false;
        }
        if ((pattern == null) || (pattern.length() == 0) || (pattern.startsWith(Symbol.DOT))
                || (pattern.endsWith(Symbol.DOUBLE_DOT))) {
            return false;
        }

        if (!hostname.endsWith(Symbol.DOT)) {
            hostname += Symbol.C_DOT;
        }
        if (!pattern.endsWith(Symbol.DOT)) {
            pattern += Symbol.C_DOT;
        }

        pattern = pattern.toLowerCase(Locale.US);
        // 主机名和模式现在是小写的——域名不区分大小写.

        if (!pattern.contains(Symbol.STAR)) {
            // 不是通配符模式——主机名和模式必须完全匹配.
            return hostname.equals(pattern);
        }

        if ((!pattern.startsWith("*.")) || (pattern.indexOf(Symbol.C_STAR, 1) != -1)) {
            return false;
        }

        if (hostname.length() < pattern.length()) {
            return false;
        }

        if ("*.".equals(pattern)) {
            return false;
        }

        String suffix = pattern.substring(1);
        if (!hostname.endsWith(suffix)) {
            return false;
        }

        int suffixStartIndexInHostname = hostname.length() - suffix.length();
        if ((suffixStartIndexInHostname > 0)
                && (hostname.lastIndexOf(Symbol.C_DOT, suffixStartIndexInHostname - 1) != -1)) {
            return false;
        }

        return true;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy