tests/test_signer.py
3.4 KB · 91 lines · python Raw
1 """Tests for BPFSigner / BPFVerifier / SignedBPFProgram."""
2
3 from __future__ import annotations
4
5 from dataclasses import replace
6
7 from pqc_ebpf_attestation import (
8 BPFProgram,
9 BPFVerifier,
10 SignedBPFProgram,
11 )
12
13
14 def test_sign_populates_envelope_fields(signed_program) -> None:
15 assert signed_program.signer_did.startswith("did:pqaid:")
16 assert signed_program.algorithm.startswith("ML-DSA")
17 assert len(signed_program.signature) > 0
18 assert len(signed_program.public_key) > 0
19 assert signed_program.signed_at # iso string
20 assert signed_program.program.bytecode_hash
21
22
23 def test_verify_success(signed_program) -> None:
24 result = BPFVerifier.verify(signed_program)
25 assert result.valid is True
26 assert result.signature_valid is True
27 assert result.hash_consistent is True
28 assert result.error is None
29 assert result.program_name == signed_program.program.metadata.name
30
31
32 def test_bytecode_tamper_detected(signed_program) -> None:
33 # Mutate the bytecode after signing; stored hash no longer matches.
34 tampered_program = replace(
35 signed_program.program,
36 bytecode=signed_program.program.bytecode + b"\x90",
37 )
38 tampered = replace(signed_program, program=tampered_program)
39 result = BPFVerifier.verify(tampered)
40 assert result.hash_consistent is False
41 assert result.valid is False
42
43
44 def test_signature_tamper_detected(signed_program) -> None:
45 # Flip a hex char in the signature.
46 sig = signed_program.signature
47 flipped = ("0" if sig[0] != "0" else "1") + sig[1:]
48 tampered = replace(signed_program, signature=flipped)
49 result = BPFVerifier.verify(tampered)
50 assert result.signature_valid is False
51 assert result.valid is False
52
53
54 def test_wrong_algorithm_rejected(signed_program) -> None:
55 bogus = replace(signed_program, algorithm="RSA-4096")
56 result = BPFVerifier.verify(bogus)
57 assert result.valid is False
58 assert result.error is not None
59 assert "unknown algorithm" in result.error
60
61
62 def test_signed_program_roundtrip(signed_program) -> None:
63 serialized = signed_program.to_dict(include_bytecode=True)
64 restored = SignedBPFProgram.from_dict(serialized)
65 assert restored.signer_did == signed_program.signer_did
66 assert restored.algorithm == signed_program.algorithm
67 assert restored.signature == signed_program.signature
68 assert restored.public_key == signed_program.public_key
69 assert restored.program.bytecode == signed_program.program.bytecode
70 assert restored.program.bytecode_hash == signed_program.program.bytecode_hash
71
72 # And the roundtripped envelope still verifies.
73 result = BPFVerifier.verify(restored)
74 assert result.valid is True
75
76
77 def test_verify_without_bytecode_is_signature_only(signed_program) -> None:
78 """Envelopes stripped of bytecode should still verify via the signed manifest."""
79 no_bytes = SignedBPFProgram.from_dict(signed_program.to_dict(include_bytecode=False))
80 assert no_bytes.program.bytecode == b""
81 result = BPFVerifier.verify(no_bytes)
82 # hash_consistent defaults True when no bytecode is present to compare.
83 assert result.hash_consistent is True
84 assert result.signature_valid is True
85 assert result.valid is True
86
87
88 def test_hash_helper_consistent(sample_bpf_metadata, sample_bytecode) -> None:
89 prog = BPFProgram.from_bytes(sample_bpf_metadata, sample_bytecode)
90 assert prog.bytecode_hash == BPFProgram.hash_bytecode(sample_bytecode)
91