1use super::CommandError;
6use crate::{
7 cli::{get_auth, SubCommand},
8 context::ContextCache,
9 convert::from_input_to_bytes,
10 device::{self, Auth, Device, DeviceError},
11 key::AnyKey,
12 uri::Uri,
13};
14use argh::FromArgs;
15use std::{cell::RefCell, rc::Rc};
16use tpm2_protocol::{
17 data::{Tpm2bName, Tpm2bPrivate, Tpm2bPublic, TpmCc, TpmSe},
18 message::TpmLoadCommand,
19 TpmHandle, TpmParse,
20};
21
22#[derive(FromArgs, Debug)]
24#[argh(subcommand, name = "load")]
25pub struct Load {
26 #[argh(positional)]
28 pub parent: Uri,
29
30 #[argh(positional)]
32 pub input: Option<Uri>,
33
34 #[argh(option, arg_name = "auth", short = 'p')]
37 pub parent_auth: Option<String>,
38
39 #[argh(option, arg_name = "auth", short = 'a')]
42 pub auth: Option<String>,
43
44 #[argh(option, arg_name = "auth", short = 'm', long = "hmac-auth")]
47 pub hmac_auth: Option<String>,
48}
49
50impl SubCommand for Load {
51 fn run(
52 &self,
53 device: Option<Rc<RefCell<Device>>>,
54 context: &mut ContextCache,
55 _plain: bool,
56 ) -> Result<(), CommandError> {
57 let parent_auth = get_auth(
58 self.parent_auth.as_ref(),
59 "TPM2SH_PARENT_AUTH",
60 &context.session_map,
61 &[TpmSe::Policy],
62 )?;
63 device::with_device(device, |device| -> Result<(), CommandError> {
64 let parent_handle = context.load_parent(device, &self.parent)?;
65 let input_bytes = from_input_to_bytes(self.input.as_ref())?;
66
67 let (object_handle, name) =
68 Self::run_input(context, device, parent_handle, &input_bytes, &[parent_auth])?;
69
70 context.new_context(device, object_handle, &name)?;
71 Ok(())
72 })
73 }
74}
75
76impl Load {
77 fn run_input(
78 context: &mut ContextCache,
79 device: &mut Device,
80 parent_handle: TpmHandle,
81 input_bytes: &[u8],
82 auths: &[Auth],
83 ) -> Result<(TpmHandle, Tpm2bName), CommandError> {
84 let tpm_key = match AnyKey::try_from(input_bytes)? {
85 AnyKey::Tpm(key) => key,
86 AnyKey::External(_) => {
87 let imported_key = context.import_key(device, parent_handle, input_bytes, auths)?;
88 Box::new(imported_key)
89 }
90 };
91
92 let (in_public, _) = Tpm2bPublic::parse(&tpm_key.pub_key)?;
93 let (in_private, _) = Tpm2bPrivate::parse(&tpm_key.priv_key)?;
94
95 let load_cmd = TpmLoadCommand {
96 parent_handle: parent_handle.0.into(),
97 in_private,
98 in_public,
99 };
100 let handles = [parent_handle.0];
101
102 let (resp, _) = context.execute(device, &load_cmd, &handles, auths)?;
103
104 let resp = resp
105 .Load()
106 .map_err(|_| DeviceError::ResponseMismatch(TpmCc::Load))?;
107
108 device.add_name_to_cache(resp.object_handle.0, resp.name);
109 context.track(resp.object_handle)?;
110 Ok((resp.object_handle, resp.name))
111 }
112}