Skip to content

8341775: Duplicate manifest files are removed by jarsigner after signing#22222

Closed
driverkt wants to merge 23 commits intoopenjdk:masterfrom
driverkt:8341775
Closed

8341775: Duplicate manifest files are removed by jarsigner after signing#22222
driverkt wants to merge 23 commits intoopenjdk:masterfrom
driverkt:8341775

Conversation

@driverkt
Copy link
Member

@driverkt driverkt commented Nov 18, 2024

JDK-8341775: In the case where there is a single META-INF directory but potentially multiple manifest files of different cases, print a warning before selecting the first one and ignoring the rest (the current behavior should be maintained).


Progress

  • Change must be properly reviewed (1 review required, with at least 1 Reviewer)
  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue

Issue

  • JDK-8341775: Duplicate manifest files are removed by jarsigner after signing (Enhancement - P4)

Reviewers

Reviewing

Using git

Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/22222/head:pull/22222
$ git checkout pull/22222

Update a local copy of the PR:
$ git checkout pull/22222
$ git pull https://git.openjdk.org/jdk.git pull/22222/head

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 22222

View PR using the GUI difftool:
$ git pr show -t 22222

Using diff file

Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/22222.diff

Using Webrev

Link to Webrev Comment

… but potentially *multiple* manifest files of different cases, print a warning before selecting the first one and ignoring the rest.
@bridgekeeper
Copy link

bridgekeeper bot commented Nov 18, 2024

👋 Welcome back kdriver! A progress list of the required criteria for merging this PR into master will be added to the body of your pull request. There are additional pull request commands available for use with this pull request.

@openjdk
Copy link

openjdk bot commented Nov 18, 2024

@driverkt This change now passes all automated pre-integration checks.

ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details.

After integration, the commit message for the final commit will be:

8341775: Duplicate manifest files are removed by jarsigner after signing

Reviewed-by: weijun, hchao

You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed.

At the time when this comment was updated there had been 17 new commits pushed to the master branch:

As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details.

➡️ To integrate this PR with the above commit message to the master branch, type /integrate in a new comment.

@openjdk
Copy link

openjdk bot commented Nov 18, 2024

@driverkt The following label will be automatically applied to this pull request:

  • security

When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing list. If you would like to change these labels, use the /label pull request command.

@openjdk openjdk bot added the security security-dev@openjdk.org label Nov 18, 2024
@driverkt
Copy link
Member Author

@haimaychao would you mind taking a look please?

@driverkt driverkt closed this Nov 18, 2024
@driverkt driverkt deleted the 8341775 branch November 18, 2024 23:23
@driverkt driverkt restored the 8341775 branch November 19, 2024 17:57
@driverkt driverkt reopened this Nov 19, 2024
@driverkt driverkt marked this pull request as ready for review November 19, 2024 19:36
@openjdk openjdk bot added the rfr Pull request is ready for review label Nov 19, 2024
@mlbridge
Copy link

mlbridge bot commented Nov 19, 2024

@haimaychao
Copy link
Contributor

The original code uses zf.getEntry() first which is direct and may not need to iterate over all entries in the ZIP file, and it does not issue a warning for multiple manifest entries. The new change uses the zf.stream() approach to iterate on the entire ZIP file first, and will it be more costly for a large archives? But to be able to issue a warning, your change looks reasonable to me.

@haimaychao
Copy link
Contributor

Would you consider adding a test case to test the new warning message?

@driverkt
Copy link
Member Author

The original code uses zf.getEntry() first which is direct and may not need to iterate over all entries in the ZIP file, and it does not issue a warning for multiple manifest entries. The new change uses the zf.stream() approach to iterate on the entire ZIP file first, and will it be more costly for a large archives? But to be able to issue a warning, your change looks reasonable to me.

Thank you. I agree there is some performance penalty, but (as you say) it is necessary to be able to issue the warning.

@driverkt
Copy link
Member Author

driverkt commented Nov 20, 2024

Would you consider adding a test case to test the new warning message?

See my comment on the JBS issue. I'm not sure how practical adding one would be. Do you have any suggestions for the best way to go about it?

@haimaychao
Copy link
Contributor

I’d like to suggest creating a test program (for better long term support) that generates a JAR file with multiple manifest entries and then uses JarSigner.Builder() and JarSigner.sign(). The JarSigner.sign() will ultimately invoke getManifestFile(), ensuring that the new warning about multiple manifest entries is emitted.

@driverkt
Copy link
Member Author

I’d like to suggest creating a test program (for better long term support) that generates a JAR file with multiple manifest entries and then uses JarSigner.Builder() and JarSigner.sign(). The JarSigner.sign() will ultimately invoke getManifestFile(), ensuring that the new warning about multiple manifest entries is emitted.

Dynamically creating the needed jar files to perform a test would depend on the file-system of the platform (ie - macOS cannot create two different files with the same name but different cases). Furthermore, we cannot create a jar with two different META-INF directories at the root, both with two different all-caps MANIFEST.MF files dynamically. Unless I am mistaken.

@eirbjo
Copy link
Contributor

eirbjo commented Nov 23, 2024

Furthermore, we cannot create a jar with two different META-INF directories at the root, both with two different all-caps MANIFEST.MF files dynamically. Unless I am mistaken.

Here's a unit test which produces a JAR file with a duplicated META-INF/MANIFEST.MF:

@Test
public void doubleManifest() throws IOException {
    var name = "META-INF/MANIFEST.MF";
    var nameBytes = name.getBytes(StandardCharsets.UTF_8);

    var baos = new ByteArrayOutputStream();
    try (var zo = new ZipOutputStream(baos)) {
        // ZOS does not allow duplicated name, use lowercase
        zo.putNextEntry(new ZipEntry(name.toLowerCase(Locale.ROOT)));
        zo.putNextEntry(new ZipEntry(name));
    }

    byte[] zip = baos.toByteArray();
    // Byte buffer to navigate the ZIP
    ByteBuffer bb = ByteBuffer.wrap(zip).order(ByteOrder.LITTLE_ENDIAN);

    // Offset of the start of the END header
    int endOff = zip.length - ZipEntry.ENDHDR;
    // Offset of the first CEN header
    short cenOff = bb.getShort(endOff + ZipEntry.ENDOFF);
    // Write uppercase name to first CEN entry
    bb.put(cenOff + ZipEntry.CENHDR, nameBytes, 0, nameBytes.length);

    // Write the file to disk
    Path zipFile = Path.of("double-man.jar");
    Files.write(zipFile, zip);

    // Verify that ZipFile reads duplicated MANIFEST files
    try (var zf = new ZipFile(zipFile.toFile())) {
        List<? extends ZipEntry> entries = Collections.list(zf.entries());
        assertEquals(2, entries.size());
        assertEquals(name, entries.get(0).getName());
        assertEquals(name, entries.get(1).getName());
    }

}

@wangweij
Copy link
Contributor

wangweij commented Dec 2, 2024

Two comments:

  1. The warning should only be shown by the jarsigner tool. JarSigner is an API and should not write to System.err.
  2. There are other warnings by jarsigner and the new one should be a part of them, i.e. no separate header. It also should be localized.

# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
@bridgekeeper
Copy link

bridgekeeper bot commented Dec 30, 2024

@driverkt This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration!

@driverkt
Copy link
Member Author

/open

@openjdk
Copy link

openjdk bot commented Dec 31, 2024

@driverkt This pull request is already open

# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
@driverkt
Copy link
Member Author

driverkt commented Jan 2, 2025

  1. The warning should only be shown by the jarsigner tool. JarSigner is an API and should not write to System.err.

@wangweij: See the note that is part of the PR description. I've copied it below for convenience:

--8<--
Note: We cannot (so far) pass whether the verbose flag is set to the class that does this processing. We may want to add a property to the builder for this. As-is, the message will be printed via System.err whether verbose is set or not.
--8<--

AFAICT, there isn't currently a way to access the Main class for logging/output (which incidentally also uses System.err with the Resources files). I'm ok to add one -- it's just not in the current scope of the fix.

@wangweij
Copy link
Contributor

wangweij commented Jan 2, 2025

What I meant is that besides using jarsigner tool to sign a JAR file, users can also use the JarSigner API to sign. In this case, I don't think there should be any System.err output. You're right that passing the verbose option into builder is awkward. Have you thought about moving the newly added lines into the jarsigner tool?

# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
@openjdk openjdk bot removed the merge-conflict Pull request has merge conflict with target branch label Mar 13, 2025
@driverkt driverkt requested a review from haimaychao March 13, 2025 18:49
jar.treated.unsigned=WARNING: Signature is either not parsable or not verifiable, and the jar will be treated as unsigned. For more information, re-run jarsigner with debug enabled (-J-Djava.security.debug=jar).
jar.treated.unsigned.see.weak=The jar will be treated as unsigned, because it is signed with a weak algorithm that is now disabled.\n\nRe-run jarsigner with the -verbose option for more details.
jar.treated.unsigned.see.weak.verbose=WARNING: The jar will be treated as unsigned, because it is signed with a weak algorithm that is now disabled by the security property:
multiple.manifest.warning.=Duplicate manifest entries were detected in the jar file. JarSigner will operate on only one and the others will be discarded.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shall we have a a past-tense phrase to make it clearer that the extra entries were actually deleted? Something like:
"Duplicate manifest entries were detected in the JAR file. JarSigner operated on only one, and the others have been discarded."

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe. When this warning shows up, the extra entries have already been removed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update.

@openjdk openjdk bot added the ready Pull request is ready to be integrated label Mar 14, 2025
@openjdk openjdk bot removed the ready Pull request is ready to be integrated label Mar 14, 2025
@openjdk openjdk bot removed the rfr Pull request is ready for review label Mar 14, 2025
@openjdk openjdk bot added the rfr Pull request is ready for review label Mar 14, 2025
certificate's expiration date (`YYYY-MM-DD`) or after any future revocation
date.

hasMultipleManifests
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest to place the new warning in alphabetical order.

@openjdk openjdk bot added the ready Pull request is ready to be integrated label Mar 14, 2025
@driverkt
Copy link
Member Author

/integrate

@openjdk
Copy link

openjdk bot commented Mar 28, 2025

Going to push as commit d809033.
Since your change was applied there have been 202 commits pushed to the master branch:

  • a269bef: 8350459: MontgomeryIntegerPolynomialP256 multiply intrinsic with AVX2 on x86_64
  • c029220: 8352896: LambdaExpr02.java runs wrong test class
  • c0b61d3: 8352680: Opensource few misc swing tests
  • 3e9a7a4: 8353063: make/ide/vscode: Invalid Configuration Values
  • 8ef7832: 8350471: Unhandled compilation bailout in GraphKit::builtin_throw
  • ddf326b: 8346888: [ubsan] block.cpp:1617:30: runtime error: 9.97582e+36 is outside the range of representable values of type 'int'
  • bac2aa4: 8352946: SEGV_BND signal code of SIGSEGV missing from our signal-code table
  • cfc648b: 8352677: Opensource JMenu tests - series2
  • 2ea1557: 8353005: AIX build broken after 8352481
  • f4428e8: 8352920: Compilation failure: comparison of unsigned expression >= 0 is always true
  • ... and 192 more: https://git.openjdk.org/jdk/compare/771e160da4daa98bfe37bf1acba65454c088910c...master

Your commit was automatically rebased without conflicts.

@openjdk openjdk bot added the integrated Pull request has been integrated label Mar 28, 2025
@openjdk openjdk bot closed this Mar 28, 2025
@openjdk openjdk bot removed ready Pull request is ready to be integrated rfr Pull request is ready for review labels Mar 28, 2025
@openjdk
Copy link

openjdk bot commented Mar 28, 2025

@driverkt Pushed as commit d809033.

💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

integrated Pull request has been integrated security security-dev@openjdk.org

Development

Successfully merging this pull request may close these issues.

6 participants