Files
bee/audit/internal/updater/trust.go
Michael Chus a4f70b17f0 feat(audit): 1.1 — project scaffold, schema types, collector stub, updater trust
- go.mod: module bee/audit
- schema/hardware.go: HardwareIngestRequest types (compatible with core)
- collector/collector.go: Run() stub, logs start/finish, returns empty snapshot
- updater/trust.go: Ed25519 multi-key verification via ldflags injection
- updater/trust_test.go: valid sig, tampered, multi-key any-match, dev build
- cmd/audit/main.go: --output stdout|file:<path>|usb, --version flag
- Version = "dev" by default, injected via ldflags at release

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 10:32:12 +03:00

60 lines
1.8 KiB
Go

// Package updater handles binary self-update with Ed25519 signature verification.
// See bible/rules/patterns/release-signing/contract.md for the full contract.
package updater
import (
"crypto/ed25519"
"encoding/base64"
"fmt"
"strings"
)
// trustedKeysRaw is injected at release build time via:
//
// -ldflags "-X bee/audit/internal/updater.trustedKeysRaw=base64key1:base64key2"
//
// Empty in dev builds — updates are disabled when empty.
var trustedKeysRaw string
// TrustedKeys decodes the embedded public keys.
// Returns an error if the binary was built without key injection (dev build).
func TrustedKeys() ([]ed25519.PublicKey, error) {
if strings.TrimSpace(trustedKeysRaw) == "" {
return nil, fmt.Errorf("dev build: trusted keys not embedded, updates disabled")
}
var keys []ed25519.PublicKey
for _, enc := range strings.Split(trustedKeysRaw, ":") {
enc = strings.TrimSpace(enc)
if enc == "" {
continue
}
b, err := base64.StdEncoding.DecodeString(enc)
if err != nil {
return nil, fmt.Errorf("decode trusted key: %w", err)
}
if len(b) != ed25519.PublicKeySize {
return nil, fmt.Errorf("trusted key has wrong size: got %d, want %d", len(b), ed25519.PublicKeySize)
}
keys = append(keys, ed25519.PublicKey(b))
}
if len(keys) == 0 {
return nil, fmt.Errorf("no valid trusted keys found in build")
}
return keys, nil
}
// VerifySignature returns nil if sig was produced by any trusted key over data.
// Returns an error (never panics) on any failure — caller logs and continues.
func VerifySignature(data, sig []byte) error {
keys, err := TrustedKeys()
if err != nil {
return err
}
for _, key := range keys {
if ed25519.Verify(key, data, sig) {
return nil
}
}
return fmt.Errorf("signature verification failed: no trusted key matched")
}