Skip to main content

isomdl/definitions/
device_signed.rs

1//! This module contains the definitions related to device signing.
2//!
3//! The [DeviceSigned] struct represents a device signed object, which includes namespaces and device authentication information.
4//!
5//! The [Error] enum represents the possible errors that can occur in this module.  
6//! - [Error::UnableToEncode]: Indicates an error when encoding a value as CBOR.
7use crate::cose::MaybeTagged;
8use crate::definitions::{
9    helpers::{NonEmptyMap, Tag24},
10    session::SessionTranscript,
11};
12use coset::{CoseMac0, CoseSign1};
13use serde::{Deserialize, Serialize};
14use std::collections::BTreeMap;
15
16/// Represents a device-signed structure.
17#[derive(Clone, Debug, Deserialize, Serialize)]
18#[serde(rename_all = "camelCase")]
19pub struct DeviceSigned {
20    #[serde(rename = "nameSpaces")]
21    /// A [DeviceNamespacesBytes] struct representing the namespaces.
22    pub namespaces: DeviceNamespacesBytes,
23
24    /// A [DeviceAuth] struct representing the device authentication.
25    pub device_auth: DeviceAuth,
26}
27
28pub type DeviceNamespacesBytes = Tag24<DeviceNamespaces>;
29pub type DeviceNamespaces = BTreeMap<String, DeviceSignedItems>;
30pub type DeviceSignedItems = NonEmptyMap<String, ciborium::Value>;
31
32/// Represents a device signature.
33///
34/// This struct contains the device signature in the form of a [CoseSign1] object.  
35/// The [CoseSign1] object represents a `COSE (CBOR Object Signing and Encryption) signature.
36#[derive(Clone, Debug, Deserialize, Serialize)]
37#[serde(rename_all = "camelCase")]
38pub enum DeviceAuth {
39    DeviceSignature(MaybeTagged<CoseSign1>),
40    DeviceMac(MaybeTagged<CoseMac0>),
41}
42
43#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
44pub enum DeviceAuthType {
45    Sign1,
46    Mac0,
47}
48
49pub type DeviceAuthenticationBytes<S> = Tag24<DeviceAuthentication<S>>;
50
51#[derive(Clone, Debug, Deserialize, Serialize)]
52pub struct DeviceAuthentication<S: SessionTranscript>(
53    &'static str,
54    // See https://github.com/serde-rs/serde/issues/1296.
55    #[serde(bound = "")] S,
56    String,
57    DeviceNamespacesBytes,
58);
59
60impl<S: SessionTranscript> DeviceAuthentication<S> {
61    pub fn new(transcript: S, doc_type: String, namespaces_bytes: DeviceNamespacesBytes) -> Self {
62        Self(
63            "DeviceAuthentication",
64            transcript,
65            doc_type,
66            namespaces_bytes,
67        )
68    }
69}
70
71#[derive(Debug, thiserror::Error)]
72pub enum Error {
73    #[error("Unable to encode value as CBOR: {0}")]
74    UnableToEncode(coset::CoseError),
75}
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80    use crate::cbor;
81    use hex::FromHex;
82
83    static COSE_SIGN1: &str = include_str!("../../test/definitions/cose/sign1/serialized.cbor");
84
85    #[test]
86    fn device_auth() {
87        let bytes = Vec::<u8>::from_hex(COSE_SIGN1).unwrap();
88        let cose_sign1: MaybeTagged<CoseSign1> =
89            cbor::from_slice(&bytes).expect("failed to parse COSE_Sign1 from bytes");
90        let bytes2 = cbor::to_vec(&cose_sign1).unwrap();
91        assert_eq!(bytes, bytes2);
92        let device_auth = DeviceAuth::DeviceSignature(cose_sign1);
93        let bytes = cbor::to_vec(&device_auth).unwrap();
94        println!("bytes {}", hex::encode(&bytes));
95        let roundtripped: DeviceAuth = cbor::from_slice(&bytes).unwrap();
96        let roundtripped_bytes = cbor::to_vec(&roundtripped).unwrap();
97        assert_eq!(bytes, roundtripped_bytes);
98    }
99}