1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 //! This module is used to implement cryptographic algorithm operations, including key generation.
17
18 use asset_common::{transfer_error_code, CallingInfo, SUCCESS};
19 use asset_definition::{Accessibility, AuthType, ErrCode, Result};
20 use asset_log::{loge, logi};
21 use asset_utils::hasher;
22
23 use crate::{HksBlob, KeyId};
24
25 /// Struct to store key attributes, excluding key materials.
26 #[derive(Clone)]
27 pub struct SecretKey {
28 auth_type: AuthType,
29 access_type: Accessibility,
30 require_password_set: bool,
31 alias: Vec<u8>,
32 user_id: i32,
33 }
34
35 enum KeyAliasVersion {
36 V1(Vec<u8>), // Old secret key alias
37 V2(Vec<u8>), // New secret key alias
38 V3, // Prefixed new secret key alias
39 None,
40 }
41
42 extern "C" {
GenerateKey(keyId: *const KeyId, need_auth: bool, require_password_set: bool) -> i3243 fn GenerateKey(keyId: *const KeyId, need_auth: bool, require_password_set: bool) -> i32;
DeleteKey(keyId: *const KeyId) -> i3244 fn DeleteKey(keyId: *const KeyId) -> i32;
IsKeyExist(keyId: *const KeyId) -> i3245 fn IsKeyExist(keyId: *const KeyId) -> i32;
RenameKeyAlias(keyId: *const KeyId, newKeyAlias: *const HksBlob) -> i3246 fn RenameKeyAlias(keyId: *const KeyId, newKeyAlias: *const HksBlob) -> i32;
47 }
48
49 const MAX_ALIAS_SIZE: usize = 64;
50 const ALIAS_PREFIX: [u8; 2] = [b'1', b'_'];
51
append_attr<T>(tag: &str, value: T, vec: &mut Vec<u8>) where T: Default + std::cmp::PartialEq, u32: std::convert::From<T>,52 fn append_attr<T>(tag: &str, value: T, vec: &mut Vec<u8>)
53 where
54 T: Default + std::cmp::PartialEq,
55 u32: std::convert::From<T>,
56 {
57 if value != T::default() {
58 vec.push(b'_');
59 vec.extend_from_slice(tag.as_bytes());
60 vec.push(b':');
61 vec.extend_from_slice(&u32::from(value).to_le_bytes());
62 }
63 }
64
calculate_key_alias( calling_info: &CallingInfo, auth_type: AuthType, access_type: Accessibility, require_password_set: bool, standard: bool, ) -> Vec<u8>65 fn calculate_key_alias(
66 calling_info: &CallingInfo,
67 auth_type: AuthType,
68 access_type: Accessibility,
69 require_password_set: bool,
70 standard: bool,
71 ) -> Vec<u8> {
72 let mut alias: Vec<u8> = Vec::with_capacity(MAX_ALIAS_SIZE);
73 alias.extend_from_slice(&calling_info.user_id().to_le_bytes());
74 alias.push(b'_');
75 match calling_info.group() {
76 Some(group) => alias.extend(group),
77 None => {
78 alias.extend_from_slice(&calling_info.owner_type().to_le_bytes());
79 alias.push(b'_');
80 alias.extend(calling_info.owner_info());
81 },
82 }
83 append_attr::<AuthType>("AuthType", auth_type, &mut alias);
84 append_attr::<Accessibility>("Accessibility", access_type, &mut alias);
85 append_attr::<bool>("RequirePasswordSet", require_password_set, &mut alias);
86 hasher::sha256(standard, &alias)
87 }
88
get_existing_key_alias( calling_info: &CallingInfo, auth_type: AuthType, access_type: Accessibility, require_password_set: bool, ) -> Result<KeyAliasVersion>89 fn get_existing_key_alias(
90 calling_info: &CallingInfo,
91 auth_type: AuthType,
92 access_type: Accessibility,
93 require_password_set: bool,
94 ) -> Result<KeyAliasVersion> {
95 let new_alias = calculate_key_alias(calling_info, auth_type, access_type, require_password_set, true);
96 let prefixed_new_alias = [ALIAS_PREFIX.to_vec(), new_alias.clone()].concat();
97 let key = SecretKey {
98 user_id: calling_info.user_id(),
99 auth_type,
100 access_type,
101 require_password_set,
102 alias: prefixed_new_alias.clone(),
103 };
104 if key.exists()? {
105 logi!("[INFO][{access_type}]-typed secret key with v3 alias exists.");
106 return Ok(KeyAliasVersion::V3);
107 }
108
109 let key = SecretKey {
110 user_id: calling_info.user_id(),
111 auth_type,
112 access_type,
113 require_password_set,
114 alias: new_alias.clone(),
115 };
116 if key.exists()? {
117 logi!("[INFO][{access_type}]-typed secret key with v2 alias exists.");
118 return Ok(KeyAliasVersion::V2(new_alias));
119 }
120
121 let old_alias = calculate_key_alias(calling_info, auth_type, access_type, require_password_set, false);
122 let key = SecretKey {
123 user_id: calling_info.user_id(),
124 auth_type,
125 access_type,
126 require_password_set,
127 alias: old_alias.clone(),
128 };
129 if key.exists()? {
130 logi!("[INFO][{access_type}]-typed secret key with v1 alias exists.");
131 return Ok(KeyAliasVersion::V1(old_alias));
132 }
133
134 Ok(KeyAliasVersion::None)
135 }
136
huks_rename_key_alias( calling_info: &CallingInfo, auth_type: AuthType, access_type: Accessibility, require_password_set: bool, alias: Vec<u8>, ) -> i32137 fn huks_rename_key_alias(
138 calling_info: &CallingInfo,
139 auth_type: AuthType,
140 access_type: Accessibility,
141 require_password_set: bool,
142 alias: Vec<u8>,
143 ) -> i32 {
144 // Prepare secret key id with outdated alias.
145 let alias_ref = &alias;
146 let alias_blob = HksBlob { size: alias.len() as u32, data: alias_ref.as_ptr() };
147 let key_id = KeyId::new(calling_info.user_id(), alias_blob, access_type);
148
149 // Prepare secret key alias to be replaced in.
150 let new_alias = calculate_key_alias(calling_info, auth_type, access_type, require_password_set, true);
151 let prefixed_new_alias = [ALIAS_PREFIX.to_vec(), new_alias].concat();
152 let prefixed_new_alias_ref = &prefixed_new_alias;
153 let prefixed_new_alias_blob =
154 HksBlob { size: prefixed_new_alias.len() as u32, data: prefixed_new_alias_ref.as_ptr() };
155
156 unsafe { RenameKeyAlias(&key_id as *const KeyId, &prefixed_new_alias_blob as *const HksBlob) }
157 }
158
159 /// Rename a secret key alias.
rename_key_alias( calling_info: &CallingInfo, auth_type: AuthType, access_type: Accessibility, require_password_set: bool, ) -> bool160 pub fn rename_key_alias(
161 calling_info: &CallingInfo,
162 auth_type: AuthType,
163 access_type: Accessibility,
164 require_password_set: bool,
165 ) -> bool {
166 match get_existing_key_alias(calling_info, auth_type, access_type, require_password_set) {
167 Ok(KeyAliasVersion::V3) => {
168 logi!("[INFO]Alias of [{access_type}]-typed secret key has already been renamed successfully.");
169 true
170 },
171 Ok(KeyAliasVersion::V2(alias)) | Ok(KeyAliasVersion::V1(alias)) => {
172 let ret = huks_rename_key_alias(calling_info, auth_type, access_type, require_password_set, alias);
173 if let SUCCESS = ret {
174 logi!("[INFO]Rename alias of [{access_type}]-typed secret key success.");
175 true
176 } else {
177 loge!("[FATAL]Rename alias of [{access_type}]-typed secret key failed, err is {}.", ret);
178 false
179 }
180 },
181 Ok(KeyAliasVersion::None) => {
182 loge!("[FATAL][{access_type}]-typed secret key does not exist.");
183 false
184 },
185 Err(e) => {
186 loge!("[FATAL]Can not determine whether [{access_type}]-typed secret key exists, err is {}", e);
187 false
188 },
189 }
190 }
191
192 impl SecretKey {
193 /// New a secret key with the input key alias argument.
new_with_alias( user_id: i32, auth_type: AuthType, access_type: Accessibility, require_password_set: bool, alias: Vec<u8>, ) -> Result<Self>194 pub fn new_with_alias(
195 user_id: i32,
196 auth_type: AuthType,
197 access_type: Accessibility,
198 require_password_set: bool,
199 alias: Vec<u8>,
200 ) -> Result<Self> {
201 Ok(Self { user_id, auth_type, access_type, require_password_set, alias })
202 }
203
204 /// Calculate key alias and then new a secret key.
new_without_alias( calling_info: &CallingInfo, auth_type: AuthType, access_type: Accessibility, require_password_set: bool, ) -> Result<Self>205 pub fn new_without_alias(
206 calling_info: &CallingInfo,
207 auth_type: AuthType,
208 access_type: Accessibility,
209 require_password_set: bool,
210 ) -> Result<Self> {
211 let new_alias = calculate_key_alias(calling_info, auth_type, access_type, require_password_set, true);
212 let prefixed_new_alias = [ALIAS_PREFIX.to_vec(), new_alias.clone()].concat();
213 let key = Self {
214 user_id: calling_info.user_id(),
215 auth_type,
216 access_type,
217 require_password_set,
218 alias: prefixed_new_alias,
219 };
220 Ok(key)
221 }
222
223 /// Check whether the secret key exists.
exists(&self) -> Result<bool>224 pub fn exists(&self) -> Result<bool> {
225 let key_alias = HksBlob { size: self.alias.len() as u32, data: self.alias.as_ptr() };
226 let key_id = KeyId::new(self.user_id, key_alias, self.access_type);
227 let ret = unsafe { IsKeyExist(&key_id as *const KeyId) };
228 match ret {
229 SUCCESS => Ok(true),
230 ret if ret == ErrCode::NotFound as i32 => Ok(false),
231 _ => Err(transfer_error_code(ErrCode::try_from(ret as u32)?)),
232 }
233 }
234
235 /// Generate the secret key and store in HUKS.
generate(&self) -> Result<()>236 pub fn generate(&self) -> Result<()> {
237 let key_alias = HksBlob { size: self.alias.len() as u32, data: self.alias.as_ptr() };
238 let key_id = KeyId::new(self.user_id, key_alias, self.access_type);
239 let ret = unsafe { GenerateKey(&key_id as *const KeyId, self.need_user_auth(), self.require_password_set) };
240 match ret {
241 SUCCESS => Ok(()),
242 _ => Err(transfer_error_code(ErrCode::try_from(ret as u32)?)),
243 }
244 }
245
246 /// Delete the secret key.
delete(&self) -> Result<()>247 pub fn delete(&self) -> Result<()> {
248 let key_alias = HksBlob { size: self.alias.len() as u32, data: self.alias.as_ptr() };
249 let key_id = KeyId::new(self.user_id, key_alias, self.access_type);
250 let ret = unsafe { DeleteKey(&key_id as *const KeyId) };
251 match ret {
252 ret if ((ret == ErrCode::NotFound as i32) || ret == SUCCESS) => Ok(()),
253 _ => Err(transfer_error_code(ErrCode::try_from(ret as u32)?)),
254 }
255 }
256
257 /// Delete secret key by owner.
delete_by_owner(calling_info: &CallingInfo) -> Result<()>258 pub fn delete_by_owner(calling_info: &CallingInfo) -> Result<()> {
259 let mut res = Ok(());
260 let accessibilitys =
261 [Accessibility::DevicePowerOn, Accessibility::DeviceFirstUnlocked, Accessibility::DeviceUnlocked];
262 for accessibility in accessibilitys.into_iter() {
263 let secret_key = SecretKey::new_without_alias(calling_info, AuthType::None, accessibility, true)?;
264 let tmp = secret_key.delete();
265 res = if tmp.is_err() { tmp } else { res };
266
267 let secret_key = SecretKey::new_without_alias(calling_info, AuthType::Any, accessibility, true)?;
268 let tmp = secret_key.delete();
269 res = if tmp.is_err() { tmp } else { res };
270
271 let secret_key = SecretKey::new_without_alias(calling_info, AuthType::None, accessibility, false)?;
272 let tmp = secret_key.delete();
273 res = if tmp.is_err() { tmp } else { res };
274
275 let secret_key = SecretKey::new_without_alias(calling_info, AuthType::Any, accessibility, false)?;
276 let tmp = secret_key.delete();
277 res = if tmp.is_err() { tmp } else { res };
278 }
279
280 res
281 }
282
283 /// Determine whether user auth is required.
need_user_auth(&self) -> bool284 pub(crate) fn need_user_auth(&self) -> bool {
285 self.auth_type == AuthType::Any
286 }
287
288 /// Determine whether device unlock is required.
need_device_unlock(&self) -> bool289 pub(crate) fn need_device_unlock(&self) -> bool {
290 self.access_type == Accessibility::DeviceUnlocked
291 }
292
293 /// Get the key alias.
alias(&self) -> &Vec<u8>294 pub fn alias(&self) -> &Vec<u8> {
295 &self.alias
296 }
297
298 /// Get the key access type
access_type(&self) -> Accessibility299 pub(crate) fn access_type(&self) -> Accessibility {
300 self.access_type
301 }
302
303 /// Get the key user id.
user_id(&self) -> i32304 pub(crate) fn user_id(&self) -> i32 {
305 self.user_id
306 }
307 }
308