1use super::CommandError;
5use crate::{
6 cli::{get_auth, SubCommand},
7 context::ContextCache,
8 convert::{from_input_to_bytes, from_str_to_alg, from_tpm_key_to_output},
9 device::{with_device, Device},
10 key::{Alg, TpmKey, TpmKeyTemplate, OID_SEALED_DATA},
11 uri::Uri,
12};
13use argh::FromArgs;
14use std::{cell::RefCell, rc::Rc};
15use tpm2_protocol::data::{Tpm2bSensitiveData, TpmSe};
16
17#[derive(FromArgs, Debug, Clone)]
19#[argh(subcommand, name = "seal", note = "Creates a sealed data object.")]
20pub struct Seal {
21 #[argh(positional)]
23 pub parent: Uri,
24
25 #[argh(positional, from_str_fn(from_str_to_alg))]
27 pub algorithm: Alg,
28
29 #[argh(option)]
31 pub policy: Option<String>,
32
33 #[argh(option, short = 'o')]
35 pub output: Option<Uri>,
36
37 #[argh(option, short = 'i')]
39 pub input: Option<Uri>,
40
41 #[argh(option, arg_name = "auth", short = 'p')]
44 pub parent_auth: Option<String>,
45
46 #[argh(option, arg_name = "auth", short = 'a')]
49 pub auth: Option<String>,
50
51 #[argh(option, arg_name = "auth", short = 'm', long = "hmac-auth")]
54 pub hmac_auth: Option<String>,
55}
56
57impl SubCommand for Seal {
58 fn run(
59 &self,
60 device: Option<Rc<RefCell<Device>>>,
61 context: &mut ContextCache,
62 _plain: bool,
63 ) -> Result<(), CommandError> {
64 let parent_auth = get_auth(
65 self.parent_auth.as_ref(),
66 "TPM2SH_PARENT_AUTH",
67 &context.session_map,
68 &[TpmSe::Policy],
69 )?;
70 let auth = get_auth(self.auth.as_ref(), "TPM2SH_AUTH", &context.session_map, &[])?;
71 with_device(device, |device| {
72 let parent_handle = context.load_parent(device, &self.parent)?;
73
74 let input_bytes = from_input_to_bytes(self.input.as_ref())?;
75
76 if input_bytes.is_empty() {
77 return Err(CommandError::InvalidInput(
78 "Cannot seal empty data; please provide data via stdin or an input file."
79 .to_string(),
80 ));
81 }
82
83 let data_to_seal = Tpm2bSensitiveData::try_from(input_bytes.as_slice())?;
84
85 let template = TpmKeyTemplate {
86 alg_desc: &self.algorithm,
87 policy: self.policy.as_ref(),
88 sensitive_data: data_to_seal,
89 key_type_oid: OID_SEALED_DATA,
90 };
91
92 let tpm_key = TpmKey::new(
93 device,
94 context,
95 &[parent_auth],
96 &auth,
97 parent_handle,
98 &template,
99 )?;
100
101 from_tpm_key_to_output(context, &tpm_key, self.output.as_ref())
102 })
103 }
104}