Skip to content

[Task][Device] Implement configurable automatic LOCK policy #140

Description

@miso-develop

Parent spec

#137

Decision dependency

Owner

  • ACTIVE_ROLE: implementation
  • DOMAIN: device

State

READY_FOR_IMPLEMENTATION

Objective

Implement the Device side of the configurable automatic LOCK policy exactly as defined by Decision #138, including Vault Format 1 read compatibility and Vault Format 2 support.

Final functional contract from #138

  • Timer basis: fixed maximum continuous UNLOCKED lifetime, not inactivity timeout.
  • Unset/absent setting = disabled/unlimited.
  • Enabled value = whole integer days 1..31.
  • Timer starts at the original transition into UNLOCKED.
  • Ordinary interaction, USB/Web Serial activity, OTP reveal/hide, navigation, management, or time sync never resets/extends it.
  • Setting changes during an active session are recalculated against the original UNLOCKED start time.
  • Expiry must use the same security boundary as explicit Lock.

Persistence / compatibility contract

Version tuple

Implement without changing:

  • PROTOCOL_VERSION = 2
  • STORAGE_SCHEMA_VERSION = 2

Add/support:

  • legacy Vault Format 1 read/runtime support
  • current Vault Format 2 read/runtime/write support
  • unknown newer Vault formats fail closed

Do not add a plaintext auto_lock_days NVS key or separate unauthenticated settings store.

Vault Format 1

Preserve the shipped v0.1.0 PT1/AAD1 behavior byte-for-byte.

  • Format-1 plaintext still ends after credentials + optional Wi-Fi.
  • Exact end-of-input remains mandatory.
  • Decoding Format 1 yields logical auto_lock_days = unset.
  • Do not reinterpret PT1 trailing bytes as extensions.

Vault Format 2

Implement the Decision #138 PT2 structure:

M5AUTH-VLT-PT2\0
u16 format = 2
credential_count + credential records   // same semantics/order as PT1
wifi_present + optional wifi record      // same semantics/order as PT1
u8 auto_lock_present
  0 => disabled/unset, end
  1 => following u8 auto_lock_days (1..31)
other presence/value => invalid
exact end required

Use Format-2-specific authenticated AAD domain (M5AUTH-VLT-AAD2\0 or equivalent explicit domain) binding Format 2 + Storage Schema 2 + vault_id + generation. Retain the existing Format-1 AAD domain for Format-1 decrypt/authentication.

Accepted format transitions in Device canonical update path

  • current F1 -> candidate F1: allowed for legacy compatible Web while current persisted state is F1
  • current F1 -> candidate F2: allowed
  • current F2 -> candidate F2: allowed
  • current F2 -> candidate F1: reject as ordinary-update format downgrade
  • any unsupported/unknown format: reject fail-closed

Generation, vault_id, AEAD, state, and existing atomic-commit checks remain authoritative in addition to the format-transition rule.

Protocol 2 capability advertisement

Add non-secret optional capability metadata to hello:

"supported_vault_formats": [1, 2]

The existing vault_format_version field continues to report the currently persisted Vault format.

Do not reinterpret supported_vault_formats as persisted state. It describes firmware capability.

Protocol version stays 2: this is additive compatibility/status metadata and the encrypted-envelope update operation remains the existing Protocol-2 operation.

v0.1.0 firmware-update behavior

A normal firmware update from v0.1.0 must:

  • preserve Schema-2 NVS and the existing Format-1 envelope;
  • initialize/read/report Format 1 successfully;
  • start LOCKED after reboot as before;
  • permit normal V1 unlock/runtime use;
  • treat automatic Lock as disabled until a Format-2 canonical generation is committed.

Device must not autonomously migrate Format 1 on boot or unlock. Web/canonical management owns the migration transaction.

Active runtime setting

  • On successful unlock of Format 1: effective auto_lock_days = unset.
  • On successful unlock of Format 2: transiently decrypt/validate the Vault and derive the effective optional day value; retain only bounded non-secret runtime policy/deadline state, not the decrypted Vault.
  • On successful F1->F2 or F2->F2 vault.update, derive/apply the newly committed setting only after the new authenticated generation has committed successfully.
  • Apply setting changes against the current session's original UNLOCKED start timestamp.
  • If enabling/shortening the value makes the current session already expired, invoke the explicit-Lock security boundary immediately after successful commit/application.
  • A failed/ambiguous Vault update must not change the effective automatic-lock policy to an uncommitted candidate value.

Scope

  • Add dual Format-1/Format-2 Vault codec/authentication support required above.
  • Add optional auto_lock_days to the logical Device Vault model for Format 2.
  • Keep Format-1 logical mapping as disabled/unset.
  • Add safe format-transition validation to Runtime / Protocol-2 update handling.
  • Advertise supported_vault_formats: [1, 2] in hello.
  • Consume and validate optional auto_lock_days: absent/null = disabled; 1..31 = enabled; otherwise reject.
  • Track the original current-session UNLOCKED start time using a monotonic runtime source suitable for multi-day intervals.
  • Enforce the deadline without relying on mutable wall-clock/NTP time.
  • On automatic expiry, transition through the same security boundary as explicit Lock.
  • Apply committed setting changes immediately according to [Decision] Define configurable automatic-lock semantics #138.
  • Preserve normal firmware-update compatibility with existing v0.1.0 Format-1 state.

Acceptance criteria

Format / compatibility

  • Existing synthetic and shipped-contract Format-1 vectors still decode/authenticate unchanged.
  • Format-1 exact-end behavior remains unchanged; appended unknown data is rejected.
  • Format-1 runtime maps to automatic Lock disabled/unset.
  • Format-2 encode/decode uses the PT2 framing and exact-end contract from [Decision] Define configurable automatic-lock semantics #138.
  • Format-2 absent setting is accepted as disabled.
  • Format-2 values 1 and 31 are accepted; 0, >31, invalid presence, truncated, malformed, or trailing data are rejected.
  • Format-1 and Format-2 use distinct correct AAD domains and cannot be cross-authenticated by version substitution.
  • Runtime/Protocol accepts F1->F1, F1->F2, F2->F2 according to normal generation rules.
  • Runtime/Protocol rejects F2->F1 downgrade even with a numerically newer generation.
  • Unknown newer Vault format fails closed without Factory Reset or speculative migration.
  • Storage Schema remains 2; no destructive NVS migration is introduced.
  • Protocol remains 2 and hello advertises supported_vault_formats: [1, 2] while vault_format_version reports persisted format.
  • Normal update from an actual/synthetic v0.1.0 Format-1 persisted snapshot initializes safely and returns LOCKED without data loss.

Automatic LOCK behavior

  • Missing/Format-1 setting behaves exactly like v0.1.0: no automatic lifetime limit.
  • A fresh unlock starts one continuous-lifetime timer.
  • User/device/Web activity does not restart or extend the timer.
  • Deadline enforcement uses monotonic elapsed runtime and is independent of trusted-time/NTP adjustments.
  • On automatic expiry, visible OTP is hidden immediately and runtime reaches LOCKED.
  • Automatic expiry wipes VMK/session/secret-bearing transient state to the same standard as explicit Lock.
  • OTP reveal and credential access are rejected after automatic Lock until valid re-unlock.
  • Re-unlock starts a new lifetime.
  • Disabled -> N days during an active session uses the original unlock start; if already beyond N days, Device locks immediately after successful application.
  • N -> M days recalculates against the same original unlock start and never grants a fresh M-day interval.
  • Enabled -> disabled cancels the current automatic deadline only after the disabling generation is successfully committed/applied.
  • Failed/rejected update leaves the previous committed policy in force.
  • Reboot/power-loss/explicit-Lock behavior remains unchanged.
  • Normal later firmware update preserves a committed Format-2 setting while reboot still returns the Device to LOCKED.

Tests

  • Native/interoperability vectors cover PT1/AAD1 and PT2/AAD2.
  • Runtime tests cover format-transition matrix, downgrade rejection, malformed Format 2, and legacy Format-1 boot/unlock.
  • Protocol tests cover capability advertisement and F1/F2 envelope acceptance/rejection.
  • Automatic-lock tests cover disabled mode, 1-day and 31-day boundaries, elapsed-deadline behavior, setting changes, reboot, explicit Lock, and re-unlock.

Security constraints

  • No new persistent plaintext secret/key material.
  • auto_lock_days stays inside encrypted authenticated Vault content.
  • Do not weaken fresh physical confirmation / Trusted Browser rules for re-unlock.
  • Reuse the existing lock/zeroization path rather than implementing a reduced cleanup path.
  • Do not use mutable wall-clock trusted time as the security timer source.
  • Do not autonomously migrate or downgrade canonical Vault state outside the Web-owned generation transaction.
  • Existing generation conflict, request-ID, transaction journal/reconciliation, and fail-closed semantics remain unchanged.
  • Protocol/storage version changes beyond those explicitly fixed in [Decision] Define configurable automatic-lock semantics #138 require another Specification handoff; do not invent them locally.

Out of scope

References

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions