Explain the files signing adds under META-INF — the manifest digests, the .SF file, and the .RSA/.DSA/.EC block — and how the runtime uses them to verify.
answer
- MANIFEST.MF = per-file digests (SHA-256-Digest)
- .SF = digest of the manifest (and its sections)
- .RSA/.DSA/.EC = actual signature + cert chain (PKCS#7)
- verify outward: file → manifest → signature → cert
- .SF indirection lets unsigned entries be added later
basics
~20 sSigning adds per-file hashes to MANIFEST.MF, a NAME.SF file holding a hash of the manifest, and a NAME.RSA/DSA/EC block containing the actual digital signature plus the certificate. Verification re-hashes entries and checks the signature against the certificate.
solid answer
~50 sSigning layers three things in META-INF. First, MANIFEST.MF gets a per-entry section for each file with a digest header like 'SHA-256-Digest: <hash>'. Second, a signature file NAME.SF mirrors those entries but stores a digest of each manifest entry plus a digest of the whole manifest header — it signs the manifest indirectly, which lets unrelated entries be added without re-signing everything. Third, NAME.RSA (or .DSA/.EC, named after the key algorithm) is the signature block: the actual digital signature computed over the .SF file, bundled with the signer's certificate chain. Verification works outward: recompute each entry's digest and compare to MANIFEST.MF (file integrity); recompute the manifest's digest and compare to the .SF (manifest integrity); then verify the .SF's signature against the certificate's public key in the block (authenticity). All three layers must check out for 'jar verified.'.
code
java · 16 lines// META-INF/MANIFEST.MF (per-file digest)
// Name: com/example/App.class
// SHA-256-Digest: K7s9...=
//
// META-INF/MYALIAS.SF (digest OF the manifest, not the file)
// Signature-Version: 1.0
// SHA-256-Digest-Manifest: 9af2...=
// Name: com/example/App.class
// SHA-256-Digest: q1Zb...= <-- hash of App.class's manifest section
//
// META-INF/MYALIAS.RSA (binary PKCS#7 signature block)
// = signature over MYALIAS.SF + signer certificate chain
//
// Verify order: recompute file hash -> match MANIFEST.MF
// recompute manifest hash -> match .SF
// check .SF signature -> against cert in .RSAgo deeper
Knows signing adds files under META-INF and that they let the JVM check the JAR wasn't changed.
Names the three layers — manifest digests, .SF, and .RSA block — and roughly what each holds.
Explains the digest chain, the .SF-indirection rationale (and the unsigned-entry subtlety), the PKCS#7 block, and the outward verification order.
Reasons about multi-signer scenarios, the security implications of partial signing in dependency supply chains, and how to enforce full-signature policies.
## Where the artifacts live Everything signing-related sits in the **`META-INF/`** directory of the JAR. Three kinds of files participate, forming a chain of digests so a single asymmetric signature can cover the whole archive efficiently. ## Layer 1 — `MANIFEST.MF` per-entry digests The manifest already lists the archive's entries. Signing adds, for **each** signed file, a per-entry section like: ``` Name: com/example/App.class SHA-256-Digest: K7s9...base64...= ``` The **digest** is the base64 of the file's cryptographic hash. This is the ground truth for *file* integrity: change `App.class` and its recomputed hash no longer matches. ## Layer 2 — `NAME.SF` (signature file) `NAME` is the signer's alias (e.g. `MYALIAS.SF`). It looks like a manifest but instead stores, per entry, a digest of **the corresponding manifest section** (not of the file itself): ``` Signature-Version: 1.0 SHA-256-Digest-Manifest: <hash of the whole MANIFEST.MF> ... Name: com/example/App.class SHA-256-Digest: <hash of App.class's manifest SECTION> ``` Why this indirection? It means the signature ultimately covers the **manifest**, not each file directly. A key consequence: you can **add new (unsigned) entries** to the JAR later without invalidating the existing signature — the verifier only insists that *signed* entries match. (This is also a subtlety: tools must treat unsigned added entries as untrusted.) The `SHA-256-Digest-Manifest` header lets a verifier validate the whole manifest in one shot. ## Layer 3 — `NAME.RSA` / `NAME.DSA` / `NAME.EC` (signature block) This binary file is the **signature block**. Its extension names the signing key's algorithm (RSA, DSA, or EC/ECDSA). It contains: - the **digital signature** computed by the private key over the bytes of the `.SF` file, and - the signer's **certificate chain** (the public certificate, plus any intermediates up toward a CA root). It is encoded in **PKCS#7 / CMS** (a standard signed-data container). Because it carries the certificate, the verifier needs nothing external to check authenticity — only to *decide whether to trust* that certificate. ## How verification flows (outermost → innermost) 1. **File integrity:** recompute each signed file's hash; compare to `MANIFEST.MF`. Mismatch → file tampered. 2. **Manifest integrity:** recompute the manifest section/whole-manifest digests; compare to `NAME.SF`. Mismatch → manifest tampered. 3. **Authenticity:** verify the digital signature in `NAME.RSA` over `NAME.SF` using the certificate's public key. Pass → signed by that key's holder. 4. **Certificate checks:** validity period (helped by a timestamp), and chain to a trusted root if CA-backed. Only if 1–3 succeed does `jarsigner -verify` print `jar verified.`. Step 4 governs *trust*, which is policy. ## Multiple signers A JAR can be signed by several parties: each adds its own `NAME.SF` + block (different aliases). Each contributes per-entry digests, so a verifier can check any/all signers. ## Term glossary - **Digest / hash:** fixed-length fingerprint of bytes; any change alters it. - **PKCS#7 / CMS:** standard format for a signature-plus-certificates blob. - **Certificate chain:** the signer's cert plus intermediates linking to a trusted root. ## Contrast with sealing These files are entirely about **signing**. Sealing, by contrast, adds only a plain `Sealed: true` header to the manifest — no `.SF`, no `.RSA`, no cryptography.
- Why does the .SF file store a digest of the manifest rather than signing each class file directly?Indirection through the manifest lets one signature cover the whole archive and lets unsigned entries be added later without re-signing. The signature binds the .SF, the .SF binds the manifest, and the manifest binds each file's hash — a digest chain. A side effect is that newly added unsigned entries are simply unverified, so tooling must treat them as untrusted.
- Why might the signature block be named .EC instead of .RSA?The extension reflects the signing key's algorithm: .RSA for RSA keys, .DSA for DSA, and .EC (ECDSA) for elliptic-curve keys. The content is otherwise the same kind of PKCS#7/CMS signed-data block carrying the signature and certificate chain.
saying these in an interview costs you the question
- Thinking the .SF file contains the digital signature — the signature lives in the .RSA/.DSA/.EC block; the .SF holds manifest digests.
- Saying the signature directly signs every class — it signs the .SF, which chains through the manifest to the files.
- Assuming a verified signature also covers any unsigned entries added afterward — it does not.
- Confusing these signing files with sealing, which adds only a plain manifest header.