1 //! This library provides bindings for C++ code to comfortably and reasonably safely interface with
2 //! the libhwtrust Rust library.
3 
4 use coset::CborSerializable;
5 use hwtrust::dice::ChainForm;
6 use hwtrust::session::{Options, Session};
7 
8 #[allow(unsafe_op_in_unsafe_fn)]
9 #[cxx::bridge(namespace = "hwtrust::rust")]
10 mod ffi {
11     /// The set of validation rules to apply.
12     enum DiceChainKind {
13         /// The DICE chain specified by VSR 13.
14         Vsr13,
15         /// The DICE chain specified by VSR 14.
16         Vsr14,
17         /// The DICE chain specified by VSR 15.
18         Vsr15,
19         /// The DICE chain specified by VSR 16.
20         Vsr16,
21     }
22 
23     /// The result type used by [`verify_dice_chain()`]. The standard [`Result`] is currently only
24     /// converted to exceptions by `cxxbridge` but we can't use exceptions so need to do something
25     /// custom.
26     struct VerifyDiceChainResult {
27         /// If non-empty, the description of the verification error that occurred.
28         error: String,
29         /// If [`error`] is empty, a handle to the verified chain.
30         chain: Box<DiceChain>,
31         /// If [`error`] is empty, the length of the chain.
32         len: usize,
33     }
34 
35     extern "Rust" {
36         type DiceChain;
37 
38         #[cxx_name = VerifyDiceChain]
verify_dice_chain(chain: &[u8], kind: DiceChainKind) -> VerifyDiceChainResult39         fn verify_dice_chain(chain: &[u8], kind: DiceChainKind) -> VerifyDiceChainResult;
40 
41         #[cxx_name = GetDiceChainPublicKey]
get_dice_chain_public_key(chain: &DiceChain, n: usize) -> Vec<u8>42         fn get_dice_chain_public_key(chain: &DiceChain, n: usize) -> Vec<u8>;
43 
44         #[cxx_name = IsDiceChainProper]
is_dice_chain_proper(chain: &DiceChain) -> bool45         fn is_dice_chain_proper(chain: &DiceChain) -> bool;
46     }
47 }
48 
49 /// A DICE chain as exposed over the cxx bridge.
50 pub struct DiceChain(Option<ChainForm>);
51 
verify_dice_chain(chain: &[u8], kind: ffi::DiceChainKind) -> ffi::VerifyDiceChainResult52 fn verify_dice_chain(chain: &[u8], kind: ffi::DiceChainKind) -> ffi::VerifyDiceChainResult {
53     let session = Session {
54         options: match kind {
55             ffi::DiceChainKind::Vsr13 => Options::vsr13(),
56             ffi::DiceChainKind::Vsr14 => Options::vsr14(),
57             ffi::DiceChainKind::Vsr15 => Options::vsr15(),
58             ffi::DiceChainKind::Vsr16 => Options::vsr16(),
59             _ => {
60                 return ffi::VerifyDiceChainResult {
61                     error: "invalid chain kind".to_string(),
62                     chain: Box::new(DiceChain(None)),
63                     len: 0,
64                 }
65             }
66         },
67     };
68     match ChainForm::from_cbor(&session, chain) {
69         Ok(chain) => {
70             let len = match chain {
71                 ChainForm::Proper(ref chain) => chain.payloads().len(),
72                 ChainForm::Degenerate(_) => 1,
73             };
74             let chain = Box::new(DiceChain(Some(chain)));
75             ffi::VerifyDiceChainResult { error: "".to_string(), chain, len }
76         }
77         Err(e) => {
78             let error = format!("{:#}", e);
79             ffi::VerifyDiceChainResult { error, chain: Box::new(DiceChain(None)), len: 0 }
80         }
81     }
82 }
83 
get_dice_chain_public_key(chain: &DiceChain, n: usize) -> Vec<u8>84 fn get_dice_chain_public_key(chain: &DiceChain, n: usize) -> Vec<u8> {
85     if let DiceChain(Some(chain)) = chain {
86         let key = match chain {
87             ChainForm::Proper(chain) => chain.payloads()[n].subject_public_key(),
88             ChainForm::Degenerate(chain) => chain.public_key(),
89         };
90         if let Ok(cose_key) = key.to_cose_key() {
91             if let Ok(bytes) = cose_key.to_vec() {
92                 return bytes;
93             }
94         }
95     }
96     Vec::new()
97 }
98 
is_dice_chain_proper(chain: &DiceChain) -> bool99 fn is_dice_chain_proper(chain: &DiceChain) -> bool {
100     if let DiceChain(Some(chain)) = chain {
101         match chain {
102             ChainForm::Proper(_) => true,
103             ChainForm::Degenerate(_) => false,
104         }
105     } else {
106         false
107     }
108 }
109