Files
crypto/wasm/signer_test.go

362 lines
9.5 KiB
Go
Raw Normal View History

2025-10-09 15:10:39 -04:00
package wasm
import (
"crypto/ed25519"
"crypto/rand"
"encoding/base64"
"encoding/hex"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestSigner_NewSigner(t *testing.T) {
signer, err := NewSigner()
require.NoError(t, err)
require.NotNil(t, signer)
assert.NotNil(t, signer.privateKey)
assert.NotNil(t, signer.publicKey)
assert.Equal(t, ed25519.PrivateKeySize, len(signer.privateKey))
assert.Equal(t, ed25519.PublicKeySize, len(signer.publicKey))
}
func TestSigner_NewSignerFromPrivateKey(t *testing.T) {
// Generate a key pair
pub, priv, err := ed25519.GenerateKey(rand.Reader)
require.NoError(t, err)
// Create signer from private key
signer, err := NewSignerFromPrivateKey(priv)
require.NoError(t, err)
assert.Equal(t, priv, signer.privateKey)
assert.Equal(t, pub, signer.publicKey)
// Test invalid key size
invalidKey := []byte("too short")
_, err = NewSignerFromPrivateKey(ed25519.PrivateKey(invalidKey))
assert.Error(t, err)
assert.Contains(t, err.Error(), "invalid private key size")
}
func TestSigner_Sign(t *testing.T) {
signer, err := NewSigner()
require.NoError(t, err)
// Test data
wasmBytes := []byte("test wasm module content")
// Sign the data
signature, err := signer.Sign(wasmBytes)
require.NoError(t, err)
assert.Equal(t, ed25519.SignatureSize, len(signature))
// Verify the signature
valid := ed25519.Verify(signer.publicKey, wasmBytes, signature)
assert.True(t, valid)
// Test signing different data produces different signature
differentData := []byte("different content")
signature2, err := signer.Sign(differentData)
require.NoError(t, err)
assert.NotEqual(t, signature, signature2)
}
func TestSignatureVerifier_AddTrustedKey(t *testing.T) {
verifier := NewSignatureVerifier()
// Generate a key pair
pub, _, err := ed25519.GenerateKey(rand.Reader)
require.NoError(t, err)
// Add trusted key
err = verifier.AddTrustedKey("test-key", pub)
assert.NoError(t, err)
// Test invalid key size
invalidKey := []byte("invalid")
err = verifier.AddTrustedKey("invalid-key", ed25519.PublicKey(invalidKey))
assert.Error(t, err)
assert.Contains(t, err.Error(), "invalid public key size")
}
func TestSignatureVerifier_AddTrustedKeyFromHex(t *testing.T) {
verifier := NewSignatureVerifier()
// Generate a key pair
pub, _, err := ed25519.GenerateKey(rand.Reader)
require.NoError(t, err)
// Add key from hex
hexKey := hex.EncodeToString(pub)
err = verifier.AddTrustedKeyFromHex("hex-key", hexKey)
assert.NoError(t, err)
// Test invalid hex
err = verifier.AddTrustedKeyFromHex("bad-hex", "not-hex")
assert.Error(t, err)
}
func TestSignatureVerifier_Verify(t *testing.T) {
// Create signer and verifier
signer, err := NewSigner()
require.NoError(t, err)
verifier := NewSignatureVerifier()
// Test data
wasmBytes := []byte("test wasm module")
// Sign the data
signature, err := signer.Sign(wasmBytes)
require.NoError(t, err)
// Test verification without trusted keys
err = verifier.Verify(wasmBytes, signature)
assert.Error(t, err)
assert.Contains(t, err.Error(), "no trusted keys")
// Add trusted key
err = verifier.AddTrustedKey("signer1", signer.publicKey)
require.NoError(t, err)
// Test successful verification
err = verifier.Verify(wasmBytes, signature)
assert.NoError(t, err)
// Test verification with wrong data
wrongData := []byte("wrong data")
err = verifier.Verify(wrongData, signature)
assert.Error(t, err)
assert.Contains(t, err.Error(), "signature verification failed")
// Test verification with wrong signature
wrongSignature := make([]byte, ed25519.SignatureSize)
err = verifier.Verify(wasmBytes, wrongSignature)
assert.Error(t, err)
}
func TestSignatureVerifier_VerifyWithKey(t *testing.T) {
signer1, err := NewSigner()
require.NoError(t, err)
signer2, err := NewSigner()
require.NoError(t, err)
verifier := NewSignatureVerifier()
verifier.AddTrustedKey("key1", signer1.publicKey)
verifier.AddTrustedKey("key2", signer2.publicKey)
wasmBytes := []byte("test module")
signature1, _ := signer1.Sign(wasmBytes)
signature2, _ := signer2.Sign(wasmBytes)
// Verify with correct key
err = verifier.VerifyWithKey("key1", wasmBytes, signature1)
assert.NoError(t, err)
err = verifier.VerifyWithKey("key2", wasmBytes, signature2)
assert.NoError(t, err)
// Verify with wrong key
err = verifier.VerifyWithKey("key1", wasmBytes, signature2)
assert.Error(t, err)
// Verify with non-existent key
err = verifier.VerifyWithKey("key3", wasmBytes, signature1)
assert.Error(t, err)
assert.Contains(t, err.Error(), "trusted key not found")
}
func TestSignatureVerifier_Management(t *testing.T) {
verifier := NewSignatureVerifier()
// Generate keys
pub1, _, _ := ed25519.GenerateKey(rand.Reader)
pub2, _, _ := ed25519.GenerateKey(rand.Reader)
// Add keys
verifier.AddTrustedKey("key1", pub1)
verifier.AddTrustedKey("key2", pub2)
// Get key IDs
ids := verifier.GetTrustedKeyIDs()
assert.Len(t, ids, 2)
assert.Contains(t, ids, "key1")
assert.Contains(t, ids, "key2")
// Remove key
verifier.RemoveTrustedKey("key1")
ids = verifier.GetTrustedKeyIDs()
assert.Len(t, ids, 1)
assert.NotContains(t, ids, "key1")
assert.Contains(t, ids, "key2")
}
func TestSignedModule(t *testing.T) {
signer, err := NewSigner()
require.NoError(t, err)
module := []byte("test wasm module")
signerID := "test-signer"
version := "v1.0.0"
// Create signed module
signed, err := SignModule(signer, module, signerID, version)
require.NoError(t, err)
assert.Equal(t, module, signed.Module)
assert.NotEmpty(t, signed.Hash)
assert.NotEmpty(t, signed.Signature)
assert.Equal(t, signerID, signed.SignerID)
assert.Equal(t, version, signed.Version)
assert.False(t, signed.Timestamp.IsZero())
// Verify signed module
verifier := NewSignatureVerifier()
verifier.AddTrustedKey(signerID, signer.publicKey)
err = VerifySignedModule(verifier, signed)
assert.NoError(t, err)
// Test with tampered module
signed.Module = []byte("tampered")
err = VerifySignedModule(verifier, signed)
assert.Error(t, err)
assert.Contains(t, err.Error(), "hash mismatch")
}
func TestSignatureManifest(t *testing.T) {
signer, err := NewSigner()
require.NoError(t, err)
module := []byte("test wasm module")
signerID := "manifest-signer"
// Create manifest
manifest, err := CreateSignatureManifest(module, signer, signerID)
require.NoError(t, err)
assert.NotEmpty(t, manifest.ModuleHash)
assert.Len(t, manifest.Signatures, 1)
assert.Len(t, manifest.TrustedKeys, 1)
assert.Equal(t, signerID, manifest.Signatures[0].SignerID)
assert.Equal(t, "Ed25519", manifest.Signatures[0].Algorithm)
assert.Equal(t, signerID, manifest.TrustedKeys[0].KeyID)
assert.Equal(t, "code-signing", manifest.TrustedKeys[0].Purpose)
// Verify with manifest
err = VerifyWithManifest(module, manifest)
assert.NoError(t, err)
// Test with wrong module
wrongModule := []byte("wrong module")
err = VerifyWithManifest(wrongModule, manifest)
assert.Error(t, err)
assert.Contains(t, err.Error(), "hash mismatch")
// Test with expired manifest
expired := time.Now().Add(-1 * time.Hour)
manifest.ExpiresAt = &expired
err = VerifyWithManifest(module, manifest)
assert.Error(t, err)
assert.Contains(t, err.Error(), "expired")
}
func TestManifestSerialization(t *testing.T) {
signer, err := NewSigner()
require.NoError(t, err)
module := []byte("test module")
manifest, err := CreateSignatureManifest(module, signer, "test-key")
require.NoError(t, err)
// Export manifest
data, err := ExportManifest(manifest)
require.NoError(t, err)
assert.NotEmpty(t, data)
// Import manifest
imported, err := ImportManifest(data)
require.NoError(t, err)
assert.Equal(t, manifest.ModuleHash, imported.ModuleHash)
assert.Len(t, imported.Signatures, 1)
assert.Len(t, imported.TrustedKeys, 1)
// Verify imported manifest
err = VerifyWithManifest(module, imported)
assert.NoError(t, err)
// Test invalid JSON
_, err = ImportManifest([]byte("invalid json"))
assert.Error(t, err)
}
func TestMultipleSignatures(t *testing.T) {
// Create multiple signers
signer1, _ := NewSigner()
signer2, _ := NewSigner()
module := []byte("multi-signed module")
// Create manifest with first signature
manifest, err := CreateSignatureManifest(module, signer1, "signer1")
require.NoError(t, err)
// Add second signature
signature2, _ := signer2.Sign(module)
manifest.Signatures = append(manifest.Signatures, SignatureEntry{
Signature: base64.StdEncoding.EncodeToString(signature2),
SignerID: "signer2",
Timestamp: time.Now(),
Algorithm: "Ed25519",
})
manifest.TrustedKeys = append(manifest.TrustedKeys, TrustedKeyEntry{
KeyID: "signer2",
PublicKey: base64.StdEncoding.EncodeToString(signer2.GetPublicKey()),
AddedAt: time.Now(),
Purpose: "code-signing",
})
// Verify with either signature
err = VerifyWithManifest(module, manifest)
assert.NoError(t, err)
// Remove first signature and key
manifest.Signatures = manifest.Signatures[1:]
manifest.TrustedKeys = manifest.TrustedKeys[1:]
// Should still verify with second signature
err = VerifyWithManifest(module, manifest)
assert.NoError(t, err)
}
func BenchmarkSign(b *testing.B) {
signer, _ := NewSigner()
data := make([]byte, 1024*1024) // 1MB
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = signer.Sign(data)
}
}
func BenchmarkVerify(b *testing.B) {
signer, _ := NewSigner()
verifier := NewSignatureVerifier()
verifier.AddTrustedKey("bench", signer.publicKey)
data := make([]byte, 1024*1024) // 1MB
signature, _ := signer.Sign(data)
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = verifier.Verify(data, signature)
}
}