Skip to content

Commit

Permalink
Add docs
Browse files Browse the repository at this point in the history
  • Loading branch information
szszszsz committed Oct 27, 2022
1 parent 3ff24e4 commit 1eed468
Show file tree
Hide file tree
Showing 10 changed files with 292 additions and 0 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,21 @@ Implementation of reverse-engineered specification of Yubico's [OATH application
[trussed]: https://trussed.dev
[yubico-oath]: https://developers.yubico.com/OATH/YKOATH_Protocol.html

#### CTAPHID Extension

See [CTAPHID](ctaphid.md) for documentation regarding the NLnet funded CTAPHID extension.


#### License

<sup>`oath-authenticator` is licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or [MIT License](LICENSE-MIT) at your option.</sup>
<br>
<sub>Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.</sub>


## Funding

[<img src="https://nlnet.nl/logo/banner.svg" width="200" alt="Logo NLnet: abstract logo of four people seen from above" hspace="20">](https://nlnet.nl/)
[<img src="https://nlnet.nl/image/logos/NGI0PET_tag.svg" width="200" alt="Logo NGI Zero: letterlogo shaped like a tag" hspace="20">](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.
238 changes: 238 additions & 0 deletions ctaphid.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@


# 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.

<!-- ![Sequence diagram of the exchange](images/exchange.svg "Exchange") -->
```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 |

| 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.
```


## Further development

Current solution does have a couple of limitations, which could be corrected in the further development:

- 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

[<img src="https://nlnet.nl/logo/banner.svg" width="200" alt="Logo NLnet: abstract logo of four people seen from above" hspace="20">](https://nlnet.nl/)
[<img src="https://nlnet.nl/image/logos/NGI0PET_tag.svg" width="200" alt="Logo NGI Zero: letterlogo shaped like a tag" hspace="20">](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.
19 changes: 19 additions & 0 deletions images/command_format.plantuml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
@startyaml
cls: 0
ins:
- Put
- Delete
- Reset
- List
- Calculate
p1:
- 0x00
- 0xDE (Reset)
p2:
- 0x00
- 0xAD (Reset)
- 0x01 (Calculate)
data:
- ISO7816 length
- TLV encoded data
@endyaml
Binary file added images/command_format.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions images/credentials.plantuml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
@startyaml
Credentials:
- Credential 1
- Credential 2
- Credential 3
- Credential 4
- ...
@endyaml
Binary file added images/credentials.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions images/exchange.mermaid
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
sequenceDiagram
Python Client ->> FIDO2 device : CTAPHID message
FIDO2 device ->> Oath Authenticator : ISO7816 message
Oath Authenticator -->> FIDO2 device : Response
FIDO2 device -->> Python Client : Response
1 change: 1 addition & 0 deletions images/exchange.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions images/get_code_result.plantuml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
@startyaml
Header:
- TOTP [0x76, 0x05]
- HOTP [0x77, 0x00]
- Digits 6|8
Digest:
- RFC digest sum
@endyaml
Binary file added images/get_code_result.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 1eed468

Please sign in to comment.