Skip to content

Commit

Permalink
8186143: keytool -ext option doesn't accept wildcards for DNS subject…
Browse files Browse the repository at this point in the history
… alternative names

Backport-of: 0c9f8e4
  • Loading branch information
GoeLin committed Jul 25, 2022
1 parent d17924f commit 20a5c40
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 13 deletions.
18 changes: 13 additions & 5 deletions src/java.base/share/classes/sun/security/tools/keytool/Main.java
Expand Up @@ -4167,9 +4167,10 @@ private static int oneOf(String s, String... list) throws Exception {
* Create a GeneralName object from known types
* @param t one of 5 known types
* @param v value
* @param exttype X.509 extension type
* @return which one
*/
private GeneralName createGeneralName(String t, String v)
private GeneralName createGeneralName(String t, String v, int exttype)
throws Exception {
GeneralNameInterface gn;
int p = oneOf(t, "EMAIL", "URI", "DNS", "IP", "OID");
Expand All @@ -4180,7 +4181,14 @@ private GeneralName createGeneralName(String t, String v)
switch (p) {
case 0: gn = new RFC822Name(v); break;
case 1: gn = new URIName(v); break;
case 2: gn = new DNSName(v); break;
case 2:
if (exttype == 3) {
// Allow wildcard only for SAN extension
gn = new DNSName(v, true);
} else {
gn = new DNSName(v);
}
break;
case 3: gn = new IPAddressName(v); break;
default: gn = new OIDName(v); break; //4
}
Expand Down Expand Up @@ -4475,7 +4483,7 @@ private CertificateExtensions createV3Extensions(
}
String t = item.substring(0, colonpos);
String v = item.substring(colonpos+1);
gnames.add(createGeneralName(t, v));
gnames.add(createGeneralName(t, v, exttype));
}
if (exttype == 3) {
setExt(result, new SubjectAlternativeNameExtension(
Expand Down Expand Up @@ -4529,7 +4537,7 @@ private CertificateExtensions createV3Extensions(
oid = new ObjectIdentifier("1.3.6.1.5.5.7.48." + p);
}
accessDescriptions.add(new AccessDescription(
oid, createGeneralName(t, v)));
oid, createGeneralName(t, v, exttype)));
}
if (exttype == 5) {
setExt(result, new SubjectInfoAccessExtension(accessDescriptions));
Expand All @@ -4552,7 +4560,7 @@ private CertificateExtensions createV3Extensions(
}
String t = item.substring(0, colonpos);
String v = item.substring(colonpos+1);
gnames.add(createGeneralName(t, v));
gnames.add(createGeneralName(t, v, exttype));
}
setExt(result, new CRLDistributionPointsExtension(
isCritical, Collections.singletonList(
Expand Down
39 changes: 33 additions & 6 deletions src/java.base/share/classes/sun/security/x509/DNSName.java
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2020, 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
Expand Down Expand Up @@ -69,9 +69,10 @@ public DNSName(DerValue derValue) throws IOException {
* Create the DNSName object with the specified name.
*
* @param name the DNSName.
* @throws IOException if the name is not a valid DNSName subjectAltName
* @param allowWildcard the flag for wildcard checking.
* @throws IOException if the name is not a valid DNSName
*/
public DNSName(String name) throws IOException {
public DNSName(String name, boolean allowWildcard) throws IOException {
if (name == null || name.isEmpty())
throw new IOException("DNSName must not be null or empty");
if (name.contains(" "))
Expand All @@ -91,9 +92,26 @@ public DNSName(String name) throws IOException {
if (endIndex - startIndex < 1)
throw new IOException("DNSName with empty components are not permitted");

// RFC 1123: DNSName components must begin with a letter or digit
if (alphaDigits.indexOf(name.charAt(startIndex)) < 0)
throw new IOException("DNSName components must begin with a letter or digit");
if (allowWildcard) {
// RFC 1123: DNSName components must begin with a letter or digit
// or RFC 4592: the first component of a DNSName can have only a wildcard
// character * (asterisk), i.e. *.example.com. Asterisks at other components
// will not be allowed as a wildcard.
if (alphaDigits.indexOf(name.charAt(startIndex)) < 0) {
// Checking to make sure the wildcard only appears in the first component,
// and it has to be at least 3-char long with the form of *.[alphaDigit]
if ((name.length() < 3) || (name.indexOf('*', 0) != 0) ||
(name.charAt(startIndex+1) != '.') ||
(alphaDigits.indexOf(name.charAt(startIndex+2)) < 0))
throw new IOException("DNSName components must begin with a letter, digit, "
+ "or the first component can have only a wildcard character *");
}
} else {
// RFC 1123: DNSName components must begin with a letter or digit
if (alphaDigits.indexOf(name.charAt(startIndex)) < 0)
throw new IOException("DNSName components must begin with a letter or digit");
}

//nonStartIndex: index for characters in the component beyond the first one
for (int nonStartIndex=startIndex+1; nonStartIndex < endIndex; nonStartIndex++) {
char x = name.charAt(nonStartIndex);
Expand All @@ -104,6 +122,15 @@ public DNSName(String name) throws IOException {
this.name = name;
}

/**
* Create the DNSName object with the specified name.
*
* @param name the DNSName.
* @throws IOException if the name is not a valid DNSName
*/
public DNSName(String name) throws IOException {
this(name, false);
}

/**
* Return the type of the GeneralName.
Expand Down
65 changes: 63 additions & 2 deletions test/jdk/sun/security/x509/GeneralName/DNSNameTest.java
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2020, 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
Expand All @@ -24,7 +24,7 @@
/**
* @test
* @summary DNSName parsing tests
* @bug 8213952
* @bug 8213952 8186143
* @modules java.base/sun.security.x509
* @run testng DNSNameTest
*/
Expand Down Expand Up @@ -53,6 +53,23 @@ public Object[][] goodNames() {
return data;
}

@DataProvider(name = "goodSanNames")
public Object[][] goodSanNames() {
Object[][] data = {
{"abc.com"},
{"ABC.COM"},
{"a12.com"},
{"a1b2c3.com"},
{"1abc.com"},
{"123.com"},
{"abc.com-"}, // end with hyphen
{"a-b-c.com"}, // hyphens
{"*.domain.com"}, // wildcard in 1st level subdomain
{"*.com"},
};
return data;
}

@DataProvider(name = "badNames")
public Object[][] badNames() {
Object[][] data = {
Expand All @@ -65,10 +82,34 @@ public Object[][] badNames() {
{"a."}, // end with .
{""}, // empty
{" "}, // space only
{"*.domain.com"}, // wildcard not allowed
{"a*.com"}, // only allow letter, digit, or hyphen
};
return data;
}

@DataProvider(name = "badSanNames")
public Object[][] badSanNames() {
Object[][] data = {
{" 1abc.com"}, // begin with space
{"1abc.com "}, // end with space
{"1a bc.com "}, // no space allowed
{"-abc.com"}, // begin with hyphen
{"a..b"}, // ..
{".a"}, // begin with .
{"a."}, // end with .
{""}, // empty
{" "}, // space only
{"*"}, // wildcard only
{"*a.com"}, // partial wildcard disallowed
{"abc.*.com"}, // wildcard not allowed in 2nd level
{"*.*.domain.com"}, // double wildcard not allowed
{"a*.com"}, // only allow letter, digit, or hyphen
};
return data;
}


@Test(dataProvider = "goodNames")
public void testGoodDNSName(String dnsNameString) {
try {
Expand All @@ -78,6 +119,15 @@ public void testGoodDNSName(String dnsNameString) {
}
}

@Test(dataProvider = "goodSanNames")
public void testGoodSanDNSName(String dnsNameString) {
try {
DNSName dn = new DNSName(dnsNameString, true);
} catch (IOException e) {
fail("Unexpected IOException");
}
}

@Test(dataProvider = "badNames")
public void testBadDNSName(String dnsNameString) {
try {
Expand All @@ -88,4 +138,15 @@ public void testBadDNSName(String dnsNameString) {
fail("Unexpeceted message: " + e);
}
}

@Test(dataProvider = "badSanNames")
public void testBadSanDNSName(String dnsNameString) {
try {
DNSName dn = new DNSName(dnsNameString, true);
fail("IOException expected");
} catch (IOException e) {
if (!e.getMessage().contains("DNSName"))
fail("Unexpeceted message: " + e);
}
}
}

1 comment on commit 20a5c40

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.