Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsCommunityBlog
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

Back to skills

Factory Flashing

ASecurity

Use when working on the SEC.3 factory-flashing pipeline — provisioning per-device keys into an STM32 at manufacture (app/services/factory_flashing/, lib/tasks/factory.rake): the one-pass silicon UID→DID derivation [FW.54], the wrong-board guard, UID collision → quarantine, the six Flash key blocks and their magics, word→big-endian byte order [FW.30], the chain-hashed audit trail, and the 2-Person supervisor rule. ⚠️ Гілка B / SE05x is EMIT-ONLY today — the provisioner writes textual legacy AT...

23 stars
0 votes
0 copies
0 views
Added 9/20/2026
developmentgorailsgitbackendsecurity

Works with

climcp

Security Analysis

A100/100

Scanned 9/20/2026

Install to Claude Code

$npx -y skills add Alexey-Lukin/silken_net --skill factory-flashing --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Factory Flashing?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Factory Flashing
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/alexey-lukin-factory-flashing/badge)](https://www.skillsdirectory.com/skills/alexey-lukin-factory-flashing)

More formats (shields.io, HTML) on the badges page.

Download Zip
Files
SKILL.md
---
name: factory-flashing
description: "Use when working on the SEC.3 factory-flashing pipeline — provisioning per-device keys into an STM32 at manufacture (app/services/factory_flashing/, lib/tasks/factory.rake): the one-pass silicon UID→DID derivation [FW.54], the wrong-board guard, UID collision → quarantine, the six Flash key blocks and their magics, word→big-endian byte order [FW.30], the chain-hashed audit trail, and the 2-Person supervisor rule. ⚠️ Гілка B / SE05x is EMIT-ONLY today — the provisioner writes textual legacy ATECC calls and no real transport, so a unit flashed by it gets no Flash KEYL and bricks; treat any SE05x request as blocked, not supported. Routes to 03_06 §5 + 03_01 §7, does not restate. Examples: \"why did factory:flash raise CollisionError\", \"add a key slot\", \"the backend DID does not match the silicon\", \"provision a new board\", \"what does the flashing session do, in order\", \"why is Гілка B not usable\"."
---

# Factory Flashing (SEC.3)

Burns per-device keys into a Soldier/Queen at manufacture, then locks the chip (RDP).
Navigation aid — the **SSOT is the code + docs below**; this skill points, it does not restate.

## SSOT Documents — Read These First

| Document | What it covers |
|----------|---------------|
| `docs/03_06_Factory_Flashing_and_Key_Provisioning.md` | THE factory home (split from 03_05 §3.4): pipeline Гілки A/B, HKDF per-device derivation, K_ota, §5 ops-security (2-Person Rule, master-key delivery variants, SEC.3 status) |
| `docs/03_05_Hardware_Symmetric_Crypto_and_Security.md` | Crypto modes, SE050 (SEC.6), key rotation, RDP (SEC.2) |
| `docs/00_07_Action_Plan_Tracker.md` | `SEC.3` (bench SWD + Bitwarden live — residuals), `SEC.2` (RDP Level 2) |

## Pipeline (entry → exit)

Entry: **`lib/tasks/factory.rake`** → **[FW.54] one-pass UID→DID at `factory:flash`**:
for a Tree the `device_uid` arg = **24-hex silicon UID** (NOT a DID) →
`SilkenNet::DidDerivation.wire_did_from_uid_hex` → `TreeResolver.resolve!`
(create with `CLUSTER_ID`+`TREE_FAMILY_ID` env / re-flash / bind legacy /
DID-collision → `CollisionError` = **quarantine**, `03_01 §7`); the session's
`device_uid` = derived wire-DID. Bare `SNET-` DID accepted only for a Tree
that already has `trees.silicon_uid_hex`; Gateway path unchanged.

Then **`FactoryFlashing::Session.run`** (after **supervisor-approved**). One `ActiveRecord::Base.transaction`:

1. **Preflight** — session `may_start?` + device exists + master key fetched into `@master_key` (fail fast before the tx; the result is NOT discarded — SEC.3 DI).
2. **Wrong-board guard [FW.54]** — `CommandBuilder.preflight_commands` (connect + `-r32 0x1FFF7590 12`) runs FIRST; live mode parses stdout via `UidReadout` and compares the board's UID to `trees.silicon_uid_hex` **before any derivation or `-w32`** — mismatch/unparseable → `WrongBoardError` (not even a HardwareKey row materializes). dry-run or passport-less device → skip.
3. **Master key** — `MasterKeySource` (Env or Bitwarden adapter); `WeakKeyDetector` refuses a weak key. The fetched key threads as `master_key:` param into every derivation below (runtime callers of the same services use the ENV fallback instead).
4. **HardwareKey** — `HardwareKeyService.provision(device, master_key:)` (the SINGLE HKDF source — same derivation the firmware runs; never derive keys elsewhere).
5. **ATECC (Гілка B + Tree only)** — `SecureElementProvisioner` emits the I²C ATCA write-zone transcript.
6. **Commands** — `CommandBuilder#flash_commands` (key writes + RDP + disconnect; connect/UID-read already ran as preflight).
7. **Execute** — `Executor` (dry-run prints; `--execute` spawns subprocesses).
8. **Audit** — `AuditTrail.record!` → chain-hashed `AuditLog` (metadata incl. `silicon_uid_hex`) + `MaintenanceRecord`; `complete!` (or `fail_with!` + rollback).

## Key Components

| Component | Role |
|-----------|------|
| `app/services/factory_flashing/session.rb` | Orchestrator (`run`, `preflight!`, `verify_silicon_uid!` wrong-board guard, AASM start!/complete!/fail_with!) |
| `app/services/factory_flashing/tree_resolver.rb` | [FW.54] UID→DID→Tree: create / re-flash / bind / collision→quarantine; deliberately does NOT enqueue peaq (offline factory) |
| `app/services/factory_flashing/uid_readout.rb` | [FW.54] tolerant `-r32` stdout parser (keyed on `1FFF7590`); live format = bench-confirm (RUNBOOK 1.3) |
| `app/services/factory_flashing/command_builder.rb` | `STM32_Programmer_CLI` emission (`preflight_commands` class-method: connect+UID-read; `flash_commands` per гілка, `write_block`, `rdp_command`) |
| `app/services/factory_flashing/secure_element_provisioner.rb` | ATECC608B data-zone provisioning (Гілка B) |
| `app/services/factory_flashing/executor.rb` | dry-run vs live subprocess (`programmer_available?`) |
| `app/services/factory_flashing/master_key_source.rb` | `Base` / `EnvAdapter` / `BitwardenAdapter` master-key fetch — the fetched key feeds HKDF via `Session` (SEC.3 DI), not just the preflight gate |
| `app/services/factory_flashing/audit_trail.rb` | chain-hashed audit log record |
| `ota_hmac_key_service.rb` | per-cluster OTA HMAC key `fetch_for(cluster_id, master_key: nil)` (Гілка A KOTA block + Гілка B ATECC provisioning) |

> Line numbers drift every commit — grep/read `Session` for live locations rather than a hardcoded table (`[[feedback_no_volatile_counts]]`).

## Gotchas Not Obvious From Code

1. **Гілка A vs Гілка B (ARCH.42 variants, post-SEC.14 2026-07-03)** — A = keys written into **Protected Flash** via SWD (`-w32`). B = **Гілка A + SE05x identity-chip**: KEYL still goes to Protected Flash in BOTH branches (`03_06 §1`); the SE adds only the Ed25519 voice / cert / anti-clone serial, **NOT** the LoRa key (SEC.14 = provisioning-only). ⚠️ The current `gilka_b_commands` is still the **legacy ATECC-model** (skip-key-writes, only RDP-lock + disconnect) — a known code-lag pending the SE050 eval-kit (`00_07` SE050-MIGRATION); a Гілка-B unit flashed by today's code would have **no Flash KEYL → brick**.
2. **Flash layout MUST match firmware** — `CommandBuilder` addresses/magics mirror `firmware/soldier/main.c` `FLASH_KEY_ADDR` (post-ARCH.42): `KEYL`(0x4B45594C)+aes@`0x0803E000`, `LSED`(0x4C534544)+k_seed@`0x0803E014` (Tree), `KEYC`(0x4B455943)+coap@`0x0803E040`, `EDSK`(0x4544534B)+ed25519_seed@`0x0803E064` (Gateway, L1 QATT), `KOTA`(0x4B4F5441)+k_ota@`0x0803E800` (Tree, FW.23), `KEYB`(0x4B455942)+bcast@`0x0803E828` (Tree, FW.2 (в) cluster control-plane). Drift here ⇒ device can't read its own key. Change one side → change both + host tests. Word→BE-bytes convention (FW.30): firmware unpacks each `-w32` word MSB-first — naive memcpy on LE Cortex-M4 reverses every word.
3. **Dry-run is the default; live is the SEC.3 residual** — real `STM32_Programmer_CLI` execution + **RDP Level 2** (`SEC.2`, irreversible chip lock) are bench-gated, not yet run on hardware.
4. **Key shapes** — Tree: 32-hex AES-128 LoRa key **+** 64-hex Lorenz `K_seed`; Gateway: 64-hex AES-256 CoAP key **+** 32-hex broadcast key written to the LoRa `KEYL` slot (FW.2 (в), post-2026-07-03 — Queen's single control-plane key = the `KEYB` broadcast value; the pre-fix «LoRa slot unused» bricked her at boot) **+** optional 64-hex Ed25519 seed (L1 QATT «голос Королеви» — generated by `Session` on the factory host, NOT HKDF; only the pubkey persists in `HardwareKey`). `CommandBuilder#validate!` enforces this.
5. **Transaction + chain-hash integrity** — the whole run is one AR transaction; a downstream raise rolls back HardwareKey + audit rows together, so rolled-back rows never enter the chain-hashed `AuditLog` (the chain stays intact).
6. **Supervisor gate** — `Session` refuses to run unless the `ProvisioningSession` is `supervisor_approved` (preflight `may_start?`).
7. **Never add WeakKeyDetector to the ENV-fallback branch** of the derivation services — the rails_helper test pin (`silken-net-test-master-key-32b!!`) is itself a placeholder *needle* in the detector, so validating inside `hkdf_derive`/`fetch_for`/`derive_seed` fails the whole suite. Coverage is already two-layer by design: `EnvAdapter` guards the factory path, the boot initializer (`master_key_strength_check.rb`) guards runtime.
8. **[FW.54] UID wire-form is frozen** — 24 hex = three `%08X` words in register order (`0x1FFF7590` first), exactly how firmware `did_derive.h` reads them; golden pair `0039002F3138511538323634 → SNET-80B12004` frozen in `did_derivation_spec` ↔ `firmware/test/test_soldier_logic.c`. Reordering/re-endianing the parse = a different DID on backend vs silicon (keys diverge silently).
9. **DID is derived EVERYWHERE by one function** — `wire_did_from_uid_hex` feeds both the factory (`TreeResolver`) and the field `ProvisioningController#register` (the old `last(8)`-suffix DID + the dead tree double-init guard were a real prod bug, fixed 2026-07-03). Never invent a third derivation path.
10. **Collision ≠ re-flash** — same derived DID + different `silicon_uid_hex` = birthday collision or wrong chip → `CollisionError`, unit goes to quarantine (`03_01 §7`); same UID = legit re-flash (idempotent no-op).

## How to Explore

1. grep/read `Session` — orchestrator callers/callees
2. grep `factory flashing` across `app/services/` — related flows
3. Read `command_builder.rb` for the exact CLI sequence; `03_06 §5` for the threat model

Attribution

Alexey-LukinAlexey-Lukin
View sourceMore from Alexey-Lukin →
SSkills DirectorySkills Directory

Your tool, in front of Claude Code builders.

3 founder slots · $299/mo · GSC-verified traffic · sponsors can never buy grades.

See placements

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Your tool, in front of Claude Code builders.

3 founder slots · $299/mo · GSC-verified traffic · sponsors can never buy grades.

See placements

Related Skills

Browser Extension Developer

Use this skill when developing or maintaining browser extension code in the `browser/` directory, including Chrome/Firefox/Edge compatibility, content scripts, background scripts, or i18n updates.

281612 votes

Seo Optimizer

SEO optimization with keyword analysis, readability assessment, technical validation, content quality. Use for search rankings, blog posts, content audits, or encountering keyword density, readability scores, meta tags, schema markup errors.

2132 votes

Google Official Seo Guide

Official Google SEO guide covering search optimization, best practices, Search Console, crawling, indexing, and improving website search visibility based on official Google documentation

1862 votes

Tanstack Start

Build a full-stack TanStack Start app on Cloudflare Workers from scratch — SSR, file-based routing, server functions, D1+Drizzle, better-auth, Tailwind v4+shadcn/ui. Use whenever the user mentions TanStack Start, asks to scaffold a full-stack Cloudflare app with SSR, wants an SSR dashboard, or asks for a React 19 + Cloudflare Workers app with file-based routing and server functions — even if they don't name TanStack Start specifically. No template repo — Claude generates every file fresh per ...

9881 votes

Pentest

PTES-aligned adversarial security audit for backend, frontend, and mobile applications. Produces a CVSS-scored Hacker Report with verified PoCs and phased remediation.

5491 votes
View all in development →