id: ffb7de8f112f456186cc0aafeac97312
parent_id: f4f47ebaa01242689958a58c140870fb
item_type: 1
item_id: 1fbaa70f2fb94ffcaabbeca7b39482da
item_updated_time: 1787060982761
title_diff: "[]"
body_diff: "[{\"diffs\":[[0,\"\\\n\\\n> \"],[-1,\"Master copy of every PlantUML diagram for the key-fob provisioning architecture.\\\n> Sources + rendered **SVG and PNG** live in the repo under `docs/diagrams/`:\\\n> - **`docs/diagrams/KDF/`** — SCP03 key-derivation phases + provisioning flows (12 sets)\\\n> - **`docs/diagrams/HSM_Backup/`** — HSM deployment, key ceremonies & backups (5 sets, added 2026-08-18)\\\n>\\\n> Rendered via the public PlantUML server (deflate+map6 encoder). **Uncommitted as of\\\n> 2026-08-18** — until committed, this note remains the durable copy. PPT/Word embeds\\\n> use the **SVG** (scalable); PNG raster fallback sits alongside each.\\\n> Companions: **Keyfob Flow 1**, **Keyfob Flow 2** (sequence detail), audit note\\\n> (**Keyfob Station — Code Audit Open Items**).\\\n\\\n> **Review status 2026-08-14, updated 2026-08-17/18** — KDF diagrams verified against\\\n> the code (kf-scp03 derive.rs, kf-provision perso.rs/helpers.rs, kf-source\\\n> container.rs, nfc_reader.rs):\\\n> - **Phase A–D KDF diagrams: correct as drawn.** Purposes 0x40/0x60/0x70, header\\\n>   `00^11‖p‖00‖0080‖01`, K1-for-full / K2-for-partial CMAC blocks, ECB call counts\\\n>   (7+8+5+3 = 23), Phase D CBC chaining — all match code + tests.\\\n> - **Phase D (A003 = AES-CBC, IV=0, M2) is CONFIRMED by hardware** and is what the\\\n>   KLMS has delivered since 2026-08-17; the station forwards the blob untouched.\\\n> - Flow 2 diagrams reflect the REST transport, seed-based generation, corrected\\\n>   INIT UPDATE layout, step 9 PENDING.\\\n> - **HSM_Backup set (2026-08-18)** documents the key-custody architecture: KLMS\\\n>   failover pair (YubiHSM per VM) + NitroHSM; Ford decrypt key generated in\\\n>   YubiHSM-1 and backed up to YubiHSM-2; NXP master key inserted into the NitroHSM\\\n>   via an asymmetric key ceremony (public key to NXP, ciphertext back), backed up\\\n>   to YubiHSM-1. All transfers use one universal wrap-key ceremony.\\\n\\\n## Diagrams\\\n\\\n### KDF/ (12 sets)\\\n\\\n| File | Shows |\\\n| --- | --- |\\\n| `kdf-overview.puml` | KDF phase overview — two-row flow (both rows start left; A003 feeds Phase D) |\\\n| `kdf-phase-a.puml` | Phase A full (master+UID → static keys) |\\\n| `kdf-phase-a-1.puml` | Phase A 1/2 (subkeys + S-ENC) — slide |\\\n| `kdf-phase-a-2.puml` | Phase A 2/2 (S-MAC + S-DEK) — slide |\\\n| `kdf-phase-b.puml` | Phase B full (session keys) |\\\n| `kdf-phase-b-1.puml` | Phase B 1/2 (subkeys + SES-ENC) — slide |\\\n| `kdf-phase-b-2.puml` | Phase B 2/2 (SES-MAC + SES-RMAC) — slide |\\\n| `kdf-phase-c.puml` | Phase C — cryptograms (card gate + host cg) |\\\n| `kdf-phase-d.puml` | Phase D — A003 AES-CBC + cleanup |\\\n| `flow-2-provisioning.puml` | Full end-to-end (Word full-page) |\\\n| `flow-2-provisioning-1.puml` | Flow 2a — Session establishment (slide, landscape) |\\\n| `flow-2-provisioning-2.puml` | Flow 2b — Personalize & finalize (slide) |\\\n\\\n### HSM_Backup/ (5 sets)\\\n\\\n| File | Shows |\\\n| --- | --- |\\\n| `hsm-topology.puml` | Deployment + key placement: KLMS VM-1/VM-2 failover, YubiHSM-1/2, NitroHSM; which key lives where |\\\n| `hsm-backup-pattern.puml` | The universal transfer ceremony: target-generated wrap keypair, ciphertext-only transfer, plaintext never outside an HSM |\\\n| `decryption-key-create-and-backup.puml` | Ford bundle decryption key: generated in YubiHSM-1, public key to Ford, wrapped backup to YubiHSM-2 |\\\n| `nxp-master-key-ceremony.puml` | NXP master key: import keypair on NitroHSM, public key to NXP, NXP encrypts M, decrypt-inside import |\\\n| `nxp-master-key-backup.puml` | NXP master key backup: NitroHSM → YubiHSM-1 via the same wrap ceremony |\\\n\\\n## Rendering\\\n\\\n```sh\\\n# local (needs java + plantuml.jar)\\\nplantuml -tpng -tsvg <file>.puml\\\n\\\n# headless, no java — public server via deflate encoder\\\n# https://www.plantuml.com/plantuml/{png,svg}/<encoded>\\\n```\\\n\\\nFor PPT/Word embed the **SVG** (scalable).\\\n\\\n* * *\\\n\\\n## HSM_Backup/hsm-topology.puml — deployment & key placement\\\n\\\n```plantuml\\\n@startuml hsm-topology\\\n' HSM deployment: KLMS failover pair (each VM with a YubiHSM) + NitroHSM (NetHSM).\\\n' Key placement:\\\n'   Ford bundle decryption key: YubiHSM-1 (generated here) + YubiHSM-2 (backup)\\\n'   NXP master key:            NitroHSM (primary, SCP03 KDF) + YubiHSM-1 (backup)\\\n\\\nskinparam defaultFontName \\\"DejaVu Sans\\\"\\\nskinparam ArrowColor #444444\\\nskinparam node {\\\n  BackgroundColor #F4F8FF\\\n  BorderColor #3B6FB6\\\n}\\\nskinparam cloud {\\\n  BackgroundColor #FFFFFF\\\n  BorderColor #888888\\\n}\\\nskinparam storage {\\\n  BackgroundColor #FFF8E1\\\n  BorderColor #B8860B\\\n}\\\n\\\ntitle HSM Deployment & Key Placement — KLMS failover pair + NitroHSM\\\n\\\ncloud \\\"Ford IVSS / GIVIS\\\" as Ford\\\ncloud \\\"NXP (key ceremony)\\\" as NXP\\\n\\\nnode \\\"KLMS VM-1\\\\\n(primary)\\\" as VM1\\\nnode \\\"KLMS VM-2\\\\\n(standby)\\\" as VM2\\\n\\\nnode \\\"YubiHSM-1\\\" as Y1 {\\\n  storage \\\"**Ford decrypt key**\\\\\n(generated here)\\\" as DK1\\\n  storage \\\"**NXP master key**\\\\\n(backup)\\\" as MK1\\\n}\\\nnode \\\"YubiHSM-2\\\" as Y2 {\\\n  storage \\\"**Ford decrypt key**\\\\\n(backup)\\\" as DK2\\\n}\\\nnode \\\"NitroHSM\\\\\n(NetHSM — SCP03 KDF)\\\" as NH {\\\n  storage \\\"**NXP master key M**\\\\\n(primary — KDF3 + ECB)\\\" as MK0\\\n}\\\n\\\nFord -down-> VM1 : encrypted bundles\\\\\n(Flow 1, mTLS)\\\nFord -down-> VM2 : encrypted bundles\\\nVM1 <--> VM2 : failover\\\\\n(heartbeat)\\\nVM1 -down-> Y1 : USB\\\nVM2 -down-> Y2 : USB\\\nVM1 -right-> NH : AES-ECB calls\\\\\n(Flow 2 KDF)\\\nVM2 --> NH\\\n\\\nNXP ..> NH : master key M, wrapped\\\\\n(one-time key ceremony)\\\nY1 ..> Y2 : decrypt-key backup\\\\\n(wrapped, one-time)\\\nNH ..> Y1 : master-key backup\\\\\n(wrapped, one-time)\\\n\\\nnote bottom of NH\\\n  NitroHSM exposes single-block AES-ECB only.\\\n  Master key M never leaves in plaintext.\\\nend note\\\n@enduml\\\n```\\\n\\\n* * *\\\n\\\n## HSM_Backup/hsm-backup-pattern.puml — the universal transfer ceremony\\\n\\\n```plantuml\\\n@startuml hsm-backup-pattern\\\n' The universal key-transfer ceremony — used for:\\\n'   - NXP master key insertion (source = NXP, target = NitroHSM)\\\n'   - Ford decrypt-key backup  (YubiHSM-1 -> YubiHSM-2)\\\n'   - NXP master-key backup    (NitroHSM -> YubiHSM-1)\\\n' Invariant: plaintext key material exists only inside HSMs; operators only\\\n' ever handle public keys and ciphertext.\\\n\\\nskinparam defaultFontName \\\"DejaVu Sans\\\"\\\ntitle Key Transfer Pattern — target-generated wrap key, ciphertext-only transfer\\\n\\\nparticipant \\\"Operator\\\\\n(ceremony, dual control)\\\" as Op\\\nparticipant \\\"Key Holder\\\\\n(source HSM or NXP)\\\" as Src\\\nparticipant \\\"Target HSM\\\\\n(YubiHSM / NitroHSM)\\\" as Tgt\\\n\\\n== 1. Target generates a wrap keypair ==\\\nTgt -> Tgt : generate asymmetric **wrap keypair**\\\\\n(private key non-exportable)\\\nTgt --> Op : export wrap **public key** (cert)\\\nOp --> Src : import wrap public key\\\\\n(over a verified channel)\\\n\\\n== 2. Source wraps the key material ==\\\nSrc -> Src : encrypt (wrap) the key material\\\\\nunder the target wrap public key\\\nSrc --> Op : wrapped blob (ciphertext)\\\n\\\n== 3. Target imports and unwraps ==\\\nOp -> Tgt : import wrapped blob\\\nTgt -> Tgt : decrypt **inside** the HSM\\\\\n-> usable, non-exportable key object\\\n\\\nnote over Op, Tgt #E8FFE8\\\n  Invariants:\\\n  - plaintext key never crosses an HSM boundary\\\n  - operator handles only public keys + ciphertext\\\n  - same ceremony for every key and every backup\\\nend note\\\n@enduml\\\n```\\\n\\\n* * *\\\n\\\n## HSM_Backup/decryption-key-create-and-backup.puml\\\n\\\n```plantuml\\\n@startuml decryption-key-create-and-backup\\\n' Ford package decryption key: generated in YubiHSM-1 (primary),\\\n' public key to Ford, backup to YubiHSM-2 via the standard wrap ceremony.\\\n\\\nskinparam defaultFontName \\\"DejaVu Sans\\\"\\\ntitle Ford Bundle Decryption Key — creation in YubiHSM-1 + backup to YubiHSM-2\\\n\\\nparticipant \\\"Ford IVSS\\\" as Ford\\\nparticipant \\\"Operator\\\" as Op\\\nparticipant \\\"YubiHSM-1\\\\\n(primary)\\\" as Y1\\\nparticipant \\\"YubiHSM-2\\\\\n(standby)\\\" as Y2\\\n\\\n== Creation (in the primary YubiHSM) ==\\\nOp -> Y1 : generate bundle **decryption keypair**\\\nY1 -> Y1 : private key generated on-device,\\\\\nnon-exportable\\\nY1 --> Op : public key (cert)\\\nOp --> Ford : public key (verified channel)\\\nnote right of Ford : Ford encrypts every per-fob\\\\\ncontent bundle to this public key\\\\\n(Flow 1). Only the YubiHSMs\\\\\ncan decrypt.\\\n\\\n== Backup to the standby YubiHSM (standard wrap ceremony) ==\\\nY2 -> Y2 : generate **wrap keypair**\\\nY2 --> Op : wrap public key\\\nOp --> Y1 : import wrap public key\\\nY1 -> Y1 : export decryption private key\\\\\nwrapped under Y2 wrap public key\\\nY1 --> Op : wrapped blob (ciphertext)\\\nOp -> Y2 : import wrapped blob\\\nY2 -> Y2 : unwrap **inside** HSM\\\\\n-> decrypt key available on standby\\\n\\\nnote over Y1, Y2 #E8FFE8\\\n  Result: both YubiHSMs hold the decryption key;\\\n  either KLMS VM can run Flow 1 bundle decryption.\\\n  Plaintext never left an HSM.\\\nend note\\\n@enduml\\\n```\\\n\\\n* * *\\\n\\\n## HSM_Backup/nxp-master-key-ceremony.puml\\\n\\\n```plantuml\\\n@startuml nxp-master-key-ceremony\\\n' NXP master key insertion: asymmetric keypair generated on the NitroHSM,\\\n' public key handed to NXP, NXP encrypts the master key, import decrypts\\\n' inside the HSM.\\\n\\\nskinparam defaultFontName \\\"DejaVu Sans\\\"\\\ntitle NXP Master Key — Key Ceremony & Insertion into the NitroHSM\\\n\\\nparticipant \\\"NXP\\\" as NXP\\\nparticipant \\\"Operator\\\\\n(ceremony, dual control)\\\" as Op\\\nparticipant \\\"NitroHSM\\\\\n(NetHSM)\\\" as NH\\\n\\\n== Ceremony ==\\\nOp -> NH : generate asymmetric **import keypair**\\\nNH -> NH : private key non-exportable\\\nNH --> Op : import **public key** (cert)\\\nOp --> NXP : public key (verified / signed channel)\\\nNXP -> NXP : encrypt the **SCP03 master key M**\\\\\n(AES-128, KDF3 base key)\\\\\nunder the NitroHSM public key\\\nNXP --> Op : encrypted master-key blob (ciphertext)\\\nOp -> NH : import encrypted blob\\\nNH -> NH : decrypt **inside** the HSM\\\\\n-> master key M as a key object\\\n\\\n== Post-conditions ==\\\nnote over NH #FFF8E1\\\n  M is used only for:\\\n  - KDF3, Phase A (S-ENC / S-MAC / S-DEK)\\\n  - AES-ECB primitives (Phases A-D)\\\n  M is never exportable in plaintext;\\\n  backup only via the wrap ceremony\\\n  (see nxp-master-key-backup).\\\nend note\\\nnote over NXP #FFEEEE : NXP is the originator of M;\\\\\nhandover is logged and audited\\\n@enduml\\\n```\\\n\\\n* * *\\\n\\\n## HSM_Backup/nxp-master-key-backup.puml\\\n\\\n```plantuml\\\n@startuml nxp-master-key-backup\\\n' NXP master key backup: NitroHSM -> YubiHSM-1 via the standard wrap ceremony.\\\n\\\nskinparam defaultFontName \\\"DejaVu Sans\\\"\\\ntitle NXP Master Key — Backup from NitroHSM to YubiHSM-1 (primary)\\\n\\\nparticipant \\\"Operator\\\" as Op\\\nparticipant \\\"NitroHSM\\\\\n(NetHSM)\\\" as NH\\\nparticipant \\\"YubiHSM-1\\\\\n(primary)\\\" as Y1\\\n\\\nY1 -> Y1 : generate **wrap keypair**\\\\\n(private key non-exportable)\\\nY1 --> Op : wrap public key\\\nOp --> NH : import wrap public key\\\\\n(verified channel)\\\nNH -> NH : export master key M\\\\\nwrapped under Y1 wrap public key\\\nNH --> Op : wrapped blob (ciphertext)\\\nOp -> Y1 : import wrapped blob\\\nY1 -> Y1 : decrypt **inside** HSM\\\\\n-> backup copy of M\\\n\\\nnote over NH, Y1 #E8FFE8\\\n  Identical ceremony to the decrypt-key backup\\\n  (hsm-backup-pattern / decryption-key-create-and-backup):\\\n  every key and every backup is created and transferred\\\n  exactly the same way — wrap public key out,\\\n  ciphertext across, plaintext never outside an HSM.\\\nend note\\\nnote over Y1 #FFF8E1\\\n  YubiHSM-1 now holds:\\\n  - Ford decrypt key (generated)\\\n  - NXP master key (backup)\\\nend note\\\n@enduml\\\n```\\\n\\\n* * *\\\n\\\n## KDF/kdf-overview.puml — Phase overview (two-row flow)\\\n\\\n```plantuml\\\n@startuml kdf-overview\\\n' KLMS <-> NetHSM KDF: phase overview (per fob). Two-row flow for PPT.\\\n' Both rows start on the LEFT; end of row1 wraps to start of row2.\\\n' A003 (OEM private key) feeds Phase D, not Phase A.\\\n\\\nskinparam monochrome false\\\nskinparam defaultFontName \\\"DejaVu Sans\\\"\\\nskinparam ArrowColor #444444\\\nskinparam rectangle {\\\n  BackgroundColor #F4F8FF\\\n  BorderColor #3B6FB6\\\n}\\\nskinparam card {\\\n  BackgroundColor #FFFFFF\\\n  BorderColor #3B6FB6\\\n}\\\n\\\ntitle KLMS <-> NetHSM KDF — Phase Overview (per fob transaction)\\\n\\\nrectangle \\\"**Inputs from station (from fob)**\\\\\n- UID\\\\\n- host_challenge\\\\\n- card_challenge\\\\\n- card_cryptogram\\\" as InStation #E8F5E9\\\nrectangle \\\"**Inputs from OEM key feed**\\\\\n- Private Key for Key Fob (A003)\\\" as InOEM #E8F5E9\\\n\\\ncard \\\"**Phase A — KDF3**\\\\\nkey = master **M**\\\\\n7 x AES-ECB\\\" as pA\\\ncard \\\"**Phase B — Session keys**\\\\\nkey = **SE / SM**\\\\\n8 x AES-ECB\\\" as pB\\\ncard \\\"**Phase C — Cryptograms**\\\\\nkey = **SESMAC**\\\\\n5 x AES-ECB\\\" as pC\\\ncard \\\"**Phase D — A003 (private key) CBC + cleanup**\\\\\nkey = **SD**\\\\\n3 x AES-ECB\\\" as pD\\\nrectangle \\\"**Outputs to station**\\\\\nSES-* keys - host_cryptogram\\\\\n- A003 ciphertext (pre-encrypted)\\\" as Out #FFF8E1\\\n\\\n' ---- ROW 1: inputs -> Phase A -> Phase B ----\\\nInStation -down-> pA\\\npA -right-> pB : static keys\\\\\n(SE / SM / SD)\\\nnote bottom of pA\\\n  master + UID -> S-ENC / S-MAC / S-DEK\\\n  imported as handles SE / SM / SD\\\nend note\\\nnote bottom of pB\\\n  SE / SM -> SES-ENC / SES-MAC / SES-RMAC\\\n  SES-MAC imported as handle SESMAC\\\nend note\\\n\\\n' ---- wrap: anchor row2 under row1's columns (C under A, D under B); arrow from end of row1 ----\\\npA -[hidden]down-> pC\\\npB -[hidden]down-> pD\\\npB -down-> pC : SES-MAC\\\\\n(SESMAC)\\\n\\\n' ---- ROW 2: Phase C -> Phase D -> outputs ----\\\npC -right-> pD : authenticated + host_cryptogram\\\\\nsecure channel trusted -> proceed\\\nInOEM -down-> pD : A003 private key (SD)\\\\\nIV = 0, AES-CBC\\\npD -right-> Out : pre-encrypted A003\\\nnote bottom of pC\\\n  VERIFY card_cryptogram -> GATE\\\n  then host_cryptogram\\\nend note\\\nnote bottom of pD\\\n  AES-CBC(S-DEK) -> A003 ciphertext\\\n  Zeroize all static & session key material\\\nend note\\\n\\\nnote top of pA #FFEEEE\\\n  NetHSM exposes only single-block AES-ECB.\\\n  Master key **M** never exposed.\\\n  ~= 23 AES-ECB calls per transaction.\\\nend note\\\nnote right of pD #E8FFE8\\\n  HW-confirmed: card expects CBC(IV=0)+M2;\\\n  ECB is rejected (6A80).\\\n  KLMS delivers CBC since 2026-08-17.\\\nend note\\\n@enduml\\\n```\\\n\\\n* * *\\\n\\\n## KDF/kdf-phase-a.puml — Phase A: KDF3 (full, Word page)\\\n\\\n```plantuml\\\n@startuml\\\n' Phase A - KDF3: master + UID -> S-ENC/S-MAC/S-DEK via AES-ECB (RFC 4493 CMAC).\\\n' Constants validated against kf-scp03 derive.rs (jcshell_reference_vector test).\\\n\\\nautonumber\\\ntitle Phase A — KDF3 (key = master M) -> static keys (S-ENC/S-MAC/S-DEK)\\\n\\\nparticipant KLMS\\\nparticipant \\\"NetHSM\\\\\nMaster Key M\\\" as HSM\\\n\\\n== Master Subkeys (RFC 4493) ==\\\nKLMS -> HSM : ECB(M, 0^16)\\\nHSM --> KLMS : L_M\\\nKLMS -> KLMS : K1_M = dbl(L_M)\\\nKLMS -> KLMS : K2_M = dbl(K1_M)\\\nnote left of KLMS : **dbl** is the doubling that CMAC uses to derive its subkeys K1 and K2.\\\\\nFor a 16‑byte block X: dbl(X) = (X << 1)  XOR  (Rb if MSB(X)=1, else 0)\\\\\nwith Rb = 00^15 87 (i.e. 15 zero bytes + 0x87).\\\\\n**In plain terms**: shift the 128‑bit value left by one bit;\\\\\nif the top bit that was shifted out was a 1, XOR 0x87 into the last byte.\\\n\\\n== S-ENC (purpose 0x40, 10-B UID from station) ==\\\nKLMS -> KLMS : header = 00^11 ‖ 40 (purpose) ‖ 00 ‖ 0080 ‖ 01\\\nKLMS -> HSM : ECB(M, header)\\\nHSM --> KLMS : C1\\\nKLMS -> HSM : ECB(M, C1 ⊕ pad(UID, 16-B) ⊕ K2_M)\\\nHSM --> KLMS : C2 = **S-ENC**\\\nKLMS -> HSM : ImportKey(S-ENC)\\\nHSM --> KLMS : handle **SE**\\\n\\\n== S-MAC (purpose 0x60, 10-B UID from station) ==\\\nKLMS -> KLMS : header = 00^11 ‖ 60 (purpose) ‖ 00 ‖ 0080 ‖ 01\\\nKLMS -> HSM : ECB(M, header)\\\nHSM --> KLMS : C1\\\nKLMS -> HSM : ECB(M, C1 ⊕ pad(UID, 16-B) ⊕ K2_M)\\\nHSM --> KLMS : C2 = **S-MAC**\\\nKLMS -> HSM : ImportKey(S-MAC)\\\nHSM --> KLMS : handle **SM**\\\n\\\n== S-DEK (purpose 0x70, 10-B UID from station) ==\\\nKLMS -> KLMS : header = 00^11 ‖ 70 (purpose) ‖ 00 ‖ 0080 ‖ 01\\\nKLMS -> HSM : ECB(M, header)\\\nHSM --> KLMS : C1\\\nKLMS -> HSM : ECB(M, C1 ⊕ pad(UID, 16-B) ⊕ K2_M)\\\nHSM --> KLMS : C2 = **S-DEK**\\\nKLMS -> HSM : ImportKey(S-DEK)\\\nHSM --> KLMS : handle **SD**\\\n\\\n@enduml\\\n```\\\n\\\n* * *\\\n\\\n## KDF/kdf-phase-a-1.puml — Phase A (1/2): subkeys + S-ENC (slide)\\\n\\\n```plantuml\\\n@startuml kdf-phase-a-1\\\n' Phase A (1/2): master subkeys + S-ENC. Continues in kdf-phase-a-2.puml.\\\n' Splits the portrait Phase A into two landscape halves for PPT.\\\nautonumber\\\ntitle Phase A — KDF3 (1/2): master subkeys + S-ENC\\\nparticipant KLMS\\\nparticipant \\\"NetHSM\\\\\nMaster Key M\\\" as HSM\\\n\\\n== Master Subkeys (RFC 4493) ==\\\nKLMS -> HSM : ECB(M, 0^16)\\\nHSM --> KLMS : L_M\\\nKLMS -> KLMS : K1_M = dbl(L_M)\\\nKLMS -> KLMS : K2_M = dbl(K1_M)\\\nnote left of KLMS : **dbl** is the doubling that CMAC uses to derive its subkeys K1 and K2.\\\\\nFor a 16‑byte block X: dbl(X) = (X << 1)  XOR  (Rb if MSB(X)=1, else 0)\\\\\nwith Rb = 00^15 87 (i.e. 15 zero bytes + 0x87).\\\\\n**In plain terms**: shift the 128‑bit value left by one bit;\\\\\nif the top bit that was shifted out was a 1, XOR 0x87 into the last byte.\\\n\\\n== S-ENC (purpose 0x40, 10-B UID from station) ==\\\nKLMS -> KLMS : header = 00^11 ‖ 40 (purpose) ‖ 00 ‖ 0080 ‖ 01\\\nKLMS -> HSM : ECB(M, header)\\\nHSM --> KLMS : C1\\\nKLMS -> HSM : ECB(M, C1 ⊕ pad(UID, 16-B) ⊕ K2_M)\\\nHSM --> KLMS : C2 = **S-ENC**\\\nKLMS -> HSM : ImportKey(S-ENC)\\\nHSM --> KLMS : handle **SE**\\\n@enduml\\\n```\\\n\\\n* * *\\\n\\\n## KDF/kdf-phase-a-2.puml — Phase A (2/2): S-MAC + S-DEK (slide)\\\n\\\n```plantuml\\\n@startuml kdf-phase-a-2\\\n' Phase A (2/2): S-MAC + S-DEK. Continues from kdf-phase-a-1.puml.\\\nautonumber\\\ntitle Phase A — KDF3 (2/2): S-MAC + S-DEK\\\nparticipant KLMS\\\nparticipant \\\"NetHSM\\\\\nMaster Key M\\\" as HSM\\\nnote left of KLMS : (continues) K1_M / K2_M already derived from L_M (see 1/2).\\\n\\\n== S-MAC (purpose 0x60, 10-B UID from station) ==\\\nKLMS -> KLMS : header = 00^11 ‖ 60 (purpose) ‖ 00 ‖ 0080 ‖ 01\\\nKLMS -> HSM : ECB(M, header)\\\nHSM --> KLMS : C1\\\nKLMS -> HSM : ECB(M, C1 ⊕ pad(UID, 16-B) ⊕ K2_M)\\\nHSM --> KLMS : C2 = **S-MAC**\\\nKLMS -> HSM : ImportKey(S-MAC)\\\nHSM --> KLMS : handle **SM**\\\n\\\n== S-DEK (purpose 0x70, 10-B UID from station) ==\\\nKLMS -> KLMS : header = 00^11 ‖ 70 (purpose) ‖ 00 ‖ 0080 ‖ 01\\\nKLMS -> HSM : ECB(M, header)\\\nHSM --> KLMS : C1\\\nKLMS -> HSM : ECB(M, C1 ⊕ pad(UID, 16-B) ⊕ K2_M)\\\nHSM --> KLMS : C2 = **S-DEK**\\\nKLMS -> HSM : ImportKey(S-DEK)\\\nHSM --> KLMS : handle **SD**\\\n@enduml\\\n```\\\n\\\n* * *\\\n\\\n## KDF/kdf-phase-b.puml — Phase B: session keys (full, Word page)\\\n\\\n```plantuml\\\n@startuml kdf-phase-b\\\n' Phase B - session keys: S-ENC/S-MAC -> SES-ENC/MAC/RMAC via AES-ECB CMAC.\\\nautonumber\\\ntitle Phase B — Session keys (key = SE / SM) -> SES-*\\\nparticipant KLMS\\\nparticipant \\\"NetHSM\\\" as HSM\\\n== session subkeys (RFC 4493) ==\\\nKLMS -> HSM : ECB(SE, 0^16)\\\nHSM --> KLMS : L_SE\\\nKLMS -> KLMS : K1_SE = dbl(L_SE)\\\nKLMS -> KLMS : K2_SE = dbl(K1_SE)\\\nKLMS -> HSM : ECB(SM, 0^16)\\\nHSM --> KLMS : L_SM\\\nKLMS -> KLMS : K1_SM = dbl(L_SM)\\\nKLMS -> KLMS : K2_SM = dbl(K1_SM)\\\nnote left of KLMS : session deriv data = 32 B = block1 ‖ block2\\\\\n(usage ‖ host_challenge ‖ card_challenge ‖ …)\\\\\nboth blocks full (16 B) -> last block XOR **K1**\\\\\n(K2 is used only for a *partial* last block, as in Phase A)\\\n== SES-ENC (usage 0x04) ==\\\nKLMS -> HSM : ECB(SE, block1)\\\nHSM --> KLMS : C1\\\nKLMS -> HSM : ECB(SE, C1 ⊕ block2 ⊕ K1_SE)\\\nHSM --> KLMS : C2 = **SES-ENC**  (-> station)\\\n== SES-MAC (usage 0x06) ==\\\nKLMS -> HSM : ECB(SM, block1)\\\nHSM --> KLMS : C1\\\nKLMS -> HSM : ECB(SM, C1 ⊕ block2 ⊕ K1_SM)\\\nHSM --> KLMS : C2 = **SES-MAC**  (-> station)\\\nKLMS -> HSM : ImportKey(SES-MAC)\\\nHSM --> KLMS : handle **SESMAC**\\\n== SES-RMAC (usage 0x07, reuse K1_SM) ==\\\nKLMS -> HSM : ECB(SM, block1)\\\nHSM --> KLMS : C1\\\nKLMS -> HSM : ECB(SM, C1 ⊕ block2 ⊕ K1_SM)\\\nHSM --> KLMS : C2 = **SES-RMAC**  (-> station)\\\n@enduml\\\n```\\\n\\\n* * *\\\n\\\n## KDF/kdf-phase-b-1.puml — Phase B (1/2): subkeys + SES-ENC (slide)\\\n\\\n```plantuml\\\n@startuml kdf-phase-b-1\\\n' Phase B (1/2): session subkeys + SES-ENC. Continues in kdf-phase-b-2.puml.\\\nautonumber\\\ntitle Phase B — Session keys (1/2): subkeys + SES-ENC\\\nparticipant KLMS\\\nparticipant \\\"NetHSM\\\" as HSM\\\n\\\n== session subkeys (RFC 4493) ==\\\nKLMS -> HSM : ECB(SE, 0^16)\\\nHSM --> KLMS : L_SE\\\nKLMS -> KLMS : K1_SE = dbl(L_SE)\\\nKLMS -> KLMS : K2_SE = dbl(K1_SE)\\\nKLMS -> HSM : ECB(SM, 0^16)\\\nHSM --> KLMS : L_SM\\\nKLMS -> KLMS : K1_SM = dbl(L_SM)\\\nKLMS -> KLMS : K2_SM = dbl(K1_SM)\\\nnote left of KLMS : session deriv data = 32 B = block1 ‖ block2\\\\\n(usage ‖ host_challenge ‖ card_challenge ‖ …)\\\\\nboth blocks full (16 B) -> last block XOR **K1**\\\\\n(K2 is used only for a *partial* last block, as in Phase A)\\\n\\\n== SES-ENC (usage 0x04) ==\\\nKLMS -> HSM : ECB(SE, block1)\\\nHSM --> KLMS : C1\\\nKLMS -> HSM : ECB(SE, C1 ⊕ block2 ⊕ K1_SE)\\\nHSM --> KLMS : C2 = **SES-ENC**  (-> station)\\\n@enduml\\\n```\\\n\\\n* * *\\\n\\\n## KDF/kdf-phase-b-2.puml — Phase B (2/2): SES-MAC + SES-RMAC (slide)\\\n\\\n```plantuml\\\n@startuml kdf-phase-b-2\\\n' Phase B (2/2): SES-MAC + SES-RMAC. Continues from kdf-phase-b-1.puml.\\\nautonumber\\\ntitle Phase B — Session keys (2/2): SES-MAC + SES-RMAC\\\nparticipant KLMS\\\nparticipant \\\"NetHSM\\\" as HSM\\\nnote left of KLMS : (continues) K1_SM / K2_SM already derived from L_SM (see 1/2).\\\n\\\n== SES-MAC (usage 0x06) ==\\\nKLMS -> HSM : ECB(SM, block1)\\\nHSM --> KLMS : C1\\\nKLMS -> HSM : ECB(SM, C1 ⊕ block2 ⊕ K1_SM)\\\nHSM --> KLMS : C2 = **SES-MAC**  (-> station)\\\nKLMS -> HSM : ImportKey(SES-MAC)\\\nHSM --> KLMS : handle **SESMAC**\\\n\\\n== SES-RMAC (usage 0x07, reuse K1_SM) ==\\\nKLMS -> HSM : ECB(SM, block1)\\\nHSM --> KLMS : C1\\\nKLMS -> HSM : ECB(SM, C1 ⊕ block2 ⊕ K1_SM)\\\nHSM --> KLMS : C2 = **SES-RMAC**  (-> station)\\\n@enduml\\\n```\\\n\\\n* * *\\\n\\\n## KDF/kdf-phase-c.puml — Phase C: cryptograms\\\n\\\n```plantuml\\\n@startuml kdf-phase-c\\\n' Phase C - cryptograms (key = SESMAC): verify card_cryptogram (gate) + host_cryptogram.\\\nautonumber\\\ntitle Phase C — Cryptograms (key = SESMAC)\\\nparticipant KLMS\\\nparticipant \\\"NetHSM\\\" as HSM\\\n== cryptogram subkeys (RFC 4493) ==\\\nKLMS -> HSM : ECB(SESMAC, 0^16)\\\nHSM --> KLMS : L\\\nKLMS -> KLMS : K1 = dbl(L)\\\nKLMS -> KLMS : K2 = dbl(K1)\\\nnote left of KLMS : cryptogram deriv data = 32 B = block1 ‖ block2\\\\\n(const ‖ host_challenge ‖ card_challenge ‖ …)\\\\\nboth blocks full (16 B) -> last block XOR **K1**\\\\\ncryptogram = CMAC tag truncated to 8 B\\\\\n(crates/kf-scp03/src/derive.rs)\\\n== card cryptogram verify (const 0x00) — GATE ==\\\nKLMS -> HSM : ECB(SESMAC, block1)\\\nHSM --> KLMS : C1\\\nKLMS -> HSM : ECB(SESMAC, C1 ⊕ block2 ⊕ K1)\\\nHSM --> KLMS : C2\\\nKLMS -> KLMS : card_crypto = C2[0:8]\\\nKLMS -> KLMS : compare card_crypto == fob **card_cryptogram**\\\nalt match\\\n  note right of KLMS #DFFFD6 : authenticated = true -> proceed\\\nelse mismatch\\\n  KLMS --> Station : auth error\\\\\n(no keys / container issued)\\\nend\\\n== host cryptogram (const 0x01, reuse K1/K2) ==\\\nKLMS -> HSM : ECB(SESMAC, block1)\\\nHSM --> KLMS : C1\\\nKLMS -> HSM : ECB(SESMAC, C1 ⊕ block2 ⊕ K1)\\\nHSM --> KLMS : C2\\\nKLMS -> KLMS : host_crypto = C2[0:8] = **host_cryptogram**  (-> station)\\\n@enduml\\\n```\\\n\\\n* * *\\\n\\\n## KDF/kdf-phase-d.puml — Phase D: A003 CBC + cleanup\\\n\\\n```plantuml\\\n@startuml kdf-phase-d\\\n' Phase D - A003 AES-CBC (key = SD, IV=0, ISO 9797-1 M2 pad) + handle cleanup.\\\n' HW-CONFIRMED: card accepts CBC(IV=0)+M2 and rejects ECB (6A80).\\\n' KLMS delivers CBC since 2026-08-17; station forwards the blob untouched.\\\nautonumber\\\ntitle Phase D — A003 AES-CBC (key = SD) + cleanup\\\nparticipant KLMS\\\nparticipant \\\"NetHSM\\\" as HSM\\\nnote left of KLMS : A003 encrypted with **S-DEK (SD)** — a static per-fob key,\\\\\nindependent of the session. IV = 0; host chains AES-CBC from\\\\\nsingle-block ECB (ISO 9797-1 Method 2 padding). SD never sent to station.\\\\\nVerified end-to-end 2026-08-17: GA ECDSA signatures pass\\\\\non provisioned fobs.\\\n== A003 encryption (AES-CBC, IV = 0) ==\\\nKLMS -> KLMS : pad 32-B scalar -> 48 B (ISO 9797-1 Method 2)\\\nKLMS -> HSM : ECB(SD, P1 ⊕ IV)\\\nHSM --> KLMS : C1\\\nKLMS -> HSM : ECB(SD, P2 ⊕ C1)\\\nHSM --> KLMS : C2\\\nKLMS -> HSM : ECB(SD, P3 ⊕ C2)\\\nHSM --> KLMS : C3\\\nKLMS -> KLMS : A003 = C1 ‖ C2 ‖ C3  (-> station, pre-encrypted)\\\n== Cleanup — destroy ephemeral handles ==\\\nKLMS -> HSM : Destroy(SE)\\\nKLMS -> HSM : Destroy(SM)\\\nKLMS -> HSM : Destroy(SD)\\\nKLMS -> HSM : Destroy(SESMAC)\\\nKLMS -> KLMS : zeroize all derived keys (RAM)\\\n@enduml\\\n```\\\n\\\n* * *\\\n\\\n## KDF/flow-2-provisioning.puml — full end-to-end (Word page)\\\n\\\n```plantuml\\\n@startuml flow-2-provisioning\\\n' Flow 2 - Provisioning: Key Fob <-> Station <-> KLMS (-> NetHSM)\\\n' Updated 2026-08-14: REST transport, seed-based generation, INIT UPDATE layout.\\\n' KDF detail: kdf-phase-a/b/c/d.puml\\\ntitle Flow 2 — Provisioning: Key Fob <-> Station <-> KLMS\\\nactor       \\\"Key Fob\\\\\n(NCJ37x)\\\"   as Fob\\\nparticipant Station               as Station\\\nparticipant KLMS                  as KLMS\\\nparticipant \\\"NetHSM\\\\\n(master key)\\\" as HSM\\\n== 0. Identify (station <-> fob) ==\\\nStation -> Fob : SELECT ISD\\\\\n00 A4 04 00 || A000000151000000\\\nStation -> Fob : GET DATA (OEF ID + UID)\\\nFob --> Station : OEF ID (B252) + UID\\\\\n(10-B JCOP UID; 7-B chip UID fallback)\\\n== 1. SCP03 initial handshake (station <-> fob) ==\\\nStation -> Fob : INITIALIZE UPDATE\\\\\n80 50 <KVN> 00 08 || host_challenge[8]\\\nFob --> Station : key_div_data[10] ‖ key_version ‖ scp_id ‖ i ‖\\\\\ncard_challenge[8] ‖ card_cryptogram[8] ‖ seq_counter[3]\\\\\nnote right: UID is NOT in this response (read in step 0)\\\n== 2. Container request (REST over mTLS; seed from POST /seeds at connect) ==\\\nStation -> KLMS : POST /cryptoContainers\\\\\nform{ typeID, seedUUID, productSerial=KF-<chip UID>,\\\\\n  extra{ transaction_id, station_id,\\\\\n  fob{oef, uid, key_version},\\\\\n  scp03{host_challenge, card_challenge,\\\\\n        sequence_counter, card_cryptogram},\\\\\n  keyBundleType } }\\\nalt HTTP 5xx / error\\\n  KLMS --> Station : error (HTTP 500 etc.)\\\\\nstation retries once without touching the card\\\nend\\\n== 3. KLMS derives keys via NetHSM (AES-ECB only; detail: kdf-phase-a/b/c/d.puml) ==\\\nnote right of KLMS : ~23 AES-ECB + 4 Import + 4 Destroy\\\\\n(master subkeys cacheable across transactions)\\\ngroup Phase A — KDF3 (key = M) : 7 ECB\\\n  KLMS -> HSM : 7 x ECB(M) -> S-ENC / S-MAC / S-DEK\\\n  KLMS -> HSM : ImportKey(S-ENC/MAC/DEK)\\\n  HSM --> KLMS : handles SE / SM / SD\\\nend\\\ngroup Phase B — session keys (key = SE / SM) : 8 ECB\\\n  KLMS -> HSM : 8 x ECB -> SES-ENC / SES-MAC / SES-RMAC   (-> station)\\\n  KLMS -> HSM : ImportKey(SES-MAC)\\\n  HSM --> KLMS : handle SESMAC\\\nend\\\ngroup Phase C — cryptograms (key = SESMAC) : 5 ECB — GATE\\\n  KLMS -> HSM : ECB(SESMAC) -> card_cryptogram\\\n  KLMS -> KLMS : verify == fob card_cryptogram\\\n  KLMS -> HSM : ECB(SESMAC) -> host_cryptogram   (-> station)\\\nend\\\ngroup Phase D — A003 AES-CBC (key = SD) : 3 ECB\\\n  KLMS -> HSM : 3 x ECB(SD) -> A003 ciphertext (CBC, IV=0, M2)\\\n  HSM --> KLMS : A003 ciphertext (pre-encrypted)\\\nend\\\n== 4. Container back to station (binary Clypeum container, wrapper-key encrypted) ==\\\nKLMS --> Station : container (13 TLV fields)\\\\\n{ UID, FESN, SPID, Authenticated,\\\\\n  S-ENC, S-MAC, S-RMAC, Host Cryptogram,\\\\\n  Private Key (A003 pre-encrypted),\\\\\n  Fob Pub Cert, IRK, ICA Cert, CMS Root Cert }\\\nStation -> Station : parse + decrypt (wrapper key from seed)\\\\\nverify card cryptogram locally (safety gate)\\\n== 5. Open secure channel (C-MAC) ==\\\nStation -> Fob : EXTERNAL AUTHENTICATE\\\\\n84 82 <level> 00 || host_cryptogram || MAC[8]\\\nFob --> Station : 9000   (channel open)\\\n== 6. Personalize — STORE DATA loop ==\\\nloop over DGI blocks (<= 245 B each, each C-MAC'd)\\\n  Station -> Fob : STORE DATA\\\\\n84 E2 <P1> <P2> || DGI payload || MAC[8]\\\n  Fob --> Station : 9000\\\nend\\\n== 7. Lifecycle transition ==\\\nStation -> Fob : STORE DATA (last)\\\\\n84 E2 80 <P2> 00 || MAC[8]\\\nnote over Fob : UNPERSONALIZED -> FACTORY\\\nFob --> Station : 9000\\\n== 8. Post-personalization (raw, no secure messaging) ==\\\nStation -> Fob : 00 DB 00 00 03 0A 01 01   (enable UICC)\\\nStation -> Fob : 00 DB 00 00 03 0B 01 01   (enable BLE)\\\nFob --> Station : 9000\\\n== 9. Result + audit — PENDING ==\\\nStation -> KLMS : provision result (report_usage)\\\\\n{ transaction_id, fesn, result,\\\\\n  stage_reached, apdu_count, timestamp }\\\\\nnote right #FFEEEE : NOT YET WIRED - awaiting KLMS\\\\\nstatus-value semantics (open item);\\\\\nlikely also populates productSerial\\\\\nin the KLMS admin\\\nStation -> Station : zeroize session keys\\\nnote over Station #E8FFE8\\\n  Station holds ONLY: ephemeral session keys\\\n  + pre-encrypted A003 (both zeroized after the transaction).\\\n  Never: master key, static keys, S-DEK.\\\nend note\\\nnote over HSM #FFEEEE : master key never leaves the NetHSM\\\n@enduml\\\n```\\\n\\\n* * *\\\n\\\n## KDF/flow-2-provisioning-1.puml — Flow 2a: Session establishment (slide)\\\n\\\n```plantuml\\\n@startuml flow-2-provisioning-1\\\n' Flow 2a - Provisioning (1/2): session establishment (slide-fit).\\\n' Updated 2026-08-14: REST transport, seed-based generation, INIT UPDATE layout.\\\n' Compact KDF block here; full per-phase detail in kdf-phase-a/b/c/d.puml\\\n' and the full-page flow-2-provisioning.puml.\\\n' Continues in flow-2-provisioning-2.puml (personalize & finalize).\\\ntitle Flow 2a — Provisioning (1/2): Session establishment\\\nactor       \\\"Key Fob\\\\\n(NCJ37x)\\\"   as Fob\\\nparticipant Station               as Station\\\nparticipant KLMS                  as KLMS\\\nparticipant \\\"NetHSM\\\\\n(master key)\\\" as HSM\\\n== 0. Identify (station <-> fob) ==\\\nStation -> Fob : SELECT ISD + GET DATA\\\nFob --> Station : OEF ID (B252) + UID\\\\\n(10-B JCOP UID; 7-B chip UID fallback)\\\n== 1. SCP03 initial handshake (station <-> fob) ==\\\nStation -> Fob : INITIALIZE UPDATE\\\\\n80 50 <KVN> 00 08 || host_challenge[8]\\\nFob --> Station : key_div_data[10] ‖ key_version ‖ scp_id ‖ i ‖\\\\\ncard_challenge[8] ‖ card_cryptogram[8] ‖ seq_counter[3]\\\n== 2. Container request (REST over mTLS; seed from POST /seeds at connect) ==\\\nStation -> KLMS : POST /cryptoContainers\\\\\nform{ typeID, seedUUID, productSerial, extra{...} }\\\nalt HTTP 5xx / error\\\n  KLMS --> Station : error — station retries once without touching the card\\\nend\\\n== 3. KLMS derives keys via NetHSM (AES-ECB only; detail: kdf-phase-a/b/c/d.puml) ==\\\nnote right of KLMS : ~23 AES-ECB + 4 Import + 4 Destroy per transaction\\\\\n(master subkeys cacheable across transactions)\\\nKLMS -> HSM : KDF3 (M + UID) -> S-ENC / S-MAC / S-DEK   (Phase A)\\\nKLMS -> HSM : session KDF -> SES-ENC / SES-MAC / SES-RMAC   (Phase B)\\\nKLMS -> HSM : verify card_cryptogram (SESMAC) -> authenticated   (Phase C, GATE)\\\nKLMS -> HSM : host_cryptogram   (Phase C)\\\nKLMS -> HSM : AES-CBC(SD) -> A003 ciphertext (pre-encrypted)   (Phase D)\\\nnote right of HSM #FFEEEE : master key M never leaves the NetHSM\\\n== 4. Container back to station (binary Clypeum container) ==\\\nKLMS --> Station : container (13 TLV fields)\\\\\n{ UID, FESN, SPID, Authenticated, S-ENC, S-MAC,\\\\\n  S-RMAC, Host Cryptogram, Private Key (A003\\\\\n  pre-encrypted), Fob Pub Cert, IRK, ICA, CMS Root }\\\nStation -> Station : parse + decrypt (wrapper key from seed)\\\\\nverify card cryptogram locally (safety gate)\\\nnote over Station #E8FFE8\\\n  Station now holds ONLY: ephemeral session keys\\\n  + pre-encrypted A003 (both zeroized after the transaction).\\\n  Never: master key, static keys, S-DEK.\\\nend note\\\n@enduml\\\n```\\\n\\\n* * *\\\n\\\n## KDF/flow-2-provisioning-2.puml — Flow 2b: Personalize & finalize (slide)\\\n\\\n```plantuml\\\n@startuml flow-2-provisioning-2\\\n' Flow 2b - Provisioning (2/2): personalize & finalize.\\\n' Continues from flow-2-provisioning-1.puml (session established).\\\ntitle Flow 2b — Provisioning (2/2): Personalize & finalize\\\nactor       \\\"Key Fob\\\\\n(NCJ37x)\\\"   as Fob\\\nparticipant Station               as Station\\\nparticipant KLMS                  as KLMS\\\nnote over Station : (continues from Flow 2a: holds session keys + pre-encrypted A003)\\\n== 5. Open secure channel (C-MAC) ==\\\nStation -> Fob : EXTERNAL AUTHENTICATE\\\\\n84 82 <level> 00 || host_cryptogram || MAC[8]\\\nFob --> Station : 9000   (channel open)\\\n== 6. Personalize — STORE DATA loop ==\\\nloop over DGI blocks (<= 245 B each, each C-MAC'd)\\\n  Station -> Fob : STORE DATA\\\\\n84 E2 <P1> <P2> || DGI payload || MAC[8]\\\n  Fob --> Station : 9000\\\nend\\\n== 7. Lifecycle transition ==\\\nStation -> Fob : STORE DATA (last)\\\\\n84 E2 80 <P2> 00 || MAC[8]\\\nnote over Fob : UNPERSONALIZED -> FACTORY\\\nFob --> Station : 9000\\\n== 8. Post-personalization (raw, no secure messaging) ==\\\nStation -> Fob : 00 DB 00 00 03 0A 01 01   (enable UICC)\\\nStation -> Fob : 00 DB 00 00 03 0B 01 01   (enable BLE)\\\nFob --> Station : 9000\\\n== 9. Result + audit — PENDING ==\\\nStation -> KLMS : provision result (report_usage)\\\\\n{ transaction_id, fesn, result,\\\\\n  stage_reached, apdu_count, timestamp }\\\nnote right #FFEEEE : NOT YET WIRED - awaiting KLMS\\\\\nstatus-value semantics (open item)\\\nStation -> Station : zeroize session keys\\\nnote over Station #E8FFE8\\\n  Station held ONLY: ephemeral session keys\\\n  + pre-encrypted A003 (both zeroized after the transaction).\\\n  Never: master key, static keys, S-DEK.\\\nend note\\\n@enduml\\\n```\\\n\\\n* * *\"],[1,\"Index + status for every PlantUML diagram. **Canonical sources live in the repo at\\\n> `docs/diagrams/`** (committed since a1c923e): `KDF/` (12 sets) and `HSM_Backup/`\\\n> (5 sets), each as `.puml` + rendered `.svg` + `.png`. The full embedded source\\\n> copies were dropped from this note once the repo became canonical (2026-08-18) —\\\n> edit the files, not the note. PPT/Word embeds use the **SVG**.\\\n> Companions: **Keyfob Flow 1**, **Keyfob Flow 2** (sequence detail), audit note.\\\n\\\n> **Review status (2026-08-18)**\\\n> - **KDF set: correct as drawn** — verified against kf-scp03 derive.rs,\\\n>   kf-provision perso.rs/helpers.rs, kf-source container.rs, nfc_reader.rs.\\\n>   Purposes 0x40/0x60/0x70, header `00^11‖p‖00‖0080‖01`, K1-full/K2-partial CMAC\\\n>   blocks, ECB counts (7+8+5+3=23), Phase D CBC chaining.\\\n> - **Phase D (A003 = AES-128-CBC, IV=0, M2) HW-confirmed**; KLMS delivers it since\\\n>   2026-08-17, station forwards untouched (ECB bridge removed).\\\n> - **HSM_Backup set**: wrap algorithm decided — **ECIES (ECDH P-256 → HKDF-SHA256 →\\\n>   AES-256-GCM)** for every ceremony/backup. Rationale: NitroHSM (SmartCard-HSM) is\\\n>   ECC-only → RSA-OAEP impossible for its two ceremonies; P-256 ECDH supported by\\\n>   YubiHSM2 (derive-ecdh), SmartCard-HSM, NXP. Implementation caveat: verify exact\\\n>   AEAD per SDK (YubiHSM native wrap = AES-CCM; SmartCard-HSM import = own AEAD).\\\n> - **2026-08-18 layout fix**: `hsm-topology` rearranged into three aligned rows\\\n>   (Ford | NXP; VM-1 | VM-2; YubiHSM-1 | YubiHSM-2 | NitroHSM) via `together` +\\\n>   hidden column-chain links + direction-hinted edges — plain `..>` arrows were\\\n>   fighting the row ranking in Graphviz.\\\n\\\n## Diagrams\\\n\\\n### docs/diagrams/KDF/ (12 sets)\\\n\\\n| File | Shows |\\\n| --- | --- |\\\n| `kdf-overview` | KDF phase overview — two-row flow (A003 feeds Phase D) |\\\n| `kdf-phase-a` / `-a-1` / `-a-2` | Phase A full + two slide halves (master+UID → static keys) |\\\n| `kdf-phase-b` / `-b-1` / `-b-2` | Phase B full + two slide halves (session keys) |\\\n| `kdf-phase-c` | Phase C — cryptograms (card-cg gate + host-cg) |\\\n| `kdf-phase-d` | Phase D — A003 AES-CBC(IV=0,M2) + cleanup |\\\n| `flow-2-provisioning` | Full end-to-end (Word full-page) |\\\n| `flow-2-provisioning-1` / `-2` | Flow 2a session establishment / 2b personalize & finalize (slides) |\\\n\\\n### docs/diagrams/HSM_Backup/ (5 sets)\\\n\\\n| File | Shows |\\\n| --- | --- |\\\n| `hsm-topology` | Deployment + key placement: three aligned rows — Ford/NXP, KLMS VM failover pair, YubiHSM-1/2 + NitroHSM |\\\n| `hsm-backup-pattern` | Universal transfer ceremony: ECIES (ECDH P-256 + HKDF + AES-256-GCM), ciphertext-only |\\\n| `decryption-key-create-and-backup` | Ford decrypt key: generated in YubiHSM-1, pubkey to Ford, ECIES backup to YubiHSM-2 |\\\n| `nxp-master-key-ceremony` | NXP master key: EC P-256 import keypair on NitroHSM, NXP ECIES-wraps M, decrypt-inside |\\\n| `nxp-master-key-backup` | NXP master key backup: NitroHSM → YubiHSM-1, same ECIES ceremony |\\\n\\\n## Rendering\\\n\\\n```sh\\\n# from the repo root — renders .svg + .png next to each .puml\\\npython scripts/render-puml.py docs/diagrams/KDF\\\npython scripts/render-puml.py docs/diagrams/HSM_Backup\\\n\\\n# local alternative (needs java + plantuml.jar)\\\nplantuml -tpng -tsvg <file>.puml\\\n```\\\n\\\nRendered via the public PlantUML server (deflate + map6 encoder).\\\n\\\n## Pending\\\n\\\n- Jan's manual `.puml` edits → re-render pass (`scripts/render-puml.py`) → SVGs into\\\n  the slideset → commit the touched sources + renders.\"]],\"start1\":43,\"start2\":43,\"length1\":31287,\"length2\":3432}]"
metadata_diff: {"new":{},"deleted":[]}
encryption_cipher_text: 
encryption_applied: 0
updated_time: 2026-08-18T13:51:39.656Z
created_time: 2026-08-18T13:51:39.656Z
is_locked: 0
type_: 13