mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8215937: Check usages of security-related Resources files
Reviewed-by: mullan
This commit is contained in:
parent
db89805fe0
commit
54815061a1
8 changed files with 271 additions and 590 deletions
|
@ -3784,9 +3784,9 @@ public final class Main {
|
||||||
replyCerts.length);
|
replyCerts.length);
|
||||||
tmpCerts[tmpCerts.length-1] = root.snd;
|
tmpCerts[tmpCerts.length-1] = root.snd;
|
||||||
replyCerts = tmpCerts;
|
replyCerts = tmpCerts;
|
||||||
checkWeak(String.format(rb.getString(fromKeyStore ?
|
checkWeak(String.format(fromKeyStore
|
||||||
"alias.in.keystore" :
|
? rb.getString("alias.in.keystore")
|
||||||
"alias.in.cacerts"),
|
: rb.getString("alias.in.cacerts"),
|
||||||
root.fst),
|
root.fst),
|
||||||
root.snd);
|
root.snd);
|
||||||
}
|
}
|
||||||
|
|
|
@ -253,7 +253,6 @@ public class Resources extends java.util.ListResourceBundle {
|
||||||
{"Keystore.password.is.too.short.must.be.at.least.6.characters",
|
{"Keystore.password.is.too.short.must.be.at.least.6.characters",
|
||||||
"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"},
|
{"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.alias.successfully.imported.",
|
||||||
"Entry for alias {0} successfully imported."},
|
"Entry for alias {0} successfully imported."},
|
||||||
{"Entry.for.alias.alias.not.imported.", "Entry for alias {0} not imported."},
|
{"Entry.for.alias.alias.not.imported.", "Entry for alias {0} not imported."},
|
||||||
|
@ -314,10 +313,6 @@ public class Resources extends java.util.ListResourceBundle {
|
||||||
{"Too.many.failures.Key.entry.not.cloned",
|
{"Too.many.failures.Key.entry.not.cloned",
|
||||||
"Too many failures. Key entry not cloned"},
|
"Too many failures. Key entry not cloned"},
|
||||||
{"key.password.for.alias.", "key password for <{0}>"},
|
{"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",
|
||||||
"No entries from identity database added"},
|
"No entries from identity database added"},
|
||||||
{"Alias.name.alias", "Alias name: {0}"},
|
{"Alias.name.alias", "Alias name: {0}"},
|
||||||
|
@ -355,7 +350,6 @@ public class Resources extends java.util.ListResourceBundle {
|
||||||
{"Do.you.still.want.to.add.it.to.your.own.keystore.no.",
|
{"Do.you.still.want.to.add.it.to.your.own.keystore.no.",
|
||||||
"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]: "},
|
{"Trust.this.certificate.no.", "Trust this certificate? [no]: "},
|
||||||
{"YES", "YES"},
|
|
||||||
{"New.prompt.", "New {0}: "},
|
{"New.prompt.", "New {0}: "},
|
||||||
{"Passwords.must.differ", "Passwords must differ"},
|
{"Passwords.must.differ", "Passwords must differ"},
|
||||||
{"Re.enter.new.prompt.", "Re-enter new {0}: "},
|
{"Re.enter.new.prompt.", "Re-enter new {0}: "},
|
||||||
|
@ -395,7 +389,6 @@ public class Resources extends java.util.ListResourceBundle {
|
||||||
{"Signer.d.", "Signer #%d:"},
|
{"Signer.d.", "Signer #%d:"},
|
||||||
{"Timestamp.", "Timestamp:"},
|
{"Timestamp.", "Timestamp:"},
|
||||||
{"Signature.", "Signature:"},
|
{"Signature.", "Signature:"},
|
||||||
{"CRLs.", "CRLs:"},
|
|
||||||
{"Certificate.owner.", "Certificate owner: "},
|
{"Certificate.owner.", "Certificate owner: "},
|
||||||
{"Not.a.signed.jar.file", "Not a signed jar file"},
|
{"Not.a.signed.jar.file", "Not a signed jar file"},
|
||||||
{"No.certificate.from.the.SSL.server",
|
{"No.certificate.from.the.SSL.server",
|
||||||
|
@ -414,13 +407,10 @@ public class Resources extends java.util.ListResourceBundle {
|
||||||
"Certificate reply does not contain public key for <{0}>"},
|
"Certificate reply does not contain public key for <{0}>"},
|
||||||
{"Incomplete.certificate.chain.in.reply",
|
{"Incomplete.certificate.chain.in.reply",
|
||||||
"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.",
|
||||||
"Top-level certificate in reply:\n"},
|
"Top-level certificate in reply:\n"},
|
||||||
{".is.not.trusted.", "... is not trusted. "},
|
{".is.not.trusted.", "... is not trusted. "},
|
||||||
{"Install.reply.anyway.no.", "Install reply anyway? [no]: "},
|
{"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",
|
||||||
"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",
|
{"Certificate.reply.and.certificate.in.keystore.are.identical",
|
||||||
|
|
|
@ -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.
|
* 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
|
||||||
|
@ -66,8 +66,6 @@ public class Resources extends java.util.ListResourceBundle {
|
||||||
{"Subject.", "Subject:\n"},
|
{"Subject.", "Subject:\n"},
|
||||||
{".Principal.", "\tPrincipal: "},
|
{".Principal.", "\tPrincipal: "},
|
||||||
{".Public.Credential.", "\tPublic Credential: "},
|
{".Public.Credential.", "\tPublic Credential: "},
|
||||||
{".Private.Credentials.inaccessible.",
|
|
||||||
"\tPrivate Credentials inaccessible\n"},
|
|
||||||
{".Private.Credential.", "\tPrivate Credential: "},
|
{".Private.Credential.", "\tPrivate Credential: "},
|
||||||
{".Private.Credential.inaccessible.",
|
{".Private.Credential.inaccessible.",
|
||||||
"\tPrivate Credential inaccessible\n"},
|
"\tPrivate Credential inaccessible\n"},
|
||||||
|
@ -89,16 +87,6 @@ public class Resources extends java.util.ListResourceBundle {
|
||||||
"invalid null CallbackHandler provided"},
|
"invalid null CallbackHandler provided"},
|
||||||
{"null.subject.logout.called.before.login",
|
{"null.subject.logout.called.before.login",
|
||||||
"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",
|
||||||
"Login Failure: all modules ignored"},
|
"Login Failure: all modules ignored"},
|
||||||
|
|
||||||
|
|
|
@ -1030,31 +1030,31 @@ public class Main {
|
||||||
(hasExpiredTsaCert && !signerNotExpired)) {
|
(hasExpiredTsaCert && !signerNotExpired)) {
|
||||||
|
|
||||||
if (strict) {
|
if (strict) {
|
||||||
result = rb.getString(isSigning
|
result = isSigning
|
||||||
? "jar.signed.with.signer.errors."
|
? rb.getString("jar.signed.with.signer.errors.")
|
||||||
: "jar.verified.with.signer.errors.");
|
: rb.getString("jar.verified.with.signer.errors.");
|
||||||
} else {
|
} else {
|
||||||
result = rb.getString(isSigning
|
result = isSigning
|
||||||
? "jar.signed."
|
? rb.getString("jar.signed.")
|
||||||
: "jar.verified.");
|
: rb.getString("jar.verified.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (badKeyUsage) {
|
if (badKeyUsage) {
|
||||||
errors.add(rb.getString(isSigning
|
errors.add(isSigning
|
||||||
? "The.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing."
|
? rb.getString("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."));
|
: rb.getString("This.jar.contains.entries.whose.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing."));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (badExtendedKeyUsage) {
|
if (badExtendedKeyUsage) {
|
||||||
errors.add(rb.getString(isSigning
|
errors.add(isSigning
|
||||||
? "The.signer.certificate.s.ExtendedKeyUsage.extension.doesn.t.allow.code.signing."
|
? rb.getString("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."));
|
: rb.getString("This.jar.contains.entries.whose.signer.certificate.s.ExtendedKeyUsage.extension.doesn.t.allow.code.signing."));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (badNetscapeCertType) {
|
if (badNetscapeCertType) {
|
||||||
errors.add(rb.getString(isSigning
|
errors.add(isSigning
|
||||||
? "The.signer.certificate.s.NetscapeCertType.extension.doesn.t.allow.code.signing."
|
? rb.getString("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."));
|
: rb.getString("This.jar.contains.entries.whose.signer.certificate.s.NetscapeCertType.extension.doesn.t.allow.code.signing."));
|
||||||
}
|
}
|
||||||
|
|
||||||
// only in verifying
|
// only in verifying
|
||||||
|
@ -1063,20 +1063,20 @@ public class Main {
|
||||||
"This.jar.contains.unsigned.entries.which.have.not.been.integrity.checked."));
|
"This.jar.contains.unsigned.entries.which.have.not.been.integrity.checked."));
|
||||||
}
|
}
|
||||||
if (hasExpiredCert) {
|
if (hasExpiredCert) {
|
||||||
errors.add(rb.getString(isSigning
|
errors.add(isSigning
|
||||||
? "The.signer.certificate.has.expired."
|
? rb.getString("The.signer.certificate.has.expired.")
|
||||||
: "This.jar.contains.entries.whose.signer.certificate.has.expired."));
|
: rb.getString("This.jar.contains.entries.whose.signer.certificate.has.expired."));
|
||||||
}
|
}
|
||||||
if (notYetValidCert) {
|
if (notYetValidCert) {
|
||||||
errors.add(rb.getString(isSigning
|
errors.add(isSigning
|
||||||
? "The.signer.certificate.is.not.yet.valid."
|
? rb.getString("The.signer.certificate.is.not.yet.valid.")
|
||||||
: "This.jar.contains.entries.whose.signer.certificate.is.not.yet.valid."));
|
: rb.getString("This.jar.contains.entries.whose.signer.certificate.is.not.yet.valid."));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chainNotValidated) {
|
if (chainNotValidated) {
|
||||||
errors.add(String.format(rb.getString(isSigning
|
errors.add(String.format(isSigning
|
||||||
? "The.signer.s.certificate.chain.is.invalid.reason.1"
|
? rb.getString("The.signer.s.certificate.chain.is.invalid.reason.1")
|
||||||
: "This.jar.contains.entries.whose.certificate.chain.is.invalid.reason.1"),
|
: rb.getString("This.jar.contains.entries.whose.certificate.chain.is.invalid.reason.1"),
|
||||||
chainNotValidatedReason.getLocalizedMessage()));
|
chainNotValidatedReason.getLocalizedMessage()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1084,9 +1084,9 @@ public class Main {
|
||||||
errors.add(rb.getString("The.timestamp.has.expired."));
|
errors.add(rb.getString("The.timestamp.has.expired."));
|
||||||
}
|
}
|
||||||
if (tsaChainNotValidated) {
|
if (tsaChainNotValidated) {
|
||||||
errors.add(String.format(rb.getString(isSigning
|
errors.add(String.format(isSigning
|
||||||
? "The.tsa.certificate.chain.is.invalid.reason.1"
|
? rb.getString("The.tsa.certificate.chain.is.invalid.reason.1")
|
||||||
: "This.jar.contains.entries.whose.tsa.certificate.chain.is.invalid.reason.1"),
|
: rb.getString("This.jar.contains.entries.whose.tsa.certificate.chain.is.invalid.reason.1"),
|
||||||
tsaChainNotValidatedReason.getLocalizedMessage()));
|
tsaChainNotValidatedReason.getLocalizedMessage()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1102,9 +1102,9 @@ public class Main {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (signerSelfSigned) {
|
if (signerSelfSigned) {
|
||||||
errors.add(rb.getString(isSigning
|
errors.add(isSigning
|
||||||
? "The.signer.s.certificate.is.self.signed."
|
? rb.getString("The.signer.s.certificate.is.self.signed.")
|
||||||
: "This.jar.contains.entries.whose.signer.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
|
// weakAlg only detected in signing. The jar file is
|
||||||
|
@ -1131,7 +1131,7 @@ public class Main {
|
||||||
privateKey.getAlgorithm(), KeyUtil.getKeySize(privateKey)));
|
privateKey.getAlgorithm(), KeyUtil.getKeySize(privateKey)));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result = rb.getString(isSigning ? "jar.signed." : "jar.verified.");
|
result = isSigning ? rb.getString("jar.signed.") : rb.getString("jar.verified.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasExpiredTsaCert) {
|
if (hasExpiredTsaCert) {
|
||||||
|
@ -1155,9 +1155,9 @@ public class Main {
|
||||||
hasExpiredTsaCert = false;
|
hasExpiredTsaCert = false;
|
||||||
}
|
}
|
||||||
if (hasExpiringCert) {
|
if (hasExpiringCert) {
|
||||||
warnings.add(rb.getString(isSigning
|
warnings.add(isSigning
|
||||||
? "The.signer.certificate.will.expire.within.six.months."
|
? rb.getString("The.signer.certificate.will.expire.within.six.months.")
|
||||||
: "This.jar.contains.entries.whose.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 (hasExpiringTsaCert && expireDate != null) {
|
||||||
if (expireDate.after(tsaExpireDate)) {
|
if (expireDate.after(tsaExpireDate)) {
|
||||||
|
@ -1170,13 +1170,13 @@ public class Main {
|
||||||
}
|
}
|
||||||
if (noTimestamp && expireDate != null) {
|
if (noTimestamp && expireDate != null) {
|
||||||
if (hasTimestampBlock) {
|
if (hasTimestampBlock) {
|
||||||
warnings.add(String.format(rb.getString(isSigning
|
warnings.add(String.format(isSigning
|
||||||
? "invalid.timestamp.signing"
|
? rb.getString("invalid.timestamp.signing")
|
||||||
: "bad.timestamp.verifying"), expireDate));
|
: rb.getString("bad.timestamp.verifying"), expireDate));
|
||||||
} else {
|
} else {
|
||||||
warnings.add(String.format(rb.getString(isSigning
|
warnings.add(String.format(isSigning
|
||||||
? "no.timestamp.signing"
|
? rb.getString("no.timestamp.signing")
|
||||||
: "no.timestamp.verifying"), expireDate));
|
: rb.getString("no.timestamp.verifying"), expireDate));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1551,7 +1551,20 @@ public class Main {
|
||||||
|
|
||||||
if (verbose != null) {
|
if (verbose != null) {
|
||||||
builder.eventHandler((action, file) -> {
|
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);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,6 @@ public class Resources extends java.util.ListResourceBundle {
|
||||||
|
|
||||||
// shared (from jarsigner)
|
// shared (from jarsigner)
|
||||||
{"SPACE", " "},
|
{"SPACE", " "},
|
||||||
{"2SPACE", " "},
|
|
||||||
{"6SPACE", " "},
|
{"6SPACE", " "},
|
||||||
{"COMMA", ", "},
|
{"COMMA", ", "},
|
||||||
|
|
||||||
|
@ -196,7 +195,6 @@ public class Resources extends java.util.ListResourceBundle {
|
||||||
"Certificate chain not found in the file specified."},
|
"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",
|
||||||
"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}: "},
|
{"Enter.key.password.for.alias.", "Enter key password for {0}: "},
|
||||||
{"unable.to.recover.key.from.keystore",
|
{"unable.to.recover.key.from.keystore",
|
||||||
"unable to recover key from keystore"},
|
"unable to recover key from keystore"},
|
||||||
|
@ -240,8 +238,6 @@ public class Resources extends java.util.ListResourceBundle {
|
||||||
"This jar contains entries whose signer certificate is not yet valid. "},
|
"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.",
|
||||||
"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.",
|
||||||
"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.",
|
{"The.signer.certificate.has.expired.",
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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");
|
|
||||||
}
|
|
||||||
}
|
|
213
test/jdk/sun/security/util/Resources/Usages.java
Normal file
213
test/jdk/sun/security/util/Resources/Usages.java
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue