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