diff --git a/README.md b/README.md
index 6e1d37c31..ca9269053 100644
--- a/README.md
+++ b/README.md
@@ -30,11 +30,13 @@ Secrets App supports the following features:
- Touch-button protected use per credential.
The pynitrokey library can be used to communicate with this application over CTAPHID, and nitropy provides the CLI using
-it.
+it. See [ctaphid.md](docs/ctaphid.md) for the details.
CCID transport is also available, and while not supported in the mentioned library yet, it can be potentially used by
the protocol-compatible applications, like the mentioned KeepassXC.
+See [design.md](docs/design.md) for the UX design choices.
+
[RFC4226]: https://www.rfc-editor.org/rfc/rfc4226
[RFC6238]: https://www.rfc-editor.org/rfc/rfc6238
@@ -99,7 +101,7 @@ e.g. due to being taken by other services, or requiring Administrator
privileges). A CTAPHID vendor command number was selected to use (`0x70`), thus allowing for a compatible extension of
any FIDO compliant device.
-See [CTAPHID](ctaphid.md) for the further documentation regarding the NLnet funded CTAPHID extension.
+See [CTAPHID](docs/ctaphid.md) for the further documentation regarding the NLnet funded CTAPHID extension.
### Further work
@@ -119,6 +121,8 @@ Tasks and features still discussed to be done:
### Development
+See [design](docs/design.md) document to see decisions taken to make the solution cohesive.
+
Use `dangerous_disable_encryption` Rust flag to disable data encryption for the debug purposes. E.g.:
```text
diff --git a/ctaphid.md b/ctaphid.md
deleted file mode 100644
index f2fc1d14a..000000000
--- a/ctaphid.md
+++ /dev/null
@@ -1,265 +0,0 @@
-
-
-# Oath Authenticator Client
-
-The [Oath Authenticator] application has been chosen as a good candidate due to being written in an extensive way, and
-offered in the same language as the platform, thus guaranteeing high compatibility and maintainability.
-
-It offers HOTP and TOTP implementations ([RFC4226] and [RFC6238] respectively), with SHA1 and SHA256 hashes support. It
-manages to process 320+ bits of the shared key.
-
-The protocol it uses - [YKOATH] - is using [ISO7816-4] commands for communication.
-
-[RFC6238]: https://www.rfc-editor.org/rfc/rfc6238
-
-[Oath Authenticator]: https://github.com/trussed-dev/oath-authenticator
-
-[YKOATH]: https://developers.yubico.com/OATH/YKOATH_Protocol.html
-
-## Protocol Description
-
-This implementation uses CTAPHID to transfer commands to the Oath Authenticator application, compiled into the Nitrokey
-3 firmware. This transport was used to improve compatibility on platforms, where the default transport for this
-application, CCID, is not easily available (e.g. due to being taken by other services, or requiring Administrator
-privileges). In CTAPHID, a custom vendor command number was selected `0x70`, thus allowing for a compatible extension of
-any FIDO device.
-
-Below is a visualization of getting the OTP code from the device. First the ISO7816 message is created and encapsulated
-into CTAPHID message, which is unpacked on the device and passed further to the Oath Authenticator. Once parsed and
-processed, the response is produced, which traverses the same way backwards, finally reaching Python client over
-CTAPHID.
-
-
-```mermaid
-sequenceDiagram
- Python Client ->> FIDO2 device : CTAPHID message
- FIDO2 device ->> Oath Authenticator : ISO7816 message
- Oath Authenticator -->> FIDO2 device : Response
- FIDO2 device -->> Python Client : Response
-```
-
-Following commands are accepted by the Oath Authenticator:
-
-| Command | Cls | Ins | P1 | P2 | Description |
-|-----------|------|------|--------|------|------------------------------------------|
-| Put | 0x00 | 0x01 | 0x00 | 0x00 | Register a new OTP credential |
-| Delete | 0x00 | 0x02 | 0x00 | 0x00 | Delete a registered OTP credential |
-| Reset | 0x00 | 0x04 | 0xDE | 0xAD | Remove all stored OTP credentials |
-| List | 0x00 | 0xA1 | 0x00 | 0x00 | List stored OTP credentials |
-| Calculate | 0x00 | 0xA2 | 0x00 | 0x01 | Calculate an OTP code for the credential |
-
-This is a standard ISO7816 encoding of the command and its parameters. The P1 and P2 are mostly unused, except for the
-case of Reset and Calculate commands. The class `cls` parameter is always `0`.
-
-Same table, but graphically:
-
-![Command format](images/command_format.png "Command format")
-
-
-
-## Commands
-
-### Put
-
-#### Input
-
-| Command | Cls | Ins | P1 | P2 | Description |
-|-----------|------|------|--------|------|------------------------------------------|
-| Put | 0x00 | 0x01 | 0x00 | 0x00 | Register a new OTP credential |
-
-| Parameters | Type | Description |
-|----------------|--------|--------------------------------------------------------------------------------------------|
-| CredentialId | Bytes | The credential name, stored for the later reference and listing |
-| Key | Bytes | The shared key in raw bytes |
-| Type* | u8 | OtpKind "bitwiseOr" Hash algorithm. Values are described below. Prefixed to the Key field. |
-| Digits* | u8 | Digits count. The common values are `6` and `8`. Prefixed to the Key field. |
-| InitialCounter | u32 BE | Initial value for the HOTP counter, encoded in big endian. |
-
-Fields marked with `*` are concatenated with the `Key` field.
-
-| Tag | Value | Description |
-|----------------|-------|---------------------------------------------------------------------------------------------|
-| CredentialId | 0x71 | The credential name, stored for the later reference and listing |
-| Key | 0x73 | \[ OtpKind bitwiseOr HashAlgorithm, digits, shared key \] |
-| Challenge | 0x74 | The challenge value for the TOTP calculations. 64-bit unsigned integer, big endian encoded. |
-| InitialCounter | 0x7A | Initial value for the HOTP counter. 32-bit unsigned integer, big endian encoded. |
-
-| Kind | Value | Description |
-|--------------|-------|-----------------------------------------------------------|
-| HOTP | 0x10 | Calculate OTP as HOTP, against the internal counter |
-| TOTP | 0x20 | Calculate OTP as TOTP, against the provided challenge |
-| REVERSE_HOTP | 0x30 | Calculate HOTP code, and compare against the provided one |
-
-| Algorithm | Value | Description |
-|-----------|-------|---------------------------|
-| Sha1 | 0x01 | Use SHA1 hash algorithm |
-| Sha256 | 0x02 | Use SHA256 hash algorithm |
-
-#### Response
-
-None
-
-### Calculate
-
-#### Input
-
-| Command | Cls | Ins | P1 | P2 | Description |
-|-----------|------|------|--------|------|------------------------------------------|
-| Calculate | 0x00 | 0xA2 | 0x00 | 0x01 | Calculate an OTP code for the credential |
-
-| Parameters | Type | Description |
-|--------------|--------|-----------------------------------------------------------------|
-| CredentialId | Bytes | The credential name, stored for the later reference and listing |
-| Challenge | u64 BE | The challenge value to run calculation against |
-
-Fields marked with `*` are concatenated with the `Key` field.
-
-#### Response
-
-![The result of the Get Code command](images/get_code_result.png "Get code result")
-
-
-The received digest is calculated according to the [RFC4226] specification. This means it has to be processed further to
-obtain the target OTP code as follows:
-
-```python
-# digits - user provided value during registration for selecting the final code length
-# digest - calculated hash some, received from the device
-truncated_code = int.from_bytes(digest, byteorder="big", signed=False)
-code = (truncated_code & 0x7FFFFFFF) % pow(10, digits)
-code_string = str(code).zfill(digits)
-```
-
-[RFC4226]: https://www.rfc-editor.org/rfc/rfc4226
-
-[ctap-vendor]: https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#usb-vendor-specific-commands
-
-[ISO7816]: https://www.iso.org/standard/54550.html
-
-[ISO7816-4]: https://www.iso.org/standard/54550.html
-
-### List
-
-List command returns a TLV encoded list of binary strings:
-
-
-![Credetials list](images/credentials.png "Credentials")
-
-
-
-### Delete
-
-| Command | Cls | Ins | P1 | P2 | Description |
-|-----------|------|------|--------|------|------------------------------------------|
-| Delete | 0x00 | 0x02 | 0x00 | 0x00 | Delete a registered OTP credential |
-
-#### Input
-
-| Parameters | Type | Description |
-|--------------|-------|-----------------------------------------------------------------|
-| CredentialId | Bytes | The credential name, stored for the later reference and listing |
-
-#### Response
-
-None
-
-## Tests
-
-The tests for communication and responses correctness according to the RFC test vectors are provided in `test_otp.py`
-file.
-
-These can be run against a USB/IP device simulation of Nitrokey 3.
-
-## Client Application
-
-The Oath Authenticator can be reached through the described protocol over a pynitrokey CLI experimental interface. Excerpt from its help screen follows:
-
-```text
-$ nitropy nk3 otp
-Command line tool to interact with Nitrokey devices 0.4.30
-Usage: nitropy nk3 otp [OPTIONS] COMMAND [ARGS]...
-
- Manage OTP secrets on the device.
-
-Options:
- --help Show this message and exit.
-
-Commands:
- get Generate OTP code from registered credential.
- register Register OTP credential.
- remove Remove OTP credential.
- reset Remove all OTP credentials from the device.
- show List registered OTP credentials.
-
-$ nitropy nk3 otp register --help
-Command line tool to interact with Nitrokey devices 0.4.30
-Usage: nitropy nk3 otp register [OPTIONS] NAME SECRET
-
- Register OTP credential.
-
- Write SECRET under the NAME. SECRET should be encoded in base32 format.
-
-Options:
- --digits_str [6|8] Digits count
- --kind [TOTP|HOTP] OTP mechanism to use
- --hash [SHA1|SHA256] Hash algorithm to use
- --counter_start INTEGER Starting value for the counter (HOTP only)
- --help Show this message and exit.
-
-$ nitropy nk3 otp get --help
-Command line tool to interact with Nitrokey devices 0.4.30
-Usage: nitropy nk3 otp get [OPTIONS] NAME
-
- Generate OTP code from registered credential.
-
-Options:
- --timestamp INTEGER The timestamp to use instead of the local time (TOTP
- only)
- --period INTEGER The period to use in seconds (TOTP only)
- --help Show this message and exit.
-```
-
-
-## Authentication Requirements
-
-
-| Command | Require Touch Button press | Require PIN Authentication | Unlocks PIN-based Encryption Key |
-|-----------------|----------------------------|----------------------------|----------------------------------|
-| Select | No | No | No |
-| Calculate | Yes* | No | No |
-| CalculateAll | No | No | No |
-| Delete | Yes | Yes* | No |
-| ListCredentials | No | Yes* | No |
-| Register | Yes | Yes* | No |
-| Reset | Yes | No | No |
-| VerifyPin | No | - | Yes |
-| SetPin | Yes | - | No |
-| ChangePin | Yes | - | No |
-| VerifyCode | Yes* | No | No |
-| SendRemaining | No | No | No |
-
-
-Notes:
-1. \* If credential was encrypted using PIN-based key, then verification with PIN through `VerifyPin()` is required to get
-access to it, otherwise it will be reported as not found. Similarly, PIN-encrypted credentials will not be listed
-with `List` command until authenticated. `Delete` command require PIN for Credentials created with PIN-encryption.
-2. Credentials can be configured to be allowed for use only after touch button is pressed.
-3. \* Touch Button press is required for Credentials, which were created with such attribute.
-
-## Further development
-
-Current solution does have a couple of limitations, which could be corrected in the further development:
-
-- initial HOTP counter value can't be bigger than 2^32;
-- SHA512 algorithm is not supported at the moment.
-
-Both limitations are not affecting the daily usage.
-
-
-
-## Funding
-
-[](https://nlnet.nl/)
-[](https://nlnet.nl/NGI0/)
-
-Changes in this project were funded through the [NGI0 PET](https://nlnet.nl/PET) Fund, a fund established by [NLnet](https://nlnet.nl/) with financial support from the European Commission's [Next Generation Internet programme](https://ngi.eu/), under the aegis of DG Communications Networks, Content and Technology under grant agreement No 825310.
diff --git a/docs/ctaphid.md b/docs/ctaphid.md
new file mode 100644
index 000000000..489be0a64
--- /dev/null
+++ b/docs/ctaphid.md
@@ -0,0 +1,317 @@
+# Secrets App CTAPHID Protocol Details
+
+## Protocol Description
+
+This implementation uses CTAPHID to transfer commands to the Secrets App application, compiled into the Nitrokey
+3 firmware. This transport was used to improve compatibility on platforms, where the default transport for this
+application, CCID, is not easily available (e.g. due to being taken by other services, or requiring Administrator
+privileges). In CTAPHID, a custom vendor command number was selected `0x70`, thus allowing for a compatible extension of
+any FIDO device.
+
+Below is a visualization of getting the OTP code from the device. First the ISO7816 message is created and encapsulated
+into CTAPHID message, which is unpacked on the device and passed further to the Secrets App. Once parsed and
+processed, the response is produced, which traverses the same way backwards, finally reaching Python client over
+CTAPHID.
+
+
+
+```mermaid
+sequenceDiagram
+ Python Client ->> FIDO2 device : CTAPHID message
+ FIDO2 device ->> Secrets App : ISO7816 message
+ Secrets App -->> FIDO2 device : Response
+ FIDO2 device -->> Python Client : Response
+```
+
+Following commands are accepted by the Secrets App:
+
+| Command | Cls | Ins | P1 | P2 | Description |
+|------------------|------|------|------|------|-----------------------------------------------------------------|
+| Put | 0x00 | 0x01 | 0x00 | 0x00 | Register a new OTP credential |
+| Delete | 0x00 | 0x02 | 0x00 | 0x00 | Delete a registered OTP credential |
+| Reset | 0x00 | 0x04 | 0xDE | 0xAD | Remove all stored OTP credentials |
+| List | 0x00 | 0xA1 | 0x00 | 0x00 | List stored OTP credentials |
+| Calculate | 0x00 | 0xA2 | 0x00 | 0x01 | Calculate an OTP code for the credential |
+| VerifyCode | 0x00 | 0xB1 | 0x00 | 0x00 | Reverse HOTP - verify incoming HOTP code |
+| VerifyPIN | 0x00 | 0xB2 | 0x00 | 0x00 | Authenticate with provided PIN |
+| ChangePIN | 0x00 | 0xB3 | 0x00 | 0x00 | Change PIN |
+| SetPIN | 0x00 | 0xB4 | 0x00 | 0x00 | Set PIN. Can be called only once, directly after factory reset. |
+| GetCredential | 0x00 | 0xB5 | 0x00 | 0x00 | Get static password entry |
+| CredentialUpdate | 0x00 | 0xB7 | 0x00 | 0x00 | Update static password entry |
+
+This is a standard ISO7816 encoding of the command and its parameters. The P1 and P2 are mostly unused, except for the
+case of Reset and Calculate commands. The class `cls` parameter is always `0`.
+
+Presenting graphically different variants for each field (selected commands) :
+
+![Command format](images/command_format.png "Command format")
+
+## Commands
+
+Chosen commands description follows:
+
+### Put
+
+#### Input
+
+| Command | Cls | Ins | P1 | P2 | Description |
+|---------|------|------|------|------|-------------------------------|
+| Put | 0x00 | 0x01 | 0x00 | 0x00 | Register a new OTP credential |
+
+| Parameters | Type | Description |
+|----------------|--------|--------------------------------------------------------------------------------------------|
+| CredentialId | Bytes | The credential name, stored for the later reference and listing |
+| Key | Bytes | The shared key in raw bytes |
+| Type* | u8 | OtpKind "bitwiseOr" Hash algorithm. Values are described below. Prefixed to the Key field. |
+| Digits* | u8 | Digits count. The common values are `6` and `8`. Prefixed to the Key field. |
+| InitialCounter | u32 BE | Initial value for the HOTP counter, encoded in big endian. |
+| PwsLogin | Bytes | Value for the Password Safe entry - login field |
+| PwsPassword | Bytes | Value for the Password Safe entry - password field |
+| PwsMetadata | Bytes | Value for the Password Safe entry - metadata field |
+
+Fields marked with `*` are concatenated with the `Key` field.
+
+| Tag | Value | Description |
+|----------------|-------|---------------------------------------------------------------------------------------------|
+| CredentialId | 0x71 | The credential name, stored for the later reference and listing |
+| Key | 0x73 | \[ OtpKind bitwiseOr HashAlgorithm, digits, shared key \] |
+| Challenge | 0x74 | The challenge value for the TOTP calculations. 64-bit unsigned integer, big endian encoded. |
+| InitialCounter | 0x7A | Initial value for the HOTP counter. 32-bit unsigned integer, big endian encoded. |
+| PwsLogin | 0x83 | Value for the Password Safe entry - login field |
+| PwsPassword | 0x84 | Value for the Password Safe entry - password field |
+| PwsMetadata | 0x85 | Value for the Password Safe entry - metadata field |
+
+| Kind | Value | Description |
+|--------------|-------|-----------------------------------------------------------|
+| HOTP | 0x10 | Calculate OTP as HOTP, against the internal counter |
+| TOTP | 0x20 | Calculate OTP as TOTP, against the provided challenge |
+| REVERSE_HOTP | 0x30 | Calculate HOTP code, and compare against the provided one |
+| HMAC | 0x40 | Calculate HMAC-challenge value |
+
+| Algorithm | Value | Description |
+|-----------|-------|---------------------------|
+| Sha1 | 0x01 | Use SHA1 hash algorithm |
+| Sha256 | 0x02 | Use SHA256 hash algorithm |
+
+#### Response
+
+None
+
+### Calculate
+
+#### Input
+
+| Command | Cls | Ins | P1 | P2 | Description |
+|-----------|------|------|------|------|------------------------------------------|
+| Calculate | 0x00 | 0xA2 | 0x00 | 0x01 | Calculate an OTP code for the credential |
+
+| Parameters | Type | Description |
+|--------------|--------|-----------------------------------------------------------------|
+| CredentialId | Bytes | The credential name, stored for the later reference and listing |
+| Challenge | u64 BE | The challenge value to run calculation against |
+
+Fields marked with `*` are concatenated with the `Key` field.
+
+#### Response
+
+![The result of the Get Code command](images/get_code_result.png "Get code result")
+
+The received digest is calculated according to the [RFC4226] specification. This means it has to be processed further to
+obtain the target OTP code as follows:
+
+```python
+# digits - user provided value during registration for selecting the final code length
+# digest - calculated hash some, received from the device
+truncated_code = int.from_bytes(digest, byteorder="big", signed=False)
+code = (truncated_code & 0x7FFFFFFF) % pow(10, digits)
+code_string = str(code).zfill(digits)
+```
+
+[RFC4226]: https://www.rfc-editor.org/rfc/rfc4226
+
+[ctap-vendor]: https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#usb-vendor-specific-commands
+
+[ISO7816]: https://www.iso.org/standard/54550.html
+
+[ISO7816-4]: https://www.iso.org/standard/54550.html
+
+### List
+
+List command returns a TLV encoded list of binary strings (version 1 format):
+
+![Credetials list](images/credentials.png "Credentials")
+
+### Delete
+
+| Command | Cls | Ins | P1 | P2 | Description |
+|---------|------|------|------|------|------------------------------------|
+| Delete | 0x00 | 0x02 | 0x00 | 0x00 | Delete a registered OTP credential |
+
+#### Input
+
+| Parameters | Type | Description |
+|--------------|-------|-----------------------------------------------------------------|
+| CredentialId | Bytes | The credential name, stored for the later reference and listing |
+
+#### Response
+
+None
+
+### CredentialUpdate
+
+| Command | Cls | Ins | P1 | P2 | Description |
+|------------------|------|------|------|------|------------------------------|
+| CredentialUpdate | 0x00 | 0xB7 | 0x00 | 0x00 | Update static password entry |
+
+
+#### Input
+
+| Parameters | Type | Description |
+|--------------|-------|-----------------------------------------------------------------|
+| CredentialId | Bytes | The credential name, stored for the later reference and listing |
+| NewName | Bytes | The credential new name |
+| PwsLogin | Bytes | Value for the Password Safe entry - login field |
+| PwsPassword | Bytes | Value for the Password Safe entry - password field |
+| PwsMetadata | Bytes | Value for the Password Safe entry - metadata field |
+
+
+| Tag | Value | Description |
+|--------------|-------|-----------------------------------------------------------------|
+| CredentialId | 0x71 | The credential name, stored for the later reference and listing |
+| NewName | 0x71 | The credential new name. Uses same tag id as the previous field |
+| PwsLogin | 0x83 | Value for the Password Safe entry - login field |
+| PwsPassword | 0x84 | Value for the Password Safe entry - password field |
+| PwsMetadata | 0x85 | Value for the Password Safe entry - metadata field |
+
+#### Response
+
+None
+
+## Tests
+
+The tests for communication and responses correctness according to the RFC test vectors are provided in `test_secrets_app.py`
+file, located in the pynitrokey repository:
+- https://github.com/Nitrokey/pynitrokey/blob/master/pynitrokey/test_secrets_app.py
+
+These can be run against a USB/IP device simulation of Nitrokey 3.
+
+## Client Application
+
+The Secrets App can be reached through the described protocol over a pynitrokey CLI experimental interface. Excerpt from
+its help screen follows:
+
+```text
+$ nitropy nk3 secrets
+Command line tool to interact with Nitrokey devices 0.4.39
+Usage: nitropy nk3 secrets [OPTIONS] COMMAND [ARGS]...
+
+ Nitrokey Secrets App. Manage OTP and Password Safe secrets on the device.
+ Use NITROPY_SECRETS_PASSWORD to pass password for the scripted execution.
+
+Options:
+ --help Show this message and exit.
+
+Commands:
+ add-challenge-response Register Challenge-Response credential.
+ add-otp (register) Register OTP credential.
+ add-password Register Password Safe credential.
+ get-otp (get) Generate OTP code from registered credential.
+ get-password Get Password Safe Entry
+ list List registered OTP credentials.
+ remove Remove OTP credential.
+ rename Rename credential.
+ reset Remove all OTP credentials from the device.
+ set-pin Set or change the PIN used to authenticate to...
+ status Show application status
+ update Update credential.
+ verify Proceed with the incoming OTP code verification...
+$ nitropy nk3 secrets register --help
+Command line tool to interact with Nitrokey devices 0.4.39
+Usage: nitropy nk3 secrets register [OPTIONS] NAME SECRET
+
+ Register OTP credential.
+
+ Write credential under the NAME. Secret should be base32 encoded.
+
+Options:
+ --digits-str [6|8] Digits count
+ --kind [HOTP|TOTP|HOTP_REVERSE|HMAC]
+ OTP mechanism to use. Case insensitive.
+ --hash [SHA1|SHA256] Hash algorithm to use
+ --counter-start INTEGER Starting value for the counter (HOTP only)
+ --touch-button This credential requires button press before
+ use
+ --protect-with-pin This credential should be additionally
+ encrypted with a PIN, which will be required
+ before each use
+ --help Show this message and exit.
+$ nitropy nk3 secrets get-otp --help
+Command line tool to interact with Nitrokey devices 0.4.39
+Usage: nitropy nk3 secrets get-otp [OPTIONS] NAME
+
+ Generate OTP code from registered credential.
+
+Options:
+ --timestamp INTEGER The timestamp to use instead of the local time (TOTP
+ only)
+ --period INTEGER The period to use in seconds (TOTP only)
+ --help Show this message and exit.
+$ nitropy nk3 secrets get-password --help
+Command line tool to interact with Nitrokey devices 0.4.39
+Usage: nitropy nk3 secrets get-password [OPTIONS] NAME
+
+ Get Password Safe Entry
+
+Options:
+ --password Print password only
+ --format [json|csv] Format of the output
+ --help Show this message and exit.
+
+```
+
+## Authentication Requirements
+
+| Command | Require Touch Button press | Require PIN Authentication | Unlocks PIN-based Encryption Key |
+|------------------|----------------------------|----------------------------|----------------------------------|
+| Select | No | No | No |
+| Calculate | Yes* | No | No |
+| Delete | Yes | Yes* | No |
+| ListCredentials | No | Yes* | No |
+| Register | Yes | Yes* | No |
+| Reset | Yes | No | No |
+| VerifyPin | No | - | Yes |
+| SetPin | Yes | - | No |
+| ChangePin | Yes | - | No |
+| VerifyCode | Yes* | No | No |
+| SendRemaining | No | No | No |
+| GetCredential | Yes* | No | No |
+| CredentialUpdate | Yes | Yes* | No |
+
+Notes:
+
+1. \* If credential was encrypted using PIN-based key, then verification with PIN through `VerifyPin()` is required to
+ get
+ access to it, otherwise it will be reported as not found. Similarly, PIN-encrypted credentials will not be listed
+ with `List` command until authenticated. `Delete` command require PIN for Credentials created with PIN-encryption.
+2. Credentials can be configured to be allowed for use only after touch button is pressed.
+3. \* Touch Button press is required for Credentials, which were created with such attribute,
+ but omitted if the PIN was already verified
+
+## Further development
+
+Current solution does have a couple of limitations, which could be corrected in the further development:
+
+- initial HOTP counter value can't be bigger than 2^32;
+- SHA512 algorithm is not supported at the moment.
+
+Both limitations are not affecting the daily usage.
+
+## Funding
+
+[](https://nlnet.nl/)
+[](https://nlnet.nl/NGI0/)
+
+Changes in this project were funded through the [NGI0 PET](https://nlnet.nl/PET) Fund, a fund established
+by [NLnet](https://nlnet.nl/) with financial support from the European
+Commission's [Next Generation Internet programme](https://ngi.eu/), under the aegis of DG Communications Networks,
+Content and Technology under grant agreement No 825310.
diff --git a/docs/design.md b/docs/design.md
new file mode 100644
index 000000000..ee59689a5
--- /dev/null
+++ b/docs/design.md
@@ -0,0 +1,29 @@
+# Design
+
+The following design choices have been implemented to strike a balance between the secure utilization and
+user-friendliness of the Secrets App project. These decisions originated from the [YKOATH] protocol and were compared with
+alternative offline solutions. Throughout this process, the aim was to ensure a basic level of safeguarding against
+malware threats by incorporating physical user presence confirmation for critical operations.
+
+[YKOATH]: https://developers.yubico.com/OATH/YKOATH_Protocol.html
+
+| | 1\. Daily use | 2\. Registration / modification | 3\. Factory Reset confirmation | 4\. PINs / passphrases | 5\. PIN change guard | 6\. Attack vector protection | 7\. Token validation period |
+|------------------------|-------------------------------------------------------------|---------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------|------------------------|------------------------------|------------------------------|-------------------------------------------------|
+| Secrets App v0.10+ | Touch button if set, and/or
PIN if set on the Credential | Touch button always, before processing (to prevent PIN attempt counter use up). | Touch button | Single PIN only | Current PIN and Touch button | Local / Malware | Each request, where PIN is needed (per request) |
+| Secrets App Next (TBD) | (no changes) | (no changes) | \- Touch button
\- Within 10 seconds of power cycle only
\- Significant UX event – LED animation red/blue blinking | (no changes) | (no changes) | (no changes) | (no changes) |
+
+
+
+| | Comments |
+|------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| Secrets App v0.10+ | Do not require PIN for user data, but offer such possibility. Keep all encrypted. PIN-encrypted Credentials are not listed until PIN is provided. Touch button should always protect PIN use to prevent local malware DOS attack. |
+| Secrets App Next (TBD) | (no changes) |
+
+
+Other:
+- do not allow to overwrite credentials - always require explicit deletion of the credential with the same name
+- remove YKOATH protocol compatibility, specifically authentication through challenge-response
+
+Privacy concerns:
+- the credential overwrite protection (for the Update and Register commands) can leak information about the presence of a PIN-encrypted credential with the same name. See below ticket for details:
+ - https://github.com/Nitrokey/trussed-secrets-app/issues/101
\ No newline at end of file
diff --git a/src/authenticator.rs b/src/authenticator.rs
index 13d37b1a0..dfc694f39 100644
--- a/src/authenticator.rs
+++ b/src/authenticator.rs
@@ -283,7 +283,7 @@ where
self.state.runtime.previously = None;
}
- // DESIGN Allow all commands to be called without PIN verification
+ // DESIGN (see design.md): Allow all commands to be called without PIN verification
// Lazy init: make sure hardware key is initialized
self.init()?;
@@ -315,7 +315,7 @@ where
};
// Call logout after processing, so the PIN-based KEK would not be kept in the memory
- // DESIGN -> Per-request authorization
+ // DESIGN (see design.md): -> Per-request authorization
if self.state.runtime.encryption_key.is_some() {
// Do not call automatic logout after these commands
match command {
@@ -384,7 +384,7 @@ where
}
fn reset(&mut self) -> Result {
- // DESIGN Reset: always confirm with touch button
+ // DESIGN (see design.md): Reset: always confirm with touch button
self.user_present()?;
// Run any structured cleanup we have
@@ -598,7 +598,7 @@ where
}
fn register(&mut self, register: command::Register<'_>) -> Result {
- // DESIGN Registration: require touch button if set on the credential, but not if the PIN was already checked
+ // DESIGN (see design.md): Registration: require touch button if set on the credential, but not if the PIN was already checked
if register.credential.touch_required
&& register.credential.encryption_key_type != EncryptionKeyType::PinBased
{
@@ -794,10 +794,10 @@ where
update_req: command::UpdateCredential<'_>,
_reply: &mut Data,
) -> Result {
- // DESIGN Get operation confirmation from user before proceeding
+ // DESIGN (see design.md): Get operation confirmation from user before proceeding
self.user_present()?;
- // DESIGN check if the target name is occupied already
+ // DESIGN (see design.md): check if the target name is occupied already
if let Some(new_label) = update_req.new_label {
self.err_if_credential_with_label_exists(new_label)?;
}
@@ -852,7 +852,7 @@ where
}
fn require_touch_if_needed(&mut self, credential: &CredentialFlat) -> Result<()> {
- // DESIGN Daily use: require touch button if set on the credential, but not if the PIN was already checked
+ // DESIGN (see design.md): Daily use: require touch button if set on the credential, but not if the PIN was already checked
// Safety: encryption_key_type should be set for credential during loading in load_credential
if credential.touch_required
&& credential.encryption_key_type.unwrap() != EncryptionKeyType::PinBased
@@ -1159,7 +1159,7 @@ where
self._extension_logout()?;
- // DESIGN Always ask for touch button confirmation before verifying PIN, to prevent
+ // DESIGN (see design.md): Always ask for touch button confirmation before verifying PIN, to prevent
// non-intentional attempt counter use up
self.user_present()?;
@@ -1179,7 +1179,7 @@ where
if self._extension_is_pin_set()? {
return Err(Status::SecurityStatusNotSatisfied);
}
- // DESIGN Set PIN: always confirm with touch button
+ // DESIGN (see design.md): Set PIN: always confirm with touch button
self.user_present()?;
let command::SetPin { password } = set_pin;
@@ -1198,7 +1198,7 @@ where
if !self._extension_is_pin_set()? {
return Err(Status::SecurityStatusNotSatisfied);
}
- // DESIGN Change PIN: always confirm with touch button
+ // DESIGN (see design.md): Change PIN: always confirm with touch button
self.user_present()?;
let command::ChangePin {