• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 "huks_master.h"
17 
18 #include <dlfcn.h>
19 #include <openssl/err.h>
20 #include <openssl/rand.h>
21 #include <openssl/sha.h>
22 
23 #include "hks_param.h"
24 
25 #include "storage_service_log.h"
26 
27 namespace OHOS {
28 namespace StorageDaemon {
HuksMaster()29 HuksMaster::HuksMaster()
30 {
31     LOGD("enter");
32     HdiCreate();
33     HdiModuleInit();
34     LOGD("finish");
35 }
36 
~HuksMaster()37 HuksMaster::~HuksMaster()
38 {
39     LOGD("enter");
40     HdiDestroy();
41     LOGD("finish");
42 }
43 
HdiCreate()44 bool HuksMaster::HdiCreate()
45 {
46     LOGD("enter");
47     if (hdiHandle_ != nullptr || halDevice_ != nullptr) {
48         return true;
49     }
50 
51     hdiHandle_ = dlopen("libhuks_engine_core_standard.z.so", RTLD_LAZY);
52     if (hdiHandle_ == nullptr) {
53         LOGE("dlopen failed %{public}s", dlerror());
54         return false;
55     }
56 
57     auto createHdi = reinterpret_cast<HkmHalCreateHandle>(dlsym(hdiHandle_, "HuksCreateHdiDevicePtr"));
58     if (createHdi == nullptr) {
59         LOGE("dlsym failed %{public}s", dlerror());
60         dlclose(hdiHandle_);
61         hdiHandle_ = nullptr;
62         return false;
63     }
64 
65     halDevice_ = (*createHdi)();
66     if (halDevice_ == nullptr) {
67         LOGE("HuksHdiCreate failed");
68         dlclose(hdiHandle_);
69         hdiHandle_ = nullptr;
70         return false;
71     }
72     LOGD("success");
73     return true;
74 }
75 
HdiDestroy()76 void HuksMaster::HdiDestroy()
77 {
78     LOGD("enter");
79     if (hdiHandle_ == nullptr) {
80         LOGI("hdiHandle_ is nullptr, already destroyed");
81         return;
82     }
83 
84     auto destroyHdi = reinterpret_cast<HkmHalDestroyHandle>(dlsym(hdiHandle_, "HuksDestoryHdiDevicePtr"));
85     if ((destroyHdi != nullptr) && (halDevice_ != nullptr)) {
86         (*destroyHdi)(halDevice_);
87     }
88 
89     // add dlclose(hdiHandle_) here will cause segmentfault when exit
90     hdiHandle_ = nullptr;
91     halDevice_ = nullptr;
92     LOGD("finish");
93 }
94 
HdiModuleInit()95 int HuksMaster::HdiModuleInit()
96 {
97     LOGD("enter");
98     if (halDevice_ == nullptr) {
99         LOGE("halDevice_ is nullptr");
100         return HKS_ERROR_NULL_POINTER;
101     }
102     if (halDevice_->HuksHdiModuleInit == nullptr) {
103         LOGE("HuksHdiModuleInit is nullptr");
104         return HKS_ERROR_NULL_POINTER;
105     }
106 
107     int ret = halDevice_->HuksHdiModuleInit();
108     if (ret != HKS_SUCCESS) {
109         LOGE("HuksHdiModuleInit failed, ret %{public}d", ret);
110     }
111     return ret;
112 }
113 
HdiGenerateKey(const HksBlob & keyAlias,const HksParamSet * paramSetIn,HksBlob & keyOut)114 int HuksMaster::HdiGenerateKey(const HksBlob &keyAlias, const HksParamSet *paramSetIn,
115                                HksBlob &keyOut)
116 {
117     LOGD("enter");
118     if (halDevice_ == nullptr) {
119         LOGE("halDevice_ is nullptr");
120         return HKS_ERROR_NULL_POINTER;
121     }
122     if (halDevice_->HuksHdiGenerateKey == nullptr) {
123         LOGE("HuksHdiAccessGenerateKey is nullptr");
124         return HKS_ERROR_NULL_POINTER;
125     }
126 
127     uint8_t d = 0;
128     HksBlob keyIn = {1, &d};
129     auto ret = halDevice_->HuksHdiGenerateKey(&keyAlias, paramSetIn, &keyIn, &keyOut);
130     if (ret != HKS_SUCCESS) {
131         LOGE("HuksHdiGenerateKey failed, ret %{public}d", ret);
132     }
133     return ret;
134 }
135 
HdiAccessInit(const HksBlob & key,const HksParamSet * paramSet,HksBlob & handle,HksBlob & token)136 int HuksMaster::HdiAccessInit(const HksBlob &key, const HksParamSet *paramSet,
137                               HksBlob &handle, HksBlob &token)
138 {
139     LOGD("enter");
140     if (halDevice_ == nullptr) {
141         LOGE("halDevice_ is nullptr");
142         return HKS_ERROR_NULL_POINTER;
143     }
144     if (halDevice_->HuksHdiInit == nullptr) {
145         LOGE("HuksHdiAccessInit is nullptr");
146         return HKS_ERROR_NULL_POINTER;
147     }
148 
149     auto ret = halDevice_->HuksHdiInit(&key, paramSet, &handle, &token);
150     if (ret != HKS_SUCCESS) {
151         LOGE("HuksHdiInit failed, ret %{public}d", ret);
152     }
153     return ret;
154 }
155 
HdiAccessFinish(const HksBlob & handle,const HksParamSet * paramSet,const HksBlob & inData,HksBlob & outData)156 int HuksMaster::HdiAccessFinish(const HksBlob &handle, const HksParamSet *paramSet,
157                                 const HksBlob &inData, HksBlob &outData)
158 {
159     LOGD("enter");
160     if (halDevice_ == nullptr) {
161         LOGE("halDevice_ is nullptr");
162         return HKS_ERROR_NULL_POINTER;
163     }
164     if (halDevice_->HuksHdiFinish == nullptr) {
165         LOGE("HuksHdiAccessFinish is nullptr");
166         return HKS_ERROR_NULL_POINTER;
167     }
168 
169     auto ret = halDevice_->HuksHdiFinish(&handle, paramSet, &inData, &outData);
170     if (ret != HKS_SUCCESS) {
171         LOGE("HuksHdiFinish failed, ret %{public}d", ret);
172     }
173     return ret;
174 }
175 
GenerateRandomKey(uint32_t keyLen)176 KeyBlob HuksMaster::GenerateRandomKey(uint32_t keyLen)
177 {
178     LOGD("enter, size %{public}d", keyLen);
179     KeyBlob out(keyLen);
180     if (out.IsEmpty()) {
181         return out;
182     }
183 
184     auto ret = RAND_bytes(out.data.get(), out.size);
185     if (ret <= 0) {
186         LOGE("RAND_bytes failed return %{public}d, errno %{public}lu", ret, ERR_get_error());
187         out.Clear();
188     }
189     return out;
190 }
191 
AppendSecureAccessParams(const UserAuth & auth,HksParamSet * paramSet)192 static int AppendSecureAccessParams(const UserAuth &auth, HksParamSet *paramSet)
193 {
194     if (auth.secret.IsEmpty() || auth.token.IsEmpty()) {
195         LOGI("auth is empty, not to enable secure access for the key");
196         return HKS_SUCCESS;
197     }
198 
199     LOGI("append the secure access params when generate key");
200     HksUserAuthToken tokenStruct;
201     auto ret = memcpy_s(&tokenStruct, sizeof(tokenStruct), auth.token.data.get(), auth.token.size);
202     if (ret != EOK) {
203         LOGE("memcpy_s error, ret=%{public}d, dstSize=%{public}u, srcSize=%{public}u", ret,
204             (uint32_t)sizeof(tokenStruct), auth.token.size);
205         return HKS_ERROR_BUFFER_TOO_SMALL;
206     }
207     uint64_t secureUid = tokenStruct.secureUid;
208     uint64_t enrollId = tokenStruct.enrolledId;
209 
210     HksParam param[] = {
211         { .tag = HKS_TAG_USER_AUTH_TYPE, .uint32Param = HKS_USER_AUTH_TYPE_PIN },
212         { .tag = HKS_TAG_KEY_AUTH_ACCESS_TYPE, .uint32Param = HKS_AUTH_ACCESS_INVALID_CLEAR_PASSWORD },
213         { .tag = HKS_TAG_CHALLENGE_TYPE, .uint32Param = HKS_CHALLENGE_TYPE_NONE },
214         { .tag = HKS_TAG_USER_AUTH_SECURE_UID,
215           .blob =
216             { sizeof(secureUid), (uint8_t *)&secureUid }
217         },
218         { .tag = HKS_TAG_USER_AUTH_ENROLL_ID_INFO,
219           .blob =
220             { sizeof(enrollId), (uint8_t *)&enrollId }
221         },
222         { .tag = HKS_TAG_AUTH_TIMEOUT,
223           .uint32Param = 30 // token timeout is 30 seconds when no challenge
224         }
225     };
226     return HksAddParams(paramSet, param, HKS_ARRAY_SIZE(param));
227 }
228 
229 static uint8_t g_processName[sizeof(uint32_t)] = {0};
230 static const HksParam g_generateKeyParam[] = {
231     { .tag = HKS_TAG_KEY_GENERATE_TYPE, .uint32Param = HKS_KEY_GENERATE_TYPE_DEFAULT },
232     { .tag = HKS_TAG_PURPOSE, .uint32Param = HKS_KEY_PURPOSE_ENCRYPT | HKS_KEY_PURPOSE_DECRYPT },
233     { .tag = HKS_TAG_ALGORITHM, .uint32Param = HKS_ALG_AES },
234     { .tag = HKS_TAG_KEY_SIZE, .uint32Param = HKS_AES_KEY_SIZE_256 },
235     { .tag = HKS_TAG_DIGEST, .uint32Param = HKS_DIGEST_SHA256 },
236     { .tag = HKS_TAG_BLOCK_MODE, .uint32Param = HKS_MODE_GCM },
237     { .tag = HKS_TAG_PADDING, .uint32Param = HKS_PADDING_NONE },
238     { .tag = HKS_TAG_PROCESS_NAME,
239       .blob =
240         { sizeof(g_processName), g_processName }
241     },
242 };
243 
GenerateKey(const UserAuth & auth,KeyBlob & keyOut)244 bool HuksMaster::GenerateKey(const UserAuth &auth, KeyBlob &keyOut)
245 {
246     LOGD("enter");
247 
248     HksParamSet *paramSet = nullptr;
249     int ret = HKS_SUCCESS;
250     do {
251         ret = HksInitParamSet(&paramSet);
252         if (ret != HKS_SUCCESS) {
253             LOGE("HksInitParamSet failed ret %{public}d", ret);
254             break;
255         }
256         ret = HksAddParams(paramSet, g_generateKeyParam, HKS_ARRAY_SIZE(g_generateKeyParam));
257         if (ret != HKS_SUCCESS) {
258             LOGE("HksAddParams failed ret %{public}d", ret);
259             break;
260         }
261         ret = AppendSecureAccessParams(auth, paramSet);
262         if (ret != HKS_SUCCESS) {
263             LOGE("AppendSecureAccessParams failed ret %{public}d", ret);
264             break;
265         }
266         ret = HksBuildParamSet(&paramSet);
267         if (ret != HKS_SUCCESS) {
268             LOGE("HksBuildParamSet failed ret %{public}d", ret);
269             break;
270         }
271         KeyBlob alias = GenerateRandomKey(CRYPTO_KEY_ALIAS_SIZE);
272         HksBlob hksAlias = alias.ToHksBlob();
273         keyOut.Alloc(CRYPTO_KEY_SHIELD_MAX_SIZE);
274         HksBlob hksKeyOut = keyOut.ToHksBlob();
275         ret = HdiGenerateKey(hksAlias, paramSet, hksKeyOut);
276         if (ret != HKS_SUCCESS) {
277             LOGE("HdiGenerateKey failed ret %{public}d", ret);
278             break;
279         }
280         keyOut.size = hksKeyOut.size;
281         LOGI("HdiGenerateKey success, out size %{public}d", keyOut.size);
282     } while (0);
283 
284     HksFreeParamSet(&paramSet);
285     return ret == HKS_SUCCESS;
286 }
287 
HashAndClip(const std::string & prefix,const KeyBlob & payload,uint32_t length)288 static KeyBlob HashAndClip(const std::string &prefix, const KeyBlob &payload, uint32_t length)
289 {
290     KeyBlob res(SHA512_DIGEST_LENGTH);
291     std::string header = prefix;
292     if (header.empty()) {
293         header = "dummy SHA512 header";
294     }
295 
296     SHA512_CTX c;
297     SHA512_Init(&c);
298     SHA512_Update(&c, header.data(), header.size());
299     if (!payload.IsEmpty()) {
300         SHA512_Update(&c, payload.data.get(), payload.size);
301     }
302     SHA512_Final(res.data.get(), &c);
303 
304     res.size = length;
305     return res;
306 }
307 
GenHuksKeyBlobParam(KeyContext & ctx)308 static HksParamSet *GenHuksKeyBlobParam(KeyContext &ctx)
309 {
310     return reinterpret_cast<HksParamSet *>(ctx.shield.data.get());
311 }
312 
AppendAeTag(KeyBlob & cipherText,HksParamSet * paramSet)313 static int AppendAeTag(KeyBlob &cipherText, HksParamSet *paramSet)
314 {
315     if (cipherText.size <= HKS_AE_TAG_LEN) {
316         LOGE("cipherText size %{public}d is too small", cipherText.size);
317         return HKS_ERROR_INVALID_KEY_INFO;
318     }
319 
320     HksParam param[] = {
321         { .tag = HKS_TAG_AE_TAG,
322           .blob =
323             { HKS_AE_TAG_LEN, cipherText.data.get() + cipherText.size - HKS_AE_TAG_LEN }
324         },
325     };
326     cipherText.size -= HKS_AE_TAG_LEN;
327     return HksAddParams(paramSet, param, HKS_ARRAY_SIZE(param));
328 }
329 
AppendNonceAad(KeyContext & ctx,HksParamSet * paramSet)330 static int AppendNonceAad(KeyContext &ctx, HksParamSet *paramSet)
331 {
332     ctx.nonce = HashAndClip("NONCE SHA512 prefix", ctx.secDiscard, CRYPTO_AES_NONCE_LEN);
333     ctx.aad = HashAndClip("AAD SHA512 prefix", ctx.secDiscard, CRYPTO_AES_AAD_LEN);
334     HksParam addParam[] = {
335         { .tag = HKS_TAG_NONCE,
336           .blob =
337             { ctx.nonce.size, ctx.nonce.data.get() }
338         },
339         { .tag = HKS_TAG_ASSOCIATED_DATA,
340           .blob =
341             { ctx.aad.size, ctx.aad.data.get() }
342         }
343     };
344     return HksAddParams(paramSet, addParam, HKS_ARRAY_SIZE(addParam));
345 }
346 
AppendNonceAadToken(KeyContext & ctx,const UserAuth & auth,HksParamSet * paramSet)347 static int AppendNonceAadToken(KeyContext &ctx, const UserAuth &auth, HksParamSet *paramSet)
348 {
349     if (auth.secret.IsEmpty() || auth.token.IsEmpty()) {
350         LOGI("auth is empty, not to use secure access tag");
351         return AppendNonceAad(ctx, paramSet);
352     }
353 
354     LOGI("append the secure access params when encrypt/decrypt");
355     ctx.nonce = HashAndClip("NONCE SHA512 prefix", auth.secret, CRYPTO_AES_NONCE_LEN);
356     ctx.aad = HashAndClip("AAD SHA512 prefix", ctx.secDiscard, CRYPTO_AES_AAD_LEN);
357     HksParam addParam[] = {
358         { .tag = HKS_TAG_NONCE,
359           .blob =
360             { ctx.nonce.size, ctx.nonce.data.get() }
361         },
362         { .tag = HKS_TAG_ASSOCIATED_DATA,
363           .blob =
364             { ctx.aad.size, ctx.aad.data.get() }
365         },
366         { .tag = HKS_TAG_AUTH_TOKEN,
367           .blob =
368             { auth.token.size, auth.token.data.get() }
369         }
370     };
371     return HksAddParams(paramSet, addParam, HKS_ARRAY_SIZE(addParam));
372 }
373 
GenHuksOptionParam(KeyContext & ctx,const UserAuth & auth,const bool isEncrypt)374 static HksParamSet *GenHuksOptionParam(KeyContext &ctx, const UserAuth &auth, const bool isEncrypt)
375 {
376     HksParam encryptParam[] = {
377         { .tag = HKS_TAG_ALGORITHM, .uint32Param = HKS_ALG_AES },
378         { .tag = HKS_TAG_BLOCK_MODE, .uint32Param = HKS_MODE_GCM },
379         { .tag = HKS_TAG_PADDING, .uint32Param = HKS_PADDING_NONE },
380         { .tag = HKS_TAG_IS_KEY_ALIAS, .boolParam = false },
381         { .tag = HKS_TAG_PURPOSE, .uint32Param = isEncrypt ? HKS_KEY_PURPOSE_ENCRYPT : HKS_KEY_PURPOSE_DECRYPT},
382         { .tag = HKS_TAG_CHALLENGE_TYPE, .uint32Param = HKS_CHALLENGE_TYPE_NONE },
383         { .tag = HKS_TAG_PROCESS_NAME,
384           .blob =
385             { sizeof(g_processName), g_processName }
386         }
387     };
388 
389     HksParamSet *paramSet = nullptr;
390     auto ret = HksInitParamSet(&paramSet);
391     if (ret != HKS_SUCCESS) {
392         LOGE("HksInitParamSet failed ret %{public}d", ret);
393         return nullptr;
394     }
395     ret = HksAddParams(paramSet, encryptParam, HKS_ARRAY_SIZE(encryptParam));
396     if (ret != HKS_SUCCESS) {
397         LOGE("HksAddParams failed ret %{public}d", ret);
398         HksFreeParamSet(&paramSet);
399         return nullptr;
400     }
401 
402     if (!isEncrypt) {
403         ret = AppendAeTag(ctx.encrypted, paramSet);
404         if (ret != HKS_SUCCESS) {
405             LOGE("AppendAeTag failed ret %{public}d", ret);
406             HksFreeParamSet(&paramSet);
407             return nullptr;
408         }
409     }
410 
411     ret = AppendNonceAadToken(ctx, auth, paramSet);
412     if (ret != HKS_SUCCESS) {
413         LOGE("AppendNonceAad failed ret %{public}d", ret);
414         HksFreeParamSet(&paramSet);
415         return nullptr;
416     }
417 
418     ret = HksBuildParamSet(&paramSet);
419     if (ret != HKS_SUCCESS) {
420         LOGE("HksBuildParamSet failed ret %{public}d", ret);
421         HksFreeParamSet(&paramSet);
422         return nullptr;
423     }
424 
425     return paramSet;
426 }
427 
HuksHalTripleStage(HksParamSet * paramSet1,const HksParamSet * paramSet2,const KeyBlob & keyIn,KeyBlob & keyOut)428 bool HuksMaster::HuksHalTripleStage(HksParamSet *paramSet1, const HksParamSet *paramSet2,
429                                     const KeyBlob &keyIn, KeyBlob &keyOut)
430 {
431     LOGD("enter");
432     HksBlob hksKey = { paramSet1->paramSetSize, reinterpret_cast<uint8_t *>(paramSet1) };
433     HksBlob hksIn = keyIn.ToHksBlob();
434     HksBlob hksOut = keyOut.ToHksBlob();
435     uint8_t h[sizeof(uint64_t)] = {0};
436     HksBlob hksHandle = { sizeof(uint64_t), h };
437     uint8_t t[CRYPTO_TOKEN_SIZE] = {0};
438     HksBlob hksToken = { sizeof(t), t };  // would not use the challenge here
439 
440     int ret = HdiAccessInit(hksKey, paramSet2, hksHandle, hksToken);
441     if (ret != HKS_SUCCESS) {
442         LOGE("HdiAccessInit failed ret %{public}d", ret);
443         return false;
444     }
445 
446     ret = HdiAccessFinish(hksHandle, paramSet2, hksIn, hksOut);
447     if (ret != HKS_SUCCESS) {
448         LOGE("HdiAccessFinish failed ret %{public}d", ret);
449         return false;
450     }
451 
452     keyOut.size = hksOut.size;
453     return true;
454 }
455 
EncryptKey(KeyContext & ctx,const UserAuth & auth,const KeyInfo & key)456 bool HuksMaster::EncryptKey(KeyContext &ctx, const UserAuth &auth, const KeyInfo &key)
457 {
458     LOGD("enter");
459     if (ctx.shield.IsEmpty()) {
460         LOGE("bad shield input, size %{public}d", ctx.shield.size);
461         return false;
462     }
463     if (key.key.IsEmpty()) {
464         LOGE("bad rawKey input, size %{public}d", key.key.size);
465         return false;
466     }
467 
468     HksParamSet *paramSet1 = GenHuksKeyBlobParam(ctx);
469     if (paramSet1 == nullptr) {
470         LOGE("GenHuksKeyBlobParam failed");
471         return false;
472     }
473     HksParamSet *paramSet2 = GenHuksOptionParam(ctx, auth, true);
474     if (paramSet2 == nullptr) {
475         LOGE("GenHuksOptionParam failed");
476         return false;
477     }
478 
479     ctx.encrypted.Alloc(CRYPTO_AES_256_KEY_ENCRYPTED_SIZE);
480     auto ret = HuksHalTripleStage(paramSet1, paramSet2, key.key, ctx.encrypted);
481     if (!ret) {
482         LOGE("HuksHalTripleStage failed");
483     }
484 
485     HksFreeParamSet(&paramSet2);
486     LOGD("finish");
487     return ret;
488 }
489 
DecryptKey(KeyContext & ctx,const UserAuth & auth,KeyInfo & key)490 bool HuksMaster::DecryptKey(KeyContext &ctx, const UserAuth &auth, KeyInfo &key)
491 {
492     LOGD("enter");
493     if (ctx.shield.IsEmpty()) {
494         LOGE("bad shield input, size %{public}d", ctx.shield.size);
495         return false;
496     }
497     if (ctx.encrypted.IsEmpty()) {
498         LOGE("bad encrypted input, size %{public}d", ctx.encrypted.size);
499         return false;
500     }
501 
502     HksParamSet *paramSet1 = GenHuksKeyBlobParam(ctx);
503     if (paramSet1 == nullptr) {
504         LOGE("GenHuksKeyBlobParam failed");
505         return false;
506     }
507     HksParamSet *paramSet2 = GenHuksOptionParam(ctx, auth, false);
508     if (paramSet2 == nullptr) {
509         LOGE("GenHuksOptionParam failed");
510         return false;
511     }
512 
513     key.key.Alloc(CRYPTO_AES_256_XTS_KEY_SIZE);
514     auto ret = HuksHalTripleStage(paramSet1, paramSet2, ctx.encrypted, key.key);
515     if (!ret) {
516         LOGE("HuksHalTripleStage failed");
517     }
518 
519     HksFreeParamSet(&paramSet2);
520     LOGD("finish");
521     return ret;
522 }
523 } // namespace StorageDaemon
524 } // namespace OHOS
525