From 421ffe359988ddbeaa7ac05428d1d612ab57e995 Mon Sep 17 00:00:00 2001 From: Heiko Schaefer Date: Fri, 20 Aug 2021 00:04:56 +0200 Subject: [PATCH] Add documentation, limit visibilities. --- openpgp-card/src/algorithm.rs | 25 +++++++++++++ openpgp-card/src/apdu/command.rs | 2 +- openpgp-card/src/apdu/commands.rs | 59 ++++++++++++++++++------------- openpgp-card/src/apdu/mod.rs | 6 ++-- openpgp-card/src/keys.rs | 24 +++---------- 5 files changed, 68 insertions(+), 48 deletions(-) diff --git a/openpgp-card/src/algorithm.rs b/openpgp-card/src/algorithm.rs index 1b91a20..7068e36 100644 --- a/openpgp-card/src/algorithm.rs +++ b/openpgp-card/src/algorithm.rs @@ -1,6 +1,14 @@ // SPDX-FileCopyrightText: 2021 Heiko Schaefer // SPDX-License-Identifier: MIT OR Apache-2.0 +//! Data structures that define OpenPGP algorithms. +//! +//! [`Algo`] and its components model "Algorithm Attributes" as described in +//! the OpenPGP card specification. +//! +//! [`AlgoSimple`] offers a shorthand for specifying an algorithm, +//! specifically for key generation on the card. + use crate::{EccType, KeyType}; use anyhow::anyhow; use std::convert::TryFrom; @@ -111,9 +119,24 @@ impl AlgoSimple { } } +/// "Algorithm Information" +/// +/// Modern cards provide a list of supported algorithms for each key type. +/// The list specifies which "Algorithm Attributes" can be set for key +/// generation or key import. +/// +/// (This feature was introduced in OpenPGP card v3.4) #[derive(Debug, Clone, Eq, PartialEq)] pub struct AlgoInfo(pub(crate) Vec<(KeyType, Algo)>); +/// "Algorithm Attributes" +/// +/// An `Algo` describes the algorithm settings for a key on the card. +/// +/// This setting specifies the data format of: +/// - Key import +/// - Key generation +/// - Export of public key data from the card (e.g. after key generation) #[derive(Debug, Clone, Eq, PartialEq)] pub enum Algo { Rsa(RsaAttrs), @@ -137,6 +160,7 @@ impl fmt::Display for Algo { } } +/// RSA specific attributes of [`Algo`] ("Algorithm Attributes") #[derive(Debug, Clone, Eq, PartialEq)] pub struct RsaAttrs { pub len_n: u16, @@ -144,6 +168,7 @@ pub struct RsaAttrs { pub import_format: u8, } +/// ECC specific attributes of [`Algo`] ("Algorithm Attributes") #[derive(Debug, Clone, Eq, PartialEq)] pub struct EccAttrs { pub ecc_type: EccType, diff --git a/openpgp-card/src/apdu/command.rs b/openpgp-card/src/apdu/command.rs index 58ba583..e635c00 100644 --- a/openpgp-card/src/apdu/command.rs +++ b/openpgp-card/src/apdu/command.rs @@ -6,7 +6,7 @@ use anyhow::Result; #[allow(clippy::upper_case_acronyms)] #[derive(Clone, Debug)] -pub struct Command { +pub(crate) struct Command { // Class byte (CLA) pub cla: u8, diff --git a/openpgp-card/src/apdu/commands.rs b/openpgp-card/src/apdu/commands.rs index c43ff6b..4d9c50c 100644 --- a/openpgp-card/src/apdu/commands.rs +++ b/openpgp-card/src/apdu/commands.rs @@ -1,11 +1,12 @@ // SPDX-FileCopyrightText: 2021 Heiko Schaefer // SPDX-License-Identifier: MIT OR Apache-2.0 -/// APDU Commands for OpenPGP card operations +//! Commands for the OpenPGP card application + use crate::apdu::command::Command; -/// Select the OpenPGP applet -pub fn select_openpgp() -> Command { +/// Select the OpenPGP application +pub(crate) fn select_openpgp() -> Command { Command::new( 0x00, 0xA4, @@ -16,63 +17,63 @@ pub fn select_openpgp() -> Command { } /// Get DO "Application related data" -pub fn get_application_data() -> Command { +pub(crate) fn get_application_data() -> Command { Command::new(0x00, 0xCA, 0x00, 0x6E, vec![]) } /// Get DO "Uniform resource locator" -pub fn get_url() -> Command { +pub(crate) fn get_url() -> Command { Command::new(0x00, 0xCA, 0x5F, 0x50, vec![]) } /// Get DO "Cardholder related data" -pub fn cardholder_related_data() -> Command { +pub(crate) fn cardholder_related_data() -> Command { Command::new(0x00, 0xCA, 0x00, 0x65, vec![]) } /// Get DO "Security support template" -pub fn get_security_support_template() -> Command { +pub(crate) fn get_security_support_template() -> Command { Command::new(0x00, 0xCA, 0x00, 0x7A, vec![]) } /// Get DO "List of supported Algorithm attributes" -pub fn get_algo_list() -> Command { +pub(crate) fn get_algo_list() -> Command { Command::new(0x00, 0xCA, 0x00, 0xFA, vec![]) } /// GET RESPONSE -pub fn get_response() -> Command { +pub(crate) fn get_response() -> Command { Command::new(0x00, 0xC0, 0x00, 0x00, vec![]) } /// VERIFY pin for PW1 (81) -pub fn verify_pw1_81(pin: Vec) -> Command { +pub(crate) fn verify_pw1_81(pin: Vec) -> Command { Command::new(0x00, 0x20, 0x00, 0x81, pin) } /// VERIFY pin for PW1 (82) -pub fn verify_pw1_82(pin: Vec) -> Command { +pub(crate) fn verify_pw1_82(pin: Vec) -> Command { Command::new(0x00, 0x20, 0x00, 0x82, pin) } /// VERIFY pin for PW3 (83) -pub fn verify_pw3(pin: Vec) -> Command { +pub(crate) fn verify_pw3(pin: Vec) -> Command { Command::new(0x00, 0x20, 0x00, 0x83, pin) } /// TERMINATE DF -pub fn terminate_df() -> Command { +pub(crate) fn terminate_df() -> Command { Command::new(0x00, 0xe6, 0x00, 0x00, vec![]) } /// ACTIVATE FILE -pub fn activate_file() -> Command { +pub(crate) fn activate_file() -> Command { Command::new(0x00, 0x44, 0x00, 0x00, vec![]) } /// 7.2.8 PUT DATA, /// ('tag' must consist of either one or two bytes) -pub fn put_data(tag: &[u8], data: Vec) -> Command { +pub(crate) fn put_data(tag: &[u8], data: Vec) -> Command { assert!(!tag.is_empty() && tag.len() <= 2); let (p1, p2) = if tag.len() == 2 { @@ -84,33 +85,33 @@ pub fn put_data(tag: &[u8], data: Vec) -> Command { } /// PUT DO Name -pub fn put_name(name: Vec) -> Command { +pub(crate) fn put_name(name: Vec) -> Command { put_data(&[0x5b], name) } /// PUT DO Language preferences -pub fn put_lang(lang: Vec) -> Command { +pub(crate) fn put_lang(lang: Vec) -> Command { put_data(&[0x5f, 0x2d], lang) } /// PUT DO Sex -pub fn put_sex(sex: u8) -> Command { +pub(crate) fn put_sex(sex: u8) -> Command { put_data(&[0x5f, 0x35], vec![sex]) } /// PUT DO Uniform resource locator (URL) -pub fn put_url(url: Vec) -> Command { +pub(crate) fn put_url(url: Vec) -> Command { put_data(&[0x5f, 0x50], url) } /// Change PW1 (user pin). /// This can be used to reset the counter and set a pin. -pub fn change_pw1(pin: Vec) -> Command { +pub(crate) fn change_pw1(pin: Vec) -> Command { Command::new(0x00, 0x2C, 0x02, 0x81, pin) } /// Change PW3 (admin pin) -pub fn change_pw3(oldpin: Vec, newpin: Vec) -> Command { +pub(crate) fn change_pw3(oldpin: Vec, newpin: Vec) -> Command { let mut fullpin = oldpin; fullpin.extend(newpin.iter()); @@ -118,21 +119,29 @@ pub fn change_pw3(oldpin: Vec, newpin: Vec) -> Command { } /// Creates new APDU for decryption operation -pub fn decryption(data: Vec) -> Command { +pub(crate) fn decryption(data: Vec) -> Command { Command::new(0x00, 0x2A, 0x80, 0x86, data) } /// Creates new APDU for decryption operation -pub fn signature(data: Vec) -> Command { +pub(crate) fn signature(data: Vec) -> Command { Command::new(0x00, 0x2A, 0x9e, 0x9a, data) } /// Creates new APDU for "GENERATE ASYMMETRIC KEY PAIR" -pub fn gen_key(data: Vec) -> Command { +pub(crate) fn gen_key(data: Vec) -> Command { Command::new(0x00, 0x47, 0x80, 0x00, data) } /// Creates new APDU for "Reading of public key template" -pub fn get_pub_key(data: Vec) -> Command { +pub(crate) fn get_pub_key(data: Vec) -> Command { Command::new(0x00, 0x47, 0x81, 0x00, data) } + +/// Creates new APDU for key import +pub(crate) fn key_import(data: Vec) -> Command { + // The key import uses a PUT DATA command with odd INS (DB) and an + // Extended header list (DO 4D) as described in ISO 7816-8 + + Command::new(0x00, 0xDB, 0x3F, 0xFF, data) +} diff --git a/openpgp-card/src/apdu/mod.rs b/openpgp-card/src/apdu/mod.rs index bdeebff..5b5c07e 100644 --- a/openpgp-card/src/apdu/mod.rs +++ b/openpgp-card/src/apdu/mod.rs @@ -1,8 +1,10 @@ // SPDX-FileCopyrightText: 2021 Heiko Schaefer // SPDX-License-Identifier: MIT OR Apache-2.0 -pub mod command; -pub mod commands; +//! Commands and responses to commands ("Application Protocol Data Unit") + +pub(crate) mod command; +pub(crate) mod commands; pub mod response; use anyhow::Result; diff --git a/openpgp-card/src/keys.rs b/openpgp-card/src/keys.rs index 8e1e39e..954696f 100644 --- a/openpgp-card/src/keys.rs +++ b/openpgp-card/src/keys.rs @@ -341,16 +341,8 @@ fn ecc_key_cmd( // "Extended header list (DO 4D)" (contains the three inner TLV) let ehl = Tlv(Tag(vec![0x4d]), TlvEntry::C(vec![crt, cpkt, cpk])); - // The key import uses a PUT DATA command with odd INS (DB) and an - // Extended header list (DO 4D) as described in ISO 7816-8 - - Ok(Command::new( - 0x00, - 0xDB, - 0x3F, - 0xFF, - ehl.serialize().to_vec(), - )) + // key import command + Ok(commands::key_import(ehl.serialize().to_vec())) } fn get_crt(key_type: KeyType) -> Result { @@ -430,16 +422,8 @@ fn rsa_key_cmd( // "Extended header list (DO 4D)" let ehl = Tlv(Tag(vec![0x4d]), TlvEntry::C(vec![crt, cpkt, cpk])); - // The key import uses a PUT DATA command with odd INS (DB) and an - // Extended header list (DO 4D) as described in ISO 7816-8 - - Ok(Command::new( - 0x00, - 0xDB, - 0x3F, - 0xFF, - ehl.serialize().to_vec(), - )) + // key import command + Ok(commands::key_import(ehl.serialize().to_vec())) } fn copy_key_to_card(