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 super::{deny_keyedhash, CommandError};
6use crate::{
7    cli::{get_auth, Hierarchy, SubCommand},
8    context::ContextCache,
9    device::{with_device, Auth, Device, DeviceError},
10    key::Alg,
11    template::{build_public_template, default_attributes},
12};
13use argh::FromArgs;
14use std::{cell::RefCell, rc::Rc};
15use tpm2_protocol::{
16    data::{
17        Tpm2bAuth, Tpm2bData, Tpm2bDigest, Tpm2bPublic, Tpm2bSensitiveCreate, Tpm2bSensitiveData,
18        TpmCc, TpmRh, TpmSe, TpmlPcrSelection, TpmsSensitiveCreate,
19    },
20    message::TpmCreatePrimaryCommand,
21};
22
23/// Creates a new primary key in a specified hierarchy.
24#[derive(FromArgs, Debug)]
25#[argh(subcommand, name = "create-primary")]
26pub struct CreatePrimary {
27    /// hierarchy: owner, platform, or endorsement
28    #[argh(option, short = 'H')]
29    pub hierarchy: Option<Hierarchy>,
30
31    /// key algorithm
32    #[argh(positional)]
33    pub algorithm: Alg,
34
35    /// auth for the hierarchy: 'password://<hex>' or 'session://<handle>'
36    /// Uses TPM2SH_AUTH environment variable if not set.
37    #[argh(option, arg_name = "auth", short = 'a')]
38    pub auth: Option<String>,
39
40    /// hmac auth: 'password://<hex>' or 'session://<handle>'
41    /// Uses TPM2SH_HMAC_AUTH environment variable if not set.
42    #[argh(option, arg_name = "auth", short = 'm', long = "hmac-auth")]
43    pub hmac_auth: Option<String>,
44}
45
46impl SubCommand for CreatePrimary {
47    fn run(
48        &self,
49        device: Option<Rc<RefCell<Device>>>,
50        context: &mut ContextCache,
51        _plain: bool,
52    ) -> Result<(), CommandError> {
53        let auth = get_auth(
54            self.auth.as_ref(),
55            "TPM2SH_AUTH",
56            &context.session_map,
57            &[TpmSe::Policy],
58        )?;
59        with_device(device, |device| {
60            deny_keyedhash(&self.algorithm)?;
61
62            let primary_handle: TpmRh = self.hierarchy.unwrap_or_default().into();
63            let handles = [primary_handle as u32];
64            let auths = std::slice::from_ref(&auth);
65
66            let new_obj_user_auth = match &auth {
67                Auth::Password(p) => Tpm2bAuth::try_from(p.as_slice())?,
68                Auth::Tracked(_) => Tpm2bAuth::default(),
69            };
70
71            let user_with_auth = !new_obj_user_auth.is_empty();
72            let object_attributes = default_attributes(&self.algorithm, user_with_auth);
73            let public_template =
74                build_public_template(&self.algorithm, Tpm2bDigest::default(), object_attributes);
75
76            let cmd = TpmCreatePrimaryCommand {
77                primary_handle: (primary_handle as u32).into(),
78                in_sensitive: Tpm2bSensitiveCreate {
79                    inner: TpmsSensitiveCreate {
80                        user_auth: new_obj_user_auth,
81                        data: Tpm2bSensitiveData::default(),
82                    },
83                },
84                in_public: Tpm2bPublic {
85                    inner: public_template,
86                },
87                outside_info: Tpm2bData::default(),
88                creation_pcr: TpmlPcrSelection::default(),
89            };
90
91            let (resp, _) = context.execute(device, &cmd, &handles, auths)?;
92
93            let resp = resp
94                .CreatePrimary()
95                .map_err(|_| DeviceError::ResponseMismatch(TpmCc::CreatePrimary))?;
96
97            let object_handle = resp.object_handle;
98            device.add_name_to_cache(object_handle.0, resp.name);
99            context.track(object_handle)?;
100
101            context.new_context(device, object_handle, &resp.name)?;
102            Ok(())
103        })
104    }
105}