--- a/src/java.base/share/classes/sun/security/tools/keytool/Main.java Fri Jan 18 15:44:17 2019 -0800
+++ b/src/java.base/share/classes/sun/security/tools/keytool/Main.java Sat Jan 19 09:20:47 2019 +0800
@@ -3784,9 +3784,9 @@
replyCerts.length);
tmpCerts[tmpCerts.length-1] = root.snd;
replyCerts = tmpCerts;
- checkWeak(String.format(rb.getString(fromKeyStore ?
- "alias.in.keystore" :
- "alias.in.cacerts"),
+ checkWeak(String.format(fromKeyStore
+ ? rb.getString("alias.in.keystore")
+ : rb.getString("alias.in.cacerts"),
root.fst),
root.snd);
}
--- a/src/java.base/share/classes/sun/security/tools/keytool/Resources.java Fri Jan 18 15:44:17 2019 -0800
+++ b/src/java.base/share/classes/sun/security/tools/keytool/Resources.java Sat Jan 19 09:20:47 2019 +0800
@@ -253,7 +253,6 @@
{"Keystore.password.is.too.short.must.be.at.least.6.characters",
"Keystore password is too short - must be at least 6 characters"},
{"Unknown.Entry.Type", "Unknown Entry Type"},
- {"Too.many.failures.Alias.not.changed", "Too many failures. Alias not changed"},
{"Entry.for.alias.alias.successfully.imported.",
"Entry for alias {0} successfully imported."},
{"Entry.for.alias.alias.not.imported.", "Entry for alias {0} not imported."},
@@ -314,10 +313,6 @@
{"Too.many.failures.Key.entry.not.cloned",
"Too many failures. Key entry not cloned"},
{"key.password.for.alias.", "key password for <{0}>"},
- {"Keystore.entry.for.id.getName.already.exists",
- "Keystore entry for <{0}> already exists"},
- {"Creating.keystore.entry.for.id.getName.",
- "Creating keystore entry for <{0}> ..."},
{"No.entries.from.identity.database.added",
"No entries from identity database added"},
{"Alias.name.alias", "Alias name: {0}"},
@@ -355,7 +350,6 @@
{"Do.you.still.want.to.add.it.to.your.own.keystore.no.",
"Do you still want to add it to your own keystore? [no]: "},
{"Trust.this.certificate.no.", "Trust this certificate? [no]: "},
- {"YES", "YES"},
{"New.prompt.", "New {0}: "},
{"Passwords.must.differ", "Passwords must differ"},
{"Re.enter.new.prompt.", "Re-enter new {0}: "},
@@ -395,7 +389,6 @@
{"Signer.d.", "Signer #%d:"},
{"Timestamp.", "Timestamp:"},
{"Signature.", "Signature:"},
- {"CRLs.", "CRLs:"},
{"Certificate.owner.", "Certificate owner: "},
{"Not.a.signed.jar.file", "Not a signed jar file"},
{"No.certificate.from.the.SSL.server",
@@ -414,13 +407,10 @@
"Certificate reply does not contain public key for <{0}>"},
{"Incomplete.certificate.chain.in.reply",
"Incomplete certificate chain in reply"},
- {"Certificate.chain.in.reply.does.not.verify.",
- "Certificate chain in reply does not verify: "},
{"Top.level.certificate.in.reply.",
"Top-level certificate in reply:\n"},
{".is.not.trusted.", "... is not trusted. "},
{"Install.reply.anyway.no.", "Install reply anyway? [no]: "},
- {"NO", "NO"},
{"Public.keys.in.reply.and.keystore.don.t.match",
"Public keys in reply and keystore don't match"},
{"Certificate.reply.and.certificate.in.keystore.are.identical",
--- a/src/java.base/share/classes/sun/security/util/Resources.java Fri Jan 18 15:44:17 2019 -0800
+++ b/src/java.base/share/classes/sun/security/util/Resources.java Sat Jan 19 09:20:47 2019 +0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2018, 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
@@ -66,8 +66,6 @@
{"Subject.", "Subject:\n"},
{".Principal.", "\tPrincipal: "},
{".Public.Credential.", "\tPublic Credential: "},
- {".Private.Credentials.inaccessible.",
- "\tPrivate Credentials inaccessible\n"},
{".Private.Credential.", "\tPrivate Credential: "},
{".Private.Credential.inaccessible.",
"\tPrivate Credential inaccessible\n"},
@@ -89,16 +87,6 @@
"invalid null CallbackHandler provided"},
{"null.subject.logout.called.before.login",
"null subject - logout called before login"},
- {"unable.to.instantiate.LoginModule.module.because.it.does.not.provide.a.no.argument.constructor",
- "unable to instantiate LoginModule, {0}, because it does not provide a no-argument constructor"},
- {"unable.to.instantiate.LoginModule",
- "unable to instantiate LoginModule"},
- {"unable.to.instantiate.LoginModule.",
- "unable to instantiate LoginModule: "},
- {"unable.to.find.LoginModule.class.",
- "unable to find LoginModule class: "},
- {"unable.to.access.LoginModule.",
- "unable to access LoginModule: "},
{"Login.Failure.all.modules.ignored",
"Login Failure: all modules ignored"},
--- a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java Fri Jan 18 15:44:17 2019 -0800
+++ b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java Sat Jan 19 09:20:47 2019 +0800
@@ -1030,31 +1030,31 @@
(hasExpiredTsaCert && !signerNotExpired)) {
if (strict) {
- result = rb.getString(isSigning
- ? "jar.signed.with.signer.errors."
- : "jar.verified.with.signer.errors.");
+ result = isSigning
+ ? rb.getString("jar.signed.with.signer.errors.")
+ : rb.getString("jar.verified.with.signer.errors.");
} else {
- result = rb.getString(isSigning
- ? "jar.signed."
- : "jar.verified.");
+ result = isSigning
+ ? rb.getString("jar.signed.")
+ : rb.getString("jar.verified.");
}
if (badKeyUsage) {
- errors.add(rb.getString(isSigning
- ? "The.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing."
- : "This.jar.contains.entries.whose.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing."));
+ errors.add(isSigning
+ ? rb.getString("The.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing.")
+ : rb.getString("This.jar.contains.entries.whose.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing."));
}
if (badExtendedKeyUsage) {
- errors.add(rb.getString(isSigning
- ? "The.signer.certificate.s.ExtendedKeyUsage.extension.doesn.t.allow.code.signing."
- : "This.jar.contains.entries.whose.signer.certificate.s.ExtendedKeyUsage.extension.doesn.t.allow.code.signing."));
+ errors.add(isSigning
+ ? rb.getString("The.signer.certificate.s.ExtendedKeyUsage.extension.doesn.t.allow.code.signing.")
+ : rb.getString("This.jar.contains.entries.whose.signer.certificate.s.ExtendedKeyUsage.extension.doesn.t.allow.code.signing."));
}
if (badNetscapeCertType) {
- errors.add(rb.getString(isSigning
- ? "The.signer.certificate.s.NetscapeCertType.extension.doesn.t.allow.code.signing."
- : "This.jar.contains.entries.whose.signer.certificate.s.NetscapeCertType.extension.doesn.t.allow.code.signing."));
+ errors.add(isSigning
+ ? rb.getString("The.signer.certificate.s.NetscapeCertType.extension.doesn.t.allow.code.signing.")
+ : rb.getString("This.jar.contains.entries.whose.signer.certificate.s.NetscapeCertType.extension.doesn.t.allow.code.signing."));
}
// only in verifying
@@ -1063,20 +1063,20 @@
"This.jar.contains.unsigned.entries.which.have.not.been.integrity.checked."));
}
if (hasExpiredCert) {
- errors.add(rb.getString(isSigning
- ? "The.signer.certificate.has.expired."
- : "This.jar.contains.entries.whose.signer.certificate.has.expired."));
+ errors.add(isSigning
+ ? rb.getString("The.signer.certificate.has.expired.")
+ : rb.getString("This.jar.contains.entries.whose.signer.certificate.has.expired."));
}
if (notYetValidCert) {
- errors.add(rb.getString(isSigning
- ? "The.signer.certificate.is.not.yet.valid."
- : "This.jar.contains.entries.whose.signer.certificate.is.not.yet.valid."));
+ errors.add(isSigning
+ ? rb.getString("The.signer.certificate.is.not.yet.valid.")
+ : rb.getString("This.jar.contains.entries.whose.signer.certificate.is.not.yet.valid."));
}
if (chainNotValidated) {
- errors.add(String.format(rb.getString(isSigning
- ? "The.signer.s.certificate.chain.is.invalid.reason.1"
- : "This.jar.contains.entries.whose.certificate.chain.is.invalid.reason.1"),
+ errors.add(String.format(isSigning
+ ? rb.getString("The.signer.s.certificate.chain.is.invalid.reason.1")
+ : rb.getString("This.jar.contains.entries.whose.certificate.chain.is.invalid.reason.1"),
chainNotValidatedReason.getLocalizedMessage()));
}
@@ -1084,9 +1084,9 @@
errors.add(rb.getString("The.timestamp.has.expired."));
}
if (tsaChainNotValidated) {
- errors.add(String.format(rb.getString(isSigning
- ? "The.tsa.certificate.chain.is.invalid.reason.1"
- : "This.jar.contains.entries.whose.tsa.certificate.chain.is.invalid.reason.1"),
+ errors.add(String.format(isSigning
+ ? rb.getString("The.tsa.certificate.chain.is.invalid.reason.1")
+ : rb.getString("This.jar.contains.entries.whose.tsa.certificate.chain.is.invalid.reason.1"),
tsaChainNotValidatedReason.getLocalizedMessage()));
}
@@ -1102,9 +1102,9 @@
}
if (signerSelfSigned) {
- errors.add(rb.getString(isSigning
- ? "The.signer.s.certificate.is.self.signed."
- : "This.jar.contains.entries.whose.signer.certificate.is.self.signed."));
+ errors.add(isSigning
+ ? rb.getString("The.signer.s.certificate.is.self.signed.")
+ : rb.getString("This.jar.contains.entries.whose.signer.certificate.is.self.signed."));
}
// weakAlg only detected in signing. The jar file is
@@ -1131,7 +1131,7 @@
privateKey.getAlgorithm(), KeyUtil.getKeySize(privateKey)));
}
} else {
- result = rb.getString(isSigning ? "jar.signed." : "jar.verified.");
+ result = isSigning ? rb.getString("jar.signed.") : rb.getString("jar.verified.");
}
if (hasExpiredTsaCert) {
@@ -1155,9 +1155,9 @@
hasExpiredTsaCert = false;
}
if (hasExpiringCert) {
- warnings.add(rb.getString(isSigning
- ? "The.signer.certificate.will.expire.within.six.months."
- : "This.jar.contains.entries.whose.signer.certificate.will.expire.within.six.months."));
+ warnings.add(isSigning
+ ? rb.getString("The.signer.certificate.will.expire.within.six.months.")
+ : rb.getString("This.jar.contains.entries.whose.signer.certificate.will.expire.within.six.months."));
}
if (hasExpiringTsaCert && expireDate != null) {
if (expireDate.after(tsaExpireDate)) {
@@ -1170,13 +1170,13 @@
}
if (noTimestamp && expireDate != null) {
if (hasTimestampBlock) {
- warnings.add(String.format(rb.getString(isSigning
- ? "invalid.timestamp.signing"
- : "bad.timestamp.verifying"), expireDate));
+ warnings.add(String.format(isSigning
+ ? rb.getString("invalid.timestamp.signing")
+ : rb.getString("bad.timestamp.verifying"), expireDate));
} else {
- warnings.add(String.format(rb.getString(isSigning
- ? "no.timestamp.signing"
- : "no.timestamp.verifying"), expireDate));
+ warnings.add(String.format(isSigning
+ ? rb.getString("no.timestamp.signing")
+ : rb.getString("no.timestamp.verifying"), expireDate));
}
}
}
@@ -1551,7 +1551,20 @@
if (verbose != null) {
builder.eventHandler((action, file) -> {
- System.out.println(rb.getString("." + action + ".") + file);
+ switch (action) {
+ case "signing":
+ System.out.println(rb.getString(".signing.") + file);
+ break;
+ case "adding":
+ System.out.println(rb.getString(".adding.") + file);
+ break;
+ case "updating":
+ System.out.println(rb.getString(".updating.") + file);
+ break;
+ default:
+ throw new IllegalArgumentException("unknown action: "
+ + action);
+ }
});
}
--- a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java Fri Jan 18 15:44:17 2019 -0800
+++ b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java Sat Jan 19 09:20:47 2019 +0800
@@ -36,7 +36,6 @@
// shared (from jarsigner)
{"SPACE", " "},
- {"2SPACE", " "},
{"6SPACE", " "},
{"COMMA", ", "},
@@ -196,7 +195,6 @@
"Certificate chain not found in the file specified."},
{"found.non.X.509.certificate.in.signer.s.chain",
"found non-X.509 certificate in signer's chain"},
- {"incomplete.certificate.chain", "incomplete certificate chain"},
{"Enter.key.password.for.alias.", "Enter key password for {0}: "},
{"unable.to.recover.key.from.keystore",
"unable to recover key from keystore"},
@@ -240,8 +238,6 @@
"This jar contains entries whose signer certificate is not yet valid. "},
{"This.jar.contains.entries.whose.signer.certificate.is.self.signed.",
"This jar contains entries whose signer certificate is self-signed."},
- {"Re.run.with.the.verbose.option.for.more.details.",
- "Re-run with the -verbose option for more details."},
{"Re.run.with.the.verbose.and.certs.options.for.more.details.",
"Re-run with the -verbose and -certs options for more details."},
{"The.signer.certificate.has.expired.",
--- a/test/jdk/sun/security/util/Resources/NewNamesFormat.java Fri Jan 18 15:44:17 2019 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 2010, 2012, 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 6987827
- * @modules java.base/sun.security.util
- * java.base/sun.security.tools.keytool
- * jdk.jartool/sun.security.tools.jarsigner
- * @summary security/util/Resources.java needs improvement
- */
-
-
-import java.lang.reflect.Method;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * This test makes sure that the keys in resources files are using the new
- * format and there is no duplication.
- */
-public class NewNamesFormat {
- public static void main(String[] args) throws Exception {
- checkRes("sun.security.util.Resources");
- checkRes("sun.security.util.AuthResources");
- checkRes("sun.security.tools.jarsigner.Resources");
- checkRes("sun.security.tools.keytool.Resources");
- }
-
- private static void checkRes(String resName) throws Exception {
- System.out.println("Checking " + resName + "...");
- Class clazz = Class.forName(resName);
- Method m = clazz.getMethod("getContents");
- Object[][] contents = (Object[][])m.invoke(clazz.newInstance());
- Set<String> keys = new HashSet<String>();
- for (Object[] pair: contents) {
- String key = (String)pair[0];
- if (keys.contains(key)) {
- System.out.println("Found dup: " + key);
- throw new Exception();
- }
- checkKey(key);
- keys.add(key);
- }
- }
-
- private static void checkKey(String key) throws Exception {
- for (char c: key.toCharArray()) {
- if (Character.isLetter(c) || Character.isDigit(c) ||
- c == '{' || c == '}' || c == '.') {
- // OK
- } else {
- System.out.println("Illegal char [" + c + "] in key: " + key);
- throw new Exception();
- }
- }
- }
-}
--- a/test/jdk/sun/security/util/Resources/NewResourcesNames.java Fri Jan 18 15:44:17 2019 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,441 +0,0 @@
-/*
- * Copyright (c) 2010, 2012, 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.
- */
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.InputStreamReader;
-import java.io.PrintWriter;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.ListResourceBundle;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Prepares new key names for Resources.java.
- * 6987827: security/util/Resources.java needs improvement
- *
- * Run inside jdk/src/share/classes:
- *
- * java NewResourcesNames $(
- * for a in $(find com/sun/security sun/security javax/security -type f); do
- * egrep -q '(ResourcesMgr.getString|rb.getString)' $a && echo $a
- * done)
- *
- * Before running this tool, run the following two commands to make sure there
- * are only these 2 types of calls into the resources:
- * for a in `find com/sun/security sun/security javax/security -type f`; do
- * cat $a | perl -ne 'print if /\bResourcesMgr\b/'; done |
- * grep -v ResourcesMgr.getString
- * for a in `find com/sun/security sun/security -type f`; do
- * cat $a | perl -ne 'print if /\brb\b/'; done |
- * grep -v rb.getString
- */
-class NewResourcesNames {
-
- // Max length of normalized names
- static int MAXLEN = 127;
-
- static String[] resources = {
- "sun/security/tools/jarsigner/Resources.java",
- "sun/security/tools/keytool/Resources.java",
- "sun/security/tools/policytool/Resources.java",
- "sun/security/util/Resources.java",
- "sun/security/util/AuthResources.java",
- };
-
- public static void main(String[] args) throws Exception {
-
- // Load all names inside resources files
- Map<String,String> allnames = loadResources();
-
- // Modify the callers. There are two patterns:
- // 1. ResourcesMgr.getString("
- // used by most JAAS codes
- // 2. rb.getString("
- // used by tools
- Set<String> allfound = new HashSet<String>();
- for (String arg: args) {
- allfound.addAll(rewriteFile(arg, "ResourcesMgr.getString(\""));
- allfound.addAll(rewriteFile(arg, "rb.getString(\""));
- }
-
- // Special case 1: KeyTool's enum definition of commands and options
- allfound.addAll(keyToolEnums());
-
- // Special case 2: PolicyFile called this 4 times
- allfound.addAll(rewriteFile("sun/security/provider/PolicyFile.java",
- "ResourcesMgr.getString(POLICY+\""));
-
- // During the calls above, you can read sth like:
- //
- // Working on com/sun/security/auth/PolicyParser.java
- // GOOD match is 17
- //
- // This means a " exists right after getString(. Sometimes you see
- //
- // Working on sun/security/tools/keytool/Main.java
- // BAD!! pmatch != match: 212 != 209
- // Working on sun/security/provider/PolicyFile.java
- // BAD!! pmatch != match: 14 != 10
- //
- // which is mismatch. There are only two such special cases list above.
- // For KeyTool, there are 3 calls for showing help. For PolicyTool, 3
- // for name prefixed with POLICY. They are covered in the two special
- // cases above.
-
- // Names used but not defined. This is mostly error, except for
- // special case 2 above. So it's OK to see 3 entries red here
- if (!allnames.keySet().containsAll(allfound)) {
- err("FATAL: Undefined names");
- for (String name: allfound) {
- if (!allnames.keySet().contains(name)) {
- err(" " + name);
- }
- }
- }
-
- // Names defined but not used. Mostly this is old entries not removed.
- // When soemone remove a line of code, he dares not remove the entry
- // in case it's also used somewhere else.
- if (!allfound.containsAll(allnames.keySet())) {
- System.err.println("WARNING: Unused names");
- for (String name: allnames.keySet()) {
- if (!allfound.contains(name)) {
- System.err.println(allnames.get(name));
- System.err.println(" " + normalize(name));
- System.err.println(" [" + name + "]");
- }
- }
- }
- }
-
-
- /**
- * Loads the three resources files. Saves names into a Map.
- */
- private static Map<String,String> loadResources() throws Exception {
-
- // Name vs Resource
- Map<String,String> allnames = new HashMap<String,String>();
-
- for (String f: resources) {
- String clazz =
- f.replace('/', '.').substring(0, f.length()-5);
-
- Set<String> expected = loadClass(clazz);
- Set<String> found = rewriteFile(f, "{\"");
-
- // This is to check that word parsing is identical to Java thinks
- if (!expected.equals(found)) {
- throw new Exception("Expected and found do not match");
- }
-
- for (String name: found) {
- allnames.put(name, f);
- }
- }
- return allnames;
- }
-
- /**
- * Special case treat for enums description in KeyTool
- */
- private static Set<String> keyToolEnums() throws Exception {
-
- Set<String> names = new HashSet<String>();
-
- String file = "sun/security/tools/keytool/Main.java";
- System.err.println("Working on " + file);
- File origFile = new File(file);
- File tmpFile = new File(file + ".tmp");
- origFile.renameTo(tmpFile);
- tmpFile.deleteOnExit();
-
- BufferedReader br = new BufferedReader(
- new InputStreamReader(new FileInputStream(tmpFile)));
- PrintWriter out = new PrintWriter(new FileOutputStream(origFile));
-
- int stage = 0; // 1. commands, 2. options, 3. finished
- int match = 0;
-
- while (true) {
- String s = br.readLine();
- if (s == null) {
- break;
- }
- if (s.indexOf("enum Command") >= 0) stage = 1;
- else if (s.indexOf("enum Option") >= 0) stage = 2;
- else if (s.indexOf("private static final String JKS") >= 0) stage = 3;
-
- if (stage == 1 || stage == 2) {
- if (s.indexOf("(\"") >= 0) {
- match++;
- int p1, p2;
- if (stage == 1) {
- p1 = s.indexOf("\"");
- p2 = s.indexOf("\"", p1+1);
- } else {
- p2 = s.lastIndexOf("\"");
- p1 = s.lastIndexOf("\"", p2-1);
- }
- String name = s.substring(p1+1, p2);
- names.add(name);
- out.println(s.substring(0, p1+1) +
- normalize(name) +
- s.substring(p2));
- } else {
- out.println(s);
- }
- } else {
- out.println(s);
- }
- }
- br.close();
- out.close();
- System.err.println(" GOOD match is " + match);
- return names;
- }
-
- /**
- * Loads a resources using JRE and returns the names
- */
- private static Set<String> loadClass(String clazz) throws Exception {
- ListResourceBundle lrb =
- (ListResourceBundle)Class.forName(clazz).newInstance();
- Set<String> keys = lrb.keySet();
- Map<String,String> newold = new HashMap<String,String>();
- boolean dup = false;
- // Check if normalize() creates dup entries. This is crucial.
- for (String k: keys) {
- String key = normalize(k);
- if (newold.containsKey(key)) {
- err("Dup found for " + key + ":");
- err("["+newold.get(key)+"]");
- err("["+k+"]");
- dup = true;
- }
- newold.put(key, k);
- }
- if (dup) throw new Exception();
- return keys;
- }
-
- /**
- * Rewrites a file using a pattern. The name string should be right after
- * the pattern. Note: pattern ignores whitespaces. Returns names found.
- */
- private static Set<String> rewriteFile(String file, String pattern)
- throws Exception {
-
- System.err.println("Working on " + file);
- Set<String> names = new HashSet<String>();
-
- int plen = pattern.length();
- int match = 0;
-
- // The bare XXX.getString is also matched. Sometimes getString is
- // called but does not use literal strings. This is harder to solve.
-
- int pmatch = 0;
- int pheadlen = plen - 2;
- String phead = pattern.substring(0, plen-2);
-
- // The non-whitespace chars read since, used to check for pattern
- StringBuilder history = new StringBuilder();
- int hlen = 0;
-
- File origFile = new File(file);
- File tmpFile = new File(file + ".tmp");
- origFile.renameTo(tmpFile);
- tmpFile.deleteOnExit();
-
- FileInputStream fis = new FileInputStream(tmpFile);
- FileOutputStream fos = new FileOutputStream(origFile);
-
- while (true) {
- int ch = fis.read();
- if (ch < 0) break;
- if (!Character.isWhitespace(ch)) {
- history.append((char)ch);
- hlen++;
- if (pheadlen > 0 && hlen >= pheadlen &&
- history.substring(hlen-pheadlen, hlen).equals(phead)) {
- pmatch++;
- }
- }
-
- if (hlen >= plen &&
- history.substring(hlen-plen, hlen).equals(pattern)) {
- match++;
- history = new StringBuilder();
- hlen = 0;
-
- fos.write(ch);
-
- // Save a name
- StringBuilder sb = new StringBuilder();
- // Save things after the second ". Maybe it's an end, maybe
- // it's just literal string concatenation.
- StringBuilder tail = new StringBuilder();
-
- boolean in = true; // inside name string
- while (true) {
- int n = fis.read();
- if (in) {
- if (n == '\\') {
- int second = fis.read();
- switch (second) {
- case 'n': sb.append('\n'); break;
- case 'r': sb.append('\r'); break;
- case 't': sb.append('\t'); break;
- case '"': sb.append('"'); break;
- default: throw new Exception(String.format(
- "I don't know this escape: %s%c",
- sb.toString(), second));
- }
- } else if (n == '"') {
- in = false;
- // Maybe string concat? say bytes until clear
- tail = new StringBuilder();
- tail.append('"');
- } else {
- sb.append((char)n);
- }
- } else {
- tail.append((char)n);
- if (n == '"') { // string concat, in again
- in = true;
- } else if (n == ',' || n == ')') { // real end
- break;
- } else if (Character.isWhitespace(n) || n == '+') {
- // string concat
- } else {
- throw new Exception("Not a correct concat");
- }
- }
- }
- String s = sb.toString();
- names.add(s);
- fos.write(normalize(s).getBytes());
- fos.write(tail.toString().getBytes());
- } else {
- fos.write(ch);
- }
- }
-
- // Check pheadlen > 0. Don't want to mess with rewrite for resources
- if (pheadlen > 0 && pmatch != match) {
- err(" BAD!! pmatch != match: " + pmatch + " != " + match);
- } else {
- System.err.println(" GOOD match is " + match);
- }
-
- fis.close();
- fos.close();
- return names;
- }
-
- /**
- * Normalize a string. Rules:
- *
- * 1. If all spacebar return "nSPACE", n is count
- * 2. If consisting at least one alphanumeric:
- * a. All alphanumeric remain
- * b. All others in a row goes to a single ".", even if at head or tail
- * 3. Otherwise:
- * a. "****\n\n" to "STARNN", special case
- * b. the English name if first char in *,.\n():'"
- *
- * Current observations show there's no dup, Hurray! Otherwise, add more
- * special cases.
- */
- private static String normalize(String s) throws Exception {
- boolean needDot = false;
-
- // All spacebar case
- int n = 0;
- for (char c: s.toCharArray()) {
- if (c == ' ') n++;
- else n = -10000;
- }
- if (n == 1) return "SPACE";
- else if (n > 1) return "" + n + "SPACE";
-
- StringBuilder sb = new StringBuilder();
- int dotpos = -1;
- for (int i=0; i<s.length(); i++) {
- char c = s.charAt(i);
- if (Character.isLetter(c) || Character.isDigit(c) ||
- c == '{' || c == '}') {
- if (needDot) {
- // Rememeber the last dot, we want shorter form nice
- if (sb.length() <= MAXLEN) dotpos = sb.length();
- // "." only added when an alphanumeric is seen. This makes
- // sure sb is empty when there's no alphanumerics at all
- sb.append(".");
- }
- sb.append(c);
- needDot = false;
- } else {
- needDot = true;
- }
- }
-
- // No alphanemeric?
- if (sb.length() == 0) {
- if (s.contains("*") && s.contains("\n")) {
- return "STARNN";
- }
- for (char c: s.toCharArray()) {
- switch (c) {
- case '*': return "STAR";
- case ',': return "COMMA";
- case '.': return "PERIOD";
- case '\n': return "NEWLINE";
- case '(': return "LPARAM";
- case ')': return "RPARAM";
- case ':': return "COLON";
- case '\'': case '"': return "QUOTE";
- }
- }
- throw new Exception("Unnamed char: [" + s + "]");
- }
-
- // tail "." only added when there are alphanumerics
- if (needDot) sb.append('.');
- String res = sb.toString();
- if (res.length() > MAXLEN) {
- if (dotpos < 0) throw new Exception("No dot all over? " + s);
- return res.substring(0, dotpos);
- } else {
- return res;
- }
- }
-
- private static void err(String string) {
- System.out.println("\u001b[1;37;41m" + string + "\u001b[m");
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/sun/security/util/Resources/Usages.java Sat Jan 19 09:20:47 2019 +0800
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2018, 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 8215937
+ * @modules java.base/sun.security.util
+ * java.base/sun.security.tools.keytool
+ * jdk.jartool/sun.security.tools.jarsigner
+ * @summary Check usages of security-related Resources files
+ */
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ListResourceBundle;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * This test checks if the strings in various Resources files are used
+ * properly. Each string must be used somewhere, and each getString() call
+ * must use an existing string.
+ * <p>
+ * For each Resources file, the test maintains a list of where the strings are
+ * used (a file or a directory) and how they are used (one or more patterns).
+ * <p>
+ * If this test fails, there can be several reasons:
+ * <p>
+ * 1. If a string is not found, it has not been added to a Resources file.
+ * <p>
+ * 2. If a string is not used, maybe the call was removed earlier but the
+ * Resources file was not updated. Or, the file is not listed or the
+ * pattern is not correct and the usage is not found.
+ * <p>
+ * Because of #2 above, this test might not be complete. If a getString()
+ * is called but either the file and calling pattern is not listed here,
+ * we cannot guarantee it exists in a Resources file.
+ */
+public class Usages {
+
+ // src folder
+ static Path SRC = Path.of(
+ System.getProperty("test.src"), "../../../../../../src/")
+ .normalize();
+
+ // rb.getString(). Used by keytool, jarsigner, and KeyStoreUtil.
+ static Pattern RB_GETSTRING = Pattern.compile(
+ "(?m)rb[ \\n]*\\.getString[ \\n]*\\([ \\n]*\"(.*?)\"\\)");
+
+ // Command and Option enums in keytool
+ static Pattern KT_ENUM = Pattern.compile("\\n +[A-Z]+\\(.*\"(.*)\"");
+
+ // ResourceMgr.getAuthResourceString
+ static Pattern GETAUTHSTRING = Pattern.compile(
+ "getAuthResourceString[ \\n]*\\([ \\n]*\"(.*?)\"\\)");
+
+ // ResourceMgr.getString
+ static Pattern MGR_GETSTRING = Pattern.compile(
+ "ResourcesMgr\\.getString[ \\n]*\\([ \\n]*\"(.*?)\"\\)");
+
+ // LocalizedMessage.getNonlocalized("...")
+ static Pattern LOC_GETNONLOC = Pattern.compile(
+ "LocalizedMessage\\.getNonlocalized[ \\n]*\\([ \\n]*\"(.*?)\"");
+
+ // LocalizedMessage.getNonlocalized(POLICY + "...")
+ static Pattern LOC_GETNONLOC_POLICY = Pattern.compile(
+ "LocalizedMessage\\.getNonlocalized[ \\n]*\\([ \\n]*(POLICY \\+ \".*?)\"");
+
+ // new LocalizedMessage("...")
+ static Pattern NEW_LOC = Pattern.compile(
+ "new LocalizedMessage[ \\n]*\\([ \\n]*\"(.*?)\"");
+
+ // ioException in ConfigFile.java
+ static Pattern IOEXCEPTION = Pattern.compile(
+ "ioException[ \\n]*\\([ \\n]*\"(.*?)\",");
+
+ // For each Resources file, where and how the strings are used.
+ static Map<ListResourceBundle, List<Pair>> MAP = Map.of(
+ new sun.security.tools.keytool.Resources(), List.of(
+ new Pair("java.base/share/classes/sun/security/tools/keytool/Main.java",
+ List.of(RB_GETSTRING, KT_ENUM)),
+ new Pair("java.base/share/classes/sun/security/tools/KeyStoreUtil.java",
+ List.of(RB_GETSTRING))),
+ new sun.security.util.AuthResources(), List.of(
+ new Pair("java.base/share/classes/sun/security/provider/ConfigFile.java",
+ List.of(GETAUTHSTRING, IOEXCEPTION)),
+ new Pair("jdk.security.auth/share/classes/com/sun/security/auth/",
+ List.of(GETAUTHSTRING))),
+ new sun.security.tools.jarsigner.Resources(), List.of(
+ new Pair("jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java",
+ List.of(RB_GETSTRING)),
+ new Pair("java.base/share/classes/sun/security/tools/KeyStoreUtil.java",
+ List.of(RB_GETSTRING))),
+ new sun.security.util.Resources(), List.of(
+ new Pair("jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java",
+ List.of(MGR_GETSTRING)),
+ new Pair("java.base/share/classes/sun/security/provider/PolicyParser.java",
+ List.of(LOC_GETNONLOC, NEW_LOC)),
+ new Pair("java.base/share/classes/sun/security/provider/PolicyFile.java",
+ List.of(MGR_GETSTRING, LOC_GETNONLOC, LOC_GETNONLOC_POLICY)),
+ new Pair("java.base/share/classes/javax/security/auth/",
+ List.of(MGR_GETSTRING)))
+ );
+
+ public static void main(String[] args) {
+ if (Files.exists(SRC)) {
+ MAP.forEach(Usages::check);
+ } else {
+ System.out.println("No src directory. Test skipped.");
+ }
+ }
+
+ private static void check(ListResourceBundle res, List<Pair> fnps) {
+ try {
+ System.out.println(">>>> Checking " + res.getClass().getName());
+
+ List<String> keys = Collections.list(res.getKeys());
+
+ // Initialize unused to be all keys. Each time a key is used it
+ // is removed. We cannot reuse keys because a key might be used
+ // multiple times. Make it a Set so we can check duplicates.
+ Set<String> unused = new HashSet<>(keys);
+
+ keys.forEach(Usages::checkKeyFormat);
+ if (keys.size() != unused.size()) {
+ throw new RuntimeException("Duplicates found");
+ }
+
+ for (Pair fnp : fnps) {
+ Files.find(SRC.resolve(fnp.path), Integer.MAX_VALUE,
+ (p, attr) -> p.toString().endsWith(".java"))
+ .forEach(pa -> {
+ try {
+ String content = Files.readString(pa);
+ for (Pattern p : fnp.patterns) {
+ Matcher m = p.matcher(content);
+ while (m.find()) {
+ String arg = m.group(1);
+ // Special case in PolicyFile.java:
+ if (arg.startsWith("POLICY + \"")) {
+ arg = "java.security.policy"
+ + arg.substring(10);
+ }
+ if (!keys.contains(arg)) {
+ throw new RuntimeException(
+ "Not found: " + arg);
+ }
+ unused.remove(arg);
+ }
+ }
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ });
+ }
+ if (!unused.isEmpty()) {
+ throw new RuntimeException("Unused keys: " + unused);
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static void checkKeyFormat(String key) {
+ for (char c : key.toCharArray()) {
+ if (Character.isLetter(c) || Character.isDigit(c) ||
+ c == '{' || c == '}' || c == '.') {
+ // OK
+ } else {
+ throw new RuntimeException(
+ "Illegal char [" + c + "] in key: " + key);
+ }
+ }
+ }
+
+ static class Pair {
+
+ public final String path;
+ public final List<Pattern> patterns;
+
+ public Pair(String path, List<Pattern> patterns) {
+ this.path = path;
+ this.patterns = patterns;
+ }
+ }
+}