xref: /aosp_15_r20/tools/security/remote_provisioning/hwtrust/src/main.rs (revision d9ecfb0f4d734c9ce41cde8ac4d585b094fd4222)
1 //! A tool for handling data related to the hardware root-of-trust.
2 
3 use anyhow::{bail, Result};
4 use clap::{Parser, Subcommand, ValueEnum};
5 use hwtrust::dice;
6 use hwtrust::dice::ChainForm;
7 use hwtrust::rkp;
8 use hwtrust::session::{Options, RkpInstance, Session};
9 use std::io::BufRead;
10 use std::{fs, io};
11 
12 #[derive(Parser)]
13 /// A tool for handling data related to the hardware root-of-trust
14 #[clap(name = "hwtrust")]
15 struct Args {
16     #[clap(subcommand)]
17     action: Action,
18 
19     /// Verbose output, including parsed data structures.
20     #[clap(long)]
21     verbose: bool,
22 
23     /// The VSR version to validate against. If omitted, the set of rules that are used have no
24     /// compromises or workarounds and new implementations should validate against them as it will
25     /// be the basis for future VSR versions.
26     #[clap(long, value_enum)]
27     vsr: Option<VsrVersion>,
28 }
29 
30 #[derive(Subcommand)]
31 enum Action {
32     /// Deprecated alias of dice-chain
33     VerifyDiceChain(DiceChainArgs),
34     DiceChain(DiceChainArgs),
35     FactoryCsr(FactoryCsrArgs),
36     Csr(CsrArgs),
37 }
38 
39 #[derive(Parser)]
40 /// Verify that a DICE chain is well-formed
41 ///
42 /// DICE chains are expected to follow the specification of the RKP HAL [1] which is based on the
43 /// Open Profile for DICE [2].
44 ///
45 /// [1] -- https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
46 /// [2] -- https://pigweed.googlesource.com/open-dice/+/refs/heads/main/docs/specification.md
47 struct DiceChainArgs {
48     /// Path to a file containing a DICE chain.
49     chain: String,
50     /// Allow non-normal DICE chain modes.
51     #[clap(long)]
52     allow_any_mode: bool,
53     /// Validate the chain against the requirements of a specific RKP instance.
54     /// If not specified, the default RKP instance is used.
55     #[clap(value_enum, long, default_value = "default")]
56     rkp_instance: RkpInstance,
57 }
58 
59 #[derive(Parser)]
60 /// Verify a CSR generated by the rkp_factory_extraction_tool
61 ///
62 /// "v1" CSRs are also decrypted using the factory EEK.
63 struct FactoryCsrArgs {
64     /// Path to a file containing one or more CSRs, in the "csr+json" format as defined by
65     /// rkp_factory_extraction_tool. Each line is interpreted as a separate JSON blob containing
66     /// a base64-encoded CSR.
67     csr_file: String,
68     /// Allow non-normal DICE chain modes.
69     #[clap(long)]
70     allow_any_mode: bool,
71 }
72 
73 #[derive(Parser)]
74 /// Parse and verify a request payload that is suitable for the RKP server's SignCertificates API.
75 /// In HALv3, this is the output of generateCertificateRequestV2. For previous HAL versions,
76 /// the CSR is constructed by the remote provisioning service client, but is constructed from the
77 /// outputs of generateCertificateRequest.
78 struct CsrArgs {
79     /// Path to a file containing a single CSR, encoded as CBOR.
80     csr_file: String,
81     /// Allow non-normal DICE chain modes.
82     #[clap(long)]
83     allow_any_mode: bool,
84     /// Validate the chain against the requirements of a specific RKP instance.
85     /// If not specified, the default RKP instance is used.
86     #[clap(value_enum, long, default_value = "default")]
87     rkp_instance: RkpInstance,
88 }
89 
90 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
91 enum VsrVersion {
92     /// VSR 13 / Android T / 2022
93     Vsr13,
94     /// VSR 14 / Android U / 2023
95     Vsr14,
96     /// VSR 15 / Android V / 2024
97     Vsr15,
98     /// VSR 16 / Android W / 2025
99     Vsr16,
100 }
101 
session_from_vsr(vsr: Option<VsrVersion>) -> Session102 fn session_from_vsr(vsr: Option<VsrVersion>) -> Session {
103     Session {
104         options: match vsr {
105             Some(VsrVersion::Vsr13) => Options::vsr13(),
106             Some(VsrVersion::Vsr14) => Options::vsr14(),
107             Some(VsrVersion::Vsr15) => Options::vsr15(),
108             Some(VsrVersion::Vsr16) => {
109                 println!();
110                 println!();
111                 println!("  ********************************************************************");
112                 println!("  ! The selected VSR is not finalized and is subject to change.      !");
113                 println!("  ! Please contact your TAM if you intend to depend on the           !");
114                 println!("  ! validation rules use for the selected VSR.                       !");
115                 println!("  ********************************************************************");
116                 println!();
117                 println!();
118                 Options::vsr16()
119             }
120             None => Options::default(),
121         },
122     }
123 }
124 
main() -> Result<()>125 fn main() -> Result<()> {
126     let args = Args::parse();
127     let message = match &args.action {
128         Action::VerifyDiceChain(sub_args) => {
129             println!();
130             println!("  ********************************************************************");
131             println!("  ! 'verify-dice-chain' has been deprecated in favor of 'dice-chain'.!");
132             println!("  ********************************************************************");
133             println!();
134             verify_dice_chain(&args, sub_args)?
135         }
136         Action::DiceChain(sub_args) => verify_dice_chain(&args, sub_args)?,
137         Action::FactoryCsr(sub_args) => parse_factory_csr(&args, sub_args)?,
138         Action::Csr(sub_args) => parse_csr(&args, sub_args)?,
139     };
140     println!("{}", message.unwrap_or(String::from("Success")));
141     Ok(())
142 }
143 
verify_dice_chain(args: &Args, sub_args: &DiceChainArgs) -> Result<Option<String>>144 fn verify_dice_chain(args: &Args, sub_args: &DiceChainArgs) -> Result<Option<String>> {
145     let mut session = session_from_vsr(args.vsr);
146     session.set_allow_any_mode(sub_args.allow_any_mode);
147     session.set_rkp_instance(sub_args.rkp_instance);
148     let chain = dice::ChainForm::from_cbor(&session, &fs::read(&sub_args.chain)?)?;
149     if args.verbose {
150         println!("{chain:#?}");
151     }
152     if let ChainForm::Degenerate(_) = chain {
153         return Ok(Some(String::from(
154             "WARNING!
155 The given 'degenerate' DICE chain is valid. However, the degenerate chain form is deprecated in
156 favor of full DICE chains, rooted in ROM, that measure the system's boot components.",
157         )));
158     }
159     Ok(None)
160 }
161 
parse_factory_csr(args: &Args, sub_args: &FactoryCsrArgs) -> Result<Option<String>>162 fn parse_factory_csr(args: &Args, sub_args: &FactoryCsrArgs) -> Result<Option<String>> {
163     let mut session = session_from_vsr(args.vsr);
164     session.set_allow_any_mode(sub_args.allow_any_mode);
165     let input = &fs::File::open(&sub_args.csr_file)?;
166     let mut csr_count = 0;
167     for line in io::BufReader::new(input).lines() {
168         let line = line?;
169         if line.is_empty() {
170             continue;
171         }
172         let csr = rkp::FactoryCsr::from_json(&session, &line)?;
173         csr_count += 1;
174         if args.verbose {
175             println!("{csr_count}: {csr:#?}");
176         }
177     }
178     if csr_count == 0 {
179         bail!("No CSRs found in the input file '{}'", sub_args.csr_file);
180     }
181     Ok(None)
182 }
183 
parse_csr(args: &Args, sub_args: &CsrArgs) -> Result<Option<String>>184 fn parse_csr(args: &Args, sub_args: &CsrArgs) -> Result<Option<String>> {
185     let mut session = session_from_vsr(args.vsr);
186     session.set_allow_any_mode(sub_args.allow_any_mode);
187     session.set_rkp_instance(sub_args.rkp_instance);
188     let input = &fs::File::open(&sub_args.csr_file)?;
189     let csr = rkp::Csr::from_cbor(&session, input)?;
190     if args.verbose {
191         print!("{csr:#?}");
192     }
193     Ok(None)
194 }
195 
196 #[cfg(test)]
197 mod tests {
198     use super::*;
199     use clap::CommandFactory;
200 
201     #[test]
verify_command()202     fn verify_command() {
203         Args::command().debug_assert();
204     }
205 }
206