Add UUID to manifest and verify integrity before decompression
- Add UUID field to both inner and outer manifest messages - Generate random v4 UUID when creating manifest - Hash compressed data (not uncompressed) for integrity check - Verify hash before decompression to prevent malicious payloads - Validate UUIDs are proper format and match between inner/outer - Sign string format: MAGIC-UUID-MULTIHASH
This commit is contained in:
@@ -2,9 +2,11 @@ package mfer
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/klauspost/compress/zstd"
|
||||
"github.com/spf13/afero"
|
||||
"google.golang.org/protobuf/proto"
|
||||
@@ -12,6 +14,19 @@ import (
|
||||
"sneak.berlin/go/mfer/internal/log"
|
||||
)
|
||||
|
||||
// validateUUID checks that the byte slice is a valid UUID (16 bytes, parseable).
|
||||
func validateUUID(data []byte) error {
|
||||
if len(data) != 16 {
|
||||
return errors.New("invalid UUID length")
|
||||
}
|
||||
// Try to parse as UUID to validate format
|
||||
_, err := uuid.FromBytes(data)
|
||||
if err != nil {
|
||||
return errors.New("invalid UUID format")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *manifest) deserializeInner() error {
|
||||
if m.pbOuter.Version != MFFileOuter_VERSION_ONE {
|
||||
return errors.New("unknown version")
|
||||
@@ -20,6 +35,20 @@ func (m *manifest) deserializeInner() error {
|
||||
return errors.New("unknown compression type")
|
||||
}
|
||||
|
||||
// Validate outer UUID before any decompression
|
||||
if err := validateUUID(m.pbOuter.Uuid); err != nil {
|
||||
return errors.New("outer UUID invalid: " + err.Error())
|
||||
}
|
||||
|
||||
// Verify hash of compressed data before decompression
|
||||
h := sha256.New()
|
||||
if _, err := h.Write(m.pbOuter.InnerMessage); err != nil {
|
||||
return err
|
||||
}
|
||||
if !bytes.Equal(h.Sum(nil), m.pbOuter.Sha256) {
|
||||
return errors.New("compressed data hash mismatch")
|
||||
}
|
||||
|
||||
bb := bytes.NewBuffer(m.pbOuter.InnerMessage)
|
||||
|
||||
zr, err := zstd.NewReader(bb)
|
||||
@@ -45,6 +74,16 @@ func (m *manifest) deserializeInner() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Validate inner UUID
|
||||
if err := validateUUID(m.pbInner.Uuid); err != nil {
|
||||
return errors.New("inner UUID invalid: " + err.Error())
|
||||
}
|
||||
|
||||
// Verify UUIDs match
|
||||
if !bytes.Equal(m.pbOuter.Uuid, m.pbInner.Uuid) {
|
||||
return errors.New("outer and inner UUID mismatch")
|
||||
}
|
||||
|
||||
log.Infof("loaded manifest with %d files", len(m.pbInner.Files))
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user