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#include "key_manager.h"
17
18#include "alg_defs.h"
19#include "alg_loader.h"
20#include "common_defs.h"
21#include "device_auth_defines.h"
22#include "hc_dev_info.h"
23#include "hc_log.h"
24#include "hc_types.h"
25#include "json_utils.h"
26#include "pseudonym_manager.h"
27#include "uint8buff_utils.h"
28
29#define PAKE_X25519_KEY_PAIR_LEN 32
30#define MK_LEN 32
31#define MK_DERIVE_INFO "dev_auth_mk_derivation"
32#define PAKE_KEY_ALIAS_LEN 64
33#define MK_ALIAS_PREFIX "MK_"
34#define PSEUDONYM_PSK_ALIAS_PREFIX "PSEUDONYM_"
35
36static int32_t ConvertHashToAlias(const Uint8Buff *keyAliasHash, Uint8Buff *outKeyAlias)
37{
38    uint32_t keyAliasHexLen = keyAliasHash->length * BYTE_TO_HEX_OPER_LENGTH + 1;
39    char *keyAliasHex = (char *)HcMalloc(keyAliasHexLen, 0);
40    if (keyAliasHex == NULL) {
41        LOGE("Failed to alloc key alias hex memory!");
42        return HC_ERR_ALLOC_MEMORY;
43    }
44    int32_t res = ByteToHexString(keyAliasHash->val, keyAliasHash->length, keyAliasHex, keyAliasHexLen);
45    if (res != HC_SUCCESS) {
46        LOGE("Failed to convert key alias hash to hex!");
47        HcFree(keyAliasHex);
48        return res;
49    }
50    if (memcpy_s(outKeyAlias->val, outKeyAlias->length, keyAliasHex, HcStrlen(keyAliasHex)) != EOK) {
51        LOGE("Failed to copy key alias hex!");
52        HcFree(keyAliasHex);
53        return HC_ERR_MEMORY_COPY;
54    }
55    HcFree(keyAliasHex);
56    return HC_SUCCESS;
57}
58
59static int32_t ConvertHashToAliasWithPrefix(const char *prefix, const Uint8Buff *keyAliasHash, Uint8Buff *keyAlias)
60{
61    uint32_t keyAliasHexLen = keyAliasHash->length * BYTE_TO_HEX_OPER_LENGTH + 1;
62    char *keyAliasHex = (char *)HcMalloc(keyAliasHexLen, 0);
63    if (keyAliasHex == NULL) {
64        LOGE("Failed to alloc key alias hex memory!");
65        return HC_ERR_ALLOC_MEMORY;
66    }
67    int32_t res = ByteToHexString(keyAliasHash->val, keyAliasHash->length, keyAliasHex, keyAliasHexLen);
68    if (res != HC_SUCCESS) {
69        LOGE("Failed to convert key alias hash to hex!");
70        HcFree(keyAliasHex);
71        return res;
72    }
73    uint32_t prefixLen = HcStrlen(prefix);
74    if (memcpy_s(keyAlias->val, keyAlias->length, prefix, prefixLen) != EOK) {
75        LOGE("Failed to copy key alias prefix!");
76        HcFree(keyAliasHex);
77        return HC_ERR_MEMORY_COPY;
78    }
79    // The remaining key alias len is less than keyAliasHexLen len after substract prefixLen,
80    // so copy the remaining len other than keyAliasHexLen in order that the key alias len is 64.
81    if (memcpy_s(keyAlias->val + prefixLen, keyAlias->length - prefixLen, keyAliasHex,
82        keyAlias->length - prefixLen) != EOK) {
83        LOGE("Failed to copy key alias hex!");
84        HcFree(keyAliasHex);
85        return HC_ERR_MEMORY_COPY;
86    }
87    HcFree(keyAliasHex);
88    return HC_SUCCESS;
89}
90
91static int32_t GenerateDevKeyAlias(Uint8Buff *outKeyAlias)
92{
93    char selfUdid[INPUT_UDID_LEN] = { 0 };
94    int32_t res = HcGetUdid((uint8_t *)selfUdid, INPUT_UDID_LEN);
95    if (res != HC_SUCCESS) {
96        LOGE("Failed to get local udid!");
97        return res;
98    }
99    uint8_t hashValue[SHA256_LEN] = { 0 };
100    Uint8Buff keyAliasHash = { hashValue, SHA256_LEN };
101    Uint8Buff msgBuff = { (uint8_t *)selfUdid, HcStrlen(selfUdid) };
102    res = GetLoaderInstance()->sha256(&msgBuff, &keyAliasHash);
103    if (res != HC_SUCCESS) {
104        LOGE("Failed to generate key alias hash!");
105        return res;
106    }
107    res = ConvertHashToAlias(&keyAliasHash, outKeyAlias);
108    if (res != HC_SUCCESS) {
109        LOGE("Failed to convert hash to alias!");
110    }
111    return res;
112}
113
114static int32_t GenerateMkAlias(const char *peerDeviceId, Uint8Buff *keyAlias)
115{
116    Uint8Buff peerDevIdBuff = { (uint8_t *)peerDeviceId, HcStrlen(peerDeviceId) };
117    uint8_t hashValue[SHA256_LEN] = { 0 };
118    Uint8Buff keyAliasHash = { hashValue, SHA256_LEN };
119    int32_t res = GetLoaderInstance()->sha256(&peerDevIdBuff, &keyAliasHash);
120    if (res != HC_SUCCESS) {
121        LOGE("Failed to generate key alias hash!");
122        return res;
123    }
124    res = ConvertHashToAliasWithPrefix(MK_ALIAS_PREFIX, &keyAliasHash, keyAlias);
125    if (res != HC_SUCCESS) {
126        LOGE("Failed to convert hash to alias!");
127    }
128    return res;
129}
130
131static int32_t GeneratePseudonymPskAlias(const char *peerDeviceId, Uint8Buff *keyAlias)
132{
133    uint8_t hashValue[SHA256_LEN] = { 0 };
134    Uint8Buff keyAliasHash = { hashValue, SHA256_LEN };
135    Uint8Buff peerDevIdBuff = { (uint8_t *)peerDeviceId, HcStrlen(peerDeviceId) };
136    int32_t res = GetLoaderInstance()->sha256(&peerDevIdBuff, &keyAliasHash);
137    if (res != HC_SUCCESS) {
138        LOGE("Failed to generate key alias hash!");
139        return res;
140    }
141
142    res = ConvertHashToAliasWithPrefix(PSEUDONYM_PSK_ALIAS_PREFIX, &keyAliasHash, keyAlias);
143    if (res != HC_SUCCESS) {
144        LOGE("Failed to convert hash to alias!");
145    }
146    return res;
147}
148
149static int32_t KeyDerivation(int32_t osAccountId, const Uint8Buff *baseAlias, const Uint8Buff *salt, bool isAlias,
150    Uint8Buff *returnKey)
151{
152    Uint8Buff keyInfo = { (uint8_t *)MK_DERIVE_INFO, HcStrlen(MK_DERIVE_INFO) };
153    KeyParams keyAliasParams = { { baseAlias->val, baseAlias->length, isAlias }, false, osAccountId };
154    int32_t res = GetLoaderInstance()->computeHkdf(&keyAliasParams, salt, &keyInfo, returnKey);
155    if (res != HC_SUCCESS) {
156        LOGE("Failed to compute hkdf!");
157    }
158    return res;
159}
160
161int32_t GenerateDeviceKeyPair(int32_t osAccountId)
162{
163    uint8_t keyAlias[PAKE_KEY_ALIAS_LEN] = { 0 };
164    Uint8Buff keyAliasBuff = { keyAlias, PAKE_KEY_ALIAS_LEN };
165    int32_t res = GenerateDevKeyAlias(&keyAliasBuff);
166    if (res != HC_SUCCESS) {
167        LOGE("Failed to generate device key alias!");
168        return res;
169    }
170    if (GetLoaderInstance()->checkKeyExist(&keyAliasBuff, false, osAccountId) == HC_SUCCESS) {
171        LOGI("Device Key pair already exists!");
172        return HC_SUCCESS;
173    }
174
175    char selfUdid[INPUT_UDID_LEN] = { 0 };
176    res = HcGetUdid((uint8_t *)selfUdid, INPUT_UDID_LEN);
177    if (res != HC_SUCCESS) {
178        LOGE("Failed to get local udid!");
179        return res;
180    }
181    Uint8Buff authIdBuff = { (uint8_t *)selfUdid, HcStrlen(selfUdid) };
182    ExtraInfo exInfo = { authIdBuff, -1, -1 };
183    KeyParams keyParams = { { keyAliasBuff.val, keyAliasBuff.length, true }, false, osAccountId };
184    res = GetLoaderInstance()->generateKeyPairWithStorage(&keyParams, PAKE_X25519_KEY_PAIR_LEN, X25519,
185        KEY_PURPOSE_SIGN_VERIFY, &exInfo);
186    if (res != HC_SUCCESS) {
187        LOGE("Failed to generate device key pair!");
188        return res;
189    }
190    LOGI("Generate device key pair successfully!");
191    return HC_SUCCESS;
192}
193
194int32_t GenerateMk(int32_t osAccountId, const char *peerDeviceId, const Uint8Buff *peerPubKey)
195{
196    if (peerDeviceId == NULL || peerPubKey == NULL) {
197        LOGE("Invalid input params!");
198        return HC_ERR_INVALID_PARAMS;
199    }
200    uint8_t mkAlias[PAKE_KEY_ALIAS_LEN] = { 0 };
201    Uint8Buff mkAliasBuff = { mkAlias, PAKE_KEY_ALIAS_LEN };
202    int32_t res = GenerateMkAlias(peerDeviceId, &mkAliasBuff);
203    if (res != HC_SUCCESS) {
204        LOGE("Failed to generate mk alias!");
205        return res;
206    }
207    uint8_t devKeyAlias[PAKE_KEY_ALIAS_LEN] = { 0 };
208    Uint8Buff devKeyAliasBuff = { devKeyAlias, PAKE_KEY_ALIAS_LEN };
209    res = GenerateDevKeyAlias(&devKeyAliasBuff);
210    if (res != HC_SUCCESS) {
211        LOGE("Failed to generate device key alias!");
212        return res;
213    }
214    KeyParams selfKeyParams = { { devKeyAliasBuff.val, devKeyAliasBuff.length, true }, false, osAccountId };
215    KeyBuff peerKeyBuff = { peerPubKey->val, peerPubKey->length, false };
216    res = GetLoaderInstance()->agreeSharedSecretWithStorage(&selfKeyParams, &peerKeyBuff, X25519,
217        MK_LEN, &mkAliasBuff);
218    if (res != HC_SUCCESS) {
219        LOGE("Failed to agree sharedSecret!");
220        return res;
221    }
222    LOGI("Generate mk successfully!");
223    return HC_SUCCESS;
224}
225
226int32_t DeleteMk(int32_t osAccountId, const char *peerDeviceId)
227{
228    if (peerDeviceId == NULL) {
229        LOGE("Invalid input param!");
230        return HC_ERR_INVALID_PARAMS;
231    }
232    uint8_t mkAlias[PAKE_KEY_ALIAS_LEN] = { 0 };
233    Uint8Buff mkAliasBuff = { mkAlias, PAKE_KEY_ALIAS_LEN };
234    int32_t res = GenerateMkAlias(peerDeviceId, &mkAliasBuff);
235    if (res != HC_SUCCESS) {
236        LOGE("Failed to generate mk alias!");
237        return res;
238    }
239    if (GetLoaderInstance()->checkKeyExist(&mkAliasBuff, false, osAccountId) != HC_SUCCESS) {
240        LOGI("mk does not exist, no need to delete!");
241        return HC_SUCCESS;
242    }
243    res = GetLoaderInstance()->deleteKey(&mkAliasBuff, false, osAccountId);
244    if (res != HC_SUCCESS) {
245        LOGE("Failed to delete mk!");
246        return res;
247    }
248    LOGI("Delete mk successfully!");
249    return HC_SUCCESS;
250}
251
252int32_t GeneratePseudonymPsk(int32_t osAccountId, const char *peerDeviceId, const Uint8Buff *salt)
253{
254    if (peerDeviceId == NULL || salt == NULL) {
255        LOGE("Invalid input params!");
256        return HC_ERR_INVALID_PARAMS;
257    }
258    uint8_t pseudonymPskAlias[PAKE_KEY_ALIAS_LEN] = { 0 };
259    Uint8Buff pskAliasBuff = { pseudonymPskAlias, PAKE_KEY_ALIAS_LEN };
260    int32_t res = GeneratePseudonymPskAlias(peerDeviceId, &pskAliasBuff);
261    if (res != HC_SUCCESS) {
262        LOGE("Failed to generate pseudonym psk alias!");
263        return res;
264    }
265    uint8_t mkAlias[PAKE_KEY_ALIAS_LEN] = { 0 };
266    Uint8Buff mkAliasBuff = { mkAlias, PAKE_KEY_ALIAS_LEN };
267    res = GenerateMkAlias(peerDeviceId, &mkAliasBuff);
268    if (res != HC_SUCCESS) {
269        LOGE("Failed to generate mk alias!");
270        return res;
271    }
272    Uint8Buff pskBuff = { NULL, 0 };
273    if (InitUint8Buff(&pskBuff, MK_LEN) != HC_SUCCESS) {
274        LOGE("Failed to init pseudonym psk!");
275        return HC_ERR_ALLOC_MEMORY;
276    }
277    res = KeyDerivation(osAccountId, &mkAliasBuff, salt, true, &pskBuff);
278    if (res != HC_SUCCESS) {
279        LOGE("Failed to derive pseudonym psk!");
280        FreeUint8Buff(&pskBuff);
281        return res;
282    }
283    KeyParams keyParams = { { pskAliasBuff.val, pskAliasBuff.length, true }, false, osAccountId };
284    res = GetLoaderInstance()->importSymmetricKey(&keyParams, &pskBuff, KEY_PURPOSE_MAC, NULL);
285    ClearFreeUint8Buff(&pskBuff);
286    if (res != HC_SUCCESS) {
287        LOGE("Failed to import pseudonym psk!");
288        return res;
289    }
290    LOGI("Generate and save pseudonym psk successfully!");
291    return HC_SUCCESS;
292}
293
294int32_t DeletePseudonymPsk(int32_t osAccountId, const char *peerDeviceId)
295{
296    if (peerDeviceId == NULL) {
297        LOGE("Invalid input param!");
298        return HC_ERR_INVALID_PARAMS;
299    }
300    uint8_t pseudonymPskAlias[PAKE_KEY_ALIAS_LEN] = { 0 };
301    Uint8Buff pskAliasBuff = { pseudonymPskAlias, PAKE_KEY_ALIAS_LEN };
302    int32_t res = GeneratePseudonymPskAlias(peerDeviceId, &pskAliasBuff);
303    if (res != HC_SUCCESS) {
304        LOGE("Failed to generate psk alias!");
305        return res;
306    }
307    if (GetLoaderInstance()->checkKeyExist(&pskAliasBuff, false, osAccountId) != HC_SUCCESS) {
308        LOGI("Pseudonym psk does not exist, no need to delete!");
309        return HC_SUCCESS;
310    }
311    res = GetLoaderInstance()->deleteKey(&pskAliasBuff, false, osAccountId);
312    if (res != HC_SUCCESS) {
313        LOGE("Failed to delete pseudonym psk!");
314        return res;
315    }
316    LOGI("Delete pseudonym psk successfully!");
317    return HC_SUCCESS;
318}
319
320int32_t GenerateAndSavePseudonymId(int32_t osAccountId, const char *peerDeviceId, const PseudonymKeyInfo *info,
321    const Uint8Buff *saltBuff, Uint8Buff *returnHmac)
322{
323    if (peerDeviceId == NULL || info == NULL || saltBuff == NULL || returnHmac == NULL) {
324        LOGE("Invalid input params!");
325        return HC_ERR_INVALID_PARAMS;
326    }
327    uint8_t pskAliasVal[PAKE_KEY_ALIAS_LEN] = { 0 };
328    Uint8Buff pskAliasBuff = { pskAliasVal, PAKE_KEY_ALIAS_LEN };
329    int32_t res = GeneratePseudonymPskAlias(peerDeviceId, &pskAliasBuff);
330    if (res != HC_SUCCESS) {
331        LOGE("Failed to generate pseudonym psk alias!");
332        return res;
333    }
334    uint8_t pseudonymIdVal[MK_LEN] = { 0 };
335    Uint8Buff pseudonymIdBuff = { pseudonymIdVal, MK_LEN };
336    KeyParams keyParams = { { pskAliasBuff.val, pskAliasBuff.length, true }, false, osAccountId };
337    res = GetLoaderInstance()->computeHmac(&keyParams, saltBuff, &pseudonymIdBuff);
338    if (res != HC_SUCCESS) {
339        LOGE("Failed to compute hmac!");
340        return res;
341    }
342    if (DeepCopyUint8Buff(&pseudonymIdBuff, returnHmac) != HC_SUCCESS) {
343        LOGE("Failed to copy hmac!");
344        return HC_ERR_ALLOC_MEMORY;
345    }
346    uint32_t pdidLen = pseudonymIdBuff.length * BYTE_TO_HEX_OPER_LENGTH + 1;
347    char *pdid = (char *)HcMalloc(pdidLen, 0);
348    if (pdid == NULL) {
349        LOGE("Failed to alloc memory for pdid!");
350        ClearFreeUint8Buff(returnHmac);
351        return HC_ERR_ALLOC_MEMORY;
352    }
353    res = ByteToHexString(pseudonymIdBuff.val, pseudonymIdBuff.length, pdid, pdidLen);
354    if (res != HC_SUCCESS) {
355        LOGE("Failed to convert pdid from byte to hex string!");
356        ClearFreeUint8Buff(returnHmac);
357        HcFree(pdid);
358        return res;
359    }
360    res = GetPseudonymInstance()->savePseudonymId(osAccountId, pdid, info->peerInfo, peerDeviceId, info->pdidIndex);
361    HcFree(pdid);
362    if (res != HC_SUCCESS) {
363        LOGE("Failed to save pdid!");
364        ClearFreeUint8Buff(returnHmac);
365        return res;
366    }
367    LOGI("Generate and save pdid successfully!");
368    return HC_SUCCESS;
369}
370
371int32_t GetDevicePubKey(int32_t osAccountId, Uint8Buff *devicePk)
372{
373    if (devicePk == NULL) {
374        LOGE("Invalid input param!");
375        return HC_ERR_INVALID_PARAMS;
376    }
377    uint8_t keyAlias[PAKE_KEY_ALIAS_LEN] = { 0 };
378    Uint8Buff keyAliasBuff = { keyAlias, PAKE_KEY_ALIAS_LEN };
379    int32_t res = GenerateDevKeyAlias(&keyAliasBuff);
380    if (res != HC_SUCCESS) {
381        LOGE("Failed to generate device key alias!");
382        return res;
383    }
384    KeyParams keyParams = { { keyAliasBuff.val, keyAliasBuff.length, true }, false, osAccountId };
385    res = GetLoaderInstance()->exportPublicKey(&keyParams, devicePk);
386    if (res != HC_SUCCESS) {
387        LOGE("Failed to export device pk!");
388    }
389    return res;
390}