## [1.0.0] #15

Merged
faicel merged 9 commits from fix/audit-2026-08-21-secu-C1 into dev 2026-08-21 11:02:17 +00:00
Owner

Security

  • Add repository-controlled cargo deny policy (root deny.toml) enforcing RustSec advisories, yanked crate detection, allowed registries (crates.io only), and license policy compatible with project dependencies
  • Enable mandatory cargo deny checks in all Forgejo workflows (enable_deny: true) for feature checks, tag creation, and publication gates
  • Document custom non-commercial license exception for root package with transparent justification in deny.toml

Fixed — Documentation and package metadata

  • Align README examples, dependency snippets and rustdoc/doctest imports with the real crate name atecc608x (public type names such as Atecc608b / Atecc608bError are unchanged). The compile_fail guards now exercise API privacy instead of failing on an unresolved crate name.
  • Cargo.toml now declares description, license-file and an exclude list so dev/CI-only artifacts (datasheet, .forgejo/, .specify/, .claude/,.cursor/, scripts/, .cargo/, .opencode-memory/) are not shipped in the published package; .opencode-memory/ is also git-ignored.
  • cargo clippy --all-features clean again: the four I²C word-address reference aliases in constants::config are test-only fixtures (all consumers are unit tests) and are now #[cfg(test)], so they are excluded from library builds entirely instead of being dead-code-allowed.
  • Correct the TempKey ECDH section: only ephemeral_ecdh_tempkey is public; generate_ephemeral_keypair_tempkey is crate-internal and ecdh_with_tempkey is test-only. Remove the stale SharedSecret::into_bytes owning-copy mention.
  • CLAUDE.md CI/CD section now describes the five real Forgejo workflows.

Fixed — Validate request_id stable across lock-data

  • validation_config_fingerprint SHA-256s Config with LockValue forced to
    0x00. HSM export prepares Validate while Data is unlocked (0x55); execute runs after lock-data (0x00). Binding the raw Config invalidated every offline validation_request_id across that intentional lock.

Fixed — stored-key ECDH mode for blank ATECC608B

  • ECDH_MODE_STORED_CLEAR_OUTPUT is now 0x00 (CryptoAuthLib ECDH_PREFIX_MODE) instead of TFLXTLS Table 5-43 mode 0x0C. Blank Rev03 silicon returns ExecutionError (surfaced as TempKeyInvalid) for mode 0x0C.
  • Nonce Random before ECDH for ReqRandom slots is unchanged.

Fixed — Slot-8 personalization without Data-zone reads

  • While Config is locked and Data/OTP unlocked, Data reads return
    ExecutionError. Added write_public_key_for_verify_personalization
    (block writes, no read-back) and prepare_stored_public_key_validation(..., known_public_key) so Validate prep can use the host-known factory key without reading the slot.
  • execute_stored_public_key_validation skips pre/post marker reads while
    Data unlocked (Verify success is the gate). write_data_slot_personalization is public for clear Data writes without read-back.

Fixed — stored-key ECDH satisfies KeyConfig.ReqRandom

  • ecdh now issues Nonce Random (Idle) before stored-key ECDH (awake),matching Sign/GenKey. Slot 0 (ReqRandom = 1) previously returned ExecutionError (mapped as TempKeyInvalid) during verify.

Fixed — GenKey Public/Private satisfy KeyConfig.ReqRandom

  • get_public_key and generate_keypair now issue Nonce Random (Idle) before GenKey, then GenKey while awake (Sleep after), matching sign_with_random_nonce. The Random command alone does not set
    TempKey.SourceFlag = Rand; slots with ReqRandom = 1 previously returned ExecutionError for both empty and occupied slots.

Fixed — Data-zone 36-byte R/W while Data unlocked

- Partial last-block access on slots 0–7 no longer uses 4-byte word Read/Write while `LockValue == 0x55` (silicon `ExecutionError`). Reads always take the partial tail via a 32-byte block; unlocked writes RMW that block. Block capacity checks allow block 1 on 36-byte slots (datasheet two-block access).

Fixed — Linux I²C padded status no longer maps to InvalidLength

  • read_and_validate_response accepts received_len >= count (ignore padded tail) instead of requiring equality. Linux i2c-dev reports the master-requested buffer length while a device error still has count = 4,
    which previously failed as InvalidLength before status parsing.

Added — optional generic provisioning surface

  • Add the opt-in Cargo feature provisioning; the default build retains only runtime discovery, crypto, counter and Data-zone functionality.
  • Gate slot-profile builders, verified Config writes and irreversible lock
    workflows behind provisioning.
  • Add ProvisioningConfig, a typed exact 128-byte image exposing documented
    identity/revision, I²C configuration, CountMatch, ChipMode, counter image,UseLock, ChipOptions/ECDHPROT, X509format, SlotConfig and KeyConfig.
  • Add a generic verified full-image application workflow. It refuses changes
    to silicon identity, counter storage and lock bytes, writes complete Config words only, verifies every write, and performs a final full-image comparison.
  • Keep all product layouts, expected values and configAtecc business rules
    outside the crate.

Breaking — ATECC608B Protocol Correction

This is a BREAKING correction of the generic configurable ATECC608B I²C protocol implementation. There is no backward compatibility with prior APIs, ATECC608A-oriented behavior,
TNG/TFLXTLS profiles, or old slot layouts. Legacy surfaces are removed, not deprecated.

Transport

  • Wake reply is now read as exactly four bytes 04 11 33 43. CRC is verified over [0x04, 0x11] and compared to 0x4333 LE. The previous length-6/length-7 wake helpers and the 04 11 33 44 fixture are removed and rejected.
  • Response read uses AteccTransport for one contiguous bounded read, reports the actual received length and requires it to be at least count (padded tails from Linux i2c-dev master over-reads are ignored). The read is bounded by the command's expected reply . Split count-then-rest is forbidden unless hardware-proven and documented. No 0x03 (Command word address) write before the response read.
  • Strict response shapes: Info Revision count=7 data [1..5]; 32-byte payload commands count=35 data [1..33]; GenKey/Sign count=67 data [1..65]; status/error count=4 status [1]. Status-prefixed data success shapes are rejected. check_response() runs only on count=4 packets.

Execution / retry policy

  • Execution uses one command write, the command-mode deadline, then one bounded response read; commands are never rewritten merely to poll readiness.
  • Retry policy is now defined by operation + mode + volatile state, not opcode alone. GenKey(Public) is retry-eligible; GenKey(Private) is not.
  • Transport writes classify NotAccepted versus MayHaveBeenAccepted. After possible write acceptance, the following are never retransmitted: Write, Lock, Counter(increment), GenKey(Private), UpdateExtra, TempKey-consuming ECDH. An unqualified HAL write fault on those maps to OutcomeUnknown.

Config Zone decoding

  • Authoritative offsets: SN [0..4]+[8..13], ChipMode 19, SlotConfig 20..52,Counter0 52..60, Counter1 60..68, UseLock 68, LockValue 86, LockConfig 87,
    SlotLocked 88..90 LE active-low (bit clear = locked), ChipOptions 90..92 LE,KeyConfig 96..128.
  • The previous approximate mappings (SlotLocked at 64..66, ChipMode at 88, UseLockderived from 82) are removed.

Lock APIs

  • Removed from public surface: lock_zone(), lock_config_without_crc().
  • Config lock (only public path): read image → compare to caller expected → compute Summary CRC in-lib → Lock with CRC → re-read require LockConfig == 0x00.
  • Data lock without CRC kept under an explicit name + typed caller confirmation bound to device SN + Config fingerprint.
  • lock_slot(KeySlot): verify SlotLocked bit 1 → 0; refuse non-lockable/already-locked.
  • Summary CRC is covered by four independent CryptoAuthLib 3.7.9 vectors with recorded source revision and inputs.

Data Zone

- Exact Data-zone APIs use `KeySlot`; unchecked public numeric-slot and padded convenience surfaces are removed. Capacities are 36 (0–7) / 416 (8) / 72 (9–15), including 4-byte word tails.
  • No implicit zero-pad past the requested range. Before every verified write, the current Config is checked for clear read-back, unauthenticated clear write and slot-lock state; unsupported policy is refused before mutation. RMW remains explicitly non-atomic.

P-256 / secrets / volatile cleanup

  • SEC1 on-curve validation enforced for host and device-produced points.
  • GenKey/read/ephemeral public keys and device-produced signatures return checked P256PublicKey / P256Signature values rather than raw arrays.
  • SharedSecret: borrow or copy-into-caller-clearing-buffer only. No public owning copy API (into_bytes removed). No Debug/Clone. Zeroize on Drop.
  • TempKey/MsgDigBuf sequences use Idle only across dependent commands and Sleep at terminal exits. Failed Idle forces Sleep; cleanup-after-success and dual failures remain distinct.
  • Removed unused crate-private MsgDigBuf Verify / 64-byte Nonce fallbacks (verify_only_*_with_msgdigbuf, nonce_fixed_msgdigbuf_64). Stored/external Verify stays on TempKey; MsgDigBuf remains for Sign only.

API surface

  • Raw command and Config-block writers are pub(crate)/private. Public slot operations use KeySlot; compile-fail tests enforce the intended surface.
  • Layout-agnostic: no configAtecc constants, slot maps, or business policy in src/.

Breaking — ATECC608B driver hardening

This is a BREAKING refactor with no legacy compatibility layers. All public APIs changed by this section are incompatible with the previous release; callers must update.

I²C transport

  • I²C word addresses normative: Reset = 0x00, Sleep = 0x01, Idle = 0x02,
    Command = 0x03. The old SWI-derived values (Idle = 0xBB, Sleep = 0xCC) are removed.
  • Wake reply must be exactly 04 11 33 43 followed by a valid CRC. The previously accepted 04 11 33 44 pattern is now rejected with InvalidResponse (bad pattern) or CrcMismatch (bad CRC).
  • Response read no longer writes a 0x03 (Command word address) byte before reading. The driver reads count first, then exactly count-1 bytes, and validates the CRC over response[0..count].
  • Wake failures are distinguishable: WakeTokenFailed (host failed to assert the wake token / I²C write error), DeviceNotResponding (device did not answer), CrcMismatch / InvalidResponse (bad wake reply).

Retry policy

  • Non-idempotent commands (GenKey, Write, Lock, TempKey ECDH, Counter) are never retransmitted after the command packet has been accepted by the device. If thevreply is lost or corrupt after acceptance, the driver returns Atecc608bError::OutcomeUnknown (execution may have occurred without a validated reply).
  • Idempotent commands (Info, Random, SelfTest, Read) are retried up to 3 times on transient status errors.

Error type

  • New variant OutcomeUnknown.
  • New variant WakeTokenFailed.
  • DeviceNotResponding now specifically indicates a wake/read I²C failure (not a bad reply).

KeySlot

  • impl From<u8> for KeySlot removed. Use KeySlot::new(u8) -> Result<KeySlot, KeySlotError> or KeySlot::try_from(u8).

SharedSecret

  • Redesigned as SharedSecret(Zeroizing<[u8; 32]>): zeroizes on drop.
  • Debug and Clone derives removed.
  • Access via as_bytes() -> &[u8; 32] (borrowed) or copy_into a caller-owned zeroizing buffer; there is deliberately no owning-copy API (into_bytes is removed).
  • All public ECDH success paths (ecdh, ephemeral_ecdh_tempkey) return SharedSecret instead of [u8; 32].

P-256 validation

  • SEC1 on-curve validation is enforced before every ECDH, Verify, and public-key write.Off-curve peer keys are rejected with InvalidPublicKey before any I²C command isissued. Usesp256::PublicKey::from_sec1_bytes.

Lock APIs

  • New LockState type (from_config(&[u8; 128])) exposes config_locked(), data_locked(), and slot_locked(slot).
  • New lock APIs in setup: lock_config_with_crc,lock_config_without_crc, lock_data_without_crc, lock_slot(KeySlot) with post-verification.
  • Summary CRC (summary_crc) implemented with CryptoAuthLib-compatible reference vectors.

Strict response parsers

  • SelfTest, Info, GenKey, Read, Nonce, ECDH, Verify parsers now reject undocumented dual response shapes. Previously tolerated malformed packets now return InvalidResponse or InvalidLength.

Added — Ephemeral P-256 TempKey ECDH

  • ephemeral_ecdh_tempkey: atomic ephemeral P-256 key agreement via TempKey. Generates an ephemeral keypair in volatile TempKey, immediately performs ECDH with a peer public key, and returns (ephemeral_public_xy[64], shared_secret[32]).
    Guarantees: no host code between GenKey and ECDH; Idle between commands preserves TempKey; Sleep on all exit paths; no EEPROM/data-zone slot writes.
  • generate_ephemeral_keypair_tempkey (crate-internal): GenKey into TempKey, returns 64-byte public X‖Y. Does not ECDH. Used internally by ephemeral_ecdh_tempkey; split TempKey primitives stay private per the contract.
  • ecdh_with_tempkey (test-only, #[cfg(test)]): ECDH using the current TempKey private key. Verifies ECDHPROT on every call. Fails with TempKeyInvalidif TempKey is not valid. The public surface exposes only the atomicephemeral_ecdh_tempkey` flow.
  • OutputProtectionRequired error variant: returned when ChipOptions.ECDHPROT forbids clear ECDH output.
  • TempKeyInvalid error variant: returned when ECDH is attempted without a valid TempKey (consumed by prior ECDH, or invalidated by Sleep/power loss).
  • New constants: ECDH_MODE_TEMPKEY_CLEAR_OUTPUT (0x0D), GENKEY_MODE_TEMPKEY_IN_TEMPKEY(0x04), GENKEY_TEMPKEY_KEYID_LO/HI(0xFF/0xFF), CHIPOPTIONS_OFFSET,CHIPOPTIONS_ECDHPROT_MASK/SHIFT, CHIPOPTIONS_ECDHPROT_CLEAR_ALLOWED`.
  • README atomic usage example + lifecycle warnings.
  • 24 new mock I2C tests covering wire bytes, atomic sequence, fail-closed behavior, and TempKey lifecycle.

Silicon validation checklist — hardening

  • Bus capture: verify wake reply is exactly 04 11 33 43 + CRC; confirm NO 0x03 byte is written before response reads; confirm word addresses 0x00/0x01/0x02/0x03.
  • Retry policy: inject NACK after write acceptance of GenKey/Write/Lock; assert the driver returns OutcomeUnknown and does NOT retransmit.
  • SEC1 on-curve: feed an off-curve peer key to ecdh/verify/write_public_key; assert InvalidPublicKey before any I²C ECDH/Verify/Write command appears on the bus.
  • SharedSecret zeroization: confirm the shared secret buffer is zeroed after drop (debugger memory inspection or mprotect guard page on test harness).
  • Cut tests: on locked devices, verify lock_config_with_crc refuses a wrong CRC and lock_slot post-verifies the SlotLock by re-reading the lock state.
  • Sleep current: confirm the device enters low-power Sleep (0x01) at the end of every logical transaction (no Idle leak except between GenKey→ECDH in ephemeral_ecdh_tempkey).
### Security - Add repository-controlled `cargo deny` policy (root `deny.toml`) enforcing RustSec advisories, yanked crate detection, allowed registries (crates.io only), and license policy compatible with project dependencies - Enable mandatory `cargo deny` checks in all Forgejo workflows (`enable_deny: true`) for feature checks, tag creation, and publication gates - Document custom non-commercial license exception for root package with transparent justification in deny.toml ### Fixed — Documentation and package metadata - Align README examples, dependency snippets and rustdoc/doctest imports with the real crate name `atecc608x` (public type names such as `Atecc608b` / `Atecc608bError` are unchanged). The `compile_fail` guards now exercise API privacy instead of failing on an unresolved crate name. - `Cargo.toml` now declares `description`, `license-file` and an `exclude` list so dev/CI-only artifacts (datasheet, `.forgejo/`, `.specify/`, `.claude/`,`.cursor/`, `scripts/`, `.cargo/`, `.opencode-memory/`) are not shipped in the published package; `.opencode-memory/` is also git-ignored. - `cargo clippy --all-features` clean again: the four I²C word-address reference aliases in `constants::config` are test-only fixtures (all consumers are unit tests) and are now `#[cfg(test)]`, so they are excluded from library builds entirely instead of being dead-code-allowed. - Correct the TempKey ECDH section: only `ephemeral_ecdh_tempkey` is public; `generate_ephemeral_keypair_tempkey` is crate-internal and `ecdh_with_tempkey` is test-only. Remove the stale `SharedSecret::into_bytes` owning-copy mention. - `CLAUDE.md` CI/CD section now describes the five real Forgejo workflows. ### Fixed — Validate request_id stable across lock-data - `validation_config_fingerprint` SHA-256s Config with `LockValue` forced to `0x00`. HSM export prepares Validate while Data is unlocked (`0x55`); execute runs after `lock-data` (`0x00`). Binding the raw Config invalidated every offline `validation_request_id` across that intentional lock. ### Fixed — stored-key ECDH mode for blank ATECC608B - `ECDH_MODE_STORED_CLEAR_OUTPUT` is now `0x00` (CryptoAuthLib `ECDH_PREFIX_MODE`) instead of TFLXTLS Table 5-43 mode `0x0C`. Blank Rev03 silicon returns `ExecutionError` (surfaced as TempKeyInvalid) for mode `0x0C`. - Nonce Random before ECDH for ReqRandom slots is unchanged. ### Fixed — Slot-8 personalization without Data-zone reads - While Config is locked and Data/OTP unlocked, Data reads return `ExecutionError`. Added `write_public_key_for_verify_personalization` (block writes, no read-back) and `prepare_stored_public_key_validation(..., known_public_key)` so Validate prep can use the host-known factory key without reading the slot. - `execute_stored_public_key_validation` skips pre/post marker reads while Data unlocked (Verify success is the gate). `write_data_slot_personalization` is public for clear Data writes without read-back. ### Fixed — stored-key ECDH satisfies KeyConfig.ReqRandom - `ecdh` now issues Nonce Random (Idle) before stored-key ECDH (awake),matching Sign/GenKey. Slot 0 (`ReqRandom = 1`) previously returned `ExecutionError` (mapped as TempKeyInvalid) during `verify`. ### Fixed — GenKey Public/Private satisfy KeyConfig.ReqRandom - `get_public_key` and `generate_keypair` now issue Nonce Random (Idle) before GenKey, then GenKey while awake (Sleep after), matching `sign_with_random_nonce`. The Random command alone does not set `TempKey.SourceFlag = Rand`; slots with `ReqRandom = 1` previously returned `ExecutionError` for both empty and occupied slots. ### Fixed — Data-zone 36-byte R/W while Data unlocked - Partial last-block access on slots 0–7 no longer uses 4-byte word Read/Write while `LockValue == 0x55` (silicon `ExecutionError`). Reads always take the partial tail via a 32-byte block; unlocked writes RMW that block. Block capacity checks allow block 1 on 36-byte slots (datasheet two-block access). ### Fixed — Linux I²C padded status no longer maps to InvalidLength - `read_and_validate_response` accepts `received_len >= count` (ignore padded tail) instead of requiring equality. Linux `i2c-dev` reports the master-requested buffer length while a device error still has `count = 4`, which previously failed as `InvalidLength` before status parsing. ### Added — optional generic provisioning surface - Add the opt-in Cargo feature `provisioning`; the default build retains only runtime discovery, crypto, counter and Data-zone functionality. - Gate slot-profile builders, verified Config writes and irreversible lock workflows behind `provisioning`. - Add `ProvisioningConfig`, a typed exact 128-byte image exposing documented identity/revision, I²C configuration, `CountMatch`, `ChipMode`, counter image,`UseLock`, `ChipOptions`/`ECDHPROT`, X509format, `SlotConfig` and `KeyConfig`. - Add a generic verified full-image application workflow. It refuses changes to silicon identity, counter storage and lock bytes, writes complete Config words only, verifies every write, and performs a final full-image comparison. - Keep all product layouts, expected values and `configAtecc` business rules outside the crate. ### Breaking — ATECC608B Protocol Correction This is a **BREAKING** correction of the generic configurable ATECC608B I²C protocol implementation. There is **no backward compatibility** with prior APIs, ATECC608A-oriented behavior, TNG/TFLXTLS profiles, or old slot layouts. Legacy surfaces are removed, not deprecated. #### Transport - **Wake reply** is now read as exactly **four bytes** `04 11 33 43`. CRC is verified over `[0x04, 0x11]` and compared to `0x4333` LE. The previous length-6/length-7 wake helpers and the `04 11 33 44` fixture are **removed** and rejected. - **Response read** uses `AteccTransport` for one **contiguous bounded read**, reports the actual received length and requires it to be **at least** `count` (padded tails from Linux i2c-dev master over-reads are ignored). The read is bounded by the command's expected reply . Split count-then-rest is **forbidden** unless hardware-proven and documented. No `0x03` (Command word address) write before the response read. - **Strict response shapes**: Info Revision `count=7` data `[1..5]`; 32-byte payload commands `count=35` data `[1..33]`; GenKey/Sign `count=67` data `[1..65]`; status/error `count=4` status `[1]`. Status-prefixed data success shapes are **rejected**. `check_response()` runs only on `count=4` packets. #### Execution / retry policy - Execution uses one command write, the command-mode deadline, then one bounded response read; commands are never rewritten merely to poll readiness. - Retry policy is now defined by **operation + mode + volatile state**, not opcode alone. `GenKey(Public)` is retry-eligible; `GenKey(Private)` is not. - Transport writes classify `NotAccepted` versus `MayHaveBeenAccepted`. After possible write acceptance, the following are **never retransmitted**: Write, Lock, Counter(increment), GenKey(Private), UpdateExtra, TempKey-consuming ECDH. An unqualified HAL write fault on those maps to `OutcomeUnknown`. #### Config Zone decoding - Authoritative offsets: SN `[0..4]+[8..13]`, ChipMode `19`, SlotConfig `20..52`,Counter0 `52..60`, Counter1 `60..68`, UseLock `68`, LockValue `86`, LockConfig `87`, **SlotLocked `88..90` LE active-low** (bit clear = locked), ChipOptions `90..92` LE,KeyConfig `96..128`. - The previous approximate mappings (SlotLocked at `64..66`, ChipMode at `88`, UseLockderived from `82`) are **removed**. #### Lock APIs - **Removed** from public surface: `lock_zone()`, `lock_config_without_crc()`. - Config lock (only public path): read image → compare to caller expected → compute Summary CRC in-lib → Lock with CRC → re-read require `LockConfig == 0x00`. - Data lock without CRC kept under an explicit name + typed caller confirmation bound to device SN + Config fingerprint. - `lock_slot(KeySlot)`: verify SlotLocked bit `1 → 0`; refuse non-lockable/already-locked. - Summary CRC is covered by four independent CryptoAuthLib 3.7.9 vectors with recorded source revision and inputs. #### Data Zone - Exact Data-zone APIs use `KeySlot`; unchecked public numeric-slot and padded convenience surfaces are removed. Capacities are 36 (0–7) / 416 (8) / 72 (9–15), including 4-byte word tails. - No implicit zero-pad past the requested range. Before every verified write, the current Config is checked for clear read-back, unauthenticated clear write and slot-lock state; unsupported policy is refused before mutation. RMW remains explicitly non-atomic. #### P-256 / secrets / volatile cleanup - SEC1 on-curve validation enforced for host and device-produced points. - GenKey/read/ephemeral public keys and device-produced signatures return checked `P256PublicKey` / `P256Signature` values rather than raw arrays. - `SharedSecret`: borrow or copy-into-caller-clearing-buffer **only**. No public owning copy API (`into_bytes` removed). No `Debug`/`Clone`. Zeroize on Drop. - TempKey/MsgDigBuf sequences use Idle only across dependent commands and Sleep at terminal exits. Failed Idle forces Sleep; cleanup-after-success and dual failures remain distinct. - Removed unused crate-private MsgDigBuf Verify / 64-byte Nonce fallbacks (`verify_only_*_with_msgdigbuf`, `nonce_fixed_msgdigbuf_64`). Stored/external Verify stays on TempKey; MsgDigBuf remains for Sign only. #### API surface - Raw command and Config-block writers are `pub(crate)`/private. Public slot operations use `KeySlot`; compile-fail tests enforce the intended surface. - Layout-agnostic: no `configAtecc` constants, slot maps, or business policy in `src/`. ### Breaking — ATECC608B driver hardening This is a **BREAKING** refactor with **no legacy compatibility layers**. All public APIs changed by this section are incompatible with the previous release; callers must update. #### I²C transport - **I²C word addresses** normative: `Reset = 0x00`, `Sleep = 0x01`, `Idle = 0x02`, `Command = 0x03`. The old SWI-derived values (`Idle = 0xBB`, `Sleep = 0xCC`) are removed. - **Wake reply** must be exactly `04 11 33 43` followed by a valid CRC. The previously accepted `04 11 33 44` pattern is now **rejected** with `InvalidResponse` (bad pattern) or `CrcMismatch` (bad CRC). - **Response read** no longer writes a `0x03` (Command word address) byte before reading. The driver reads `count` first, then exactly `count-1` bytes, and validates the CRC over `response[0..count]`. - **Wake failures are distinguishable**: `WakeTokenFailed` (host failed to assert the wake token / I²C write error), `DeviceNotResponding` (device did not answer), `CrcMismatch` / `InvalidResponse` (bad wake reply). #### Retry policy - **Non-idempotent commands** (`GenKey`, `Write`, `Lock`, TempKey `ECDH`, `Counter`) are **never retransmitted** after the command packet has been accepted by the device. If thevreply is lost or corrupt after acceptance, the driver returns `Atecc608bError::OutcomeUnknown` (execution may have occurred without a validated reply). - Idempotent commands (`Info`, `Random`, `SelfTest`, `Read`) are retried up to 3 times on transient status errors. #### Error type - New variant `OutcomeUnknown`. - New variant `WakeTokenFailed`. - `DeviceNotResponding` now specifically indicates a wake/read I²C failure (not a bad reply). #### `KeySlot` - `impl From<u8> for KeySlot` **removed**. Use `KeySlot::new(u8) -> Result<KeySlot, KeySlotError>` or `KeySlot::try_from(u8)`. #### `SharedSecret` - Redesigned as `SharedSecret(Zeroizing<[u8; 32]>)`: zeroizes on drop. - `Debug` and `Clone` derives **removed**. - Access via `as_bytes() -> &[u8; 32]` (borrowed) or `copy_into` a caller-owned zeroizing buffer; there is deliberately **no owning-copy API** (`into_bytes` is removed). - All public ECDH success paths (`ecdh`, `ephemeral_ecdh_tempkey`) return `SharedSecret` instead of `[u8; 32]`. #### P-256 validation - **SEC1 on-curve validation** is enforced before every ECDH, Verify, and public-key write.Off-curve peer keys are rejected with `InvalidPublicKey` **before** any I²C command isissued. Uses`p256::PublicKey::from_sec1_bytes`. #### Lock APIs - New `LockState` type (`from_config(&[u8; 128])`) exposes `config_locked()`, `data_locked()`, and `slot_locked(slot)`. - New lock APIs in `setup`: `lock_config_with_crc`,`lock_config_without_crc`, `lock_data_without_crc`, `lock_slot(KeySlot)` with post-verification. - Summary CRC (`summary_crc`) implemented with CryptoAuthLib-compatible reference vectors. #### Strict response parsers - `SelfTest`, `Info`, `GenKey`, `Read`, `Nonce`, `ECDH`, `Verify` parsers now reject undocumented dual response shapes. Previously tolerated malformed packets now return `InvalidResponse` or `InvalidLength`. ### Added — Ephemeral P-256 TempKey ECDH - **`ephemeral_ecdh_tempkey`**: atomic ephemeral P-256 key agreement via TempKey. Generates an ephemeral keypair in volatile TempKey, immediately performs ECDH with a peer public key, and returns `(ephemeral_public_xy[64], shared_secret[32])`. Guarantees: no host code between GenKey and ECDH; Idle between commands preserves TempKey; Sleep on all exit paths; no EEPROM/data-zone slot writes. - **`generate_ephemeral_keypair_tempkey`** _(crate-internal)_: GenKey into TempKey, returns 64-byte public `X‖Y`. Does not ECDH. Used internally by `ephemeral_ecdh_tempkey`; split TempKey primitives stay private per the contract. - **`ecdh_with_tempkey`** _(test-only, `#[cfg(test)]`)_: ECDH using the current TempKey private key. Verifies `ECDHPROT` on every call. Fails with TempKeyInvalid`if TempKey is not valid. The public surface exposes only the atomic`ephemeral_ecdh_tempkey` flow. - **`OutputProtectionRequired`** error variant: returned when `ChipOptions.ECDHPROT` forbids clear ECDH output. - **`TempKeyInvalid`** error variant: returned when ECDH is attempted without a valid TempKey (consumed by prior ECDH, or invalidated by Sleep/power loss). - New constants: `ECDH_MODE_TEMPKEY_CLEAR_OUTPUT` (`0x0D`), `GENKEY_MODE_TEMPKEY_IN_TEMPKEY`(`0x04`), `GENKEY_TEMPKEY_KEYID_LO/HI(`0xFF/0xFF`), `CHIPOPTIONS_OFFSET`,`CHIPOPTIONS_ECDHPROT_MASK/SHIFT`, `CHIPOPTIONS_ECDHPROT_CLEAR_ALLOWED`. - README atomic usage example + lifecycle warnings. - 24 new mock I2C tests covering wire bytes, atomic sequence, fail-closed behavior, and TempKey lifecycle. ### Silicon validation checklist — hardening - **Bus capture**: verify wake reply is exactly `04 11 33 43 + CRC`; confirm NO `0x03` byte is written before response reads; confirm word addresses `0x00`/`0x01`/`0x02`/`0x03`. - **Retry policy**: inject NACK after write acceptance of `GenKey`/`Write`/`Lock`; assert the driver returns `OutcomeUnknown` and does NOT retransmit. - **SEC1 on-curve**: feed an off-curve peer key to `ecdh`/`verify`/`write_public_key`; assert `InvalidPublicKey` before any I²C ECDH/Verify/Write command appears on the bus. - **SharedSecret zeroization**: confirm the shared secret buffer is zeroed after drop (debugger memory inspection or mprotect guard page on test harness). - **Cut tests**: on locked devices, verify `lock_config_with_crc` refuses a wrong CRC and `lock_slot` post-verifies the SlotLock by re-reading the lock state. - **Sleep current**: confirm the device enters low-power Sleep (`0x01`) at the end of every logical transaction (no Idle leak except between GenKey→ECDH in `ephemeral_ecdh_tempkey`).
Update CI workflows to improve versioning and tagging processes. Refactor existing YAML files for better clarity and maintainability, and enhance documentation in README.md to reflect recent changes.
Some checks failed
Run checks on feature branches / rust-crate-checks (push) Failing after 19s
Run checks on feature branches / checks (push) Failing after 0s
2d4ef96069
- Introduced the `zeroize` crate to ensure sensitive ECDH shared secrets are zeroed on drop, enhancing security.
- Updated `Cargo.toml` to include `zeroize` with `default-features = false` for `no_std` compatibility.
- Modified `CHANGELOG.md` to reflect this addition and its implications for security.
- Enhanced error handling in `src/error.rs` to distinguish between wake token generation failures and device response issues.
- Updated documentation and comments across various modules to clarify changes and maintain consistency.
Refactor ATECC608 driver to support ATECC608B with new features and breaking changes
Some checks failed
Run checks on feature branches / rust-crate-checks (push) Failing after 28s
Run checks on feature branches / checks (push) Failing after 0s
59afefac40
- Updated driver implementation to support the ATECC608B Secure Element, including renaming from `atecc608x` to `atecc608b`.
- Introduced a new optional `provisioning` feature for typed Config images, slot profiles, and verified Config writes.
- Enhanced error handling with new error types specific to ATECC608B, improving clarity in failure scenarios.
- Updated documentation across README.md, CHANGELOG.md, and various modules to reflect changes and new functionalities.
- Adjusted `.gitignore` to track new specification markdown files for feature 003.
- Implemented breaking changes in the API, including modifications to command handling and response validation.
- Updated Cargo.toml and Cargo.lock to reflect version changes and new dependencies.
- Renamed crate from `atecc608b` to `atecc608x` and updated version to `1.0.0`.
- Added `deny.toml` for cargo-deny security and policy configuration, enforcing RustSec advisories and license policies.
- Enhanced `.gitignore` to exclude local SQLite DB files and other development artifacts.
- Updated documentation in `README.md` and `CHANGELOG.md` to reflect new features and changes.
- Improved error handling and response validation in the driver implementation.
- Adjusted Cargo.toml and Cargo.lock to reflect new dependencies and versioning.
Remove deprecated Git extension files and update .gitignore to exclude new directories. This includes the removal of settings, rules, and configuration files related to the Git integration, streamlining the project structure.
All checks were successful
Validate branch flow / validate-flow (pull_request_target) Successful in 2s
Validate branch flow / validate (pull_request_target) Successful in 0s
5714f6b0c8
Merge branch 'dev' into fix/audit-2026-08-21-secu-C1
All checks were successful
Validate branch flow / validate-flow (pull_request_target) Successful in 1s
Validate branch flow / validate (pull_request_target) Successful in 0s
64cb584fcf
faicel deleted branch fix/audit-2026-08-21-secu-C1 2026-08-21 11:02:17 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
homeiot/atecc608x!15
No description provided.