From 861a051ff52a8cbdb52a93284bbe4c860af2de99 Mon Sep 17 00:00:00 2001 From: Heiko Schaefer Date: Wed, 4 May 2022 11:43:56 +0200 Subject: [PATCH] Add ShortTag type to model tags that are guaranteed to be 1 or 2 bytes long. --- openpgp-card/src/apdu/commands.rs | 20 +++++++------- openpgp-card/src/lib.rs | 45 ++++++++++++++++++++++++++++--- openpgp-card/src/tlv/tag.rs | 9 ++++++- 3 files changed, 59 insertions(+), 15 deletions(-) diff --git a/openpgp-card/src/apdu/commands.rs b/openpgp-card/src/apdu/commands.rs index 58b4727..1b48d8e 100644 --- a/openpgp-card/src/apdu/commands.rs +++ b/openpgp-card/src/apdu/commands.rs @@ -4,7 +4,7 @@ //! Pre-defined `Command` values for the OpenPGP card application use crate::apdu::command::Command; -use crate::{Tag, Tags}; +use crate::{ShortTag, Tags}; /// 7.2.1 SELECT /// (select the OpenPGP application on the card) @@ -19,11 +19,10 @@ pub(crate) fn select_openpgp() -> Command { } /// 7.2.6 GET DATA -fn get_data>(tag: T) -> Command { - match *tag.into().get() { - [tag0] => Command::new(0x00, 0xCA, 0, tag0, vec![]), - [tag0, tag1] => Command::new(0x00, 0xCA, tag0, tag1, vec![]), - _ => panic!("this should never happen"), // FIXME +fn get_data>(tag: T) -> Command { + match tag.into() { + ShortTag::One(tag0) => Command::new(0x00, 0xCA, 0, tag0, vec![]), + ShortTag::Two(tag0, tag1) => Command::new(0x00, 0xCA, tag0, tag1, vec![]), } } @@ -104,11 +103,10 @@ pub(crate) fn verify_pw3(pin: Vec) -> Command { } /// 7.2.8 PUT DATA, -pub(crate) fn put_data>(tag: T, data: Vec) -> Command { - match *tag.into().get() { - [tag0] => Command::new(0x00, 0xda, 0, tag0, data), - [tag0, tag1] => Command::new(0x00, 0xda, tag0, tag1, data), - _ => panic!("this should never happen"), // FIXME +pub(crate) fn put_data>(tag: T, data: Vec) -> Command { + match tag.into() { + ShortTag::One(tag0) => Command::new(0x00, 0xda, 0, tag0, data), + ShortTag::Two(tag0, tag1) => Command::new(0x00, 0xda, tag0, tag1, data), } } diff --git a/openpgp-card/src/lib.rs b/openpgp-card/src/lib.rs index 780a82e..4165e8a 100644 --- a/openpgp-card/src/lib.rs +++ b/openpgp-card/src/lib.rs @@ -330,6 +330,12 @@ pub(crate) enum Tags { } impl From for Tag { + fn from(t: Tags) -> Self { + ShortTag::from(t).into() + } +} + +impl From for ShortTag { fn from(t: Tags) -> Self { match t { // BER identifiers https://en.wikipedia.org/wiki/X.690#BER_encoding @@ -405,6 +411,39 @@ impl From for Tag { } } +/// A ShortTag is a Tlv tag that is guaranteed to be either 1 or 2 bytes long. +/// +/// This covers any tag that can be used in the OpenPGP card context (the spec doesn't describe how +/// longer tags might be used.) +/// +/// (The type tlv::Tag will usually/always contain 1 or 2 byte long tags, in this library. +/// But its length is not guaranteed by the type system) +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +enum ShortTag { + One(u8), + Two(u8, u8), +} + +impl From for Tag { + fn from(n: ShortTag) -> Self { + match n { + ShortTag::One(t0) => [t0].into(), + ShortTag::Two(t0, t1) => [t0, t1].into(), + } + } +} + +impl From<[u8; 1]> for ShortTag { + fn from(v: [u8; 1]) -> Self { + ShortTag::One(v[0]) + } +} +impl From<[u8; 2]> for ShortTag { + fn from(v: [u8; 2]) -> Self { + ShortTag::Two(v[0], v[1]) + } +} + #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub enum PinType { Sign, @@ -434,7 +473,7 @@ pub enum KeyType { impl KeyType { /// Get C1/C2/C3/DA values for this KeyTypes, to use as Tag - fn algorithm_tag(&self) -> Tag { + fn algorithm_tag(&self) -> ShortTag { match self { Self::Signing => Tags::AlgorithmAttributesSignature, Self::Decryption => Tags::AlgorithmAttributesDecryption, @@ -448,7 +487,7 @@ impl KeyType { /// /// (NOTE: these Tags are only used for "PUT DO", but GETting /// fingerprint information from the card uses the combined Tag C5) - fn fingerprint_put_tag(&self) -> Tag { + fn fingerprint_put_tag(&self) -> ShortTag { match self { Self::Signing => Tags::FingerprintSignature, Self::Decryption => Tags::FingerprintDecryption, @@ -462,7 +501,7 @@ impl KeyType { /// /// (NOTE: these Tags are only used for "PUT DO", but GETting /// timestamp information from the card uses the combined Tag CD) - fn timestamp_put_tag(&self) -> Tag { + fn timestamp_put_tag(&self) -> ShortTag { match self { Self::Signing => Tags::GenerationTimeSignature, Self::Decryption => Tags::GenerationTimeDecryption, diff --git a/openpgp-card/src/tlv/tag.rs b/openpgp-card/src/tlv/tag.rs index 74bc01e..620f556 100644 --- a/openpgp-card/src/tlv/tag.rs +++ b/openpgp-card/src/tlv/tag.rs @@ -1,7 +1,14 @@ // SPDX-FileCopyrightText: 2021 Heiko Schaefer // SPDX-License-Identifier: MIT OR Apache-2.0 -//! Tag in a TLV data structure +//! Tag in a TLV data structure. +//! +//! A Tag can span multiple octets, in the OpenPGP card context, only Tags spanning 1 or 2 octets +//! should come up. However, this type can deal with arbitrary length Tags. +//! +//! (The `ShortTag` type models tags that are exactly 1 or 2 octets long) +//! +//! https://en.wikipedia.org/wiki/X.690#Encoding use nom::{branch, bytes::complete as bytes, combinator, number::complete as number, sequence};