Skip to main content

matc/
fabric.rs

1use anyhow::Result;
2
3use byteorder::{BigEndian, WriteBytesExt};
4
5pub struct Fabric {
6    pub id: u64,
7    pub ipk_epoch_key: Vec<u8>,
8    pub ca_id: u64,
9    ca_public_key: Vec<u8>,
10}
11
12impl Fabric {
13    /// Create a new Fabric.
14    ///
15    /// `ipk_epoch_key` is the 16-byte IPK epoch key for this fabric. On the controller side it
16    /// should come from [`certmanager::CertManager::get_ipk_epoch_key`] (generated at bootstrap
17    /// and persisted in `metadata.json`). On the device side it is supplied by the controller
18    /// via AddNOC and stored in `FabricInfo.ipk`.
19    pub fn new(fabric_id: u64, ca_id: u64, ca_public_key: &[u8], ipk_epoch_key: &[u8]) -> Self {
20        Self {
21            id: fabric_id,
22            ipk_epoch_key: ipk_epoch_key.to_owned(),
23            ca_id,
24            ca_public_key: ca_public_key.to_owned(),
25        }
26    }
27
28    /// Compressed fabric identifier
29    pub fn compressed(&self) -> Result<Vec<u8>> {
30        let mut buf_id = Vec::new();
31        buf_id.write_u64::<BigEndian>(self.id)?;
32        crate::util::cryptoutil::hkdf_sha256(
33            &buf_id,
34            &self.ca_public_key.as_slice()[1..],
35            "CompressedFabric".as_bytes(),
36            8,
37        )
38    }
39
40    /// Integrity Protection Key
41    pub fn signed_ipk(&self) -> Result<Vec<u8>> {
42        crate::util::cryptoutil::hkdf_sha256(
43            &self.compressed()?,
44            &self.ipk_epoch_key,
45            "GroupKey v1.0".as_bytes(),
46            16,
47        )
48    }
49}