Chapter 7 — Cryptography and trust services: controls and verification
Lesson map
Lesson 07 published. Map, example, EX031.
flowchart TD
N0["Learning outcomes"]
N1["7.1 Verifying notifications"]
N2["Lab — Notification verification"]
N3["7.2 Verifying TLS settings"]
N4["Synthesis"]
N0 --> N1 --> N2 --> N3 --> N4
N4 --> EX["Worked example"]
EX --> Q["Exercise EX031"]
Logical drawing
flowchart LR
N0["Learning outcomes"]
N1["7.1 Verifying notifications"]
N2["Lab — Notification verification"]
N3["7.2 Verifying TLS settings"]
N4["Synthesis"]
N0 --> N1 --> N2 --> N3 --> N4 --> Q["EX031"]
[Learning outcomes]
|
v
[7.1 Verifying notifications]
|
v
[Lab — Notification verification]
|
v
[7.2 Verifying TLS settings]
|
v
[Synthesis]
|
v
[Worked example] --> [Exercise EX031]
Learning outcomes
You will (1) verify payment notification controls with HMAC and replay checks; (2) verify TLS settings against a baseline; (3) write verification statements with their limits.
7.1 Verifying notifications
Bayside's booking site receives payment notifications from the processor. Each carries an HMAC-SHA-256 tag computed with a shared secret over a timestamp and the message body. The agency's code should recompute the tag, compare it with hmac.compare_digest and reject any message older than five minutes. Dana is not allowed to test the live processor, so she verifies the logic in a lab with synthetic messages: one authentic, one with a changed amount and one replayed after an hour. The lab below shows the verifier accepting only the authentic message, which matches the behaviour the agency described.
Lab — Notification verification
# Verify synthetic payment notifications: HMAC-SHA-256 + 300 s replay window.
import hmac, hashlib
SECRET = b"synthetic-processor-secret"; NOW = 1_772_000_000; WINDOW = 300
def tag(ts, body): return hmac.new(SECRET, str(ts).encode() + b"." + body, hashlib.sha256).hexdigest()
def accept(ts, body, t): return NOW - ts <= WINDOW and hmac.compare_digest(tag(ts, body), t)
body = b'{"booking":"BDG-2207","amount":"85.00"}'
t = tag(NOW - 30, body)
print("authentic:", accept(NOW - 30, body, t))
print("changed amount:", accept(NOW - 30, body.replace(b"85.00", b"8.50"), t))
print("replayed after 1 h:", accept(NOW - 3600, body, tag(NOW - 3600, body)))
Run with python3 lab_notify.py. Verified output:
authentic: True
changed amount: False
replayed after 1 h: False
7.2 Verifying TLS settings
For TLS, Dana checks each in-scope endpoint against the baseline: TLS 1.3 offered, TLS 1.2 allowed only if needed, older versions refused, a complete chain served and the certificate name correct. She uses openssl s_client with explicit version options, for example trying -tls1_1 and expecting a refusal. Each test records the command, the result and the time. Where a client cannot be tested directly, such as an old dental imaging workstation, she records the gap honestly instead of assuming it behaves like the rest. Verification is only as strong as the cases actually tried.
7.3 Statements with limits
Dana writes verification statements in a fixed form: what was checked, how, when, the result and what was not checked. For example: notification verification logic accepted authentic and rejected altered and replayed synthetic messages in a lab on 3 March; the production code path and secret storage were not reviewed. This form protects both Copperleaf and the client. Clients make decisions on these statements, so a statement that hides its limits can lead them to skip a needed review. Marcus checks every statement for words like secure or compliant that claim more than the test showed.
Worked example
Dana runs the notification lab, tests TLS versions on three endpoints and writes four verification statements, each ending with what was not checked.
Synthetic case. Messages, secrets and endpoints are synthetic.
Errors and limits
Lab logic checks do not prove production code matches. Refusal of one old version does not prove all weak options are disabled.
Exercises
- EX031 — Replay window. What age limit does the verifier enforce on notifications? Rubric: 3 = five minutes (300 seconds);; 2 = five minutes;; 1 = vague;; 0 = none.
- EX032 — Changed amount. What did the lab report for the notification with a changed amount? Rubric: 3 = rejected (False) because the tag no longer matched;; 2 = rejected;; 1 = accepted;; 0 = none.
- EX033 — TLS 1.1 probe. How does Dana check that TLS 1.1 is refused? Rubric: 3 = openssl s_client with -tls1_1 and expect handshake failure;; 2 = command;; 1 = assumes;; 0 = none.
- EX034 — Imaging workstation. What does Dana do about the untestable imaging workstation? Rubric: 3 = records the gap honestly instead of assuming;; 2 = records gap;; 1 = assumes fine;; 0 = none.
- EX035 — Banned words. Which words does Marcus check for in statements, and why? Rubric: 3 = secure or compliant, because they claim more than tests show;; 2 = words named;; 1 = vague;; 0 = none.
Synthesis
Verification proves specific behaviour under specific tests, and honest statements say exactly which cases were tried.
Continue studying — chapter 07 of 12
← Chapter 06 (draft) · Course chapter index · Chapter 08 (draft) →