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.X509Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateParsingException;
|
||||
import java.security.cert.TrustAnchor;
|
||||
import java.security.cert.URICertStoreParameters;
|
||||
|
||||
|
||||
import java.security.spec.ECParameterSpec;
|
||||
import java.text.Collator;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.*;
|
||||
@ -66,7 +64,6 @@ import sun.security.provider.certpath.CertPathConstraintsParameters;
|
||||
import sun.security.util.ConstraintsParameters;
|
||||
import sun.security.util.ECKeySizeParameterSpec;
|
||||
import sun.security.util.KeyUtil;
|
||||
import sun.security.util.NamedCurve;
|
||||
import sun.security.util.ObjectIdentifier;
|
||||
import sun.security.pkcs10.PKCS10;
|
||||
import sun.security.pkcs10.PKCS10Attribute;
|
||||
@ -3731,11 +3728,13 @@ public final class Main {
|
||||
String userInput = null;
|
||||
|
||||
int maxRetry = 20;
|
||||
boolean needRepeat;
|
||||
do {
|
||||
if (maxRetry-- < 0) {
|
||||
throw new RuntimeException(rb.getString(
|
||||
"Too.many.retries.program.terminated"));
|
||||
}
|
||||
System.err.println(rb.getString("enter.dname.components"));
|
||||
commonName = inputString(in,
|
||||
rb.getString("What.is.your.first.and.last.name."),
|
||||
commonName);
|
||||
@ -3756,20 +3755,32 @@ public final class Main {
|
||||
rb.getString
|
||||
("What.is.the.two.letter.country.code.for.this.unit."),
|
||||
country);
|
||||
name = new X500Name(commonName, organizationalUnit, organization,
|
||||
city, state, country);
|
||||
MessageFormat form = new MessageFormat
|
||||
(rb.getString("Is.name.correct."));
|
||||
Object[] source = {name};
|
||||
userInput = inputString
|
||||
(in, form.format(source), rb.getString("no"));
|
||||
} while (collator.compare(userInput, rb.getString("yes")) != 0 &&
|
||||
collator.compare(userInput, rb.getString("y")) != 0);
|
||||
name = new X500Name(
|
||||
dotToNull(commonName), dotToNull(organizationalUnit),
|
||||
dotToNull(organization), dotToNull(city),
|
||||
dotToNull(state), dotToNull(country));
|
||||
if (name.isEmpty()) {
|
||||
System.err.println(rb.getString("no.field.in.dname"));
|
||||
needRepeat = true;
|
||||
} else {
|
||||
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();
|
||||
return name;
|
||||
}
|
||||
|
||||
private static String dotToNull(String input) {
|
||||
return ".".equals(input) ? null : input;
|
||||
}
|
||||
|
||||
private String inputString(BufferedReader in, String prompt,
|
||||
String defaultValue)
|
||||
throws IOException
|
||||
@ -3777,7 +3788,7 @@ public final class Main {
|
||||
System.err.println(prompt);
|
||||
MessageFormat form = new MessageFormat
|
||||
(rb.getString(".defaultValue."));
|
||||
Object[] source = {defaultValue};
|
||||
Object[] source = { ".".equals(defaultValue) ? "" : defaultValue };
|
||||
System.err.print(form.format(source));
|
||||
System.err.flush();
|
||||
|
||||
|
@ -374,6 +374,8 @@ public class Resources extends java.util.ListResourceBundle {
|
||||
{"Enter.alias.name.", "Enter alias name: "},
|
||||
{".RETURN.if.same.as.for.otherAlias.",
|
||||
"\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.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.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?"},
|
||||
{"no", "no"},
|
||||
{"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.
|
||||
*
|
||||
* 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 stateName, String country)
|
||||
throws IOException {
|
||||
names = new RDN[6];
|
||||
/*
|
||||
* NOTE: it's only on output that little-endian
|
||||
* ordering is used.
|
||||
*/
|
||||
names[5] = new RDN(1);
|
||||
names[5].assertion[0] = new AVA(commonName_oid,
|
||||
new DerValue(commonName));
|
||||
names[4] = new RDN(1);
|
||||
names[4].assertion[0] = new AVA(orgUnitName_oid,
|
||||
new DerValue(organizationUnit));
|
||||
names[3] = new RDN(1);
|
||||
names[3].assertion[0] = new AVA(orgName_oid,
|
||||
new DerValue(organizationName));
|
||||
names[2] = new RDN(1);
|
||||
names[2].assertion[0] = new AVA(localityName_oid,
|
||||
new DerValue(localityName));
|
||||
names[1] = new RDN(1);
|
||||
names[1].assertion[0] = new AVA(stateName_oid,
|
||||
new DerValue(stateName));
|
||||
names[0] = new RDN(1);
|
||||
names[0].assertion[0] = new AVA(countryName_oid,
|
||||
new DerValue(country));
|
||||
RDN name;
|
||||
List<RDN> list = new ArrayList<>(6);
|
||||
if (country != null) {
|
||||
name = new RDN(1);
|
||||
name.assertion[0] = new AVA(countryName_oid,
|
||||
new DerValue(country));
|
||||
list.add(name);
|
||||
}
|
||||
if (stateName != null) {
|
||||
name = new RDN(1);
|
||||
name.assertion[0] = new AVA(stateName_oid,
|
||||
new DerValue(stateName));
|
||||
list.add(name);
|
||||
}
|
||||
if (localityName != null) {
|
||||
name = new RDN(1);
|
||||
name.assertion[0] = new AVA(localityName_oid,
|
||||
new DerValue(localityName));
|
||||
list.add(name);
|
||||
}
|
||||
if (organizationName != null) {
|
||||
name = new RDN(1);
|
||||
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