7192189: Support endpoint identification algorithm in RFC 6125

Reviewed-by: xuelei, rhalade
This commit is contained in:
Sean Mullan 2022-03-08 18:18:57 +00:00
parent 288d1afc5a
commit 72e987e3b4
8 changed files with 29 additions and 43 deletions
src/java.base/share/classes/sun/security/util
test/jdk/sun/security/util/HostnameChecker

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -178,7 +178,7 @@ public class HostnameChecker {
* Certification Authorities are encouraged to use the dNSName instead.
*
* Matching is performed using the matching rules specified by
* [RFC5280]. If more than one identity of a given type is present in
* [RFC6125]. If more than one identity of a given type is present in
* the certificate (e.g., more than one dNSName name, a match in any one
* of the set is considered acceptable.)
*/
@ -262,7 +262,7 @@ public class HostnameChecker {
/**
* Returns true if name matches against template.<p>
*
* The matching is performed as per RFC 2818 rules for TLS and
* The matching is performed as per RFC 2818/6125 rules for TLS and
* RFC 2830 rules for LDAP.<p>
*
* The <code>name</code> parameter should represent a DNS name. The
@ -299,9 +299,7 @@ public class HostnameChecker {
return false;
}
if (checkType == TYPE_TLS) {
return matchAllWildcards(name, template);
} else if (checkType == TYPE_LDAP) {
if (checkType == TYPE_TLS || checkType == TYPE_LDAP) {
return matchLeftmostWildcard(name, template);
} else {
return false;
@ -371,37 +369,6 @@ public class HostnameChecker {
return false;
}
/**
* Returns true if name matches against template.<p>
*
* According to RFC 2818, section 3.1 -
* Names may contain the wildcard character * which is
* considered to match any single domain name component
* or component fragment.
* E.g., *.a.com matches foo.a.com but not
* bar.foo.a.com. f*.com matches foo.com but not bar.com.
*/
private static boolean matchAllWildcards(String name,
String template) {
name = name.toLowerCase(Locale.ENGLISH);
template = template.toLowerCase(Locale.ENGLISH);
StringTokenizer nameSt = new StringTokenizer(name, ".");
StringTokenizer templateSt = new StringTokenizer(template, ".");
if (nameSt.countTokens() != templateSt.countTokens()) {
return false;
}
while (nameSt.hasMoreTokens()) {
if (!matchWildCards(nameSt.nextToken(),
templateSt.nextToken())) {
return false;
}
}
return true;
}
/**
* Returns true if name matches against template.<p>
*

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -23,16 +23,19 @@
/*
* @test
* @bug 4514108
* @summary Verify host name matching behaves as defined in RFC2818.
* @bug 4514108 7192189
* @summary Verify host name matching behaves as defined in RFC2818 and RFC6125.
* @library /test/lib
* @modules java.base/sun.security.util
* @modules java.base/sun.security.util java.base/sun.security.x509
*/
import java.security.cert.*;
import java.util.Collection;
import java.util.List;
import jdk.test.lib.security.CertUtils;
import sun.security.util.*;
import sun.security.x509.X509CertImpl;
/**
* Certificate 1:
@ -193,10 +196,17 @@ public class TestHostnameChecker {
check(checker, "altfoo2.com", cert3, true);
check(checker, "5.6.7.8", cert3, true);
check(checker, "foo.bar.com", cert4, true);
check(checker, "altfoo.bar.com", cert4, true);
check(checker, "altfoo.bar.com", cert4, false);
check(checker, "2001:db8:3c4d:15::1a2f:1a2b", cert5, true);
check(checker, "2001:0db8:3c4d:0015:0000:0000:1a2f:1a2b", cert5, true);
check(checker, "2002:db8:3c4d:15::1a2f:1a2b", cert5, false);
check(checker, "foo.bar.example.net", mock("foo.*.example.net"), false);
check(checker, "baz1.example.net", mock("baz*.example.net"), true);
check(checker, "foobaz.example.net", mock("*baz.example.net"), true);
check(checker, "buzz.example.net", mock("b*z.example.net"), true);
check(checker, "公司.example.net", mock("xn--5*.example.net"), false);
check(checker, "公司.江利子.example.net",
mock("*.xn--kcry6tjko.example.net"), true);
checker = HostnameChecker.getInstance(
HostnameChecker.TYPE_LDAP);
@ -214,6 +224,15 @@ public class TestHostnameChecker {
check(checker, "altfoo.bar.com", cert4, false);
}
private static X509Certificate mock(String domain) {
return new X509CertImpl() {
@Override
public Collection<List<?>> getSubjectAlternativeNames() {
return List.of(List.of(2, domain));
}
};
}
private static void check(HostnameChecker checker, String name,
X509Certificate cert, boolean expectedResult)
throws Exception {
@ -224,7 +243,7 @@ public class TestHostnameChecker {
}
} catch (CertificateException e) {
if (expectedResult == true) {
throw e;
throw new Exception("Failed valid test: " + name, e);
}
}
System.out.println("OK: " + name);