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