• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #[cxx::bridge(namespace = "hwtrust::rust")]
9 mod ffi {
10     /// The set of validation rules to apply.
11     enum DiceChainKind {
12         /// The DICE chain specified by VSR 13.
13         Vsr13,
14         /// The DICE chain specified by VSR 14.
15         Vsr14,
16     }
17 
18     /// The result type used by [`verify_dice_chain()`]. The standard [`Result`] is currently only
19     /// converted to exceptions by `cxxbridge` but we can't use exceptions so need to do something
20     /// custom.
21     struct VerifyDiceChainResult {
22         /// If non-empty, the description of the verification error that occurred.
23         error: String,
24         /// If [`error`] is empty, a handle to the verified chain.
25         chain: Box<DiceChain>,
26         /// If [`error`] is empty, the length of the chain.
27         len: usize,
28     }
29 
30     extern "Rust" {
31         type DiceChain;
32 
33         #[cxx_name = VerifyDiceChain]
verify_dice_chain(chain: &[u8], kind: DiceChainKind) -> VerifyDiceChainResult34         fn verify_dice_chain(chain: &[u8], kind: DiceChainKind) -> VerifyDiceChainResult;
35 
36         #[cxx_name = GetDiceChainPublicKey]
get_dice_chain_public_key(chain: &DiceChain, n: usize) -> Vec<u8>37         fn get_dice_chain_public_key(chain: &DiceChain, n: usize) -> Vec<u8>;
38     }
39 }
40 
41 /// A DICE chain as exposed over the cxx bridge.
42 pub struct DiceChain(Option<ChainForm>);
43 
verify_dice_chain(chain: &[u8], kind: ffi::DiceChainKind) -> ffi::VerifyDiceChainResult44 fn verify_dice_chain(chain: &[u8], kind: ffi::DiceChainKind) -> ffi::VerifyDiceChainResult {
45     let session = Session {
46         options: match kind {
47             ffi::DiceChainKind::Vsr13 => Options::vsr13(),
48             ffi::DiceChainKind::Vsr14 => Options::vsr14(),
49             _ => {
50                 return ffi::VerifyDiceChainResult {
51                     error: "invalid chain kind".to_string(),
52                     chain: Box::new(DiceChain(None)),
53                     len: 0,
54                 }
55             }
56         },
57     };
58     match ChainForm::from_cbor(&session, chain) {
59         Ok(chain) => {
60             let len = match chain {
61                 ChainForm::Proper(ref chain) => chain.payloads().len(),
62                 ChainForm::Degenerate(_) => 1,
63             };
64             let chain = Box::new(DiceChain(Some(chain)));
65             ffi::VerifyDiceChainResult { error: "".to_string(), chain, len }
66         }
67         Err(e) => {
68             let error = format!("{:#}", e);
69             ffi::VerifyDiceChainResult { error, chain: Box::new(DiceChain(None)), len: 0 }
70         }
71     }
72 }
73 
get_dice_chain_public_key(chain: &DiceChain, n: usize) -> Vec<u8>74 fn get_dice_chain_public_key(chain: &DiceChain, n: usize) -> Vec<u8> {
75     if let DiceChain(Some(chain)) = chain {
76         let key = match chain {
77             ChainForm::Proper(chain) => chain.payloads()[n].subject_public_key(),
78             ChainForm::Degenerate(chain) => chain.public_key(),
79         };
80         if let Ok(cose_key) = key.to_cose_key() {
81             if let Ok(bytes) = cose_key.to_vec() {
82                 return bytes;
83             }
84         }
85     }
86     Vec::new()
87 }
88