xref: /aosp_15_r20/tools/security/remote_provisioning/hwtrust/cxxbridge/lib.rs (revision d9ecfb0f4d734c9ce41cde8ac4d585b094fd4222)
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::rkp::Csr as InnerCsr;
7 use hwtrust::session::{Options, RkpInstance, Session};
8 use std::str::FromStr;
9 
10 #[allow(clippy::needless_maybe_sized)]
11 #[allow(unsafe_op_in_unsafe_fn)]
12 #[cxx::bridge(namespace = "hwtrust::rust")]
13 mod ffi {
14     /// The set of validation rules to apply.
15     enum DiceChainKind {
16         /// The DICE chain specified by VSR 13.
17         Vsr13,
18         /// The DICE chain specified by VSR 14.
19         Vsr14,
20         /// The DICE chain specified by VSR 15.
21         Vsr15,
22         /// The DICE chain specified by VSR 16.
23         Vsr16,
24     }
25 
26     /// The result type used by [`verify_dice_chain()`]. The standard [`Result`] is currently only
27     /// converted to exceptions by `cxxbridge` but we can't use exceptions so need to do something
28     /// custom.
29     struct VerifyDiceChainResult {
30         /// If non-empty, the description of the verification error that occurred.
31         error: String,
32         /// If [`error`] is empty, a handle to the verified chain.
33         chain: Box<DiceChain>,
34         /// If [`error`] is empty, the length of the chain.
35         len: usize,
36     }
37 
38     /// The result type used by [`validate_csr()`]. The standard [`Result`] is currently only
39     /// converted to exceptions by `cxxbridge` but we can't use exceptions so need to do something
40     /// custom.
41     struct ValidateCsrResult {
42         /// If non-empty, the description of the verification error that occurred.
43         error: String,
44         /// If [`error`] is empty, a handle to the validated Csr.
45         csr: Box<Csr>,
46     }
47 
48     extern "Rust" {
49         type DiceChain;
50 
51         #[cxx_name = VerifyDiceChain]
verify_dice_chain( chain: &[u8], kind: DiceChainKind, allow_any_mode: bool, instance: &str, ) -> VerifyDiceChainResult52         fn verify_dice_chain(
53             chain: &[u8],
54             kind: DiceChainKind,
55             allow_any_mode: bool,
56             instance: &str,
57         ) -> VerifyDiceChainResult;
58 
59         #[cxx_name = GetDiceChainPublicKey]
get_dice_chain_public_key(chain: &DiceChain, n: usize) -> Vec<u8>60         fn get_dice_chain_public_key(chain: &DiceChain, n: usize) -> Vec<u8>;
61 
62         #[cxx_name = IsDiceChainProper]
is_dice_chain_proper(chain: &DiceChain) -> bool63         fn is_dice_chain_proper(chain: &DiceChain) -> bool;
64 
65         type Csr;
66 
67         #[cxx_name = validateCsr]
validate_csr( csr: &[u8], kind: DiceChainKind, allow_any_mode: bool, instance: &str, ) -> ValidateCsrResult68         fn validate_csr(
69             csr: &[u8],
70             kind: DiceChainKind,
71             allow_any_mode: bool,
72             instance: &str,
73         ) -> ValidateCsrResult;
74 
75         #[cxx_name = getDiceChainFromCsr]
get_dice_chain_from_csr(csr: &Csr) -> VerifyDiceChainResult76         fn get_dice_chain_from_csr(csr: &Csr) -> VerifyDiceChainResult;
77     }
78 }
79 
80 /// A DICE chain as exposed over the cxx bridge.
81 pub struct DiceChain(Option<ChainForm>);
82 
verify_dice_chain( chain: &[u8], kind: ffi::DiceChainKind, allow_any_mode: bool, instance: &str, ) -> ffi::VerifyDiceChainResult83 fn verify_dice_chain(
84     chain: &[u8],
85     kind: ffi::DiceChainKind,
86     allow_any_mode: bool,
87     instance: &str,
88 ) -> ffi::VerifyDiceChainResult {
89     let mut session = Session {
90         options: match kind {
91             ffi::DiceChainKind::Vsr13 => Options::vsr13(),
92             ffi::DiceChainKind::Vsr14 => Options::vsr14(),
93             ffi::DiceChainKind::Vsr15 => Options::vsr15(),
94             ffi::DiceChainKind::Vsr16 => Options::vsr16(),
95             _ => {
96                 return ffi::VerifyDiceChainResult {
97                     error: "invalid chain kind".to_string(),
98                     chain: Box::new(DiceChain(None)),
99                     len: 0,
100                 }
101             }
102         },
103     };
104     let Ok(rkp_instance) = RkpInstance::from_str(instance) else {
105         return ffi::VerifyDiceChainResult {
106             error: format!("invalid RKP instance: {}", instance),
107             chain: Box::new(DiceChain(None)),
108             len: 0,
109         };
110     };
111     session.set_allow_any_mode(allow_any_mode);
112     session.set_rkp_instance(rkp_instance);
113     match ChainForm::from_cbor(&session, chain) {
114         Ok(chain) => {
115             let len = chain.length();
116             let chain = Box::new(DiceChain(Some(chain)));
117             ffi::VerifyDiceChainResult { error: "".to_string(), chain, len }
118         }
119         Err(e) => {
120             let error = format!("{:#}", e);
121             ffi::VerifyDiceChainResult { error, chain: Box::new(DiceChain(None)), len: 0 }
122         }
123     }
124 }
125 
get_dice_chain_public_key(chain: &DiceChain, n: usize) -> Vec<u8>126 fn get_dice_chain_public_key(chain: &DiceChain, n: usize) -> Vec<u8> {
127     if let DiceChain(Some(chain)) = chain {
128         let key = match chain {
129             ChainForm::Proper(chain) => chain.payloads()[n].subject_public_key(),
130             ChainForm::Degenerate(chain) => chain.public_key(),
131         };
132         if let Ok(cose_key) = key.to_cose_key() {
133             if let Ok(bytes) = cose_key.to_vec() {
134                 return bytes;
135             }
136         }
137     }
138     Vec::new()
139 }
140 
is_dice_chain_proper(chain: &DiceChain) -> bool141 fn is_dice_chain_proper(chain: &DiceChain) -> bool {
142     if let DiceChain(Some(chain)) = chain {
143         match chain {
144             ChainForm::Proper(_) => true,
145             ChainForm::Degenerate(_) => false,
146         }
147     } else {
148         false
149     }
150 }
151 
152 /// A Csr as exposed over the cxx bridge.
153 pub struct Csr(Option<InnerCsr>);
154 
validate_csr( csr: &[u8], kind: ffi::DiceChainKind, allow_any_mode: bool, instance: &str, ) -> ffi::ValidateCsrResult155 fn validate_csr(
156     csr: &[u8],
157     kind: ffi::DiceChainKind,
158     allow_any_mode: bool,
159     instance: &str,
160 ) -> ffi::ValidateCsrResult {
161     let mut session = Session {
162         options: match kind {
163             ffi::DiceChainKind::Vsr13 => Options::vsr13(),
164             ffi::DiceChainKind::Vsr14 => Options::vsr14(),
165             ffi::DiceChainKind::Vsr15 => Options::vsr15(),
166             ffi::DiceChainKind::Vsr16 => Options::vsr16(),
167             _ => {
168                 return ffi::ValidateCsrResult {
169                     error: "invalid chain kind".to_string(),
170                     csr: Box::new(Csr(None)),
171                 }
172             }
173         },
174     };
175     let Ok(rkp_instance) = RkpInstance::from_str(instance) else {
176         return ffi::ValidateCsrResult {
177             error: format!("invalid RKP instance: {}", instance),
178             csr: Box::new(Csr(None)),
179         };
180     };
181     session.set_allow_any_mode(allow_any_mode);
182     session.set_rkp_instance(rkp_instance);
183     match InnerCsr::from_cbor(&session, csr) {
184         Ok(csr) => {
185             let csr = Box::new(Csr(Some(csr)));
186             ffi::ValidateCsrResult { error: "".to_string(), csr }
187         }
188         Err(e) => {
189             let error = format!("{:#}", e);
190             ffi::ValidateCsrResult { error, csr: Box::new(Csr(None)) }
191         }
192     }
193 }
194 
get_dice_chain_from_csr(csr: &Csr) -> ffi::VerifyDiceChainResult195 fn get_dice_chain_from_csr(csr: &Csr) -> ffi::VerifyDiceChainResult {
196     match csr {
197         Csr(Some(csr)) => {
198             let chain = csr.dice_chain();
199             let len = chain.length();
200             let chain = Box::new(DiceChain(Some(chain)));
201             ffi::VerifyDiceChainResult { error: "".to_string(), chain, len }
202         }
203         _ => ffi::VerifyDiceChainResult {
204             error: "CSR could not be destructured".to_string(),
205             chain: Box::new(DiceChain(None)),
206             len: 0,
207         },
208     }
209 }
210