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

net.luminis.tls.DefaultHostnameVerifier Maven / Gradle / Ivy

Go to download

A (partial) TLS 1.3 implementation in Java, suitable and intended for use in a QUIC implementation.

There is a newer version: 2.3
Show newest version
/*
 * Copyright © 2019, 2020, 2021, 2022, 2023 Peter Doornbosch
 *
 * This file is part of Agent15, an implementation of TLS 1.3 in Java.
 *
 * Agent15 is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 *
 * Agent15 is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
 * more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program. If not, see .
 */
package net.luminis.tls;

import java.security.Principal;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

/**
 * A hostname verifier that requires that the server name equals the CN part of the certificate's subject DN,
 * or matches one of the dnsName-type "Subject Alternative Name" entries of the certificate.
 */
public class DefaultHostnameVerifier implements HostnameVerifier {

    @Override
    public boolean verify(String serverName, X509Certificate serverCertificate) {
        try {
            boolean matchesSan = verifyHostname(serverName, serverCertificate.getSubjectAlternativeNames());
            if (matchesSan) {
                return true;
            }
            else {
                return verifyHostname(serverName, serverCertificate.getSubjectDN());
            }
        } catch (CertificateParsingException e) {
            Logger.debug("Retrieving subject alternative names from certificate failed");
            return false;
        }
    }

    boolean verifyHostname(String serverName, Collection> subjectAlternativeNames) {
        if (subjectAlternativeNames == null) {
            return false;
        }

        return subjectAlternativeNames.stream()
                // Each entry is a List whose first entry is an Integer (the name type, 0-8) and whose
                // second entry is a String or a byte array (the name, in string or ASN.1 DER encoded form, respectively).
                .filter(entryList -> entryList.get(0).equals(2))   // 2  is "dNSName"
                .map(entryList -> (String) entryList.get(1))
                .anyMatch(dnsName -> serverNameMatchesDnsName(serverName, dnsName));
    }

    boolean serverNameMatchesDnsName(String serverName, String dnsName) {
        if (serverName == null || dnsName == null || serverName.trim().equals("") || dnsName.trim().equals("")) {
            throw new IllegalArgumentException("can't be null or empty");
        }

        if (dnsName.startsWith("*.")) {
            int firstFullStop = serverName.indexOf(".");
            boolean matchesTrueSubdomain = firstFullStop > 0 && serverName.substring(firstFullStop + 1).equals(dnsName.substring(2));
            boolean matchesFullDomain = serverName.equals(dnsName.substring(2));
            return matchesTrueSubdomain || matchesFullDomain;
        }
        else {
            return serverName.equals(dnsName);
        }
    }

    boolean verifyHostname(String serverName, Principal subjectDN) {
        String dn = subjectDN.getName();
        boolean matches = Arrays.stream(dn.split(","))
                .map(s -> s.trim())
                .filter(s -> s.startsWith("CN="))
                .map(s -> s.replace("CN=", ""))
                .allMatch(s -> s.equals(serverName));
        return matches;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy