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