8284194: Allow empty subject fields in keytool
Reviewed-by: jnimeh, hchao
This commit is contained in:
parent
dc9462137c
commit
f4f1dddfef
@ -37,12 +37,10 @@ import java.security.cert.CertStoreException;
|
|||||||
import java.security.cert.CRL;
|
import java.security.cert.CRL;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.security.cert.CertificateParsingException;
|
|
||||||
import java.security.cert.TrustAnchor;
|
import java.security.cert.TrustAnchor;
|
||||||
import java.security.cert.URICertStoreParameters;
|
import java.security.cert.URICertStoreParameters;
|
||||||
|
|
||||||
|
|
||||||
import java.security.spec.ECParameterSpec;
|
|
||||||
import java.text.Collator;
|
import java.text.Collator;
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@ -66,7 +64,6 @@ import sun.security.provider.certpath.CertPathConstraintsParameters;
|
|||||||
import sun.security.util.ConstraintsParameters;
|
import sun.security.util.ConstraintsParameters;
|
||||||
import sun.security.util.ECKeySizeParameterSpec;
|
import sun.security.util.ECKeySizeParameterSpec;
|
||||||
import sun.security.util.KeyUtil;
|
import sun.security.util.KeyUtil;
|
||||||
import sun.security.util.NamedCurve;
|
|
||||||
import sun.security.util.ObjectIdentifier;
|
import sun.security.util.ObjectIdentifier;
|
||||||
import sun.security.pkcs10.PKCS10;
|
import sun.security.pkcs10.PKCS10;
|
||||||
import sun.security.pkcs10.PKCS10Attribute;
|
import sun.security.pkcs10.PKCS10Attribute;
|
||||||
@ -3731,11 +3728,13 @@ public final class Main {
|
|||||||
String userInput = null;
|
String userInput = null;
|
||||||
|
|
||||||
int maxRetry = 20;
|
int maxRetry = 20;
|
||||||
|
boolean needRepeat;
|
||||||
do {
|
do {
|
||||||
if (maxRetry-- < 0) {
|
if (maxRetry-- < 0) {
|
||||||
throw new RuntimeException(rb.getString(
|
throw new RuntimeException(rb.getString(
|
||||||
"Too.many.retries.program.terminated"));
|
"Too.many.retries.program.terminated"));
|
||||||
}
|
}
|
||||||
|
System.err.println(rb.getString("enter.dname.components"));
|
||||||
commonName = inputString(in,
|
commonName = inputString(in,
|
||||||
rb.getString("What.is.your.first.and.last.name."),
|
rb.getString("What.is.your.first.and.last.name."),
|
||||||
commonName);
|
commonName);
|
||||||
@ -3756,20 +3755,32 @@ public final class Main {
|
|||||||
rb.getString
|
rb.getString
|
||||||
("What.is.the.two.letter.country.code.for.this.unit."),
|
("What.is.the.two.letter.country.code.for.this.unit."),
|
||||||
country);
|
country);
|
||||||
name = new X500Name(commonName, organizationalUnit, organization,
|
name = new X500Name(
|
||||||
city, state, country);
|
dotToNull(commonName), dotToNull(organizationalUnit),
|
||||||
MessageFormat form = new MessageFormat
|
dotToNull(organization), dotToNull(city),
|
||||||
(rb.getString("Is.name.correct."));
|
dotToNull(state), dotToNull(country));
|
||||||
Object[] source = {name};
|
if (name.isEmpty()) {
|
||||||
userInput = inputString
|
System.err.println(rb.getString("no.field.in.dname"));
|
||||||
(in, form.format(source), rb.getString("no"));
|
needRepeat = true;
|
||||||
} while (collator.compare(userInput, rb.getString("yes")) != 0 &&
|
} else {
|
||||||
collator.compare(userInput, rb.getString("y")) != 0);
|
MessageFormat form = new MessageFormat
|
||||||
|
(rb.getString("Is.name.correct."));
|
||||||
|
Object[] source = {name};
|
||||||
|
userInput = inputString
|
||||||
|
(in, form.format(source), rb.getString("no"));
|
||||||
|
needRepeat = collator.compare(userInput, rb.getString("yes")) != 0 &&
|
||||||
|
collator.compare(userInput, rb.getString("y")) != 0;
|
||||||
|
}
|
||||||
|
} while (needRepeat);
|
||||||
|
|
||||||
System.err.println();
|
System.err.println();
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String dotToNull(String input) {
|
||||||
|
return ".".equals(input) ? null : input;
|
||||||
|
}
|
||||||
|
|
||||||
private String inputString(BufferedReader in, String prompt,
|
private String inputString(BufferedReader in, String prompt,
|
||||||
String defaultValue)
|
String defaultValue)
|
||||||
throws IOException
|
throws IOException
|
||||||
@ -3777,7 +3788,7 @@ public final class Main {
|
|||||||
System.err.println(prompt);
|
System.err.println(prompt);
|
||||||
MessageFormat form = new MessageFormat
|
MessageFormat form = new MessageFormat
|
||||||
(rb.getString(".defaultValue."));
|
(rb.getString(".defaultValue."));
|
||||||
Object[] source = {defaultValue};
|
Object[] source = { ".".equals(defaultValue) ? "" : defaultValue };
|
||||||
System.err.print(form.format(source));
|
System.err.print(form.format(source));
|
||||||
System.err.flush();
|
System.err.flush();
|
||||||
|
|
||||||
|
@ -374,6 +374,8 @@ public class Resources extends java.util.ListResourceBundle {
|
|||||||
{"Enter.alias.name.", "Enter alias name: "},
|
{"Enter.alias.name.", "Enter alias name: "},
|
||||||
{".RETURN.if.same.as.for.otherAlias.",
|
{".RETURN.if.same.as.for.otherAlias.",
|
||||||
"\t(RETURN if same as for <{0}>)"},
|
"\t(RETURN if same as for <{0}>)"},
|
||||||
|
{"enter.dname.components",
|
||||||
|
"Enter the distinguished name. Provide a single dot (.) to leave a sub-component empty or press ENTER to use the default value in braces."},
|
||||||
{"What.is.your.first.and.last.name.",
|
{"What.is.your.first.and.last.name.",
|
||||||
"What is your first and last name?"},
|
"What is your first and last name?"},
|
||||||
{"What.is.the.name.of.your.organizational.unit.",
|
{"What.is.the.name.of.your.organizational.unit.",
|
||||||
@ -386,6 +388,8 @@ public class Resources extends java.util.ListResourceBundle {
|
|||||||
"What is the name of your State or Province?"},
|
"What is the name of your State or Province?"},
|
||||||
{"What.is.the.two.letter.country.code.for.this.unit.",
|
{"What.is.the.two.letter.country.code.for.this.unit.",
|
||||||
"What is the two-letter country code for this unit?"},
|
"What is the two-letter country code for this unit?"},
|
||||||
|
{"no.field.in.dname",
|
||||||
|
"At least one field must be provided. Enter again."},
|
||||||
{"Is.name.correct.", "Is {0} correct?"},
|
{"Is.name.correct.", "Is {0} correct?"},
|
||||||
{"no", "no"},
|
{"no", "no"},
|
||||||
{"yes", "yes"},
|
{"yes", "yes"},
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -241,29 +241,45 @@ public class X500Name implements GeneralNameInterface, Principal {
|
|||||||
String organizationName, String localityName,
|
String organizationName, String localityName,
|
||||||
String stateName, String country)
|
String stateName, String country)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
names = new RDN[6];
|
RDN name;
|
||||||
/*
|
List<RDN> list = new ArrayList<>(6);
|
||||||
* NOTE: it's only on output that little-endian
|
if (country != null) {
|
||||||
* ordering is used.
|
name = new RDN(1);
|
||||||
*/
|
name.assertion[0] = new AVA(countryName_oid,
|
||||||
names[5] = new RDN(1);
|
new DerValue(country));
|
||||||
names[5].assertion[0] = new AVA(commonName_oid,
|
list.add(name);
|
||||||
new DerValue(commonName));
|
}
|
||||||
names[4] = new RDN(1);
|
if (stateName != null) {
|
||||||
names[4].assertion[0] = new AVA(orgUnitName_oid,
|
name = new RDN(1);
|
||||||
new DerValue(organizationUnit));
|
name.assertion[0] = new AVA(stateName_oid,
|
||||||
names[3] = new RDN(1);
|
new DerValue(stateName));
|
||||||
names[3].assertion[0] = new AVA(orgName_oid,
|
list.add(name);
|
||||||
new DerValue(organizationName));
|
}
|
||||||
names[2] = new RDN(1);
|
if (localityName != null) {
|
||||||
names[2].assertion[0] = new AVA(localityName_oid,
|
name = new RDN(1);
|
||||||
new DerValue(localityName));
|
name.assertion[0] = new AVA(localityName_oid,
|
||||||
names[1] = new RDN(1);
|
new DerValue(localityName));
|
||||||
names[1].assertion[0] = new AVA(stateName_oid,
|
list.add(name);
|
||||||
new DerValue(stateName));
|
}
|
||||||
names[0] = new RDN(1);
|
if (organizationName != null) {
|
||||||
names[0].assertion[0] = new AVA(countryName_oid,
|
name = new RDN(1);
|
||||||
new DerValue(country));
|
name.assertion[0] = new AVA(orgName_oid,
|
||||||
|
new DerValue(organizationName));
|
||||||
|
list.add(name);
|
||||||
|
}
|
||||||
|
if (organizationUnit != null) {
|
||||||
|
name = new RDN(1);
|
||||||
|
name.assertion[0] = new AVA(orgUnitName_oid,
|
||||||
|
new DerValue(organizationUnit));
|
||||||
|
list.add(name);
|
||||||
|
}
|
||||||
|
if (commonName != null) {
|
||||||
|
name = new RDN(1);
|
||||||
|
name.assertion[0] = new AVA(commonName_oid,
|
||||||
|
new DerValue(commonName));
|
||||||
|
list.add(name);
|
||||||
|
}
|
||||||
|
names = list.toArray(new RDN[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
57
test/jdk/sun/security/tools/keytool/EmptyField.java
Normal file
57
test/jdk/sun/security/tools/keytool/EmptyField.java
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 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
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code 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 General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8284194
|
||||||
|
* @summary Allow empty subject fields in keytool
|
||||||
|
* @library /test/lib
|
||||||
|
*/
|
||||||
|
|
||||||
|
import jdk.test.lib.Asserts;
|
||||||
|
import jdk.test.lib.SecurityTools;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
|
||||||
|
public class EmptyField {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
// All "." in first round, "Me" as name in 2nd round.
|
||||||
|
SecurityTools.setResponse(
|
||||||
|
".\n.\n.\n.\n.\n.\n" // all empty, must retry
|
||||||
|
+ "Me\n\n\n\n\n\nno\n" // one non-empty, ask yes/no
|
||||||
|
+ "\n\n\n\n\n\nyes\n"); // remember input
|
||||||
|
SecurityTools.keytool("-genkeypair -keystore ks -storepass changeit -alias b -keyalg EC")
|
||||||
|
.shouldContain("[Unknown]") // old default
|
||||||
|
.shouldContain("At least one field must be provided. Enter again.")
|
||||||
|
.shouldContain("[]") // new value in 2nd round
|
||||||
|
.shouldContain("[Me]") // new value in 3nd round
|
||||||
|
.shouldContain("Is CN=Me correct?")
|
||||||
|
.shouldHaveExitValue(0);
|
||||||
|
var ks = KeyStore.getInstance(new File("ks"), "changeit".toCharArray());
|
||||||
|
var cert = (X509Certificate) ks.getCertificate("b");
|
||||||
|
Asserts.assertEQ(cert.getSubjectX500Principal().toString(), "CN=Me");
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user