|
Note
|
This draft extension is not yet implemented in any device or reader. It builds on revision 2026-10-22 of the main specification. The envelope format and key management may still change. |
|
Note
|
|
Signature envelope
The envelope is ASCII text with LF line endings, at the end of the ZIP archive comment.
-
It starts at the first
BORSIG<n>line. -
Text before it, such as
LIM, is kept. If that text does not end with a line feed, the writer adds one before the envelope. -
Every envelope line, including the last one, ends with a line feed.
-
A file has at most one envelope.
LIM BORSIG1 key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA... sig: Zm9vYmFy...
| Line | Description | Type | Required |
|---|---|---|---|
|
Version, fixes the profile below |
text |
required |
|
Public key, base64 DER SubjectPublicKeyInfo |
text |
required |
|
Signature, base64 |
text |
required |
Signed bytes
The signature covers the archive as if its comment were empty, prefixed by the version line. In order:
-
BORSIG1followed by a line feed; -
the archive from offset 0 up to, but not including, the EOCD comment length field (the first 20 bytes of the EOCD are included);
-
two zero bytes (empty comment length).
The archive comment is not signed: neither the envelope nor the text before it.
ZIP64 archives are signed the same way: the classic EOCD is still the last record.
Profile BORSIG1
| Parameter | Value | Note |
|---|---|---|
Key type |
RSA |
At least 2048 bits. A smaller key, or a key that is not RSA, makes the signature invalid. |
Signature scheme |
RSASSA-PSS (RFC 8017, section 8.1) |
|
Hash |
SHA-256 |
The input of the signature operation is the signed bytes, not a digest of them. |
Mask generation |
MGF1 with SHA-256 |
|
Salt length |
32 bytes |
A signature made with another salt length is invalid. |
Public key |
DER SubjectPublicKeyInfo with the |
|
Signature |
Raw RSA output, base64 |
As long as the key modulus: 256 bytes for a 2048-bit key. |
Base64 |
RFC 4648, section 4, with padding |
No line breaks. |
# signed bytes (file.bor has no envelope yet)
eocd=$(grep -obUaP 'PK\x05\x06' file.bor | tail -n 1 | cut -d: -f1)
{ printf 'BORSIG1\n'; head -c $((eocd + 20)) file.bor; printf '\0\0'; } > signed-bytes.bin
# sign, then verify
opts="-sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:32 -sigopt rsa_mgf1_md:sha256"
openssl dgst -sha256 -sign key.pem $opts -out sig.bin signed-bytes.bin
openssl dgst -sha256 -verify pub.pem $opts -signature sig.bin signed-bytes.bin
# values of the key: and sig: lines
openssl pkey -in key.pem -pubout -outform DER | base64 -w0
base64 -w0 sig.bin
Verification result
A reader that supports this extension reports one of these states:
| State | Meaning |
|---|---|
absent |
No line of the form |
unsupported |
The envelope version is not supported by the reader, for example |
invalid |
The envelope is malformed, or the signature does not match the signed bytes |
valid, unknown key |
The signature matches, but the key is not in the reader’s trust list |
valid, recognized generator |
The signature matches, and the reader’s trust list associates the key with the |
Compatibility
ZIP readers find the EOCD from the end of the file and read the comment
with it. The comment holds up to 65535 bytes; the envelope is about 0.8 KB
with an RSA 2048 key. Python zipfile, rubyzip 0.9.4 and fflate 0.8
unzipSync open a signed file and return the comment unchanged.
Any change to the signed bytes invalidates the signature. A tool that rewrites the archive without copying the comment removes the signature.
Out of scope
Generator approval, key ownership, trust lists and key revocation are internal to LIM and not covered by this draft.