Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8186143: keytool -ext option doesn't accept wildcards for DNS subject alternative names #629

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions jdk/src/share/classes/sun/security/tools/keytool/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -3982,9 +3982,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 @@ -3995,7 +3996,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 @@ -4249,7 +4257,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) {
ext.set(SubjectAlternativeNameExtension.NAME,
Expand Down Expand Up @@ -4305,7 +4313,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) {
ext.set(SubjectInfoAccessExtension.NAME,
Expand All @@ -4330,7 +4338,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));
}
ext.set(CRLDistributionPointsExtension.NAME,
new CRLDistributionPointsExtension(
Expand Down
39 changes: 33 additions & 6 deletions jdk/src/share/classes/sun/security/x509/DNSName.java
Original file line number Diff line number Diff line change
@@ -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.length() == 0)
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 jdk/test/sun/security/x509/GeneralName/DNSNameTest.java
Original file line number Diff line number Diff line change
@@ -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);
}
}
}