◇ OpenCyber Academy
Engineering · Chapter 28 · English

Chapter 28 — Critical infrastructure and sector security: implementation I

Open, free learning for anyone who wants to protect people and technology. No account is required to read this text or its worked answers.

Chapter 28 — Critical infrastructure and sector security: implementation I

Lesson map

Lesson 28 published. Map, example, EX055.

flowchart TD
  N0["Learning outcomes and connection"]
  N1["28.1 From specification to code"]
  N2["28.2 Secure coding for control paths"]
  N3["28.3 The test bench"]
  N4["28.4 Evidence"]
  N5["28.6 Practical activity"]
  N6["Chapter synthesis"]
  N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> N6
  N6 --> EX["Worked example"]
  EX --> Q["Exercise EX055"]

Logical drawing

flowchart LR
  N0["Learning outcomes and connection"]
  N1["28.1 From specification to code"]
  N2["28.2 Secure coding for control paths"]
  N3["28.3 The test bench"]
  N4["28.4 Evidence"]
  N5["28.6 Practical activity"]
  N6["Chapter synthesis"]
  N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> N6 --> Q["EX055"]
[Learning outcomes and connection]
    |
    v
[28.1 From specification to code]
    |
    v
[28.2 Secure coding for control paths]
    |
    v
[28.3 The test bench]
    |
    v
[28.4 Evidence]
    |
    v
[28.6 Practical activity]
    |
    v
[Chapter synthesis]
    |
    v
[Worked example] --> [Exercise EX055]

Learning outcomes and connection

After this chapter you can (1) implement a security control as working code with tests, from specification; (2) apply secure coding practices for input handling, cryptography and error handling; (3) build a test bench that exercises the control offline; and (4) record implementation evidence that links back to requirements. It implements Chapter 27's specifications and prepares Chapter 29.

28.1 From specification to code

Start from the control specification (Chapter 27): every "shall" becomes at least one test before or alongside the code. Keep the implementation small and dependency-free where possible — the gateway in this book uses only the Python standard library. Structure it as Chapter 9 recommends: a parser (Chapter 4), a verifier (Chapter 19), a state store (replay counters), and an output interface, each tested separately.

TMRP's gateway follows this structure, which is why its NaN bug could be found and fixed in the validator alone.

28.2 Secure coding for control paths

These rules come straight from Labs 3, 8 and 11. Each one has a test in the gateway suite.

28.3 The test bench

A test bench reproduces the control's environment offline: simulated RTUs that send valid, malformed, forged, replayed and delayed messages; a simulated SCADA that receives the gateway's output; and a clock you can control. Lab 15 (Chapter 40) is a compact version. Benches let you test failure modes that would be unsafe or impossible to provoke on a live system.

TMRP's bench includes simulated RTUs at PS2 and PS4, a simulated SCADA receiver and a controllable clock, so restarts, delays and replays can be produced on demand. The same harness later carries the seeded fault-injection campaign, which is why investing in it early saves time when the capstone verification begins.

28.4 Evidence

Record for each implementation: the requirement and specification versions implemented; the source revision; test results with tool versions; known limitations; and reviewer sign-off. This becomes part of the evidence dossier (Chapter 48).

For TMRP's setpoint validator, the record shows the specification version, the commits for v1 and v2, the T3 results for each, the known limitation that v1 accepted NaN, and the reviewer who asked the NaN question. Without that record, the later dossier finding about T3's status would have been impossible to resolve, because nobody could show which version had passed. Recording evidence while the work is done costs minutes; reconstructing it later costs days.

28.5 Worked example: setpoint validator v1 (synthetic)

The TMRP team implements R3 from the §27.5 specification. Version 1 checks new < lo, new > hi and the step limit, and passes the example tests: in-range accepted, above and below range rejected, too-large step rejected. Code review asks: what about NaN? In IEEE 754 arithmetic, every ordered comparison with NaN is false, so nan < lo and nan > hi are both false and abs(nan - old) > max_step is false — v1 accepts NaN. Version 2 rejects non-finite values explicitly and expresses the safe region positively (lo <= new <= hi), which is false for NaN. Chapter 30's property-based tests confirm the difference systematically (Lab 11). This is test T3's failure in Chapter 10's sign-off scenario.

28.6 Practical activity

Implement a minimal gateway that combines Lab 3's parser output with Lab 8's sealing, so that a validated Modbus reading becomes an authenticated frame. Write tests for each rejection path.

Keep the two parts separate behind clear interfaces: the parser returns a validated reading or a reason for rejection, and only a validated reading is sealed. Test each rejection path from Lab 3 and confirm that nothing reaches the sealing function. Then check that the sealed frame passes Lab 8's receiver and that a tampered copy is refused. Store the key outside the source file, even for this exercise, so the habit is in place before real keys appear.

28.7 Common errors and limits

The setpoint validator's first version shows the third error, and TMRP's dossier exists to prevent the last. Its NaN acceptance came from negative checks, and the fix was to state the safe region positively. Keys in TMRP's bench code are loaded from a protected file, never written in the source, and every exception in the verification path ends in a rejection that is logged.

Exercises — chapter 28

EX055 — NaN and friends. Objective: find unsafe acceptances. Inputs: validate_v1 in Lab 11. Steps: evaluate v1 and v2 by hand for new = NaN, +∞, −∞, 5.5 and 5.50001 with old = 5.2, and explain each result. Expected evidence: table. Rubric: 3 = v1 accepts NaN only among the specials (∞ rejected by > hi, −∞ by < lo), 5.5 accepted by both (boundary inclusive), 5.50001 rejected; v2 rejects all non-finite; explanations correct; 2 = one error; 1 = no explanations; 0 = none.

EX056 — Rejection logging. Objective: design useful logs. Inputs: the gateway. Steps: define a log record for each rejection type (tag, replay, stale, shape, range) with fields, and explain one field you deliberately exclude. Expected evidence: schema. Rubric: 3 = fields allow investigation (time source, station, counter, reason, gateway ID, message hash), excludes key material and full payload where sensitive; 2 = missing time source or station; 1 = free text; 0 = none.

Chapter synthesis

Implement controls from specifications with tests for every "shall". Code the control path defensively: validate fully, compare in constant time, protect keys, reject on any error, bound resources, log usefully. Prefer positive checks of the safe region. Test on a bench that can produce the failures you cannot provoke live, and record evidence as you go.

Continue studying — chapter 28 of 50

← Chapter 27 · Course chapter index · Chapter 29 →

Continue to the next authored lesson.