mirror of
https://github.com/sonr-io/crypto.git
synced 2026-08-02 15:31:38 +00:00
No commit suggestions generated
This commit is contained in:
@@ -0,0 +1,224 @@
|
||||
// Package wasm provides cryptographic verification for WebAssembly modules
|
||||
package wasm
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// HashVerifier provides SHA256 hash verification for WASM modules
|
||||
type HashVerifier struct {
|
||||
// trustedHashes stores SHA256 hashes of trusted WASM modules
|
||||
trustedHashes map[string]string
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
// NewHashVerifier creates a new WASM hash verifier
|
||||
func NewHashVerifier() *HashVerifier {
|
||||
return &HashVerifier{
|
||||
trustedHashes: make(map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
// ComputeHash calculates SHA256 hash of WASM bytecode
|
||||
func (v *HashVerifier) ComputeHash(wasmBytes []byte) string {
|
||||
hash := sha256.Sum256(wasmBytes)
|
||||
return hex.EncodeToString(hash[:])
|
||||
}
|
||||
|
||||
// AddTrustedHash adds a trusted hash for a named WASM module
|
||||
func (v *HashVerifier) AddTrustedHash(name, hash string) {
|
||||
v.mu.Lock()
|
||||
defer v.mu.Unlock()
|
||||
v.trustedHashes[name] = hash
|
||||
}
|
||||
|
||||
// VerifyHash verifies WASM bytecode against trusted hash
|
||||
func (v *HashVerifier) VerifyHash(name string, wasmBytes []byte) error {
|
||||
v.mu.RLock()
|
||||
trustedHash, exists := v.trustedHashes[name]
|
||||
v.mu.RUnlock()
|
||||
|
||||
if !exists {
|
||||
return fmt.Errorf("no trusted hash found for WASM module: %s", name)
|
||||
}
|
||||
|
||||
computedHash := v.ComputeHash(wasmBytes)
|
||||
if computedHash != trustedHash {
|
||||
return fmt.Errorf(
|
||||
"WASM hash verification failed for %s: expected %s, got %s",
|
||||
name, trustedHash, computedHash,
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// VerifyHashWithFallback verifies against primary hash or fallback list
|
||||
func (v *HashVerifier) VerifyHashWithFallback(name string, wasmBytes []byte, fallbackHashes []string) error {
|
||||
// Try primary verification first
|
||||
if err := v.VerifyHash(name, wasmBytes); err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check against fallback hashes
|
||||
computedHash := v.ComputeHash(wasmBytes)
|
||||
for _, fallbackHash := range fallbackHashes {
|
||||
if computedHash == fallbackHash {
|
||||
// Update trusted hash for future use
|
||||
v.AddTrustedHash(name, computedHash)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf(
|
||||
"WASM hash verification failed: computed hash %s not in trusted set",
|
||||
computedHash,
|
||||
)
|
||||
}
|
||||
|
||||
// GetTrustedHash retrieves the trusted hash for a module
|
||||
func (v *HashVerifier) GetTrustedHash(name string) (string, bool) {
|
||||
v.mu.RLock()
|
||||
defer v.mu.RUnlock()
|
||||
hash, exists := v.trustedHashes[name]
|
||||
return hash, exists
|
||||
}
|
||||
|
||||
// ClearTrustedHashes removes all trusted hashes
|
||||
func (v *HashVerifier) ClearTrustedHashes() {
|
||||
v.mu.Lock()
|
||||
defer v.mu.Unlock()
|
||||
v.trustedHashes = make(map[string]string)
|
||||
}
|
||||
|
||||
// HashChain provides hash chain verification for plugin updates
|
||||
type HashChain struct {
|
||||
chain []HashEntry
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
// HashEntry represents a single entry in the hash chain
|
||||
type HashEntry struct {
|
||||
Version string `json:"version"`
|
||||
Hash string `json:"hash"`
|
||||
PreviousHash string `json:"previous_hash"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
}
|
||||
|
||||
// NewHashChain creates a new hash chain
|
||||
func NewHashChain() *HashChain {
|
||||
return &HashChain{
|
||||
chain: make([]HashEntry, 0),
|
||||
}
|
||||
}
|
||||
|
||||
// AddEntry adds a new entry to the hash chain
|
||||
func (hc *HashChain) AddEntry(version, hash string, timestamp int64) error {
|
||||
hc.mu.Lock()
|
||||
defer hc.mu.Unlock()
|
||||
|
||||
previousHash := ""
|
||||
if len(hc.chain) > 0 {
|
||||
previousHash = hc.chain[len(hc.chain)-1].Hash
|
||||
}
|
||||
|
||||
entry := HashEntry{
|
||||
Version: version,
|
||||
Hash: hash,
|
||||
PreviousHash: previousHash,
|
||||
Timestamp: timestamp,
|
||||
}
|
||||
|
||||
hc.chain = append(hc.chain, entry)
|
||||
return nil
|
||||
}
|
||||
|
||||
// VerifyChain verifies the integrity of the hash chain
|
||||
func (hc *HashChain) VerifyChain() error {
|
||||
hc.mu.RLock()
|
||||
defer hc.mu.RUnlock()
|
||||
|
||||
if len(hc.chain) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// First entry should have empty previous hash
|
||||
if hc.chain[0].PreviousHash != "" {
|
||||
return fmt.Errorf("invalid hash chain: first entry has non-empty previous hash")
|
||||
}
|
||||
|
||||
// Verify chain continuity
|
||||
for i := 1; i < len(hc.chain); i++ {
|
||||
if hc.chain[i].PreviousHash != hc.chain[i-1].Hash {
|
||||
return fmt.Errorf(
|
||||
"hash chain broken at version %s: expected previous hash %s, got %s",
|
||||
hc.chain[i].Version,
|
||||
hc.chain[i-1].Hash,
|
||||
hc.chain[i].PreviousHash,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetLatestEntry returns the most recent hash chain entry
|
||||
func (hc *HashChain) GetLatestEntry() (*HashEntry, error) {
|
||||
hc.mu.RLock()
|
||||
defer hc.mu.RUnlock()
|
||||
|
||||
if len(hc.chain) == 0 {
|
||||
return nil, fmt.Errorf("hash chain is empty")
|
||||
}
|
||||
|
||||
latest := hc.chain[len(hc.chain)-1]
|
||||
return &latest, nil
|
||||
}
|
||||
|
||||
// VerificationError represents a WASM verification failure
|
||||
type VerificationError struct {
|
||||
Module string
|
||||
ExpectedHash string
|
||||
ActualHash string
|
||||
Reason string
|
||||
}
|
||||
|
||||
// Error implements the error interface
|
||||
func (e *VerificationError) Error() string {
|
||||
return fmt.Sprintf(
|
||||
"WASM verification failed for %s: %s (expected: %s, actual: %s)",
|
||||
e.Module, e.Reason, e.ExpectedHash, e.ActualHash,
|
||||
)
|
||||
}
|
||||
|
||||
// SecurityPolicy defines verification requirements
|
||||
type SecurityPolicy struct {
|
||||
RequireHashVerification bool
|
||||
RequireSignature bool
|
||||
AllowedHashes []string
|
||||
MaxModuleSize int64
|
||||
}
|
||||
|
||||
// DefaultSecurityPolicy returns a secure default policy
|
||||
func DefaultSecurityPolicy() *SecurityPolicy {
|
||||
return &SecurityPolicy{
|
||||
RequireHashVerification: true,
|
||||
RequireSignature: false, // Will be enabled in next phase
|
||||
AllowedHashes: []string{},
|
||||
MaxModuleSize: 10 * 1024 * 1024, // 10MB max
|
||||
}
|
||||
}
|
||||
|
||||
// Validate checks if WASM module meets security policy
|
||||
func (p *SecurityPolicy) Validate(wasmBytes []byte) error {
|
||||
if p.MaxModuleSize > 0 && int64(len(wasmBytes)) > p.MaxModuleSize {
|
||||
return fmt.Errorf(
|
||||
"WASM module size %d exceeds maximum allowed size %d",
|
||||
len(wasmBytes), p.MaxModuleSize,
|
||||
)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user