Skip to content

Commit

Permalink
Add examples, integration tests and docs for simulated device and rea… (
Browse files Browse the repository at this point in the history
#87)

**Integration tests:**
- add simulated device and reader interaction
- also for simulated device and reader interaction, add a more structured one using `state pattern`, `Mutex` and `Arc`
- one test from the holder's POV with a simulated reader, and vice-versa for another test

**Docs:**
- add example from the holder's POV with a simulated reader, and vice-versa for another example
- add diagram for simulated device and reader interaction
- add diagrams for simulated device perspective and simulated reader perspective
- add diagrams in readme and links to examples
- add ASCII diagrams in `lib.rs` and include examples from device and reader's perspective
- fix some docs

**Code:**
- add `allow invisible_characters` for clippy in a file

**CI:**
- upgrade `actions/checkout`
- add `--all-targets` to build so that it builds tests too (to make sure they don't fall behind)
- add `--all-targets` to `clippy` so that it runs on tests too (it will run o tests too but I assume it's fine)
    - don't explicitly run in in `macros` because `--all-targets` takes care of that
- add `--all` to `fmt --check` so that it runs on examples too
    - don't explicitly run in in `macros` because `--all` takes care of that
  • Loading branch information
radumarias authored Aug 6, 2024
1 parent 41823af commit 9d99da6
Show file tree
Hide file tree
Showing 14 changed files with 830 additions and 28 deletions.
34 changes: 14 additions & 20 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,26 @@ on:

env:
CARGO_TERM_COLOR: always
RUSTFLAGS: "-Dwarnings"
RUSTFLAGS: "-Dwarnings"

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Checkout
uses: actions/checkout@v4

- name: Build
run: cargo build
- name: Build
run: cargo build --all-targets

- name: Run tests
run: |
cargo test
cd macros
cargo test
- name: Run tests
run: |
cargo test
cd macros
cargo test
- name: Clippy
run: |
cargo clippy
cd macros
cargo clippy
- name: Clippy
run: cargo clippy --all-targets

- name: Fmt
run: |
cargo fmt -- --check
cd macros
cargo fmt -- --check
- name: Fmt
run: cargo fmt --all -- --check
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
**/Cargo.lock
**/target
*~
*~
**/.idea
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ description = "ISO mDL implementation in Rust"
readme = "README.md"
homepage = "https://github.com/spruceid/isomdl"
repository = "https://github.com/spruceid/isomdl"
documentation = "https://docs.rs/isomdl"
license = "Apache-2.0 OR MIT"
exclude = ["test/"]

Expand All @@ -27,7 +28,7 @@ aes-gcm = "0.10.1"
hmac = "0.12.1"
aes = "0.8.2"
sec1 = "0.7.1"
uuid = { version = "1.3", features = ["v1", "std", "rng", "serde"] }
uuid = { version = "1.3", features = ["v1", "v4", "std", "rng", "serde"] }
time = { version = "0.3.20", features = ["formatting", "parsing", "macros"] }
zeroize = { version = "1.5", features = ["zeroize_derive"] }
signature = { version = "2.0.0", features = ["std"] }
Expand All @@ -50,3 +51,4 @@ rev = "4104505"
hex = "0.4.3"
p256 = "0.13.0"
serde_json = "*"

123 changes: 120 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# isomdl

ISO mDL implementation in Rust
[ISO/IEC DIS 18013-5](https://www.iso.org/standard/69084.html) `mDL` implementation in Rust.

It is intended to be used in creating apps for devices and readers that can interact with each other to exchange `mDL`
data.

## CLI tool

Expand All @@ -10,7 +13,121 @@ This crate contains a CLI tool. Run the `--help` command to see what actions you
cargo run -- --help
```

For example you can get the namespaces and elements defined in an mDL:
For example, you can get the namespaces and elements defined in an mDL:

```bash
cat test/stringified-mdl.txt | cargo run -- get-namespaces -
```
```

## Library

Here are some examples on how to use the library.
You can see more in [tests](tests) and read about in the
dedicated [README](tests/README.md).

### Examples

#### Simulated device and reader interaction

This example demonstrates a simulated device and reader interaction.
The reader requests the `age_over_21` element, and the device responds with that value.

```mermaid
sequenceDiagram
autonumber
Note over Device: Initialize session
Device ->> Device: Create QR Code Engagement
Device -) + Reader: Send QR Code
Reader ->> - Reader: Establish Session
Reader -) + Device: Request age_over_21
Device -)- Reader: Send age_over_21
Reader ->> Reader: Process age_over_21
Note over Device, Reader: Session finished
```

### The flow of the interaction

1. **Device initialization and engagement:**
- The device creates a `QR code` containing `DeviceEngagement` data, which includes its public key.
- Internally:
- The device initializes with the `mDL` data, private key, and public key.
2. **Reader processing QR code and requesting needed fields:**
- The reader processes the `QR code` and creates a request for the `age_over_21` element.
- Internally:
- Generates its private and public keys.
- Initiates a key exchange, and generates the session keys.
- The request is encrypted with the reader's session key.
3. **Device accepting request and responding:**
- The device receives the request and creates a response with the `age_over_21` element.
- Internally:
- Initiates the key exchange, and generates the session keys.
- Decrypts the request with the reader's session key.
- Parse and validate it creating error response if needed.
- The response is encrypted with the device's session key.
4. **Reader Processing mDL data:**
- The reader processes the response and prints the value of the `age_over_21` element.

##### Device perspective

There are several states through which the device goes during the interaction:

```mermaid
stateDiagram
state Device {
[*] --> SessionManagerInit: initialise
SessionManagerInit --> SessionManagerEngaged: qr_engagement
SessionManagerEngaged --> SessionManager: process_session_establishment
}
state SessionManagerInit {
[*] --> [*]
}
state SessionManagerEngaged {
[*] --> [*]
}
state Reader {
[*] --> [*]
}
state SessionManager {
[*] --> AwaitingRequest
AwaitingRequest --> Signing: prepare_response
Signing --> Signing: get_next_signature_payload
Signing --> ReadyToRespond: submit_next_signature
ReadyToRespond --> AwaitingRequest: retrieve_response
AwaitingRequest --> Signing: handle_request
}
User --> Device
SessionManagerInit --> Reader: qr_engagement
Reader --> SessionManagerEngaged: establish_session
ReadyToRespond --> Reader: handle_response
```

##### Reader perspective

From the reader's perspective, the flow is simpler:

```mermaid
stateDiagram
state Device {
[*] --> [*]
}
state Reader {
SessionManager --> SessionManager: handle_response
}
User --> Device
Device --> Reader: qr_engagement
Reader --> Device: establish_session
Device --> Reader
Reader --> Device: new_request
```

### Example

You can see the full example in [simulated_device_and_reader](tests/simulated_device_and_reader.rs) and a version that
uses `State` pattern, `Arc` and `Mutex` [simulated_device_and_reader](tests/simulated_device_and_reader_state.rs).
1 change: 1 addition & 0 deletions src/definitions/namespaces/latin1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ mod test {

#[test]
fn upper_latin() {
#[allow(clippy::invisible_characters)]
let upper_latin_chars = vec![
' ', '¡', '¢', '£', '¤', '¥', '¦', '§', '¨', '©', 'ª', '«', '¬', '­', '®', '¯', '°',
'±', '²', '³', '´', 'µ', '¶', '·', '¸', '¹', 'º', '»', '¼', '½', '¾', '¿', 'À', 'Á',
Expand Down
4 changes: 2 additions & 2 deletions src/definitions/traits/to_cbor.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//! ToCbor is specifically NOT implemented for Vec<T> where T: ToCbor, as Vec<u8> likely should be
//! represented as a bytestr instead of an array in cbor.
//! ToCbor is specifically NOT implemented for `Vec<T>` where `T: ToCbor`, as `Vec<u8>` likely should be
//! represented as a `bytestr` instead of an `array` in `cbor`.
use serde_cbor::Value;
use std::collections::BTreeMap;
Expand Down
Loading

0 comments on commit 9d99da6

Please sign in to comment.