forked from ChelseaKR/habitable
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_tsa_real_authority.py
More file actions
197 lines (157 loc) · 8.23 KB
/
Copy pathtest_tsa_real_authority.py
File metadata and controls
197 lines (157 loc) · 8.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# SPDX-License-Identifier: AGPL-3.0-or-later
# Copyright 2026 Chelsea Kelly-Reif
"""Authority trust, anchored to a certificate this repository did not generate.
Issue #159. ``timestamp_authority_trusted`` gates every READY verdict habitable
emits, and it had never been exercised against a certificate this project did
not mint: 48 ``trusted_certs=`` call sites, every anchor either
``LocalRfc3161TSA``'s own certificate, a certificate generated inside the test,
or the synthetic authority written by ``scripts/make_site_sample.py``. The one
test that touched a real authority (``tests/test_tsa_integration.py``) proved
only that a token could be *obtained*, calling ``verify_token`` with no anchor
at all.
So the production path was proven to produce a real token, and separately proven
to anchor a token we wrote. This module asserts the join, offline, from the
committed fixture in ``tests/golden/tsa-freetsa/`` (see its README for
provenance): a real public authority's token, anchored to that authority's
published root certificate.
"""
from __future__ import annotations
from collections.abc import Callable
from pathlib import Path
import pytest
from cryptography import x509
from habitable.canonical import sha256_bytes
from habitable.capture import capture
from habitable.errors import TimestampError
from habitable.packet import build_packet
from habitable.tsa import LocalRfc3161TSA, TimestampToken, TokenKind, verify_token
from habitable.vault import Vault
from habitable.verify import verify_packet
_FIXTURE = Path(__file__).parent / "golden" / "tsa-freetsa"
# The exact bytes whose SHA-256 was submitted to the authority. The digest is
# recomputed from them here rather than hard-coded, so a fixture that no longer
# matches its own stated provenance fails instead of quietly agreeing with
# whatever is on disk.
_STAMPED_BYTES = b"habitable golden real-authority fixture v1 - synthetic, never evidence"
def _token() -> TimestampToken:
return TimestampToken(
kind=TokenKind.RFC3161.value,
tsa_name="freetsa",
data=(_FIXTURE / "token.tsr").read_bytes(),
)
def _cert(name: str) -> x509.Certificate:
return x509.load_pem_x509_certificate((_FIXTURE / name).read_bytes())
def test_a_real_authority_token_anchors_to_that_authoritys_published_root() -> None:
"""The join issue #159 says is asserted nowhere.
The anchor is FreeTSA's published root, fetched from FreeTSA — not extracted
from the token, and not generated by this repository.
"""
info = verify_token(
_token(), sha256_bytes(_STAMPED_BYTES), trusted_certs=[_cert("freetsa-cacert.pem")]
)
assert info.trusted_chain is True
assert info.note == ""
assert info.gen_time == "2026-08-14T18:07:04Z"
assert info.digest_hex == sha256_bytes(_STAMPED_BYTES)
def test_the_same_token_pinned_to_the_published_responder_certificate() -> None:
"""The other accepted anchor shape: pinning the responder itself."""
info = verify_token(
_token(), sha256_bytes(_STAMPED_BYTES), trusted_certs=[_cert("freetsa-responder.pem")]
)
assert info.trusted_chain is True
def test_an_unrelated_authoritys_certificate_does_not_anchor_it() -> None:
"""Negative control: trust must be losable, and must not be granted by any
certificate that happens to be supplied."""
unrelated = LocalRfc3161TSA("not-freetsa").certificate
info = verify_token(_token(), sha256_bytes(_STAMPED_BYTES), trusted_certs=[unrelated])
assert info.trusted_chain is False
assert "none of the 1 supplied certificate anchor(s)" in info.note
def test_the_real_token_still_fails_closed_on_the_wrong_digest() -> None:
"""A real authority's signature does not make the imprint check optional."""
with pytest.raises(TimestampError, match="imprint does not match"):
verify_token(
_token(),
sha256_bytes(b"different content"),
trusted_certs=[_cert("freetsa-cacert.pem")],
)
def test_mutating_a_real_token_moves_neither_the_attested_time_nor_the_digest() -> None:
"""The project's stated token property, applied to a real authority for the
first time.
An RFC 3161 CMS wrapper legitimately carries bytes outside its signature, so
"any byte change is rejected" is not the property and is not claimed (see the
RFC 3161 row in ``docs/capabilities.md``). What is claimed is that no
mutation can move the attested ``gen_time`` or ``digest``, and that none can
*manufacture* trust. Until now both were pinned only against tokens this
repository issued.
"""
original = (_FIXTURE / "token.tsr").read_bytes()
digest = sha256_bytes(_STAMPED_BYTES)
root = _cert("freetsa-cacert.pem")
genuine = verify_token(_token(), digest, trusted_certs=[root])
offsets = range(0, len(original), max(1, len(original) // 64))
survived = 0
for offset in offsets:
raw = bytearray(original)
raw[offset] ^= 0xFF
mutated = TimestampToken(kind=TokenKind.RFC3161.value, tsa_name="freetsa", data=bytes(raw))
try:
info = verify_token(mutated, digest, trusted_certs=[root])
except TimestampError:
continue # rejected outright: the fail-closed outcome
survived += 1
# Accepted only because the mutated byte is outside the signature; the
# attested facts must be untouched.
assert info.gen_time == genuine.gen_time
assert info.digest_hex == genuine.digest_hex
# And trust must never be *created* by tampering: with no anchor
# supplied, no mutation can produce a trusted verdict.
assert verify_token(mutated, digest).trusted_chain is False
assert survived < len(list(offsets)), "no mutation was rejected — the signature is not checked"
def test_the_committed_fixture_matches_its_documented_provenance() -> None:
"""The README states what was hashed and by whom; check the files agree.
Keeps the fixture from silently becoming something other than what its
provenance claims — the same failure mode as the rest of this issue.
"""
responder = _cert("freetsa-responder.pem")
root = _cert("freetsa-cacert.pem")
assert responder.issuer == root.subject
assert root.issuer == root.subject # self-signed root, as published
readme = (_FIXTURE / "README.md").read_text("utf-8")
assert _STAMPED_BYTES.decode() in readme
assert sha256_bytes(_STAMPED_BYTES) in readme
def test_a_packet_verified_with_a_non_chaining_anchor_says_so(
make_vault: Callable[..., Vault],
make_jpeg: Callable[..., Path],
local_tsa: LocalRfc3161TSA,
tmp_path: Path,
) -> None:
"""Issue #159 item 3, at the verdict level.
A reviewer who downloads an authority's published root, passes it, and gets
NOT TRUSTED used to be told to "rerun with --trusted-cert PEM for an
authority you independently trust" — the thing they had just done — with
nothing distinguishing their anchor failing to chain from the packet's
timestamps not being from who it says.
"""
vault = make_vault()
issue = vault.document.add_issue(category="mold", issue_id="i1")
capture(vault, make_jpeg(), issue_id=issue, tsa=local_tsa)
vault.save()
packet = tmp_path / "packet"
build_packet(vault, packet, generated_at="2026-01-02T00:10:00Z", make_pdf=False)
unassessed = verify_packet(packet)
wrong_anchor = verify_packet(
packet, trusted_certs=[LocalRfc3161TSA("someone-else").certificate]
)
anchored = verify_packet(packet, trusted_certs=[local_tsa.certificate])
assert unassessed.status == wrong_anchor.status == "timestamp_authority_untrusted"
assert unassessed.anchors_supplied == 0
assert wrong_anchor.anchors_supplied == 1
# The absence under test: the two failures no longer read identically.
assert unassessed.guidance() != wrong_anchor.guidance()
assert "no certificate anchor was supplied" in unassessed.guidance()
assert "did not match or issue" in wrong_anchor.guidance()
assert "not, by itself, a finding that the timestamps are forged" in wrong_anchor.guidance()
# Spanish keeps the distinction rather than falling back to one string.
assert unassessed.guidance("es") != wrong_anchor.guidance("es")
assert anchored.timestamp_authority_trusted is True
assert all(not item.notes for item in anchored.items)