8260967: Better jar file validation

Reviewed-by: hchao, valeriep
This commit is contained in:
Weijun Wang 2021-03-16 18:58:55 +00:00 committed by Henry Jen
parent fc38331f44
commit ef9315bead
6 changed files with 50 additions and 18 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2021, 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
@ -419,7 +419,13 @@ public class JarFile extends ZipFile {
if (verify) {
byte[] b = getBytes(manEntry);
if (!jvInitialized) {
jv = new JarVerifier(b);
if (JUZFA.getManifestNum(this) == 1) {
jv = new JarVerifier(manEntry.getName(), b);
} else {
if (JarVerifier.debug != null) {
JarVerifier.debug.println("Multiple MANIFEST.MF found. Treat JAR file as unsigned");
}
}
}
man = new Manifest(jv, new ByteArrayInputStream(b), getName());
} else {
@ -745,7 +751,7 @@ public class JarFile extends ZipFile {
mev = new ManifestEntryVerifier
(getManifestFromReference());
}
if (name.equals(MANIFEST_NAME)) {
if (name.equalsIgnoreCase(MANIFEST_NAME)) {
b = jv.manifestRawBytes;
} else {
b = getBytes(e);

View file

@ -94,7 +94,7 @@ public class JarInputStream extends ZipInputStream {
man.read(new ByteArrayInputStream(bytes));
closeEntry();
if (doVerify) {
jv = new JarVerifier(bytes);
jv = new JarVerifier(e.getName(), bytes);
mev = new ManifestEntryVerifier(man);
}
return (JarEntry)super.getNextEntry();

View file

@ -84,6 +84,9 @@ class JarVerifier {
/** the bytes for the manDig object */
byte manifestRawBytes[] = null;
/** the manifest name this JarVerifier is created upon */
final String manifestName;
/** controls eager signature validation */
boolean eagerValidation;
@ -93,7 +96,8 @@ class JarVerifier {
/** collect -DIGEST-MANIFEST values for deny list */
private List<Object> manifestDigests;
public JarVerifier(byte rawBytes[]) {
public JarVerifier(String name, byte rawBytes[]) {
manifestName = name;
manifestRawBytes = rawBytes;
sigFileSigners = new Hashtable<>();
verifiedSigners = new Hashtable<>();
@ -180,7 +184,7 @@ class JarVerifier {
// only set the jev object for entries that have a signature
// (either verified or not)
if (!name.equals(JarFile.MANIFEST_NAME)) {
if (!name.equalsIgnoreCase(JarFile.MANIFEST_NAME)) {
if (sigFileSigners.get(name) != null ||
verifiedSigners.get(name) != null) {
mev.setEntry(name, je);
@ -270,7 +274,8 @@ class JarVerifier {
}
sfv.setSignatureFile(bytes);
sfv.process(sigFileSigners, manifestDigests);
sfv.process(sigFileSigners, manifestDigests,
manifestName);
}
}
return;
@ -313,7 +318,7 @@ class JarVerifier {
sfv.setSignatureFile(bytes);
}
}
sfv.process(sigFileSigners, manifestDigests);
sfv.process(sigFileSigners, manifestDigests, manifestName);
} catch (IOException | CertificateException |
NoSuchAlgorithmException | SignatureException e) {
@ -419,9 +424,9 @@ class JarVerifier {
manDig = null;
// MANIFEST.MF is always treated as signed and verified,
// move its signers from sigFileSigners to verifiedSigners.
if (sigFileSigners.containsKey(JarFile.MANIFEST_NAME)) {
CodeSigner[] codeSigners = sigFileSigners.remove(JarFile.MANIFEST_NAME);
verifiedSigners.put(JarFile.MANIFEST_NAME, codeSigners);
if (sigFileSigners.containsKey(manifestName)) {
CodeSigner[] codeSigners = sigFileSigners.remove(manifestName);
verifiedSigners.put(manifestName, codeSigners);
}
}
@ -873,7 +878,7 @@ class JarVerifier {
*/
boolean isTrustedManifestEntry(String name) {
// How many signers? MANIFEST.MF is always verified
CodeSigner[] forMan = verifiedSigners.get(JarFile.MANIFEST_NAME);
CodeSigner[] forMan = verifiedSigners.get(manifestName);
if (forMan == null) {
return true;
}