mirror of
https://github.com/openjdk/jdk.git
synced 2026-03-06 14:10:36 +00:00
8300272: Improve readability of the test JarWithOneNonDisabledDigestAlg
Reviewed-by: weijun
This commit is contained in:
parent
b678e70003
commit
cf46004f27
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022, 2023, 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
|
||||
@ -27,6 +27,7 @@
|
||||
* @summary Check that jar entry with at least one non-disabled digest
|
||||
* algorithm in manifest is treated as signed
|
||||
* @modules java.base/sun.security.tools.keytool
|
||||
* @modules java.base/sun.security.util
|
||||
* @library /test/lib
|
||||
* @build jdk.test.lib.util.JarUtils
|
||||
* jdk.test.lib.security.SecurityUtils
|
||||
@ -34,61 +35,94 @@
|
||||
*/
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.CodeSigner;
|
||||
import java.security.KeyStore;
|
||||
import java.security.cert.CertPathValidatorException;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.zip.ZipFile;
|
||||
import jdk.security.jarsigner.JarSigner;
|
||||
|
||||
import jdk.test.lib.util.JarUtils;
|
||||
import jdk.test.lib.security.SecurityUtils;
|
||||
import sun.security.util.ConstraintsParameters;
|
||||
import sun.security.util.DisabledAlgorithmConstraints;
|
||||
import sun.security.util.JarConstraintsParameters;
|
||||
|
||||
public class JarWithOneNonDisabledDigestAlg {
|
||||
|
||||
private static final String PASS = "changeit";
|
||||
private static final String TESTFILE1 = "testfile1";
|
||||
private static final String TESTFILE2 = "testfile2";
|
||||
private static final Path TESTFILE1 = Path.of("testfile1");
|
||||
private static final Path TESTFILE2 = Path.of("testfile2");
|
||||
private static final Path UNSIGNED_JAR = Path.of("unsigned.jar");
|
||||
private static final Path SIGNED_JAR = Path.of("signed.jar");
|
||||
private static final Path SIGNED_TWICE_JAR = Path.of("signed2.jar");
|
||||
private static final Path MULTI_SIGNED_JAR = Path.of("multi-signed.jar");
|
||||
private static final Path CURRENT_DIR = Path.of(".");
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
SecurityUtils.removeFromDisabledAlgs("jdk.jar.disabledAlgorithms",
|
||||
List.of("SHA1"));
|
||||
Files.write(Path.of(TESTFILE1), TESTFILE1.getBytes());
|
||||
JarUtils.createJarFile(Path.of("unsigned.jar"), Path.of("."),
|
||||
Path.of(TESTFILE1));
|
||||
// Sanity check: Assert that MD5 is disabled, SHA-256 enabled
|
||||
checkDigestAlgorithmPermits();
|
||||
|
||||
genkeypair("-alias SHA1 -sigalg SHA1withRSA");
|
||||
genkeypair("-alias SHA256 -sigalg SHA256withRSA");
|
||||
// Create an unsigned JAR with a single file
|
||||
Files.write(TESTFILE1, TESTFILE1.toString().getBytes());
|
||||
JarUtils.createJarFile(UNSIGNED_JAR, CURRENT_DIR, TESTFILE1);
|
||||
|
||||
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
try (FileInputStream fis = new FileInputStream("keystore")) {
|
||||
ks.load(fis, PASS.toCharArray());
|
||||
}
|
||||
// Generate a keystore with two different signers
|
||||
genkeypair("-alias SIGNER1");
|
||||
genkeypair("-alias SIGNER2");
|
||||
KeyStore ks = loadKeyStore();
|
||||
|
||||
// Sign JAR twice with same signer but different digest algorithms
|
||||
// so that each entry in manifest file contains two digest values.
|
||||
signJarFile(ks, "SHA1", "MD5", "unsigned.jar", "signed.jar");
|
||||
signJarFile(ks, "SHA1", "SHA1", "signed.jar", "signed2.jar");
|
||||
checkThatJarIsSigned("signed2.jar", false);
|
||||
// Note that MD5 is a disabled digest algorithm, while SHA-256 is not
|
||||
signJarFile(ks, "SIGNER1", "MD5", UNSIGNED_JAR, SIGNED_JAR);
|
||||
signJarFile(ks, "SIGNER1", "SHA256", SIGNED_JAR, SIGNED_TWICE_JAR);
|
||||
checkThatJarIsSigned(SIGNED_TWICE_JAR, Map.of(TESTFILE1.toString(), 1));
|
||||
|
||||
// add another file to the JAR
|
||||
Files.write(Path.of(TESTFILE2), "testFile2".getBytes());
|
||||
JarUtils.updateJarFile(Path.of("signed2.jar"), Path.of("."),
|
||||
Path.of(TESTFILE2));
|
||||
Files.write(TESTFILE2, TESTFILE2.toString().getBytes());
|
||||
JarUtils.updateJarFile(SIGNED_TWICE_JAR, CURRENT_DIR, TESTFILE2);
|
||||
|
||||
// Sign again with different signer (SHA256) and SHA-1 digestalg.
|
||||
// TESTFILE1 should have two signers and TESTFILE2 should have one
|
||||
// signer.
|
||||
signJarFile(ks, "SHA256", "SHA1", "signed2.jar", "multi-signed.jar");
|
||||
// Sign the updated JAR, now with a different signer and with an enabled digest alg
|
||||
signJarFile(ks, "SIGNER2", "SHA256", SIGNED_TWICE_JAR, MULTI_SIGNED_JAR);
|
||||
|
||||
checkThatJarIsSigned("multi-signed.jar", true);
|
||||
// TESTFILE1 should have two signers and TESTFILE2 should have one signer.
|
||||
checkThatJarIsSigned(MULTI_SIGNED_JAR,
|
||||
Map.of(TESTFILE1.toString(), 2,
|
||||
TESTFILE2.toString(), 1)
|
||||
);
|
||||
}
|
||||
|
||||
private static void checkDigestAlgorithmPermits() throws Exception {
|
||||
ConstraintsParameters cp = new JarConstraintsParameters(Collections.emptyList(), new Date());
|
||||
DisabledAlgorithmConstraints jarConstraints = DisabledAlgorithmConstraints.jarConstraints();
|
||||
try {
|
||||
jarConstraints.permits("MD5", cp, false);
|
||||
throw new Exception("This test assumes that MD5 is disabled");
|
||||
} catch (CertPathValidatorException e) {
|
||||
// Ignore
|
||||
}
|
||||
try {
|
||||
jarConstraints.permits("SHA256", cp, false);
|
||||
} catch (CertPathValidatorException e) {
|
||||
throw new Exception("This test assumes that SHA256 is enabled");
|
||||
}
|
||||
}
|
||||
|
||||
private static KeyStore loadKeyStore() throws Exception {
|
||||
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
try (InputStream fis = Files.newInputStream(Path.of("keystore"))) {
|
||||
ks.load(fis, PASS.toCharArray());
|
||||
}
|
||||
return ks;
|
||||
}
|
||||
|
||||
private static KeyStore.PrivateKeyEntry getEntry(KeyStore ks, String alias)
|
||||
@ -101,12 +135,13 @@ public class JarWithOneNonDisabledDigestAlg {
|
||||
|
||||
private static void genkeypair(String cmd) throws Exception {
|
||||
cmd = "-genkeypair -keystore keystore -storepass " + PASS +
|
||||
" -keypass " + PASS + " -keyalg rsa -dname CN=Duke " + cmd;
|
||||
" -keypass " + PASS + " -keyalg rsa -sigalg SHA256withRSA " +
|
||||
"-dname CN=Duke " + cmd;
|
||||
sun.security.tools.keytool.Main.main(cmd.split(" "));
|
||||
}
|
||||
|
||||
private static void signJarFile(KeyStore ks, String alias,
|
||||
String digestAlg, String inputFile, String outputFile)
|
||||
String digestAlg, Path inputFile, Path outputFile)
|
||||
throws Exception {
|
||||
|
||||
JarSigner signer = new JarSigner.Builder(getEntry(ks, alias))
|
||||
@ -114,38 +149,36 @@ public class JarWithOneNonDisabledDigestAlg {
|
||||
.signerName(alias)
|
||||
.build();
|
||||
|
||||
try (ZipFile in = new ZipFile(inputFile);
|
||||
FileOutputStream out = new FileOutputStream(outputFile)) {
|
||||
try (ZipFile in = new ZipFile(inputFile.toFile());
|
||||
OutputStream out = Files.newOutputStream(outputFile)) {
|
||||
signer.sign(in, out);
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkThatJarIsSigned(String jarFile, boolean multi)
|
||||
private static void checkThatJarIsSigned(Path jarFile, Map<String, Integer> expected)
|
||||
throws Exception {
|
||||
|
||||
try (JarFile jf = new JarFile(jarFile, true)) {
|
||||
try (JarFile jf = new JarFile(jarFile.toFile(), true)) {
|
||||
Enumeration<JarEntry> entries = jf.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
JarEntry entry = entries.nextElement();
|
||||
if (entry.isDirectory() || isSigningRelated(entry.getName())) {
|
||||
continue;
|
||||
}
|
||||
InputStream is = jf.getInputStream(entry);
|
||||
while (is.read() != -1);
|
||||
try (InputStream is = jf.getInputStream(entry)) {
|
||||
is.transferTo(OutputStream.nullOutputStream());
|
||||
}
|
||||
CodeSigner[] signers = entry.getCodeSigners();
|
||||
if (signers == null) {
|
||||
throw new Exception("JarEntry " + entry.getName() +
|
||||
" is not signed");
|
||||
} else if (multi) {
|
||||
if (entry.getName().equals(TESTFILE1) &&
|
||||
signers.length != 2) {
|
||||
throw new Exception("Unexpected number of signers " +
|
||||
"for " + entry.getName() + ": " + signers.length);
|
||||
} else if (entry.getName().equals(TESTFILE2) &&
|
||||
signers.length != 1) {
|
||||
throw new Exception("Unexpected number of signers " +
|
||||
"for " + entry.getName() + ": " + signers.length);
|
||||
}
|
||||
if (!expected.containsKey(entry.getName())) {
|
||||
throw new Exception("Unexpected entry " + entry.getName());
|
||||
}
|
||||
int expectedSigners = expected.get(entry.getName());
|
||||
int actualSigners = signers == null ? 0 : signers.length;
|
||||
|
||||
if (expectedSigners != actualSigners) {
|
||||
throw new Exception("Unexpected number of signers " +
|
||||
"for " + entry.getName() + ": " + actualSigners +
|
||||
", expected " + expectedSigners);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user