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 alias.extend_from_slice(&calling_info.owner_type().to_le_bytes());
76 alias.push(b'_');
77 alias.extend(calling_info.owner_info());
78 append_attr::<AuthType>("AuthType", auth_type, &mut alias);
79 append_attr::<Accessibility>("Accessibility", access_type, &mut alias);
80 append_attr::<bool>("RequirePasswordSet", require_password_set, &mut alias);
81 hasher::sha256(standard, &alias)
82 }
83
get_existing_key_alias( calling_info: &CallingInfo, auth_type: AuthType, access_type: Accessibility, require_password_set: bool, ) -> Result<KeyAliasVersion>84 fn get_existing_key_alias(
85 calling_info: &CallingInfo,
86 auth_type: AuthType,
87 access_type: Accessibility,
88 require_password_set: bool,
89 ) -> Result<KeyAliasVersion> {
90 let new_alias = calculate_key_alias(calling_info, auth_type, access_type, require_password_set, true);
91 let prefixed_new_alias = [ALIAS_PREFIX.to_vec(), new_alias.clone()].concat();
92 let key = SecretKey {
93 user_id: calling_info.user_id(),
94 auth_type,
95 access_type,
96 require_password_set,
97 alias: prefixed_new_alias.clone(),
98 };
99 if key.exists()? {
100 logi!("[INFO][{access_type}]-typed secret key with v3 alias exists.");
101 return Ok(KeyAliasVersion::V3);
102 }
103
104 let key = SecretKey {
105 user_id: calling_info.user_id(),
106 auth_type,
107 access_type,
108 require_password_set,
109 alias: new_alias.clone(),
110 };
111 if key.exists()? {
112 logi!("[INFO][{access_type}]-typed secret key with v2 alias exists.");
113 return Ok(KeyAliasVersion::V2(new_alias));
114 }
115
116 let old_alias = calculate_key_alias(calling_info, auth_type, access_type, require_password_set, false);
117 let key = SecretKey {
118 user_id: calling_info.user_id(),
119 auth_type,
120 access_type,
121 require_password_set,
122 alias: old_alias.clone(),
123 };
124 if key.exists()? {
125 logi!("[INFO][{access_type}]-typed secret key with v1 alias exists.");
126 return Ok(KeyAliasVersion::V1(old_alias));
127 }
128
129 Ok(KeyAliasVersion::None)
130 }
131
huks_rename_key_alias( calling_info: &CallingInfo, auth_type: AuthType, access_type: Accessibility, require_password_set: bool, alias: Vec<u8>, ) -> i32132 fn huks_rename_key_alias(
133 calling_info: &CallingInfo,
134 auth_type: AuthType,
135 access_type: Accessibility,
136 require_password_set: bool,
137 alias: Vec<u8>,
138 ) -> i32 {
139 // Prepare secret key id with outdated alias.
140 let alias_ref = &alias;
141 let alias_blob = HksBlob { size: alias.len() as u32, data: alias_ref.as_ptr() };
142 let key_id = KeyId::new(calling_info.user_id(), alias_blob, access_type);
143
144 // Prepare secret key alias to be replaced in.
145 let new_alias = calculate_key_alias(calling_info, auth_type, access_type, require_password_set, true);
146 let prefixed_new_alias = [ALIAS_PREFIX.to_vec(), new_alias].concat();
147 let prefixed_new_alias_ref = &prefixed_new_alias;
148 let prefixed_new_alias_blob =
149 HksBlob { size: prefixed_new_alias.len() as u32, data: prefixed_new_alias_ref.as_ptr() };
150
151 unsafe { RenameKeyAlias(&key_id as *const KeyId, &prefixed_new_alias_blob as *const HksBlob) }
152 }
153
154 /// Rename a secret key alias.
rename_key_alias( calling_info: &CallingInfo, auth_type: AuthType, access_type: Accessibility, require_password_set: bool, ) -> bool155 pub fn rename_key_alias(
156 calling_info: &CallingInfo,
157 auth_type: AuthType,
158 access_type: Accessibility,
159 require_password_set: bool,
160 ) -> bool {
161 match get_existing_key_alias(calling_info, auth_type, access_type, require_password_set) {
162 Ok(KeyAliasVersion::V3) => {
163 logi!("[INFO]Alias of [{access_type}]-typed secret key has already been renamed successfully.");
164 true
165 },
166 Ok(KeyAliasVersion::V2(alias)) | Ok(KeyAliasVersion::V1(alias)) => {
167 let ret = huks_rename_key_alias(calling_info, auth_type, access_type, require_password_set, alias);
168 if let SUCCESS = ret {
169 logi!("[INFO]Rename alias of [{access_type}]-typed secret key success.");
170 true
171 } else {
172 loge!("[FATAL]Rename alias of [{access_type}]-typed secret key failed, err is {}.", ret);
173 false
174 }
175 },
176 Ok(KeyAliasVersion::None) => {
177 loge!("[FATAL][{access_type}]-typed secret key does not exist.");
178 false
179 },
180 Err(e) => {
181 loge!("[FATAL]Can not determine whether [{access_type}]-typed secret key exists, err is {}", e);
182 false
183 },
184 }
185 }
186
187 impl SecretKey {
188 /// 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>189 pub fn new_with_alias(
190 user_id: i32,
191 auth_type: AuthType,
192 access_type: Accessibility,
193 require_password_set: bool,
194 alias: Vec<u8>,
195 ) -> Result<Self> {
196 Ok(Self { user_id, auth_type, access_type, require_password_set, alias })
197 }
198
199 /// 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>200 pub fn new_without_alias(
201 calling_info: &CallingInfo,
202 auth_type: AuthType,
203 access_type: Accessibility,
204 require_password_set: bool,
205 ) -> Result<Self> {
206 let new_alias = calculate_key_alias(calling_info, auth_type, access_type, require_password_set, true);
207 let prefixed_new_alias = [ALIAS_PREFIX.to_vec(), new_alias.clone()].concat();
208 let key = Self {
209 user_id: calling_info.user_id(),
210 auth_type,
211 access_type,
212 require_password_set,
213 alias: prefixed_new_alias,
214 };
215 Ok(key)
216 }
217
218 /// Check whether the secret key exists.
exists(&self) -> Result<bool>219 pub fn exists(&self) -> Result<bool> {
220 let key_alias = HksBlob { size: self.alias.len() as u32, data: self.alias.as_ptr() };
221 let key_id = KeyId::new(self.user_id, key_alias, self.access_type);
222 let ret = unsafe { IsKeyExist(&key_id as *const KeyId) };
223 match ret {
224 SUCCESS => Ok(true),
225 ret if ret == ErrCode::NotFound as i32 => Ok(false),
226 _ => Err(transfer_error_code(ErrCode::try_from(ret as u32)?)),
227 }
228 }
229
230 /// Generate the secret key and store in HUKS.
generate(&self) -> Result<()>231 pub fn generate(&self) -> Result<()> {
232 let key_alias = HksBlob { size: self.alias.len() as u32, data: self.alias.as_ptr() };
233 let key_id = KeyId::new(self.user_id, key_alias, self.access_type);
234 let ret = unsafe { GenerateKey(&key_id as *const KeyId, self.need_user_auth(), self.require_password_set) };
235 match ret {
236 SUCCESS => Ok(()),
237 _ => Err(transfer_error_code(ErrCode::try_from(ret as u32)?)),
238 }
239 }
240
241 /// Delete the secret key.
delete(&self) -> Result<()>242 pub fn delete(&self) -> Result<()> {
243 let key_alias = HksBlob { size: self.alias.len() as u32, data: self.alias.as_ptr() };
244 let key_id = KeyId::new(self.user_id, key_alias, self.access_type);
245 let ret = unsafe { DeleteKey(&key_id as *const KeyId) };
246 match ret {
247 ret if ((ret == ErrCode::NotFound as i32) || ret == SUCCESS) => Ok(()),
248 _ => Err(transfer_error_code(ErrCode::try_from(ret as u32)?)),
249 }
250 }
251
252 /// Delete secret key by owner.
delete_by_owner(calling_info: &CallingInfo) -> Result<()>253 pub fn delete_by_owner(calling_info: &CallingInfo) -> Result<()> {
254 let mut res = Ok(());
255 let accessibilitys =
256 [Accessibility::DevicePowerOn, Accessibility::DeviceFirstUnlocked, Accessibility::DeviceUnlocked];
257 for accessibility in accessibilitys.into_iter() {
258 let secret_key = SecretKey::new_without_alias(calling_info, AuthType::None, accessibility, true)?;
259 let tmp = secret_key.delete();
260 res = if tmp.is_err() { tmp } else { res };
261
262 let secret_key = SecretKey::new_without_alias(calling_info, AuthType::Any, accessibility, true)?;
263 let tmp = secret_key.delete();
264 res = if tmp.is_err() { tmp } else { res };
265
266 let secret_key = SecretKey::new_without_alias(calling_info, AuthType::None, accessibility, false)?;
267 let tmp = secret_key.delete();
268 res = if tmp.is_err() { tmp } else { res };
269
270 let secret_key = SecretKey::new_without_alias(calling_info, AuthType::Any, accessibility, false)?;
271 let tmp = secret_key.delete();
272 res = if tmp.is_err() { tmp } else { res };
273 }
274
275 res
276 }
277
278 /// Determine whether user auth is required.
need_user_auth(&self) -> bool279 pub(crate) fn need_user_auth(&self) -> bool {
280 self.auth_type == AuthType::Any
281 }
282
283 /// Determine whether device unlock is required.
need_device_unlock(&self) -> bool284 pub(crate) fn need_device_unlock(&self) -> bool {
285 self.access_type == Accessibility::DeviceUnlocked
286 }
287
288 /// Get the key alias.
alias(&self) -> &Vec<u8>289 pub(crate) fn alias(&self) -> &Vec<u8> {
290 &self.alias
291 }
292
293 /// Get the key access type
access_type(&self) -> Accessibility294 pub(crate) fn access_type(&self) -> Accessibility {
295 self.access_type
296 }
297
298 /// Get the key user id.
user_id(&self) -> i32299 pub(crate) fn user_id(&self) -> i32 {
300 self.user_id
301 }
302 }
303