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(¶mSet);
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(¶mSet);
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(¶mSet);
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(¶mSet);
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(¶mSet);
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(¶mSet);
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(¶mSet);
415 return nullptr;
416 }
417
418 ret = HksBuildParamSet(¶mSet);
419 if (ret != HKS_SUCCESS) {
420 LOGE("HksBuildParamSet failed ret %{public}d", ret);
421 HksFreeParamSet(¶mSet);
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(¶mSet2);
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(¶mSet2);
520 LOGD("finish");
521 return ret;
522 }
523 } // namespace StorageDaemon
524 } // namespace OHOS
525