SID Remix Workflow — From HVSC to Finished Production

## Project Overview

**End-of-Line (EoL) provisioning station** that writes key material to NFC key fobs using **Secure Channel Protocol 03 (SCP03)**. Built in **Rust** for **Windows**, communicating with industrial-grade NFC readers via USB.

| Detail | Value |
|---|---|
| OEM | Ford |
| KLMS | SecOps "Clypeum" |
| Language | Rust |
| Target OS | Windows |
| Protocol | GlobalPlatform SCP03 |
| Smart Card Platform | JCOP 4 |
| Hardware | Industrial NFC reader via USB (CCID) |

---

## Architecture

### Final System Architecture

The EoL station is a **lean APDU pipeline**:

1. Read fob UID via `pcsc`
2. POST UID to Clypeum KLMS via REST API (mTLS)
3. KLMS returns pre-diversified static keys + Ford's payload
4. Perform session KDF (Phase 2) in software
5. SCP03 wrap → inject key material → lock ISD → zeroize memory

### Key Design Decision: KLMS Does All KDF

The architecture evolved from local Nitrokey HSM-based key derivation to having the **Clypeum KLMS server perform all KDF**. The EoL station is considered an untrusted factory floor environment.

**Phase 1 (NXP KDF3)** — Performed by Clypeum inside their HSM:
- Master Key → S-ENC, S-MAC, S-DEK using AES-CMAC
- Labels: `00000001` (ENC), `00000002` (MAC), `00000003` (DEK)
- Context: 10-byte JCOP UID
- Key length: `0080` (128-bit)

**Phase 2 (GP SCP03)** — Performed by EoL station in RAM:
- Static keys → Session keys (SES-ENC, SES-MAC, SES-RMAC) using AES-CMAC
- Context: `SeqCnt(3 bytes) || RND.IC(8 bytes) || RND.CC(8 bytes)`

---

## SCP03 Protocol Flow

> **Reference:** [GlobalPlatform Card Spec v2.3 Amendment D — Secure Channel Protocol 03 (GPC_2.3_D_SCP03)](https://globalplatform.org/specs-library/?filter-committee=se)

### Step 1: INITIALIZE UPDATE
- Command: `80 50 00 00 08 [Key Version] 00 00 00`
- Response contains: Host Challenge (RND.IC), Card Challenge (RND.CC), Key Info, Sequence Counter (SeqCnt)

### Step 2: Derive Session Keys
- SES-ENC, SES-MAC, SES-RMAC derived from static keys + SeqCnt + RND.IC + RND.CC
- Uses AES-CMAC (RustCrypto `cmac` crate)

### Step 3: EXTERNAL AUTHENTICATE
- Calculate Host Cryptogram: `AES-CMAC(S-MAC, RND.IC || RND.CH || RND.CC)`
- Wrap APDU: encrypt data with S-ENC (AES-CBC, ISO 9797-1 Method 2 padding), append MAC with S-MAC
- Command: `84 82 00 00 [Lc] [Encrypted Data] [MAC]`
- Success: `90 00`

### Step 4: Secure Messaging (Wrap/Unwrap)
For every subsequent APDU:
1. Increment local Sequence Counter
2. Pad payload (ISO 9797-1 Method 2)
3. Encrypt with SES-ENC (AES-CBC, IV=0)
4. Calculate MAC over header + encrypted payload using SES-MAC
5. Append MAC

### Step 5: Key Injection
- Send Ford's payload via STORE DATA (`80 DA ...`) or PUT KEY (`80 D8 ...`) APDU
- Must be SCP03-wrapped

### Step 6: ISD Lock (Defense-in-Depth)
- Lock Issuer Security Domain: `80 F0 0F 00 00` (SCP03-wrapped)
- Cryptographically invalidates static keys
- Makes RAM exposure window (~400ms) negligible

---

## KLMS API Contract

### Request (EoL → Clypeum)
```json
{
  "fob_uid": "112233445566778899AA",
  "reader_id": "LINE_04_READER_01"
}
```

### Response (Clypeum → EoL)
```json
{
  "transaction_id": "trx_889900",
  "key_version": 3,
  "scp03_static_keys": {
    "enc": "A1B2C3D4E5F600A1B2C3D4E5F60011",
    "mac": "A1B2C3D4E5F600A1B2C3D4E5F60022",
    "dek": "A1B2C3D4E5F600A1B2C3D4E5F60033"
  },
  "ford_payload": {
    "apdu_cla_ins_p1_p2": "80DA0100",
    "data_hex": "F1E2D3..."
  }
}
```

### Audit Response (EoL → Clypeum)
```json
{
  "transaction_id": "trx_889900",
  "fob_uid": "11223344556677",
  "timestamp_iso8601": "2023-10-27T14:32:01.123Z",
  "overall_result": "SUCCESS",
  "stage_reached": "PAYLOAD_DELIVERY",
  "apdu_trace": [
    {"direction": "TX", "apdu_hex": "8050000008000300000000"},
    {"direction": "RX", "apdu_hex": "0000314A2B3C...9000", "sw1": "90", "sw2": "00"}
  ],
  "eol_station_id": "LINE-04-PC-12"
}
```

---

## Roles & Responsibilities

| Role | Entity | Responsibility |
|---|---|---|
| OEM | Ford | Provides application data to be stored on fob |
| Card Issuer | Supplier (us) | Manages SCP03 channel keys, provisions card, locks ISD |
| KLMS | SecOps (Clypeum) | Stores master keys, performs KDF, delivers static keys + payload |
| EoL Station | Our Rust app | PC/SC pipe, session KDF, SCP03 state machine, audit reporting |

Ford has **no involvement** in card management keys.

---

## Key Diversification (JCOP 4)

> **Reference:** [NXP AN10922 — Symmetric Key Diversifications](https://www.nxp.com/docs/en/application-note/AN10922.pdf)

### KDF3 Input Structure (Phase 1)
```
[Counter: 01] || [Label: 00 00 00 01/02/03] || [Separator: 00] || [Context: 10-byte UID] || [Length: 00 80]
```

### Session Key Context (Phase 2)
```
SeqCnt (3 bytes) || RND.IC (8 bytes) || RND.CC (8 bytes)
```

The 10-byte UID from JCOP is only part of the diversification data. Remaining bytes are **issuer-defined** (Ford/security policy) and can include random nonces, batch IDs, or system constants. Must be consistent between KLMS and card.

---

## NFC Reader Recommendations

### Development
- **ACS ACR1252U** — Widely compatible, CCID compliant, successor to end-of-life ACR122U
- **ACS ACR1255U-J1** — Compact alternative

### Production (Industrial Grade)
- **ACS ACR1281U-C1 DualBoost II** — Dual-interface (contact/contactless), ISO 7816 + ISO 14443, 24/7 rated
- **HID OMNIKEY 5027 CL** — Enterprise/industrial durability, CCID compliant

### Selection Criteria
- CCID compliance (generic Windows driver, no vendor drivers)
- ISO 14443 A/B support
- Extended Length APDU support (most industrial readers support this)
- Panel-mount form factor for production

---

## Rust Technology Stack

| Crate | Purpose |
|---|---|
| `pcsc` | Windows Smart Card API (WinSCard.dll) |
| `aes` | AES encryption (RustCrypto) |
| `cmac` | AES-CMAC for key derivation and MACing |
| `cbc` | AES-CBC for APDU encryption |
| `serde` / `serde_json` | KLMS JSON parsing |
| `reqwest` | KLMS REST API client (with mTLS) |
| `zeroize` | Secure memory wiping after ISD lock |
| `hex` | APDU debugging |
| `tracing` | Structured logging |

### Key Code: Memory Zeroization
```rust
use zeroize::Zeroize;

struct CardStaticKeys {
    s_enc: [u8; 16],
    s_mac: [u8; 16],
    s_dek: [u8; 16],
}

impl Zeroize for CardStaticKeys {
    fn zeroize(&mut self) {
        self.s_enc.zeroize();
        self.s_mac.zeroize();
        self.s_dek.zeroize();
    }
}
```

### Key Code: Session Key Derivation
```rust
use aes::Aes128;
use cmac::{Cmac, Mac};

type Aes128Cmac = Cmac<Aes128>;

let mut mac = Aes128Cmac::new_from_slice(&s_enc).unwrap();
mac.update(&build_kdf3_input(Label::Enc, &session_context));
let ses_enc = mac.finalize().into_bytes();
```

---

## Error Handling (APDU Status Words)

| SW1/SW2 | Meaning | Action |
|---|---|---|
| `90 00` | Success | Proceed |
| `69 82` | Security status not satisfied | Halt — wrong key/MAC. Flag for review. |
| `6A 86` | Incorrect P1/P2 | Halt — bug in APDU construction |
| `67 00` | Wrong length | Halt — bug in APDU construction |
| `6D 00` | Instruction not supported | Halt — wrong applet selected? |
| `65 81` | Memory failure | Halt — defective card |
| `63 CX` | Verify fail, X retries left | Analyze — `63 C0` = permanently locked |

---

## Windows-Specific Considerations

- Use **generic Windows CCID driver** (`infocard.dll`) — do not install vendor proprietary drivers
- Handle `Error::RemovedCard` gracefully for flaky NFC fields
- Standard APDU max = 255 bytes; use Extended Length APDUs if payload is larger
- Sequence counter is 3 bytes, Big-Endian (watch for byte order bugs)

---

## Items to Confirm with SecOps/Clypeum

- [ ] REST API contract (request/response JSON format)
- [ ] Mutual TLS (mTLS) for KLMS↔EoL network link
- [ ] Exact NXP KDF3 byte layout (UID padding: raw, left-padded, or right-padded)
- [ ] Exact APDU for Ford's data injection (STORE DATA vs PUT KEY)
- [ ] Key Version strategy (how to know which version the fob expects)
- [ ] Audit payload format and Ford compliance requirements
- [ ] TTL on issued key packages (recommended: 5 seconds)
- [ ] KLMS logging and audit trail capabilities

---

## Development Sequence

1. Procure **ACS ACR1252U** for dev; **ACR1281U-C1** and **HID OMNIKEY 5027 CL** for production eval
2. Build minimal Rust CLI using `pcsc` — connect to reader, send SELECT/GET DATA APDU
3. Implement session key derivation (Phase 2) with unit tests against GlobalPlatform test vectors
4. Implement full SCP03 state machine: INITIALIZE UPDATE → session keys → EXTERNAL AUTHENTICATE → secure messaging
5. Integrate KLMS REST API client (`reqwest` with mTLS)
6. Implement ISD locking and memory zeroization
7. End-to-end test on both development and production readers

---

*Source: Z.ai chat session (2025-06-08)*

id: edfafe932d814a59bbcccdd91b9056e0
parent_id: d28c711605dd482bac3a3ab61163a4cd
created_time: 2026-05-31T12:58:01.163Z
updated_time: 2026-06-08T07:39:23.362Z
is_conflict: 0
latitude: 0.00000000
longitude: 0.00000000
altitude: 0.0000
author: 
source_url: 
is_todo: 0
todo_due: 0
todo_completed: 0
source: joplin-desktop
source_application: net.cozic.joplin-desktop
application_data: 
order: 1780232281163
user_created_time: 2026-05-31T12:58:01.163Z
user_updated_time: 2026-06-08T07:39:23.362Z
encryption_cipher_text: 
encryption_applied: 0
markup_language: 1
is_shared: 0
share_id: 
conflict_original_id: 
master_key_id: 
user_data: 
deleted_time: 0
type_: 1