Skip to content

Commit 5452da9

Browse files
franferraxjerboaa
authored andcommitted
8339280: jarsigner -verify performs cross-checking between CEN and LOC
8353299: VerifyJarEntryName.java test fails 8367782: VerifyJarEntryName.java: Fix modifyJarEntryName to operate on bytes and re-introduce verifySignatureEntryName Reviewed-by: abakhtin, sgehwolf, andrew Backport-of: bbd5b174c50346152a624317b6bd76ec48f7e551
1 parent 8304a76 commit 5452da9

File tree

6 files changed

+335
-0
lines changed

6 files changed

+335
-0
lines changed

jdk/src/bsd/doc/man/jarsigner.1

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,11 @@ Informational warnings include those that are not errors but regarded as bad pra
624624
hasExpiringCert
625625
This jar contains entries whose signer certificate will expire within six months\&.
626626
.TP
627+
internalInconsistenciesDetected
628+
This jar contains internal inconsistencies detected during verification
629+
that may result in different contents when reading via JarFile
630+
and JarInputStream\&.
631+
.TP
627632
noTimestamp
628633
This jar contains signatures that does not include a timestamp\&. Without a timestamp, users may not be able to validate this JAR file after the signer certificate\&'s expiration date (\f3YYYY-MM-DD\fR) or after any future revocation date\&.
629634
.SH EXAMPLES

jdk/src/linux/doc/man/jarsigner.1

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,11 @@ Informational warnings include those that are not errors but regarded as bad pra
624624
hasExpiringCert
625625
This jar contains entries whose signer certificate will expire within six months\&.
626626
.TP
627+
internalInconsistenciesDetected
628+
This jar contains internal inconsistencies detected during verification
629+
that may result in different contents when reading via JarFile
630+
and JarInputStream\&.
631+
.TP
627632
noTimestamp
628633
This jar contains signatures that does not include a timestamp\&. Without a timestamp, users may not be able to validate this JAR file after the signer certificate\&'s expiration date (\f3YYYY-MM-DD\fR) or after any future revocation date\&.
629634
.SH EXAMPLES

jdk/src/share/classes/sun/security/tools/jarsigner/Main.java

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
package sun.security.tools.jarsigner;
2727

2828
import java.io.*;
29+
import java.nio.file.Files;
30+
import java.nio.file.Paths;
2931
import java.security.cert.CertPathValidatorException;
3032
import java.security.cert.PKIXBuilderParameters;
3133
import java.util.*;
@@ -223,6 +225,8 @@ public static void main(String args[]) throws Exception {
223225
private Throwable chainNotValidatedReason = null;
224226
private Throwable tsaChainNotValidatedReason = null;
225227

228+
private List<String> crossChkWarnings = new ArrayList<>();
229+
226230
PKIXBuilderParameters pkixParameters;
227231
Set<X509Certificate> trustedCerts = new HashSet<>();
228232

@@ -976,6 +980,7 @@ void verifyJar(String jarName)
976980
}
977981
}
978982
System.out.println();
983+
crossCheckEntries(jarName);
979984

980985
// If signer is a trusted cert or private entry in user's own
981986
// keystore, it can be self-signed. Please note aliasNotInStore
@@ -1017,6 +1022,144 @@ void verifyJar(String jarName)
10171022
System.exit(1);
10181023
}
10191024

1025+
private void crossCheckEntries(String jarName) throws Exception {
1026+
Set<String> locEntries = new HashSet<>();
1027+
1028+
try (JarFile jarFile = new JarFile(jarName);
1029+
JarInputStream jis = new JarInputStream(
1030+
Files.newInputStream(Paths.get(jarName)))) {
1031+
1032+
Manifest cenManifest = jarFile.getManifest();
1033+
Manifest locManifest = jis.getManifest();
1034+
compareManifest(cenManifest, locManifest);
1035+
1036+
JarEntry locEntry;
1037+
while ((locEntry = jis.getNextJarEntry()) != null) {
1038+
String entryName = locEntry.getName();
1039+
locEntries.add(entryName);
1040+
1041+
JarEntry cenEntry = jarFile.getJarEntry(entryName);
1042+
if (cenEntry == null) {
1043+
crossChkWarnings.add(String.format(rb.getString(
1044+
"entry.1.present.when.reading.jarinputstream.but.missing.via.jarfile"),
1045+
entryName));
1046+
continue;
1047+
}
1048+
1049+
try {
1050+
readEntry(jis);
1051+
} catch (SecurityException e) {
1052+
crossChkWarnings.add(String.format(rb.getString(
1053+
"signature.verification.failed.on.entry.1.when.reading.via.jarinputstream"),
1054+
entryName));
1055+
continue;
1056+
}
1057+
1058+
try (InputStream cenInputStream = jarFile.getInputStream(cenEntry)) {
1059+
if (cenInputStream == null) {
1060+
crossChkWarnings.add(String.format(rb.getString(
1061+
"entry.1.present.in.jarfile.but.unreadable"),
1062+
entryName));
1063+
continue;
1064+
} else {
1065+
try {
1066+
readEntry(cenInputStream);
1067+
} catch (SecurityException e) {
1068+
crossChkWarnings.add(String.format(rb.getString(
1069+
"signature.verification.failed.on.entry.1.when.reading.via.jarfile"),
1070+
entryName));
1071+
continue;
1072+
}
1073+
}
1074+
}
1075+
1076+
compareSigners(cenEntry, locEntry);
1077+
}
1078+
1079+
jarFile.stream()
1080+
.map(JarEntry::getName)
1081+
.filter(n -> !locEntries.contains(n) && !n.equals(JarFile.MANIFEST_NAME))
1082+
.forEach(n -> crossChkWarnings.add(String.format(rb.getString(
1083+
"entry.1.present.when.reading.jarfile.but.missing.via.jarinputstream"), n)));
1084+
}
1085+
}
1086+
1087+
private void readEntry(InputStream is) throws IOException {
1088+
byte[] buffer = new byte[8192];
1089+
while (is.read(buffer) != -1) { }
1090+
}
1091+
1092+
private void compareManifest(Manifest cenManifest, Manifest locManifest) {
1093+
if (cenManifest == null) {
1094+
crossChkWarnings.add(rb.getString(
1095+
"manifest.missing.when.reading.jarfile"));
1096+
return;
1097+
}
1098+
if (locManifest == null) {
1099+
crossChkWarnings.add(rb.getString(
1100+
"manifest.missing.when.reading.jarinputstream"));
1101+
return;
1102+
}
1103+
1104+
Attributes cenMainAttrs = cenManifest.getMainAttributes();
1105+
Attributes locMainAttrs = locManifest.getMainAttributes();
1106+
1107+
for (Object key : cenMainAttrs.keySet()) {
1108+
Object cenValue = cenMainAttrs.get(key);
1109+
Object locValue = locMainAttrs.get(key);
1110+
1111+
if (locValue == null) {
1112+
crossChkWarnings.add(String.format(rb.getString(
1113+
"manifest.attribute.1.present.when.reading.jarfile.but.missing.via.jarinputstream"),
1114+
key));
1115+
} else if (!cenValue.equals(locValue)) {
1116+
crossChkWarnings.add(String.format(rb.getString(
1117+
"manifest.attribute.1.differs.jarfile.value.2.jarinputstream.value.3"),
1118+
key, cenValue, locValue));
1119+
}
1120+
}
1121+
1122+
for (Object key : locMainAttrs.keySet()) {
1123+
if (!cenMainAttrs.containsKey(key)) {
1124+
crossChkWarnings.add(String.format(rb.getString(
1125+
"manifest.attribute.1.present.when.reading.jarinputstream.but.missing.via.jarfile"),
1126+
key));
1127+
}
1128+
}
1129+
}
1130+
1131+
private void compareSigners(JarEntry cenEntry, JarEntry locEntry) {
1132+
CodeSigner[] cenSigners = cenEntry.getCodeSigners();
1133+
CodeSigner[] locSigners = locEntry.getCodeSigners();
1134+
1135+
boolean cenHasSigners = cenSigners != null;
1136+
boolean locHasSigners = locSigners != null;
1137+
1138+
if (cenHasSigners && locHasSigners) {
1139+
if (!Arrays.equals(cenSigners, locSigners)) {
1140+
crossChkWarnings.add(String.format(rb.getString(
1141+
"codesigners.different.for.entry.1.when.reading.jarfile.and.jarinputstream"),
1142+
cenEntry.getName()));
1143+
}
1144+
} else if (cenHasSigners) {
1145+
crossChkWarnings.add(String.format(rb.getString(
1146+
"entry.1.is.signed.in.jarfile.but.is.not.signed.in.jarinputstream"),
1147+
cenEntry.getName()));
1148+
} else if (locHasSigners) {
1149+
crossChkWarnings.add(String.format(rb.getString(
1150+
"entry.1.is.signed.in.jarinputstream.but.is.not.signed.in.jarfile"),
1151+
locEntry.getName()));
1152+
}
1153+
}
1154+
1155+
private void displayCrossChkWarnings() {
1156+
System.out.println();
1157+
// First is a summary warning
1158+
System.out.println(rb.getString("jar.contains.internal.inconsistencies.result.in.different.contents.via.jarfile.and.jarinputstream"));
1159+
// each warning message with prefix "- "
1160+
crossChkWarnings.forEach(warning -> System.out.println("- " + warning));
1161+
}
1162+
10201163
private void displayMessagesAndResult(boolean isSigning) {
10211164
String result;
10221165
List<String> errors = new ArrayList<>();
@@ -1248,13 +1391,19 @@ private void displayMessagesAndResult(boolean isSigning) {
12481391
System.out.println(rb.getString("Warning."));
12491392
warnings.forEach(System.out::println);
12501393
}
1394+
if (!crossChkWarnings.isEmpty()) {
1395+
displayCrossChkWarnings();
1396+
}
12511397
} else {
12521398
if (!errors.isEmpty() || !warnings.isEmpty()) {
12531399
System.out.println();
12541400
System.out.println(rb.getString("Warning."));
12551401
errors.forEach(System.out::println);
12561402
warnings.forEach(System.out::println);
12571403
}
1404+
if (!crossChkWarnings.isEmpty()) {
1405+
displayCrossChkWarnings();
1406+
}
12581407
}
12591408
if (!isSigning && (!errors.isEmpty() || !warnings.isEmpty())) {
12601409
if (! (verbose != null && showcerts)) {

jdk/src/share/classes/sun/security/tools/jarsigner/Resources.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,34 @@ public class Resources extends java.util.ListResourceBundle {
312312
{"Cannot.find.environment.variable.",
313313
"Cannot find environment variable: "},
314314
{"Cannot.find.file.", "Cannot find file: "},
315+
{"manifest.missing.when.reading.jarfile",
316+
"Manifest is missing when reading via JarFile"},
317+
{"manifest.missing.when.reading.jarinputstream",
318+
"Manifest is missing when reading via JarInputStream"},
319+
{"manifest.attribute.1.present.when.reading.jarfile.but.missing.via.jarinputstream",
320+
"Manifest main attribute %s is present when reading via JarFile but missing when reading via JarInputStream"},
321+
{"manifest.attribute.1.present.when.reading.jarinputstream.but.missing.via.jarfile",
322+
"Manifest main attribute %s is present when reading via JarInputStream but missing when reading via JarFile"},
323+
{"manifest.attribute.1.differs.jarfile.value.2.jarinputstream.value.3",
324+
"Manifest main attribute %1$s differs: JarFile value = %2$s, JarInputStream value = %3$s"},
325+
{"entry.1.present.when.reading.jarinputstream.but.missing.via.jarfile",
326+
"Entry %s is present when reading via JarInputStream but missing when reading via JarFile"},
327+
{"entry.1.present.when.reading.jarfile.but.missing.via.jarinputstream",
328+
"Entry %s is present when reading via JarFile but missing when reading via JarInputStream"},
329+
{"entry.1.present.in.jarfile.but.unreadable",
330+
"Entry %s is present in JarFile but unreadable"},
331+
{"codesigners.different.for.entry.1.when.reading.jarfile.and.jarinputstream",
332+
"Code signers are different for entry %s when reading from JarFile and JarInputStream"},
333+
{"entry.1.is.signed.in.jarfile.but.is.not.signed.in.jarinputstream",
334+
"Entry %s is signed in JarFile but is not signed in JarInputStream"},
335+
{"entry.1.is.signed.in.jarinputstream.but.is.not.signed.in.jarfile",
336+
"Entry %s is signed in JarInputStream but is not signed in JarFile"},
337+
{"jar.contains.internal.inconsistencies.result.in.different.contents.via.jarfile.and.jarinputstream",
338+
"This JAR file contains internal inconsistencies that may result in different contents when reading via JarFile and JarInputStream:"},
339+
{"signature.verification.failed.on.entry.1.when.reading.via.jarinputstream",
340+
"Signature verification failed on entry %s when reading via JarInputStream"},
341+
{"signature.verification.failed.on.entry.1.when.reading.via.jarfile",
342+
"Signature verification failed on entry %s when reading via JarFile"},
315343
};
316344

317345
/**

jdk/src/solaris/doc/sun/man/man1/jarsigner.1

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,11 @@ Informational warnings include those that are not errors but regarded as bad pra
624624
hasExpiringCert
625625
This jar contains entries whose signer certificate will expire within six months\&.
626626
.TP
627+
internalInconsistenciesDetected
628+
This jar contains internal inconsistencies detected during verification
629+
that may result in different contents when reading via JarFile
630+
and JarInputStream\&.
631+
.TP
627632
noTimestamp
628633
This jar contains signatures that does not include a timestamp\&. Without a timestamp, users may not be able to validate this JAR file after the signer certificate\&'s expiration date (\f3YYYY-MM-DD\fR) or after any future revocation date\&.
629634
.SH EXAMPLES

0 commit comments

Comments
 (0)