On this page
Integrity
A package's integrity is verified at two levels:
- The package level: the entire
.peipkgfile has a hash and a signature that prove the file as a whole has not been altered since it was signed. - The per-file level: each payload file has an individual hash that proves the file's content has not been altered between archive creation and installation.
§3.5.1 Per-file integrity manifest
Each package's tar archive contains a per-file integrity
manifest at .peipkg/files.json. The integrity manifest is
a JSON document conforming to the schema in this section.
§3.5.1.1 Schema
{
"schema_version": 1,
"algorithm": "sha256",
"entries": [
{
"path": "<string>",
"size": <integer>,
"hash": "<hex string>"
}
]
}
| Field | Type | Description |
|---|---|---|
schema_version |
integer | MUST be 1 in this specification. |
algorithm |
string | Hash algorithm. MUST be sha256 in this specification. |
entries |
array | One entry per regular-file payload entry. |
§3.5.1.2 Entry schema
| Field | Type | Description |
|---|---|---|
path |
string | Payload-relative path, identical to the corresponding tar entry path. |
size |
integer | Size in bytes of the file's content. |
hash |
string | Lowercase hexadecimal hash of the file's content using the declared algorithm. |
The entries array MUST be sorted lexicographically by
path.
§3.5.1.3 Coverage
The integrity manifest MUST contain exactly one entry per regular-file payload entry in the tar archive. It MUST NOT contain entries for:
- Metadata entries under
.peipkg/ - Directory entries
- Symlink entries
A regular-file payload entry without a corresponding entry in the integrity manifest, or an entry in the integrity manifest without a corresponding tar entry, is INVALID and MUST cause the package to be rejected on parse.
§3.5.2 Package hash
The package hash is the hash of the entire .peipkg file
(the compressed tar archive) computed with the algorithm
declared in the repository index (§6.2). The default and
required-supported algorithm is SHA-256.
The package hash is recorded in:
- The repository index (§6.2), to verify the downloaded file matches what the repo advertises.
- The signature payload (§5.1), to bind the signature to this exact file.
The package hash is NOT recorded inside the package itself. A package cannot contain its own hash.
§3.5.3 Verification flow
A consumer verifying a package MUST perform the following steps in order:
- Compute the SHA-256 of the downloaded
.peipkgfile. - Compare against the hash recorded in the repository index (§6.2). If they differ, the package is corrupted or substituted; abort.
- Verify the inline signature (§5.3). If verification fails, the package's authenticity is unproven; abort.
- Decompress and parse the tar archive.
- Read
.peipkg/manifest.jsonand verify it parses against the schema in §3.3. - Read
.peipkg/files.jsonand verify it parses against the schema in §3.5.1. - For each payload entry: compute its content hash and
compare against the corresponding entry in
.peipkg/files.json. If any file's hash does not match, abort. - The package is verified.
A consumer MUST NOT install any payload before all eight steps complete successfully. Partial installation in the event of verification failure leaves the system in an indeterminate state and is forbidden.
A consumer MUST NOT make any decompressed payload bytes visible to other processes (including via staging directories that are reachable from outside the package manager's own process tree) before signature verification (step 3) has succeeded. Streaming decompression and hashing is permitted; observable filesystem effects are not.
§3.5.4 Decompression bounds
A consumer MUST enforce upper bounds on package decompression to prevent resource-exhaustion attacks via maliciously-constructed packages with extreme compression ratios.
Two bounds apply:
- The repository index entry's
size_compressedandsize_installedfields (§6.2.4) bound the legitimate sizes of the compressed and uncompressed forms. A consumer MUST verify, during streaming decompression, that:- the cumulative compressed bytes consumed do not
exceed
size_compressedby more than the lesser of 1% or 16 MiB; - the cumulative decompressed bytes produced do not
exceed
size_installedplus a fixed overhead allowance of 320 MiB. The allowance accommodates tar header and block-padding overhead and the metadata files; it is sized so that no package conforming to the §3.2.7 resource limits is ever rejected.
- the cumulative compressed bytes consumed do not
exceed
- Independent of index-declared sizes, a consumer MUST abort decompression if the cumulative decompressed output exceeds an absolute cap. The default absolute cap is 4 GiB; the cap MAY be raised by operator configuration but MUST NOT be raised silently.
Exceeding either bound MUST cause the package to be rejected with no further processing and no payload committed to disk.
The 320 MiB decompressed allowance bounds the structural
overhead a conformant package may legitimately carry
above its installed payload: tar headers and block
padding for up to the §3.2.7 limit of 100,000 entries,
plus the metadata files (manifest.json up to 16 MiB,
files.json up to 64 MiB). A typical package's overhead
is a tiny fraction of this; the fixed allowance is sized
so that a consumer never rejects a package that conforms
to the §3.2.7 limits.
§3.5.5 Hash algorithm agility
This version of the specification supports SHA-256 only.
The algorithm field in .peipkg/files.json and the hash
identifier in the repository index reserve syntactic space
for future algorithms. A future version of this
specification MAY introduce additional algorithms; consumers
of v0.22 MUST reject any algorithm value other than
sha256.
§3.5.6 Tampering and partial trust
The two-level integrity model defends against different threats:
- The package hash plus signature defends against malicious substitution of the package as a whole.
- The per-file integrity manifest defends against corruption or tampering during extraction, after the signature has been verified.
A consumer MUST verify both levels. Verifying only the package signature without checking per-file hashes leaves extraction errors and on-disk corruption undetectable; verifying only per-file hashes without checking the signature leaves the manifest itself untrusted.