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