hsmtool/
profile.rs

1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5use anyhow::{Context, Result};
6use cryptoki::session::UserType;
7use directories::ProjectDirs;
8use serde::Deserialize;
9use std::collections::HashMap;
10use std::os::unix::fs::PermissionsExt;
11use std::path::Path;
12
13use crate::error::HsmError;
14use crate::module;
15
16#[derive(Deserialize)]
17/// The HSM `Profile` contains authentication credentials for the named token.
18///
19/// The profiles file is a JSON map of profile names to per-token credentials:
20/// ```ignore
21/// {
22///     "earlgrey": {
23///         "token": "my_personal_token",
24///         "user": "user",
25///         "pin": "abc123"
26///     }
27/// }
28/// ```
29pub struct Profile {
30    /// The name of the HSM token.
31    pub token: String,
32
33    /// The user type to authenticate to the token.
34    #[serde(deserialize_with = "module::deserialize_user")]
35    pub user: UserType,
36
37    /// The pin for the user.
38    pub pin: Option<String>,
39}
40
41impl Profile {
42    pub fn load(filename: &Path) -> Result<HashMap<String, Profile>> {
43        let path = if let Some(base) = ProjectDirs::from("org", "opentitan", "hsmtool") {
44            base.config_dir().join(filename)
45        } else {
46            filename.to_owned()
47        };
48        let perm = path
49            .metadata()
50            .context(format!("Accessing {path:?}"))?
51            .permissions()
52            .mode()
53            & 0o777;
54        // Verify the profile is only accessible by owner.
55        if perm & 0o077 != 0 {
56            return Err(HsmError::FilePermissionError(perm)).context(format!("Accessing {path:?}"));
57        }
58        let profiles = std::fs::read_to_string(&path).context(format!("Cannot read {path:?}"))?;
59        Ok(serde_annotate::from_str(&profiles)?)
60    }
61}