Crate apdu

Source
Expand description

High-level API for APDU commands and responses.

§Features

§Low-level APDU types

apdu-core crate declares types for APDU command and response in low-level. It is fully cross-platform since this crate contains only type declarations.

let command = apdu_core::Command::new_with_payload(0x00, 0xA4, 0x12, 0x34, &[0x56, 0x78]);
let bytes: Vec<u8> = command.into();

assert_eq!(
    vec![
        0x00, 0xA4, 0x12, 0x34, // CLA + INS + P1 + P2 (required),
        0x02,                   // Lc, automatically calculated from Vec,
        0x56, 0x78,             // ...and the command payload.
    ],
    bytes,
);

§High-level APIs

This apdu crate declares some high-level APIs to compose APDU commands or parse their responses easily. It is cross-platform now, but some os-specific features can be added in the future.

let command = apdu::command::select_file(0x12, 0x34, &[0x56, 0x78]);
let bytes: Vec<u8> = command.into();

assert_eq!(vec![0x00, 0xA4, 0x12, 0x34, 0x02, 0x56, 0x78], bytes);

Collection of APDU commands are incomplete and still in development. We are welcome for your contribution at any time :)

§Abstraction

Among crates that supports communicating using APDU, it can use apdu-core crate for abstraction. For example:

/// You have an command that can be transmitted as APDU:
struct DoSomethingCommand {
    parameters: Vec<String>,
}

/// Now implement `From<YourType>` for `apdu_core::Command`:
impl<'a> From<DoSomethingCommand> for apdu_core::Command<'a> {
    fn from(cmd: DoSomethingCommand) -> Self {
        Self::new(0x12, 0x34, 0x56, 0x78)
    }
}

/// ... then dependents of your library can be used with other crate that has an APDU implementation:
fn handle_apdu_command<'a>(cmd: impl Into<apdu_core::Command<'a>>) {
    // connect to your card ...
    // transmit the command ...
    // ... and wait for the response
}

For advance, this crate also supports abstraction of APDU transmitter (called Handler in apdu_core). handle_apdu_command from the above example can be transformed to:

struct NfcReader;

impl apdu_core::HandlerInCtx<()> for NfcReader {
    fn handle_in_ctx(&self, _ctx: (), command: &[u8], response: &mut [u8]) -> apdu_core::Result {
        // connect to your card ...
        // transmit the command ...
        // ... and wait for the response

        Ok(len) // return the length of response
    }
}

Thanks to this abstraction, application developer can choose how the APDU command is transmitted to the card independently to their payload. This enables you to implement your libraries that uses APDU in cross-platform easily!

§Examples

jpki-rs is implemented using this apdu crate. Take a look for catch example usages for this crate.

Re-exports§

pub use crate::error::Error;
pub use apdu_core as core;

Modules§

command
High-level API to compose commands easily.
error

Structs§

Command
An APDU command to be transmitted
Response
An response that was received from the card

Traits§

Handler
An handler to handle an APDU command and receive a response

Derive Macros§

Response
Procedural macro to derive APDU response. See apdu-derive for details.