Add ShortTag type to model tags that are guaranteed to be 1 or 2 bytes long.

This commit is contained in:
Heiko Schaefer 2022-05-04 11:43:56 +02:00
parent 7854a40b5b
commit 861a051ff5
No known key found for this signature in database
GPG key ID: 4A849A1904CCBD7D
3 changed files with 59 additions and 15 deletions

View file

@ -4,7 +4,7 @@
//! Pre-defined `Command` values for the OpenPGP card application //! Pre-defined `Command` values for the OpenPGP card application
use crate::apdu::command::Command; use crate::apdu::command::Command;
use crate::{Tag, Tags}; use crate::{ShortTag, Tags};
/// 7.2.1 SELECT /// 7.2.1 SELECT
/// (select the OpenPGP application on the card) /// (select the OpenPGP application on the card)
@ -19,11 +19,10 @@ pub(crate) fn select_openpgp() -> Command {
} }
/// 7.2.6 GET DATA /// 7.2.6 GET DATA
fn get_data<T: Into<Tag>>(tag: T) -> Command { fn get_data<T: Into<ShortTag>>(tag: T) -> Command {
match *tag.into().get() { match tag.into() {
[tag0] => Command::new(0x00, 0xCA, 0, tag0, vec![]), ShortTag::One(tag0) => Command::new(0x00, 0xCA, 0, tag0, vec![]),
[tag0, tag1] => Command::new(0x00, 0xCA, tag0, tag1, vec![]), ShortTag::Two(tag0, tag1) => Command::new(0x00, 0xCA, tag0, tag1, vec![]),
_ => panic!("this should never happen"), // FIXME
} }
} }
@ -104,11 +103,10 @@ pub(crate) fn verify_pw3(pin: Vec<u8>) -> Command {
} }
/// 7.2.8 PUT DATA, /// 7.2.8 PUT DATA,
pub(crate) fn put_data<T: Into<Tag>>(tag: T, data: Vec<u8>) -> Command { pub(crate) fn put_data<T: Into<ShortTag>>(tag: T, data: Vec<u8>) -> Command {
match *tag.into().get() { match tag.into() {
[tag0] => Command::new(0x00, 0xda, 0, tag0, data), ShortTag::One(tag0) => Command::new(0x00, 0xda, 0, tag0, data),
[tag0, tag1] => Command::new(0x00, 0xda, tag0, tag1, data), ShortTag::Two(tag0, tag1) => Command::new(0x00, 0xda, tag0, tag1, data),
_ => panic!("this should never happen"), // FIXME
} }
} }

View file

@ -330,6 +330,12 @@ pub(crate) enum Tags {
} }
impl From<Tags> for Tag { impl From<Tags> for Tag {
fn from(t: Tags) -> Self {
ShortTag::from(t).into()
}
}
impl From<Tags> for ShortTag {
fn from(t: Tags) -> Self { fn from(t: Tags) -> Self {
match t { match t {
// BER identifiers https://en.wikipedia.org/wiki/X.690#BER_encoding // BER identifiers https://en.wikipedia.org/wiki/X.690#BER_encoding
@ -405,6 +411,39 @@ impl From<Tags> 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<ShortTag> 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)] #[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum PinType { pub enum PinType {
Sign, Sign,
@ -434,7 +473,7 @@ pub enum KeyType {
impl KeyType { impl KeyType {
/// Get C1/C2/C3/DA values for this KeyTypes, to use as Tag /// 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 { match self {
Self::Signing => Tags::AlgorithmAttributesSignature, Self::Signing => Tags::AlgorithmAttributesSignature,
Self::Decryption => Tags::AlgorithmAttributesDecryption, Self::Decryption => Tags::AlgorithmAttributesDecryption,
@ -448,7 +487,7 @@ impl KeyType {
/// ///
/// (NOTE: these Tags are only used for "PUT DO", but GETting /// (NOTE: these Tags are only used for "PUT DO", but GETting
/// fingerprint information from the card uses the combined Tag C5) /// fingerprint information from the card uses the combined Tag C5)
fn fingerprint_put_tag(&self) -> Tag { fn fingerprint_put_tag(&self) -> ShortTag {
match self { match self {
Self::Signing => Tags::FingerprintSignature, Self::Signing => Tags::FingerprintSignature,
Self::Decryption => Tags::FingerprintDecryption, Self::Decryption => Tags::FingerprintDecryption,
@ -462,7 +501,7 @@ impl KeyType {
/// ///
/// (NOTE: these Tags are only used for "PUT DO", but GETting /// (NOTE: these Tags are only used for "PUT DO", but GETting
/// timestamp information from the card uses the combined Tag CD) /// timestamp information from the card uses the combined Tag CD)
fn timestamp_put_tag(&self) -> Tag { fn timestamp_put_tag(&self) -> ShortTag {
match self { match self {
Self::Signing => Tags::GenerationTimeSignature, Self::Signing => Tags::GenerationTimeSignature,
Self::Decryption => Tags::GenerationTimeDecryption, Self::Decryption => Tags::GenerationTimeDecryption,

View file

@ -1,7 +1,14 @@
// SPDX-FileCopyrightText: 2021 Heiko Schaefer <heiko@schaefer.name> // SPDX-FileCopyrightText: 2021 Heiko Schaefer <heiko@schaefer.name>
// SPDX-License-Identifier: MIT OR Apache-2.0 // 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}; use nom::{branch, bytes::complete as bytes, combinator, number::complete as number, sequence};