hsmtool/util/
ef.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::Result;
6use cryptoki::session::Session;
7
8use crate::util::attribute::{AttrData, AttributeError, AttributeMap, AttributeType, ObjectClass};
9use crate::util::helper;
10
11#[derive(Clone, Debug, Default)]
12pub struct ElementaryFile {
13    pub name: String,
14    pub application: Option<String>,
15    pub private: bool,
16}
17
18impl ElementaryFile {
19    pub fn new(name: String) -> Self {
20        Self {
21            name,
22            ..Default::default()
23        }
24    }
25
26    pub fn application(mut self, app: String) -> Self {
27        self.application = Some(app);
28        self
29    }
30
31    pub fn private(mut self, private: bool) -> Self {
32        self.private = private;
33        self
34    }
35
36    pub fn find(session: &Session, search: AttributeMap) -> Result<Vec<Self>> {
37        let mut search = search;
38        search.insert(
39            AttributeType::Class,
40            AttrData::ObjectClass(ObjectClass::Data),
41        );
42        let search = search.to_vec()?;
43        let attr = [
44            AttributeType::Label,
45            AttributeType::Application,
46            AttributeType::Private,
47        ];
48        let attr = attr
49            .iter()
50            .map(|&a| Ok(a.try_into()?))
51            .collect::<Result<Vec<cryptoki::object::AttributeType>>>()?;
52
53        let mut result = Vec::new();
54        for object in session.find_objects(&search)? {
55            let data = session.get_attributes(object, &attr)?;
56            let data = AttributeMap::from(data.as_slice());
57            result.push(Self {
58                name: data
59                    .get(&AttributeType::Label)
60                    .map(|x| x.try_string())
61                    .transpose()?
62                    .unwrap_or_else(|| String::from("<unnamed>")),
63                application: data
64                    .get(&AttributeType::Application)
65                    .map(|x| x.try_string())
66                    .transpose()?,
67                private: data
68                    .get(&AttributeType::Private)
69                    .map(|x| x.try_into())
70                    .transpose()?
71                    .unwrap_or(false),
72            });
73        }
74        Ok(result)
75    }
76
77    pub fn list(session: &Session) -> Result<Vec<Self>> {
78        Self::find(session, AttributeMap::default())
79    }
80
81    pub fn exists(self, session: &Session) -> Result<bool> {
82        let mut attr = AttributeMap::default();
83        attr.insert(
84            AttributeType::Class,
85            AttrData::ObjectClass(ObjectClass::Data),
86        );
87        attr.insert(AttributeType::Label, AttrData::Str(self.name.clone()));
88        if let Some(app) = &self.application {
89            attr.insert(AttributeType::Application, AttrData::Str(app.clone()));
90        }
91        let attr = attr.to_vec()?;
92        let objects = session.find_objects(&attr)?;
93        Ok(!objects.is_empty())
94    }
95
96    pub fn read(self, session: &Session) -> Result<Vec<u8>> {
97        let mut attr = AttributeMap::default();
98        attr.insert(
99            AttributeType::Class,
100            AttrData::ObjectClass(ObjectClass::Data),
101        );
102        attr.insert(AttributeType::Label, AttrData::Str(self.name.clone()));
103        if let Some(app) = &self.application {
104            attr.insert(AttributeType::Application, AttrData::Str(app.clone()));
105        }
106        let attr = attr.to_vec()?;
107
108        let object = helper::find_one_object(session, &attr)?;
109        let data = AttributeMap::from_object(session, object)?;
110        let value = data
111            .get(&AttributeType::Value)
112            .ok_or(AttributeError::AttributeNotFound(AttributeType::Value))?;
113        let value = Vec::<u8>::try_from(value)?;
114        Ok(value)
115    }
116
117    pub fn write(self, session: &Session, data: &[u8]) -> Result<()> {
118        let mut attr = AttributeMap::default();
119        attr.insert(
120            AttributeType::Class,
121            AttrData::ObjectClass(ObjectClass::Data),
122        );
123        attr.insert(AttributeType::Label, AttrData::Str(self.name.clone()));
124        if let Some(application) = &self.application {
125            // Is this a bug in opensc-pkcs11 or in the Nitrokey?
126            // It seems the application string needs a nul terminator.
127            let mut val = application.clone();
128            val.push(0 as char);
129            attr.insert(AttributeType::Application, AttrData::Str(val));
130        }
131        attr.insert(AttributeType::Token, AttrData::from(true));
132        attr.insert(AttributeType::Private, AttrData::from(self.private));
133        attr.insert(AttributeType::Value, AttrData::from(data));
134        let attr = attr.to_vec()?;
135        session.create_object(&attr)?;
136        Ok(())
137    }
138}