Skip to content

Commit ef9315b

Browse files
wangweijslowhog
authored andcommitted
8260967: Better jar file validation
Reviewed-by: hchao, valeriep
1 parent fc38331 commit ef9315b

6 files changed

Lines changed: 50 additions & 18 deletions

File tree

src/java.base/share/classes/java/util/jar/JarFile.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -419,7 +419,13 @@ private Manifest getManifestFromReference() throws IOException {
419419
if (verify) {
420420
byte[] b = getBytes(manEntry);
421421
if (!jvInitialized) {
422-
jv = new JarVerifier(b);
422+
if (JUZFA.getManifestNum(this) == 1) {
423+
jv = new JarVerifier(manEntry.getName(), b);
424+
} else {
425+
if (JarVerifier.debug != null) {
426+
JarVerifier.debug.println("Multiple MANIFEST.MF found. Treat JAR file as unsigned");
427+
}
428+
}
423429
}
424430
man = new Manifest(jv, new ByteArrayInputStream(b), getName());
425431
} else {
@@ -745,7 +751,7 @@ private void initializeVerifier() {
745751
mev = new ManifestEntryVerifier
746752
(getManifestFromReference());
747753
}
748-
if (name.equals(MANIFEST_NAME)) {
754+
if (name.equalsIgnoreCase(MANIFEST_NAME)) {
749755
b = jv.manifestRawBytes;
750756
} else {
751757
b = getBytes(e);

src/java.base/share/classes/java/util/jar/JarInputStream.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ private JarEntry checkManifest(JarEntry e)
9494
man.read(new ByteArrayInputStream(bytes));
9595
closeEntry();
9696
if (doVerify) {
97-
jv = new JarVerifier(bytes);
97+
jv = new JarVerifier(e.getName(), bytes);
9898
mev = new ManifestEntryVerifier(man);
9999
}
100100
return (JarEntry)super.getNextEntry();

src/java.base/share/classes/java/util/jar/JarVerifier.java

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ class JarVerifier {
8484
/** the bytes for the manDig object */
8585
byte manifestRawBytes[] = null;
8686

87+
/** the manifest name this JarVerifier is created upon */
88+
final String manifestName;
89+
8790
/** controls eager signature validation */
8891
boolean eagerValidation;
8992

@@ -93,7 +96,8 @@ class JarVerifier {
9396
/** collect -DIGEST-MANIFEST values for deny list */
9497
private List<Object> manifestDigests;
9598

96-
public JarVerifier(byte rawBytes[]) {
99+
public JarVerifier(String name, byte rawBytes[]) {
100+
manifestName = name;
97101
manifestRawBytes = rawBytes;
98102
sigFileSigners = new Hashtable<>();
99103
verifiedSigners = new Hashtable<>();
@@ -180,7 +184,7 @@ public void beginEntry(JarEntry je, ManifestEntryVerifier mev)
180184

181185
// only set the jev object for entries that have a signature
182186
// (either verified or not)
183-
if (!name.equals(JarFile.MANIFEST_NAME)) {
187+
if (!name.equalsIgnoreCase(JarFile.MANIFEST_NAME)) {
184188
if (sigFileSigners.get(name) != null ||
185189
verifiedSigners.get(name) != null) {
186190
mev.setEntry(name, je);
@@ -270,7 +274,8 @@ private void processEntry(ManifestEntryVerifier mev)
270274
}
271275

272276
sfv.setSignatureFile(bytes);
273-
sfv.process(sigFileSigners, manifestDigests);
277+
sfv.process(sigFileSigners, manifestDigests,
278+
manifestName);
274279
}
275280
}
276281
return;
@@ -313,7 +318,7 @@ private void processEntry(ManifestEntryVerifier mev)
313318
sfv.setSignatureFile(bytes);
314319
}
315320
}
316-
sfv.process(sigFileSigners, manifestDigests);
321+
sfv.process(sigFileSigners, manifestDigests, manifestName);
317322

318323
} catch (IOException | CertificateException |
319324
NoSuchAlgorithmException | SignatureException e) {
@@ -419,9 +424,9 @@ void doneWithMeta()
419424
manDig = null;
420425
// MANIFEST.MF is always treated as signed and verified,
421426
// move its signers from sigFileSigners to verifiedSigners.
422-
if (sigFileSigners.containsKey(JarFile.MANIFEST_NAME)) {
423-
CodeSigner[] codeSigners = sigFileSigners.remove(JarFile.MANIFEST_NAME);
424-
verifiedSigners.put(JarFile.MANIFEST_NAME, codeSigners);
427+
if (sigFileSigners.containsKey(manifestName)) {
428+
CodeSigner[] codeSigners = sigFileSigners.remove(manifestName);
429+
verifiedSigners.put(manifestName, codeSigners);
425430
}
426431
}
427432

@@ -873,7 +878,7 @@ static CodeSource getUnsignedCS(URL url) {
873878
*/
874879
boolean isTrustedManifestEntry(String name) {
875880
// How many signers? MANIFEST.MF is always verified
876-
CodeSigner[] forMan = verifiedSigners.get(JarFile.MANIFEST_NAME);
881+
CodeSigner[] forMan = verifiedSigners.get(manifestName);
877882
if (forMan == null) {
878883
return true;
879884
}

src/java.base/share/classes/java/util/zip/ZipFile.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,6 +1032,18 @@ private List<String> getManifestAndSignatureRelatedFiles() {
10321032
}
10331033
}
10341034

1035+
/**
1036+
* Returns the number of the META-INF/MANIFEST.MF entries, case insensitive.
1037+
* When this number is greater than 1, JarVerifier will treat a file as
1038+
* unsigned.
1039+
*/
1040+
private int getManifestNum() {
1041+
synchronized (this) {
1042+
ensureOpen();
1043+
return res.zsrc.manifestNum;
1044+
}
1045+
}
1046+
10351047
/**
10361048
* Returns the name of the META-INF/MANIFEST.MF entry, ignoring
10371049
* case. If {@code onlyIfSignatureRelatedFiles} is true, we only return the
@@ -1079,6 +1091,10 @@ public List<String> getManifestAndSignatureRelatedFiles(JarFile jar) {
10791091
return ((ZipFile)jar).getManifestAndSignatureRelatedFiles();
10801092
}
10811093
@Override
1094+
public int getManifestNum(JarFile jar) {
1095+
return ((ZipFile)jar).getManifestNum();
1096+
}
1097+
@Override
10821098
public String getManifestName(JarFile jar, boolean onlyIfHasSignatureRelatedFiles) {
10831099
return ((ZipFile)jar).getManifestName(onlyIfHasSignatureRelatedFiles);
10841100
}
@@ -1131,6 +1147,7 @@ private static class Source {
11311147
private byte[] comment; // zip file comment
11321148
// list of meta entries in META-INF dir
11331149
private int manifestPos = -1; // position of the META-INF/MANIFEST.MF, if exists
1150+
private int manifestNum = 0; // number of META-INF/MANIFEST.MF, case insensitive
11341151
private int[] signatureMetaNames; // positions of signature related entries, if such exist
11351152
private int[] metaVersions; // list of unique versions found in META-INF/versions/
11361153
private final boolean startsWithLoc; // true, if zip file starts with LOCSIG (usually true)
@@ -1313,6 +1330,7 @@ private void close() throws IOException {
13131330
entries = null;
13141331
table = null;
13151332
manifestPos = -1;
1333+
manifestNum = 0;
13161334
signatureMetaNames = null;
13171335
metaVersions = EMPTY_META_VERSIONS;
13181336
}
@@ -1504,6 +1522,7 @@ private void initCEN(int knownTotal) throws IOException {
15041522
int pos = 0;
15051523
int entryPos = CENHDR;
15061524
int limit = cen.length - ENDHDR;
1525+
manifestNum = 0;
15071526
while (entryPos <= limit) {
15081527
if (idx >= entriesLength) {
15091528
// This will only happen if the zip file has an incorrect
@@ -1522,6 +1541,7 @@ private void initCEN(int knownTotal) throws IOException {
15221541
// nlen is at least META_INF_LENGTH
15231542
if (isManifestName(entryPos + META_INF_LEN, nlen - META_INF_LEN)) {
15241543
manifestPos = pos;
1544+
manifestNum++;
15251545
} else {
15261546
if (isSignatureRelated(entryPos, nlen)) {
15271547
if (signatureNames == null)

src/java.base/share/classes/jdk/internal/access/JavaUtilZipFileAccess.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -37,6 +37,7 @@ public interface JavaUtilZipFileAccess {
3737
public boolean startsWithLocHeader(ZipFile zip);
3838
public List<String> getManifestAndSignatureRelatedFiles(JarFile zip);
3939
public String getManifestName(JarFile zip, boolean onlyIfSignatureRelatedFiles);
40+
public int getManifestNum(JarFile zip);
4041
public int[] getMetaInfVersions(JarFile zip);
4142
public Enumeration<JarEntry> entries(ZipFile zip);
4243
public Stream<JarEntry> stream(ZipFile zip);

src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -270,7 +270,7 @@ private MessageDigest getDigest(String algorithm)
270270
*
271271
*/
272272
public void process(Hashtable<String, CodeSigner[]> signers,
273-
List<Object> manifestDigests)
273+
List<Object> manifestDigests, String manifestName)
274274
throws IOException, SignatureException, NoSuchAlgorithmException,
275275
JarException, CertificateException
276276
{
@@ -279,15 +279,15 @@ public void process(Hashtable<String, CodeSigner[]> signers,
279279
Object obj = null;
280280
try {
281281
obj = Providers.startJarVerification();
282-
processImpl(signers, manifestDigests);
282+
processImpl(signers, manifestDigests, manifestName);
283283
} finally {
284284
Providers.stopJarVerification(obj);
285285
}
286286

287287
}
288288

289289
private void processImpl(Hashtable<String, CodeSigner[]> signers,
290-
List<Object> manifestDigests)
290+
List<Object> manifestDigests, String manifestName)
291291
throws IOException, SignatureException, NoSuchAlgorithmException,
292292
JarException, CertificateException
293293
{
@@ -368,7 +368,7 @@ private void processImpl(Hashtable<String, CodeSigner[]> signers,
368368
}
369369

370370
// MANIFEST.MF is always regarded as signed
371-
updateSigners(newSigners, signers, JarFile.MANIFEST_NAME);
371+
updateSigners(newSigners, signers, manifestName);
372372
}
373373

374374
/**

0 commit comments

Comments
 (0)