1use super::CommandError;
5use crate::{
6 cli::{get_auth, SubCommand},
7 context::ContextCache,
8 device::{self, Auth, Device, DeviceError},
9 uri::Uri,
10};
11use argh::FromArgs;
12use std::{cell::RefCell, rc::Rc, str::FromStr};
13use tpm2_protocol::{data::TpmCc, data::TpmSe, message::TpmUnsealCommand};
14
15#[derive(FromArgs, Debug)]
17#[argh(
18 subcommand,
19 name = "unseal",
20 note = "Retrieves data from a sealed data object."
21)]
22pub struct Unseal {
23 #[argh(positional)]
25 pub input: String,
26
27 #[argh(option, arg_name = "auth", short = 'a')]
30 pub auth: Option<String>,
31
32 #[argh(option, arg_name = "auth", short = 'm', long = "hmac-auth")]
35 pub hmac_auth: Option<String>,
36}
37
38impl SubCommand for Unseal {
39 fn run(
47 &self,
48 device: Option<Rc<RefCell<Device>>>,
49 context: &mut ContextCache,
50 _plain: bool,
51 ) -> Result<(), CommandError> {
52 let auth = match (self.auth.as_ref(), self.hmac_auth.as_ref()) {
53 (Some(_), Some(_)) => {
54 return Err(CommandError::InvalidInput(
55 "Cannot use --auth and --hmac-auth at the same time".to_string(),
56 ));
57 }
58 (Some(auth_str), None) => get_auth(
59 Some(auth_str),
60 "TPM2SH_AUTH",
61 &context.session_map,
62 &[TpmSe::Policy],
63 )?,
64 (None, Some(hmac_auth_str)) => get_auth(
65 Some(hmac_auth_str),
66 "TPM2SH_HMAC_AUTH",
67 &context.session_map,
68 &[TpmSe::Hmac],
69 )?,
70 (None, None) => {
71 let auth = get_auth(None, "TPM2SH_AUTH", &context.session_map, &[TpmSe::Policy])?;
72 if matches!(&auth, Auth::Password(p) if p.is_empty()) {
73 get_auth(
74 None,
75 "TPM2SH_HMAC_AUTH",
76 &context.session_map,
77 &[TpmSe::Hmac],
78 )?
79 } else {
80 auth
81 }
82 }
83 };
84 device::with_device(device, |device| {
85 let input_uri = Uri::from_str(&self.input)?;
86
87 if matches!(input_uri, Uri::Path(_) | Uri::Password(_)) {
88 return Err(CommandError::InvalidInput("{input_uri}".to_string()));
89 }
90
91 let item_handle = context.load_context(device, &input_uri)?;
92
93 let unseal_cmd = TpmUnsealCommand {
94 item_handle: item_handle.0.into(),
95 };
96 let unseal_handles = [item_handle.0];
97 let auths = &[auth];
98
99 let (unseal_resp, _) = context.execute(device, &unseal_cmd, &unseal_handles, auths)?;
100
101 let out_data = unseal_resp
102 .Unseal()
103 .map_err(|_| DeviceError::ResponseMismatch(TpmCc::Unseal))?
104 .out_data;
105
106 context.write_data(None, &out_data)?;
107
108 Ok(())
109 })
110 }
111}