cli/command/
create_primary.rs

1// SPDX-License-Identifier: GPL-3-0-or-later
2// Copyright (c) 2025 Opinsys Oy
3// Copyright (c) 2024-2025 Jarkko Sakkinen
4
5use crate::{
6    cli::SubCommand,
7    command::{deny_keyedhash, CommandError, CreationArgs, HierarchyArgs},
8    device::with_device,
9    job::Job,
10    key::Alg,
11    template::build_public,
12};
13use clap::Args;
14use tpm2_protocol::{
15    data::{
16        Tpm2bData, Tpm2bPublic, Tpm2bSensitiveCreate, Tpm2bSensitiveData, TpmCc, TpmRh,
17        TpmlPcrSelection, TpmsSensitiveCreate,
18    },
19    message::TpmCreatePrimaryCommand,
20};
21
22/// Creates a new primary key in a specified hierarchy.
23#[derive(Args, Debug, Clone)]
24pub struct CreatePrimary {
25    #[clap(flatten)]
26    pub hierarchy_args: HierarchyArgs,
27
28    /// Key algorithm
29    #[arg(value_parser = clap::value_parser!(Alg))]
30    pub algorithm: Alg,
31
32    #[clap(flatten)]
33    pub creation_args: CreationArgs,
34}
35
36impl SubCommand for CreatePrimary {
37    fn run(&self, job: &mut Job) -> Result<(), CommandError> {
38        with_device(job.device.clone(), |device| {
39            deny_keyedhash(&self.algorithm)?;
40
41            let primary_handle: TpmRh = self.hierarchy_args.hierarchy.into();
42            let auths = vec![job.auth_list.first().cloned().unwrap_or_default()];
43            let handles = [primary_handle as u32];
44
45            let (object_attributes, user_auth, auth_policy) =
46                self.creation_args.parse(&self.algorithm)?;
47            let public_template = build_public(&self.algorithm, auth_policy, object_attributes);
48
49            let cmd = TpmCreatePrimaryCommand {
50                primary_handle: (primary_handle as u32).into(),
51                in_sensitive: Tpm2bSensitiveCreate {
52                    inner: TpmsSensitiveCreate {
53                        user_auth,
54                        data: Tpm2bSensitiveData::default(),
55                    },
56                },
57                in_public: Tpm2bPublic {
58                    inner: public_template,
59                },
60                outside_info: Tpm2bData::default(),
61                creation_pcr: TpmlPcrSelection::default(),
62            };
63
64            let (resp, _) = job.execute(device, &cmd, &handles, &auths)?;
65
66            let resp = resp
67                .CreatePrimary()
68                .map_err(|_| CommandError::ResponseMismatch(TpmCc::CreatePrimary))?;
69
70            let object_handle = resp.object_handle;
71            job.cache.track(object_handle)?;
72            let vhandle = job.cache.save_context(
73                device,
74                object_handle,
75                &resp.out_public,
76                &Tpm2bPublic::default(),
77            )?;
78            writeln!(job.writer, "vtpm:{vhandle:08x}")?;
79            Ok(())
80        })
81    }
82}