Flatten API (#274)
Re-exports types from the toplevel instead of placing them in individual modules (often which only contain one type). This makes the API easier for users to navigate, while still retaining the same module structure internally. Additionally, this commit uses the `uuid` crate for modeling UUIDs.
This commit is contained in:
committed by
GitHub
parent
1228d16439
commit
1765e11bc0
+44
-40
@@ -1,7 +1,4 @@
|
||||
//! MS Container Map Records
|
||||
//!
|
||||
//! These appear(?) to be defined in Microsoft's Smart Card Minidriver Specification:
|
||||
//! <https://docs.microsoft.com/en-us/previous-versions/windows/hardware/design/dn631754(v=vs.85)>
|
||||
//! MS Container Map Records.
|
||||
|
||||
// Adapted from yubico-piv-tool:
|
||||
// <https://github.com/Yubico/yubico-piv-tool/>
|
||||
@@ -37,46 +34,53 @@ use crate::{key::SlotId, serialization::*, Error, Result, YubiKey, CB_OBJ_MAX};
|
||||
use log::error;
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
|
||||
/// Container name length
|
||||
const CONTAINER_NAME_LEN: usize = 40;
|
||||
|
||||
/// Container record length: 27 = 80 + 1 + 1 + 2 + 1 + 1 + 1 + 20
|
||||
const CONTAINER_REC_LEN: usize = (2 * CONTAINER_NAME_LEN) + 27;
|
||||
|
||||
const OBJ_MSCMAP: u32 = 0x005f_ff10;
|
||||
|
||||
const TAG_MSCMAP: u8 = 0x81;
|
||||
|
||||
/// MS Container Map(?) Records
|
||||
/// MS Container Map records.
|
||||
///
|
||||
/// Defined in Microsoft's Smart Card Minidriver Specification:
|
||||
/// <https://docs.microsoft.com/en-us/previous-versions/windows/hardware/design/dn631754(v=vs.85)>
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "untested")))]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Container {
|
||||
/// Container name
|
||||
pub name: [u16; CONTAINER_NAME_LEN],
|
||||
pub struct MsContainer {
|
||||
/// Container name.
|
||||
pub name: [u16; Self::NAME_LEN],
|
||||
|
||||
/// Card slot
|
||||
/// Card slot.
|
||||
pub slot: SlotId,
|
||||
|
||||
/// Key spec
|
||||
/// Key spec.
|
||||
pub key_spec: u8,
|
||||
|
||||
/// Key size in bits
|
||||
/// Key size in bits.
|
||||
pub key_size_bits: u16,
|
||||
|
||||
/// Flags
|
||||
/// Flags.
|
||||
pub flags: u8,
|
||||
|
||||
/// PIN ID
|
||||
/// PIN ID.
|
||||
pub pin_id: u8,
|
||||
|
||||
/// Associated ECHD(?) container (typo of "ecdh" perhaps?)
|
||||
/// Associated ECHD container.
|
||||
pub associated_echd_container: u8,
|
||||
|
||||
/// Cert fingerprint
|
||||
pub cert_fingerprint: [u8; 20],
|
||||
/// Cert fingerprint.
|
||||
pub cert_fingerprint: [u8; Self::CERT_FINGERPRINT_LEN],
|
||||
}
|
||||
|
||||
impl Container {
|
||||
/// Read MS Container Map records
|
||||
impl MsContainer {
|
||||
/// Container name length in UTF-16 chars.
|
||||
const NAME_LEN: usize = 40;
|
||||
|
||||
/// Container record length: 27 = 80 + 1 + 1 + 2 + 1 + 1 + 1 + 20
|
||||
const REC_LEN: usize = (2 * Self::NAME_LEN) + 27;
|
||||
|
||||
/// Length of a certificate fingerprint.
|
||||
const CERT_FINGERPRINT_LEN: usize = 20;
|
||||
|
||||
/// Read MS Container Map records.
|
||||
pub fn read_mscmap(yubikey: &mut YubiKey) -> Result<Vec<Self>> {
|
||||
let txn = yubikey.begin_transaction()?;
|
||||
let response = txn.fetch_object(OBJ_MSCMAP)?;
|
||||
@@ -95,8 +99,8 @@ impl Container {
|
||||
return Err(Error::InvalidObject);
|
||||
}
|
||||
|
||||
for chunk in tlv.value.chunks_exact(CONTAINER_REC_LEN) {
|
||||
containers.push(Container::new(chunk)?);
|
||||
for chunk in tlv.value.chunks_exact(Self::REC_LEN) {
|
||||
containers.push(MsContainer::new(chunk)?);
|
||||
}
|
||||
|
||||
Ok(containers)
|
||||
@@ -105,7 +109,7 @@ impl Container {
|
||||
/// Write MS Container Map records.
|
||||
pub fn write_mscmap(yubikey: &mut YubiKey, containers: &[Self]) -> Result<()> {
|
||||
let n_containers = containers.len();
|
||||
let data_len = n_containers * CONTAINER_REC_LEN;
|
||||
let data_len = n_containers * Self::REC_LEN;
|
||||
|
||||
let txn = yubikey.begin_transaction()?;
|
||||
|
||||
@@ -115,7 +119,7 @@ impl Container {
|
||||
|
||||
let mut buf = [0u8; CB_OBJ_MAX];
|
||||
let offset = Tlv::write_as(&mut buf, TAG_MSCMAP, data_len, |buf| {
|
||||
for (i, chunk) in buf.chunks_exact_mut(CONTAINER_REC_LEN).enumerate() {
|
||||
for (i, chunk) in buf.chunks_exact_mut(Self::REC_LEN).enumerate() {
|
||||
chunk.copy_from_slice(&containers[i].to_bytes());
|
||||
}
|
||||
})?;
|
||||
@@ -123,19 +127,19 @@ impl Container {
|
||||
txn.save_object(OBJ_MSCMAP, &buf[..offset])
|
||||
}
|
||||
|
||||
/// Parse a container record from a byte slice
|
||||
/// Parse a container record from a byte slice.
|
||||
pub fn new(bytes: &[u8]) -> Result<Self> {
|
||||
if bytes.len() != CONTAINER_REC_LEN {
|
||||
if bytes.len() != Self::REC_LEN {
|
||||
error!(
|
||||
"couldn't parse PIV container: expected {}-bytes, got {}-bytes",
|
||||
CONTAINER_REC_LEN,
|
||||
Self::REC_LEN,
|
||||
bytes.len()
|
||||
);
|
||||
return Err(Error::ParseError);
|
||||
}
|
||||
|
||||
let mut name = [0u16; CONTAINER_NAME_LEN];
|
||||
let name_bytes_len = CONTAINER_NAME_LEN * 2;
|
||||
let mut name = [0u16; Self::NAME_LEN];
|
||||
let name_bytes_len = Self::NAME_LEN * 2;
|
||||
|
||||
for (i, chunk) in bytes[..name_bytes_len].chunks_exact(2).enumerate() {
|
||||
name[i] = u16::from_le_bytes(chunk.try_into().unwrap());
|
||||
@@ -144,7 +148,7 @@ impl Container {
|
||||
let mut cert_fingerprint = [0u8; 20];
|
||||
cert_fingerprint.copy_from_slice(&bytes[(bytes.len() - 20)..]);
|
||||
|
||||
Ok(Container {
|
||||
Ok(Self {
|
||||
name,
|
||||
slot: bytes[name_bytes_len].try_into()?,
|
||||
key_spec: bytes[name_bytes_len + 1],
|
||||
@@ -160,17 +164,17 @@ impl Container {
|
||||
})
|
||||
}
|
||||
|
||||
/// Parse the container name as a UTF-16 string
|
||||
/// Parse the container name as a UTF-16 string.
|
||||
pub fn parse_name(&self) -> Result<String> {
|
||||
String::from_utf16(&self.name).map_err(|_| Error::ParseError)
|
||||
}
|
||||
|
||||
/// Serialize a container record as a byte size
|
||||
pub fn to_bytes(&self) -> [u8; CONTAINER_REC_LEN] {
|
||||
/// Serialize a container record as a byte size.
|
||||
pub fn to_bytes(&self) -> [u8; Self::REC_LEN] {
|
||||
// TODO(tarcieri): use array instead of `Vec`
|
||||
let mut bytes = Vec::with_capacity(CONTAINER_REC_LEN);
|
||||
let mut bytes = Vec::with_capacity(Self::REC_LEN);
|
||||
|
||||
for i in 0..CONTAINER_NAME_LEN {
|
||||
for i in 0..Self::NAME_LEN {
|
||||
bytes.extend_from_slice(&self.name[i].to_le_bytes());
|
||||
}
|
||||
|
||||
@@ -185,7 +189,7 @@ impl Container {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&'a [u8]> for Container {
|
||||
impl<'a> TryFrom<&'a [u8]> for MsContainer {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(bytes: &'a [u8]) -> Result<Self> {
|
||||
|
||||
Reference in New Issue
Block a user