Documentation
¶
Overview ¶
Package ziputil validates and safely reads ZIP archives used by evidence packs. Invariants: entry paths are validated, zip-bomb ratios are bounded, and unsafe collisions are rejected.
Index ¶
- Constants
- func CheckCompressionRatio(archive *zip.Reader, maxRatio int) error
- func IsAppleDoubleFile(path string) bool
- func ValidateDirectoryEntry(f *zip.File) error
- func ValidateNotAppleDouble(path string) error
- func ValidateNotDeviceFile(f *zip.File) error
- func ValidateNotSymlink(f *zip.File) error
- func ValidatePath(name string) error
- func WindowsCanonicalPath(path string) string
- type SafeReader
- type SafeReaderOption
Constants ¶
const ( // Path validation constants per spec Section 2.3. MaxPathLength = 240 // Maximum total path length in bytes MaxSegmentLength = 80 // Maximum segment length in bytes (accommodates attestation filenames) // DefaultMaxCompressionRatio is the default maximum compression ratio allowed. // A ratio of 100 means the uncompressed size can be at most 100x the compressed size. // This helps prevent zip bomb attacks. DefaultMaxCompressionRatio = 100 )
Variables ¶
This section is empty.
Functions ¶
func CheckCompressionRatio ¶
CheckCompressionRatio rejects archives containing entries whose uncompressed-to-compressed ratio exceeds maxRatio. If maxRatio <= 0, DefaultMaxCompressionRatio is used.
func IsAppleDoubleFile ¶
IsAppleDoubleFile checks if a path is an AppleDouble metadata file. Per spec Section 7.3 (R-101), these SHOULD be rejected: - Files under __MACOSX/ directory (resource fork storage) - Files starting with ._ (AppleDouble sidecar files)
func ValidateDirectoryEntry ¶
ValidateDirectoryEntry checks that a ZIP entry's attributes are consistent with its path. Per spec Section 2.3 (R-321 through R-323, R-347): - A trailing "/" in the path indicates a directory entry - Directory entries MUST have size 0 - ZIP mode bits indicating directory MUST match path ending with "/" - ZIP mode bits indicating file MUST NOT have path ending with "/"
func ValidateNotAppleDouble ¶
ValidateNotAppleDouble rejects AppleDouble metadata files. Per spec Section 7.3 (R-101), these SHOULD be rejected as they: - Contain macOS-specific metadata not relevant to evidence packs - May contain unexpected executable content - Cause confusion when packs are created on macOS and consumed elsewhere
func ValidateNotDeviceFile ¶
ValidateNotDeviceFile checks that a ZIP entry is not a device file. Device files in ZIP archives are a security risk.
func ValidateNotSymlink ¶
ValidateNotSymlink checks that a ZIP entry is not a symlink. Symlinks in ZIP archives are a security risk as they can escape the extraction directory.
func ValidatePath ¶
ValidatePath checks that a zip entry path is safe per spec Section 2.3. It rejects: - Empty paths - Control characters - Backslashes (must use forward slashes only) - Trailing slashes (files must not end with /) - Empty segments (consecutive slashes like //) - Path traversal (. and .. segments) - Absolute paths (leading / or Windows drive letters) - Windows reserved characters (colons) - Windows reserved names (CON, PRN, etc. without extensions) - UNC paths (//server/share) - Non-NFC Unicode (path must equal its NFC normalization) - Paths exceeding length limits
func WindowsCanonicalPath ¶
WindowsCanonicalPath returns the Windows-canonical form of a path for collision detection. On Windows, paths are case-insensitive and certain characters are stripped: - Trailing dots are stripped from each segment - Trailing spaces are stripped from each segment - Case is normalized to lowercase
Two paths that produce the same canonical form will collide on Windows. Use for duplicate detection in manifests.
Types ¶
type SafeReader ¶
SafeReader wraps a zip.Reader with pre-validated security checks. All entries are validated at construction time, ensuring that iteration over the reader's files is safe.
SECURITY: SafeReader provides defense-in-depth by validating: - Compression ratio limits (zip bomb prevention) - Path safety (traversal, reserved names, encoding) - Entry count limits (DoS prevention) - Windows path collision detection
Use NewSafeReader to create validated instances. Direct construction bypasses validation and should be avoided.
func NewSafeReader ¶
func NewSafeReader(r io.ReaderAt, size int64, opts ...SafeReaderOption) (*SafeReader, error)
NewSafeReader creates a SafeReader from an io.ReaderAt with comprehensive validation. Returns an error if any security check fails: - Entry count exceeds limits - Compression ratio exceeds limits (zip bomb detection) - Any path fails validation (traversal, encoding, reserved names) - Windows path collisions detected
Once created, iteration over r.File is guaranteed safe.
func NewSafeReaderFromZip ¶
func NewSafeReaderFromZip(zr *zip.Reader, opts ...SafeReaderOption) (*SafeReader, error)
NewSafeReaderFromZip wraps an existing zip.Reader with validation. Use this when you already have a zip.Reader (e.g., from zip.OpenReader).
func (*SafeReader) FileNames ¶
func (sr *SafeReader) FileNames() []string
FileNames returns a list of all file names in the archive (excluding directories).
func (*SafeReader) IsValidated ¶
func (sr *SafeReader) IsValidated() bool
IsValidated returns true if the reader passed all security checks. This should always be true for readers created via NewSafeReader.
func (*SafeReader) OpenFile ¶
func (sr *SafeReader) OpenFile(name string) (io.ReadCloser, error)
OpenFile opens a file from the archive by name. Returns an error if the file is not found.
type SafeReaderOption ¶
type SafeReaderOption func(*safeReaderConfig)
SafeReaderOption configures SafeReader behavior.
func WithMaxCompressionRatio ¶
func WithMaxCompressionRatio(ratio int) SafeReaderOption
WithMaxCompressionRatio sets a custom maximum compression ratio. Default is limits.MaxCompressionRatio (100:1).
func WithMaxEntries ¶
func WithMaxEntries(max int) SafeReaderOption
WithMaxEntries sets a custom maximum entry count. Default is limits.MaxZipEntries.
func WithSkipCollisionCheck ¶
func WithSkipCollisionCheck() SafeReaderOption
WithSkipCollisionCheck disables Windows path collision checking. Only use this for archives known to be safe or in test scenarios.