Skip to content

Commit

Permalink
Merge pull request #7 from Nitrokey/doc-update
Browse files Browse the repository at this point in the history
Udpate readme.md and doc to leverage updated documentation
  • Loading branch information
sosthene-nitrokey authored Apr 11, 2024
2 parents 43866af + c90f6bc commit 58a701a
Show file tree
Hide file tree
Showing 4 changed files with 213 additions and 50 deletions.
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,6 @@ lint: src/se05x/commands.rs verify-commands
cargo clippy
cargo clippy --features nrf,nrf-hal-common/52840 --target thumbv7em-none-eabihf
cargo clippy --features lpc55 --target thumbv8m.main-none-eabi

README.md: src/lib.rs Makefile
grep '//!' src/lib.rs |grep -v '//! # ' | sed 's/^...//g' | sed 's/^ //g' > README.md
90 changes: 42 additions & 48 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,77 +1,71 @@
<!--
Copyright (C) 2023 Nitrokey GmbH
SPDX-License-Identifier: CC0-1.0
-->

SE05X driver
===========

This crate contains a Rust driver for the SE05x series of secure elements from NXP.
It contains an implementation of the T=1 protocol and the ISO7816-4 APDUs that are used to communicate with the se05x.

This crate is under heavy development.

```rust,ignore
let i2c: impl I2CForT1 = todo!();
let delay: impl DelayUs<u32> = todo!();
let mut se05x = se05x::new(i2c, address, delay);
let user_id = ObjectId(hex!("01020304"));
```rust,no_run
use se05x::se05x::commands::*;
use se05x::se05x::policies::*;
use se05x::se05x::*;
let i2c = get_i2c();
let delay = get_delay();
let address = 0x48;
let mut se05x = Se05X::new(i2c, address, delay);
let user_id = ObjectId([0x01, 0x00, 0x00, 0x00]);
let object_id = ObjectId([0x01, 0x02, 0x03, 0x04]);
let buf = &mut [0; 128];
let atr = se05x.enable();
// Running a WriteUserId command:
se05x.run_command(&WriteUserId {
policy: None,
max_attempts: None,
object_id: user_id,
value: b"Some value"
})?;
se05x.run_command(
&WriteUserId::builder()
.object_id(user_id)
.data(b"Some value")
.build(),
buf,
)?;
// Creating a file with a policy
let policy = &[Policy {
object_id: user_id,
access_rule: ObjectAccessRule::from_flags(
ObjectPolicyFlags::ALLOW_READ,
),
access_rule: ObjectAccessRule::from_flags(ObjectPolicyFlags::ALLOW_READ),
}];
se05x.run_command(
&WriteBinary {
transient: false,
policy: Some(PolicySet(policy)),
object_id,
offset: None,
file_length: Some(9.into()),
data: Some(&b"Some data"),
},
&mut buf,
&WriteBinary::builder()
.policy(PolicySet(policy))
.object_id(object_id)
.file_length(9.into())
.data(b"Some data")
.build(),
buf,
)?;
// Opening a session with teh UserID
let session = se05x.run_command(&CreateSession { object_id: user_id }, &mut buf)?;
let session_id = se05x
.run_command(&CreateSession { object_id: user_id }, buf)?
.session_id;
// Verifying the UserId
se05x.run_command(
&ProcessSessionCmd {
session_id: session.session_id,
apdu: VerifySessionUserId {
user_id: b"Some value",
},
se05x.run_session_command(
session_id,
&VerifySessionUserId {
user_id: b"Some value",
},
&mut buf,
buf,
)?;
// Reading the data with the verified session
let data = se05x.run_command(
&ProcessSessionCmd {
session_id: session.session_id,
apdu: ReadObject {
object_id,
offset: Some(0.into()),
length: Some(9.into()),
rsa_key_component: None,
},
},
&mut buf,
let data = se05x.run_session_command(
session_id,
&ReadObject::builder()
.object_id(object_id)
.offset(0.into())
.length(9.into())
.build(),
buf,
)?;
```

Expand Down
58 changes: 58 additions & 0 deletions src/doc_utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// utilities for doctests
//
// Not included in the crate, meant to be used with `include!`

use embedded_hal::blocking::delay::DelayUs;
use embedded_hal::blocking::i2c::{Read, Write, WriteRead};

#[derive(Debug)]
pub struct DummyI2c;
#[derive(Debug)]
pub struct DummyI2cError;

impl se05x::t1::I2CErrorNack for DummyI2cError {
fn is_address_nack(&self) -> bool {
false
}
fn is_data_nack(&self) -> bool {
false
}
}

impl Read<u8> for DummyI2c {
type Error = DummyI2cError;
fn read(&mut self, _: u8, _: &mut [u8]) -> Result<(), DummyI2cError> {
unimplemented!()
}
}
impl Write<u8> for DummyI2c {
type Error = DummyI2cError;
fn write(&mut self, _: u8, _: &[u8]) -> Result<(), DummyI2cError> {
unimplemented!()
}
}
impl WriteRead<u8> for DummyI2c {
type Error = DummyI2cError;
fn write_read(&mut self, _: u8, _: &[u8], _: &mut [u8]) -> Result<(), Self::Error> {
unimplemented!()
}
}

#[derive(Debug)]
pub struct DummyDelay;

impl DelayUs<u32> for DummyDelay {
fn delay_us(&mut self, _: u32) {
unimplemented!()
}
}

pub fn get_i2c() -> impl se05x::t1::I2CForT1 {
unimplemented!();
DummyI2c
}

pub fn get_delay() -> impl DelayUs<u32> {
unimplemented!();
DummyDelay
}
112 changes: 110 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,117 @@
// Copyright (C) 2023 Nitrokey GmbH
// SPDX-License-Identifier: LGPL-3.0-only

#![cfg_attr(not(test), no_std)]
#![doc = include_str!("../README.md")]

//!
//! SE05X driver
//! ===========
//!
//! This crate contains a Rust driver for the SE05x series of secure elements from NXP.
//! It contains an implementation of the T=1 protocol and the ISO7816-4 APDUs that are used to communicate with the se05x.
//!
//! ```rust,no_run
//! # include!("doc_utils.rs");
//! # #[cfg(feature = "builder")]
//! # fn main() -> Result<(), se05x::se05x::Error>{
//! use se05x::se05x::commands::*;
//! use se05x::se05x::policies::*;
//! use se05x::se05x::*;
//! let i2c = get_i2c();
//! let delay = get_delay();
//! let address = 0x48;
//! let mut se05x = Se05X::new(i2c, address, delay);
//! let user_id = ObjectId([0x01, 0x00, 0x00, 0x00]);
//! let object_id = ObjectId([0x01, 0x02, 0x03, 0x04]);
//! let buf = &mut [0; 128];
//!
//! let atr = se05x.enable();
//!
//! // Running a WriteUserId command:
//! se05x.run_command(
//! &WriteUserId::builder()
//! .object_id(user_id)
//! .data(b"Some value")
//! .build(),
//! buf,
//! )?;
//!
//! // Creating a file with a policy
//! let policy = &[Policy {
//! object_id: user_id,
//! access_rule: ObjectAccessRule::from_flags(ObjectPolicyFlags::ALLOW_READ),
//! }];
//!
//! se05x.run_command(
//! &WriteBinary::builder()
//! .policy(PolicySet(policy))
//! .object_id(object_id)
//! .file_length(9.into())
//! .data(b"Some data")
//! .build(),
//! buf,
//! )?;
//!
//! // Opening a session with teh UserID
//! let session_id = se05x
//! .run_command(&CreateSession { object_id: user_id }, buf)?
//! .session_id;
//!
//! // Verifying the UserId
//! se05x.run_session_command(
//! session_id,
//! &VerifySessionUserId {
//! user_id: b"Some value",
//! },
//! buf,
//! )?;
//! // Reading the data with the verified session
//! let data = se05x.run_session_command(
//! session_id,
//! &ReadObject::builder()
//! .object_id(object_id)
//! .offset(0.into())
//! .length(9.into())
//! .build(),
//! buf,
//! )?;
//! # Ok(())
//! # }
//! # #[cfg(not(feature = "builder"))]
//! # fn main() {}
//! ```
//!
//! Architecture
//! ------------
//!
//! ### T=1
//!
//! This driver communicates with the se05x over the T=1 protocol over I2C, as described in [UM11225](https://www.nxp.com/webapp/Download?colCode=UM11225).
//!
//! To do so and be compatible with most embedded controlers, it depends on the I2C [Read](https://docs.rs/embedded-hal/latest/embedded_hal/blocking/i2c/trait.Read.html) and [Write](https://docs.rs/embedded-hal/latest/embedded_hal/blocking/i2c/trait.Write.html) from [embedded-hal](https://docs.rs/embedded-hal/latest/embedded_hal).
//! However these traits do not expose the enough, as the T=1 protocol requires detecting I2C NACKs, which are not exposed in this protocol.
//!
//! Nacks are exposed in the `Error` types for each `HAL` crate. As such an extension to the embedded-hal traits is defined as `I2CErrorNack`, exposing the missing information.
//! It is implemented for the NRF and LPC55 Hals in `src/t1/i2cimpl.rs`, gated by the features `nrf` and `lpc55` respectively.
//!
//! This may not be necessary with future releases of `embedded-hal`, which [adds the missing information](https://docs.rs/embedded-hal/1.0.0-alpha.11/embedded_hal/i2c/enum.ErrorKind.html).
//!
//!
//! ### Iso7816
//!
//! This driver uses the [`iso7816`](https://docs.rs/iso7816/latest/iso7816/) crate to implement serialization of APDUs.
//!
//! ### Generation of commands
//!
//! To simplify implementation, all supported se05x APDUs are described in `src/se05x/commands.toml`.
//! The python script `generate_commands.py` parses the `command.toml` file and generates `src/se05x/commands.rs`, which implements all the APDUs.
//!
//! 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/NGIAssure_tag.svg" width="200" alt="Logo NGI Assure: letterlogo shaped like a tag" hspace="20">](https://nlnet.nl/assure/)
//!
//! This project was funded through the [NGI Assure](https://nlnet.nl/assure/) 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 957073.
extern crate delog;
delog::generate_macros!();

Expand Down

0 comments on commit 58a701a

Please sign in to comment.