284 lines
9.4 KiB
Nim
284 lines
9.4 KiB
Nim
import std/[unittest, times, base64, json, os, tempfiles, strutils, options]
|
|
import ../src/nimpak/security/signature_verifier
|
|
|
|
suite "Signature Algorithm Detection":
|
|
test "detect Ed25519 signature formats":
|
|
check detectSignatureAlgorithm("ed25519-abc123") == SigEd25519
|
|
check detectSignatureAlgorithm("a".repeat(128)) == SigEd25519 # 128 hex chars
|
|
|
|
test "detect Dilithium signature formats":
|
|
expect ValueError:
|
|
discard detectSignatureAlgorithm("dilithium-abc123") # Not implemented yet
|
|
|
|
test "invalid signature formats":
|
|
expect ValueError:
|
|
discard detectSignatureAlgorithm("invalid-sig")
|
|
expect ValueError:
|
|
discard detectSignatureAlgorithm("abc") # Too short
|
|
|
|
suite "Signature String Parsing":
|
|
test "parse Ed25519 signature strings":
|
|
let (alg1, sig1) = parseSignatureString("ed25519-abc123def456")
|
|
check alg1 == SigEd25519
|
|
check sig1 == "abc123def456"
|
|
|
|
let (alg2, sig2) = parseSignatureString("a".repeat(128))
|
|
check alg2 == SigEd25519
|
|
check sig2 == "a".repeat(128)
|
|
|
|
test "format signature strings":
|
|
check formatSignatureString(SigEd25519, "abc123") == "ed25519-abc123"
|
|
check formatSignatureString(SigDilithium, "def456") == "dilithium-def456"
|
|
check formatSignatureString(SigRSA, "789abc") == "rsa-789abc"
|
|
|
|
suite "Ed25519 Signature Verification":
|
|
# Test vectors for Ed25519 (RFC 8032)
|
|
const ED25519_TEST_VECTORS = [
|
|
(
|
|
message: "",
|
|
publicKey: "11qYAYKxCrfVS/7TyWQHOg7hcvPapiMlrwIaaPcHURo=",
|
|
signature: "hgyY0il+MGCjP0JzlnkSPjt9HQjyOh1XBL2QX5AjXtYzOjIh2+3IfGG07fAuNqq41PvvRMzFRuV+DqbpBRlHBg==",
|
|
valid: true
|
|
),
|
|
(
|
|
message: "test message",
|
|
publicKey: "11qYAYKxCrfVS/7TyWQHOg7hcvPapiMlrwIaaPcHURo=",
|
|
signature: "invalid-signature-data",
|
|
valid: false
|
|
)
|
|
]
|
|
|
|
test "Ed25519 signature verification with test vectors":
|
|
for vector in ED25519_TEST_VECTORS:
|
|
let result = verifyEd25519Signature(vector.message, vector.signature, vector.publicKey)
|
|
if vector.valid:
|
|
check result == true
|
|
else:
|
|
check result == false
|
|
|
|
test "Ed25519 signature with invalid inputs":
|
|
# Invalid signature length
|
|
check verifyEd25519Signature("test", "short", "validkey") == false
|
|
|
|
# Invalid public key length
|
|
check verifyEd25519Signature("test", "valid-sig", "short") == false
|
|
|
|
# Invalid base64
|
|
check verifyEd25519Signature("test", "invalid-base64!", "invalid-base64!") == false
|
|
|
|
suite "Signature Verifier":
|
|
test "create signature verifier":
|
|
let verifier = newSignatureVerifier()
|
|
check verifier.trustedKeys.len == 0
|
|
check verifier.requireValidTimestamp == true
|
|
check SigEd25519 in verifier.allowedAlgorithms
|
|
|
|
test "add trusted key":
|
|
var verifier = newSignatureVerifier()
|
|
let key = createPublicKey(
|
|
SigEd25519,
|
|
"test-key-1",
|
|
"test-key-data",
|
|
now().utc() - initDuration(days = 1),
|
|
now().utc() + initDuration(days = 365)
|
|
)
|
|
|
|
verifier.addTrustedKey(key)
|
|
check verifier.trustedKeys.len == 1
|
|
check verifier.trustedKeys[0].keyId == "test-key-1"
|
|
|
|
test "find trusted key":
|
|
var verifier = newSignatureVerifier()
|
|
let key = createPublicKey(
|
|
SigEd25519,
|
|
"findable-key",
|
|
"test-key-data",
|
|
now().utc() - initDuration(days = 1),
|
|
now().utc() + initDuration(days = 365)
|
|
)
|
|
|
|
verifier.addTrustedKey(key)
|
|
|
|
let foundKey = verifier.findTrustedKey("findable-key")
|
|
check foundKey.isSome()
|
|
check foundKey.get().keyId == "findable-key"
|
|
|
|
let notFoundKey = verifier.findTrustedKey("nonexistent-key")
|
|
check notFoundKey.isNone()
|
|
|
|
suite "Key Validation":
|
|
test "key validity checks":
|
|
let now = times.now().utc()
|
|
|
|
# Valid key
|
|
let validKey = createPublicKey(
|
|
SigEd25519,
|
|
"valid-key",
|
|
"key-data",
|
|
now - initDuration(days = 1),
|
|
now + initDuration(days = 365)
|
|
)
|
|
check isKeyValid(validKey, now) == true
|
|
|
|
# Expired key
|
|
let expiredKey = createPublicKey(
|
|
SigEd25519,
|
|
"expired-key",
|
|
"key-data",
|
|
now - initDuration(days = 365),
|
|
now - initDuration(days = 1)
|
|
)
|
|
check isKeyValid(expiredKey, now) == false
|
|
|
|
# Not yet valid key
|
|
let futureKey = createPublicKey(
|
|
SigEd25519,
|
|
"future-key",
|
|
"key-data",
|
|
now + initDuration(days = 1),
|
|
now + initDuration(days = 365)
|
|
)
|
|
check isKeyValid(futureKey, now) == false
|
|
|
|
# Revoked key
|
|
var revokedKey = validKey
|
|
revokedKey.revoked = true
|
|
check isKeyValid(revokedKey, now) == false
|
|
|
|
suite "Digital Signature Objects":
|
|
test "create digital signature":
|
|
let timestamp = now().utc()
|
|
let sig = createDigitalSignature(SigEd25519, "test-key", "signature-data", timestamp)
|
|
|
|
check sig.algorithm == SigEd25519
|
|
check sig.keyId == "test-key"
|
|
check sig.signature == "signature-data"
|
|
check sig.timestamp == timestamp
|
|
|
|
test "create public key":
|
|
let validFrom = now().utc()
|
|
let validUntil = validFrom + initDuration(days = 365)
|
|
let key = createPublicKey(SigEd25519, "test-key", "key-data", validFrom, validUntil)
|
|
|
|
check key.algorithm == SigEd25519
|
|
check key.keyId == "test-key"
|
|
check key.keyData == "key-data"
|
|
check key.validFrom == validFrom
|
|
check key.validUntil == validUntil
|
|
check key.revoked == false
|
|
|
|
test "signature validation":
|
|
let validSig = createDigitalSignature(SigEd25519, "key-1", "sig-data")
|
|
check isSignatureValid(validSig) == true
|
|
|
|
let invalidSig = createDigitalSignature(SigEd25519, "", "sig-data")
|
|
check isSignatureValid(invalidSig) == false
|
|
|
|
let invalidSig2 = createDigitalSignature(SigEd25519, "key-1", "")
|
|
check isSignatureValid(invalidSig2) == false
|
|
|
|
suite "Signature Policy":
|
|
test "create signature policy":
|
|
let policy = newSignaturePolicy()
|
|
check policy.requireSignatures == true
|
|
check SigEd25519 in policy.allowedAlgorithms
|
|
check policy.minimumKeySize == 256
|
|
check policy.maxSignatureAge == 86400
|
|
check policy.requireTimestamp == true
|
|
check policy.allowSelfSigned == false
|
|
|
|
test "validate signature against policy":
|
|
let policy = newSignaturePolicy()
|
|
|
|
# Valid signature
|
|
let validSig = createDigitalSignature(SigEd25519, "key-1", "sig-data", now().utc())
|
|
check validateSignaturePolicy(validSig, policy) == true
|
|
|
|
# Invalid algorithm
|
|
let invalidAlgSig = createDigitalSignature(SigRSA, "key-1", "sig-data", now().utc())
|
|
check validateSignaturePolicy(invalidAlgSig, policy) == false
|
|
|
|
# Too old signature
|
|
let oldSig = createDigitalSignature(SigEd25519, "key-1", "sig-data",
|
|
now().utc() - initDuration(days = 2))
|
|
check validateSignaturePolicy(oldSig, policy) == false
|
|
|
|
suite "File Signature Verification":
|
|
test "verify file signature":
|
|
# Create a temporary file
|
|
let (tempFile, tempPath) = createTempFile("nimpak_sig_test_", ".txt")
|
|
tempFile.write("Test file content for signature verification")
|
|
tempFile.close()
|
|
|
|
try:
|
|
# This test would require actual Ed25519 key generation and signing
|
|
# For now, we test the error handling
|
|
expect IOError:
|
|
let verifier = newSignatureVerifier()
|
|
let sig = createDigitalSignature(SigEd25519, "test-key", "fake-signature")
|
|
discard verifier.verifyFileSignature("/nonexistent/file.txt", sig)
|
|
|
|
finally:
|
|
removeFile(tempPath)
|
|
|
|
suite "Hybrid Signature Support":
|
|
test "create hybrid signature":
|
|
let classicalSig = createDigitalSignature(SigEd25519, "classical-key", "classical-sig")
|
|
let quantumSig = createDigitalSignature(SigDilithium, "quantum-key", "quantum-sig")
|
|
|
|
let hybridSig = HybridSignature(
|
|
classicalSig: classicalSig,
|
|
quantumSig: some(quantumSig),
|
|
requireBoth: true
|
|
)
|
|
|
|
check hybridSig.classicalSig.algorithm == SigEd25519
|
|
check hybridSig.quantumSig.isSome()
|
|
check hybridSig.quantumSig.get().algorithm == SigDilithium
|
|
check hybridSig.requireBoth == true
|
|
|
|
suite "Signature Information":
|
|
test "get signature info":
|
|
let timestamp = now().utc()
|
|
let sig = createDigitalSignature(SigEd25519, "info-key", "info-sig", timestamp)
|
|
let info = getSignatureInfo(sig)
|
|
|
|
check "ed25519" in info.toLower()
|
|
check "info-key" in info
|
|
check $timestamp in info
|
|
|
|
suite "Error Handling":
|
|
test "signature verification errors":
|
|
let verifier = newSignatureVerifier()
|
|
let sig = createDigitalSignature(SigEd25519, "nonexistent-key", "fake-signature")
|
|
|
|
expect SignatureVerificationError:
|
|
discard verifier.verifySignature("test message", sig)
|
|
|
|
test "unsupported algorithm errors":
|
|
expect ValueError:
|
|
discard verifyDilithiumSignature("test", "sig", "key")
|
|
|
|
expect ValueError:
|
|
discard verifyRSASignature("test", "sig", "key")
|
|
|
|
suite "Integration with Hash Verifier":
|
|
test "verify hash signature":
|
|
let verifier = newSignatureVerifier()
|
|
let hash = "blake2b-abc123def456"
|
|
let sig = createDigitalSignature(SigEd25519, "hash-key", "hash-signature")
|
|
|
|
# This would fail because we don't have the trusted key
|
|
expect SignatureVerificationError:
|
|
discard verifier.verifyHashSignature(hash, sig)
|
|
|
|
suite "Performance and Statistics":
|
|
test "signature verification timing":
|
|
# Create a mock signature that will fail verification
|
|
let verifier = newSignatureVerifier()
|
|
let sig = createDigitalSignature(SigEd25519, "timing-key", "timing-signature")
|
|
|
|
expect SignatureVerificationError:
|
|
let result = verifier.verifySignature("timing test", sig)
|
|
# Even failed verification should have timing information
|
|
check result.verificationTime >= 0.0 |