1 /*
2 * Copyright (c) 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 "dslm_credential_utils.h"
17
18 #include <stdbool.h>
19 #include <stddef.h>
20 #include <string.h>
21
22 #include <openssl/evp.h>
23 #include <openssl/ossl_typ.h>
24 #include <openssl/x509.h>
25
26 #include "securec.h"
27
28 #include "device_security_defines.h"
29 #include "utils_base64.h"
30 #include "utils_json.h"
31 #include "utils_log.h"
32 #include "utils_mem.h"
33
34 #define PK_ATTEST_LIST_LEN 3
35
36 #define PK_ATTEST_INDEX_ROOT 2
37 #define PK_ATTEST_INDEX_INTER 1
38 #define PK_ATTEST_INDEX_LAST 0
39
40 #define TYPE_ECDSA_SHA_256 0
41 #define TYPE_ECDSA_SHA_384 1
42
43 #define JSON_KEY_USER_PUBLIC_KEY "userPublicKey"
44 #define JSON_KEY_SIGNATURE "signature"
45 #define JSON_KEY_ALGORITHM "algorithm"
46
47 #define CRED_KEY_TYPE "type"
48 #define CRED_KEY_MANUFACTURE "manufacture"
49 #define CRED_KEY_BRAND "brand"
50 #define CRED_KEY_MODEL_NAME "model"
51 #define CRED_KEY_CRED_VERSION "version"
52 #define CRED_KEY_OS_VERSION "softwareVersion"
53 #define CRED_KEY_UDID "udid"
54 #define CRED_KEY_SN "sn"
55 #define CRED_KEY_SIGN_TIME "signTime"
56 #define CRED_KEY_SECURITY_LEVEL "securityLevel"
57
58 typedef struct PublicKeyAttestation {
59 DataBuffer signature;
60 PublicKey publicKey;
61 uint32_t algorithm;
62 } PublicKeyAttestation;
63
64 typedef struct PayloadAttestation {
65 DataBuffer signature;
66 DataBuffer payload;
67 } PayloadAttestation;
68
69 typedef struct CredentialCb {
70 char *saved;
71 const char *header;
72 const char *payload;
73 const char *signature;
74 const char *attestationInfo;
75 PayloadAttestation load;
76 PublicKeyAttestation root;
77 PublicKeyAttestation intermediate;
78 PublicKeyAttestation last;
79 } CredentialCb;
80
81 static bool CreateCredentialCb(const char *credentialString, CredentialCb *credCb);
82 static bool VerifyCredentialCb(const CredentialCb *credCb);
83
84 static void MovePublicKeysToAttestationList(CredentialCb *credCb, AttestationList *list);
85 static void CredentialCbToDslmCredInfo(CredentialCb *credCb, DslmCredInfo *credInfo, bool verified);
86
87 static void DestroyCredentialCb(CredentialCb *credCb);
88
89 static bool InitCredential(const char *credentialString, CredentialCb *credCb);
90 static bool SplitCredentialString(CredentialCb *credCb);
91 static bool SplitCredentialAttestationList(CredentialCb *credCb);
92
93 static void FreePayloadAttestation(PayloadAttestation *attestation);
94 static void FreePublicKeyAttestation(PublicKeyAttestation *attestation);
95
96 int32_t EcdsaVerify(const struct DataBuffer *srcData, const struct DataBuffer *sigData,
97 const struct DataBuffer *pbkData, uint32_t algorithm);
98
VerifyDslmCredential(const char * credentialString,DslmCredInfo * credentialInfo,AttestationList * list)99 int32_t VerifyDslmCredential(const char *credentialString, DslmCredInfo *credentialInfo, AttestationList *list)
100 {
101 if (credentialString == NULL || credentialInfo == NULL) {
102 SECURITY_LOG_ERROR("invalid prams, credentialString or credentialInfo is null");
103 return ERR_PARSE_CLOUD_CRED_DATA;
104 }
105 CredentialCb credentialCb = {0};
106
107 bool ret = CreateCredentialCb(credentialString, &credentialCb);
108 if (!ret) {
109 SECURITY_LOG_ERROR("CreateCredentialCb error");
110 return ERR_PARSE_CLOUD_CRED_DATA;
111 }
112
113 ret = VerifyCredentialCb(&credentialCb);
114 CredentialCbToDslmCredInfo(&credentialCb, credentialInfo, ret);
115 if (!ret) {
116 SECURITY_LOG_ERROR("VerifyCredentialCb error");
117 DestroyCredentialCb(&credentialCb);
118 return ERR_PARSE_CLOUD_CRED_DATA;
119 }
120
121 MovePublicKeysToAttestationList(&credentialCb, list);
122
123 DestroyCredentialCb(&credentialCb);
124 return SUCCESS;
125 }
126
FreeAttestationList(AttestationList * list)127 void FreeAttestationList(AttestationList *list)
128 {
129 if (list == NULL) {
130 return;
131 }
132 FREE(list->root.data);
133 FREE(list->intermediate.data);
134 FREE(list->last.data);
135 (void)memset_s(list, sizeof(AttestationList), 0, sizeof(AttestationList));
136 }
137
CreateCredentialCb(const char * credentialString,CredentialCb * credCb)138 static bool CreateCredentialCb(const char *credentialString, CredentialCb *credCb)
139 {
140 if (credentialString == NULL || credCb == NULL) {
141 return false;
142 }
143
144 (void)memset_s(credCb, sizeof(CredentialCb), 0, sizeof(CredentialCb));
145
146 bool result = false;
147 do {
148 if (!InitCredential(credentialString, credCb)) {
149 SECURITY_LOG_ERROR("InitCredential failed");
150 break;
151 }
152 if (!SplitCredentialString(credCb)) {
153 SECURITY_LOG_ERROR("SplitCredentialString failed");
154 break;
155 }
156 if (!SplitCredentialAttestationList(credCb)) {
157 SECURITY_LOG_ERROR("SplitCredentialAttestationList failed");
158 break;
159 }
160 result = true;
161 } while (0);
162
163 if (result != true) {
164 DestroyCredentialCb(credCb);
165 }
166
167 SECURITY_LOG_INFO("success");
168 return result;
169 }
170
VerifyCredentialCb(const CredentialCb * credCb)171 static bool VerifyCredentialCb(const CredentialCb *credCb)
172 {
173 const PublicKeyAttestation *root = &credCb->root;
174 const PublicKeyAttestation *intermediate = &credCb->intermediate;
175 const PublicKeyAttestation *last = &credCb->last;
176 const PayloadAttestation *payload = &credCb->load;
177
178 // root key, signed by self
179 int32_t ret = EcdsaVerify(&root->publicKey, &root->signature, &root->publicKey, root->algorithm);
180 if (ret != SUCCESS) {
181 SECURITY_LOG_ERROR("verify root key failed, ret is %{public}d", ret);
182 return false;
183 }
184 SECURITY_LOG_INFO("verify root success");
185
186 // intermediate key, signed by root key
187 ret = EcdsaVerify(&intermediate->publicKey, &intermediate->signature, &root->publicKey, intermediate->algorithm);
188 if (ret != SUCCESS) {
189 SECURITY_LOG_ERROR("verify intermediate key failed, ret is %{public}d", ret);
190 return false;
191 }
192 SECURITY_LOG_INFO("verify intermediate success");
193
194 // last key, signed by intermediate key
195 ret = EcdsaVerify(&last->publicKey, &last->signature, &intermediate->publicKey, last->algorithm);
196 if (ret != SUCCESS) {
197 SECURITY_LOG_ERROR("verify last key failed, ret is %{public}d", ret);
198 return false;
199 }
200 SECURITY_LOG_INFO("verify last success");
201
202 // payload, signed by last key
203 ret = EcdsaVerify(&payload->payload, &payload->signature, &last->publicKey, TYPE_ECDSA_SHA_384);
204 if (ret != SUCCESS) {
205 ret = EcdsaVerify(&payload->payload, &payload->signature, &last->publicKey, TYPE_ECDSA_SHA_256);
206 }
207 if (ret != SUCCESS) {
208 SECURITY_LOG_ERROR("verify payload failed, ret is %{public}d", ret);
209 return false;
210 }
211 SECURITY_LOG_INFO("verify payload success");
212
213 return true;
214 }
215
InitCredential(const char * credentialString,CredentialCb * credCb)216 static bool InitCredential(const char *credentialString, CredentialCb *credCb)
217 {
218 if (credentialString == NULL || credCb == NULL) {
219 return false;
220 }
221 size_t strSize = strlen(credentialString) + 1;
222 credCb->saved = (char *)MALLOC(strSize);
223 if (credCb->saved == NULL) {
224 return false;
225 }
226 if (strcpy_s(credCb->saved, strSize, credentialString) != EOK) {
227 FREE(credCb->saved);
228 credCb->saved = NULL;
229 return false;
230 }
231 return true;
232 }
233
DestroyCredentialCb(CredentialCb * credCb)234 static void DestroyCredentialCb(CredentialCb *credCb)
235 {
236 if (credCb == NULL) {
237 return;
238 }
239 if (credCb->saved != NULL) {
240 FREE(credCb->saved);
241 credCb->saved = NULL;
242 }
243 FreePayloadAttestation(&credCb->load);
244 FreePublicKeyAttestation(&credCb->root);
245 FreePublicKeyAttestation(&credCb->intermediate);
246 FreePublicKeyAttestation(&credCb->last);
247 (void)memset_s(credCb, sizeof(CredentialCb), 0, sizeof(CredentialCb));
248 }
249
SplitCredentialString(CredentialCb * credCb)250 static bool SplitCredentialString(CredentialCb *credCb)
251 {
252 if (credCb == NULL || credCb->saved == NULL) {
253 return false;
254 }
255 char *context = NULL;
256 credCb->header = strtok_s(credCb->saved, ".", &context);
257 if (context == NULL || credCb->header == NULL) {
258 return false;
259 }
260
261 credCb->payload = strtok_s(NULL, ".", &context);
262 if (context == NULL || credCb->payload == NULL) {
263 return false;
264 }
265 credCb->signature = strtok_s(NULL, ".", &context);
266 if (context == NULL || credCb->signature == NULL) {
267 return false;
268 }
269 credCb->attestationInfo = strtok_s(NULL, ".", &context);
270 if (context == NULL || credCb->attestationInfo == NULL) {
271 return false;
272 }
273 return true;
274 }
275
GetAlgorithmType(const char * algorithm)276 static uint32_t GetAlgorithmType(const char *algorithm)
277 {
278 if (algorithm == NULL) {
279 return TYPE_ECDSA_SHA_384;
280 }
281
282 if (strncmp(algorithm, "SHA256withECDSA", strlen("SHA256withECDSA")) == 0) {
283 return TYPE_ECDSA_SHA_256;
284 }
285
286 if (strncmp(algorithm, "SHA384withECDSA", strlen("SHA384withECDSA")) == 0) {
287 return TYPE_ECDSA_SHA_384;
288 }
289
290 return TYPE_ECDSA_SHA_384;
291 }
292
FreePublicKeyAttestation(PublicKeyAttestation * attestation)293 static void FreePublicKeyAttestation(PublicKeyAttestation *attestation)
294 {
295 if (attestation == NULL) {
296 return;
297 }
298 if (attestation->publicKey.data != NULL) {
299 FREE(attestation->publicKey.data);
300 }
301 if (attestation->signature.data != NULL) {
302 FREE(attestation->signature.data);
303 }
304 (void)memset_s(attestation, sizeof(PublicKeyAttestation), 0, sizeof(PublicKeyAttestation));
305 }
306
FreePayloadAttestation(PayloadAttestation * attestation)307 static void FreePayloadAttestation(PayloadAttestation *attestation)
308 {
309 if (attestation == NULL) {
310 return;
311 }
312 if (attestation->payload.data != NULL) {
313 FREE(attestation->payload.data);
314 }
315 if (attestation->signature.data != NULL) {
316 FREE(attestation->signature.data);
317 }
318 (void)memset_s(attestation, sizeof(PayloadAttestation), 0, sizeof(PayloadAttestation));
319 }
320
ParsePayloadAttestation(CredentialCb * credCb,PayloadAttestation * attestation)321 static bool ParsePayloadAttestation(CredentialCb *credCb, PayloadAttestation *attestation)
322 {
323 if (credCb == NULL || attestation == NULL) {
324 return false;
325 }
326 bool result = false;
327 do {
328 DataBuffer *signature = &attestation->signature;
329 signature->length = (uint32_t)Base64UrlDecodeApp((uint8_t *)credCb->signature, &signature->data);
330 if (signature->length == 0 || signature->data == NULL) {
331 break;
332 }
333 DataBuffer *payload = &attestation->payload;
334 payload->length = strlen(credCb->header) + strlen(credCb->payload) + 1;
335 payload->data = MALLOC(payload->length + 1);
336 if (attestation->payload.data == NULL) {
337 break;
338 }
339 int ret = sprintf_s((char *)payload->data, payload->length + 1, "%s.%s", credCb->header, credCb->payload);
340 if (ret <= EOK) {
341 break;
342 }
343 result = true;
344 } while (0);
345
346 if (result == false) {
347 FreePayloadAttestation(attestation);
348 }
349 return result;
350 }
351
ParsePublicKeyAttestation(JsonHandle json,uint32_t attestationIndex,PublicKeyAttestation * attestation)352 static bool ParsePublicKeyAttestation(JsonHandle json, uint32_t attestationIndex, PublicKeyAttestation *attestation)
353 {
354 if (json == NULL || attestation == NULL || attestationIndex > PK_ATTEST_INDEX_ROOT) {
355 return false;
356 }
357 (void)memset_s(attestation, sizeof(PublicKeyAttestation), 0, sizeof(PublicKeyAttestation));
358
359 JsonHandle item = GetJsonFieldJsonArray(json, attestationIndex);
360 if (item == NULL) {
361 return false;
362 }
363
364 bool result = false;
365 do {
366 const char *sigData = GetJsonFieldString(item, JSON_KEY_SIGNATURE);
367 if (sigData == NULL) {
368 break;
369 }
370 attestation->signature.length = (uint32_t)Base64UrlDecodeApp((uint8_t *)sigData, &attestation->signature.data);
371 if (attestation->signature.length == 0 || attestation->signature.data == NULL) {
372 break;
373 }
374
375 const char *pbkData = GetJsonFieldString(item, JSON_KEY_USER_PUBLIC_KEY);
376 if (pbkData == NULL) {
377 break;
378 }
379 attestation->publicKey.length = (uint32_t)Base64UrlDecodeApp((uint8_t *)pbkData, &attestation->publicKey.data);
380 if (attestation->publicKey.length == 0 || attestation->publicKey.data == NULL) {
381 break;
382 }
383
384 attestation->algorithm = GetAlgorithmType(GetJsonFieldString(item, JSON_KEY_ALGORITHM));
385
386 result = true;
387 } while (0);
388
389 if (result == false) {
390 FreePublicKeyAttestation(attestation);
391 }
392 return result;
393 }
394
SplitCredentialAttestationList(CredentialCb * credCb)395 static bool SplitCredentialAttestationList(CredentialCb *credCb)
396 {
397 if (credCb == NULL) {
398 return false;
399 }
400 uint8_t *buffer = NULL;
401 JsonHandle json = NULL;
402 bool result = false;
403 do {
404 if (!ParsePayloadAttestation(credCb, &credCb->load)) {
405 SECURITY_LOG_ERROR("ParsePayloadAttestation failed");
406 break;
407 }
408 Base64DecodeApp((uint8_t *)credCb->attestationInfo, &buffer);
409 if (buffer == NULL) {
410 SECURITY_LOG_ERROR("Base64DecodeApp failed");
411 break;
412 }
413 json = CreateJson((char *)buffer);
414 if (json == NULL) {
415 break;
416 }
417 if (GetJsonFieldJsonArraySize(json) != PK_ATTEST_LIST_LEN) {
418 SECURITY_LOG_ERROR("GetJsonFieldJsonArraySize failed");
419 break;
420 }
421 if (!ParsePublicKeyAttestation(json, PK_ATTEST_INDEX_ROOT, &credCb->root)) {
422 SECURITY_LOG_ERROR("ParsePublicKeyAttestation root failed");
423 break;
424 }
425 if (!ParsePublicKeyAttestation(json, PK_ATTEST_INDEX_INTER, &credCb->intermediate)) {
426 SECURITY_LOG_ERROR("ParsePublicKeyAttestation intermediate failed");
427 break;
428 }
429 if (!ParsePublicKeyAttestation(json, PK_ATTEST_INDEX_LAST, &credCb->last)) {
430 SECURITY_LOG_ERROR("ParsePublicKeyAttestation last failed");
431 break;
432 }
433
434 result = true;
435 } while (0);
436
437 if (buffer) {
438 FREE(buffer);
439 }
440
441 if (json) {
442 DestroyJson(json);
443 }
444
445 return result;
446 }
447
MovePublicKeysToAttestationList(CredentialCb * credCb,AttestationList * list)448 static void MovePublicKeysToAttestationList(CredentialCb *credCb, AttestationList *list)
449 {
450 if (credCb == NULL || list == NULL) {
451 return;
452 }
453
454 list->root.data = credCb->root.publicKey.data;
455 list->root.length = credCb->root.publicKey.length;
456 list->intermediate.data = credCb->intermediate.publicKey.data;
457 list->intermediate.length = credCb->intermediate.publicKey.length;
458 list->last.data = credCb->last.publicKey.data;
459 list->last.length = credCb->last.publicKey.length;
460
461 credCb->root.publicKey.data = NULL;
462 credCb->intermediate.publicKey.data = NULL;
463 credCb->last.publicKey.data = NULL;
464 }
465
GetDataFromJson(JsonHandle json,const char * paramKey,char * dest,uint32_t destLen)466 static int32_t GetDataFromJson(JsonHandle json, const char *paramKey, char *dest, uint32_t destLen)
467 {
468 const char *data = GetJsonFieldString(json, paramKey);
469 if (data == NULL) {
470 return ERR_INVALID_PARA;
471 }
472 if (strncpy_s(dest, destLen, data, destLen - 1) != EOK) {
473 return ERR_MEMORY_ERR;
474 }
475 return SUCCESS;
476 }
477
CredentialCbToDslmCredInfo(CredentialCb * credCb,DslmCredInfo * credInfo,bool verified)478 static void CredentialCbToDslmCredInfo(CredentialCb *credCb, DslmCredInfo *credInfo, bool verified)
479 {
480 if (credCb == NULL || credInfo == NULL) {
481 return;
482 }
483
484 CredType credType = credInfo->credType;
485 (void)memset_s(credInfo, sizeof(DslmCredInfo), 0, sizeof(DslmCredInfo));
486 credInfo->credType = credType;
487
488 uint8_t *buffer = NULL;
489
490 (void)Base64DecodeApp((uint8_t *)credCb->payload, &buffer);
491 if (buffer == NULL) {
492 return;
493 }
494
495 JsonHandle json = CreateJson((char *)buffer);
496 if (json == NULL) {
497 return;
498 }
499
500 (void)GetDataFromJson(json, CRED_KEY_TYPE, credInfo->releaseType, CRED_INFO_TYPE_LEN);
501 (void)GetDataFromJson(json, CRED_KEY_MANUFACTURE, credInfo->manufacture, CRED_INFO_MANU_LEN);
502 (void)GetDataFromJson(json, CRED_KEY_BRAND, credInfo->brand, CRED_INFO_BRAND_LEN);
503 (void)GetDataFromJson(json, CRED_KEY_MODEL_NAME, credInfo->model, CRED_INFO_MODEL_LEN);
504 (void)GetDataFromJson(json, CRED_KEY_CRED_VERSION, credInfo->version, CRED_INFO_VERSION_LEN);
505 (void)GetDataFromJson(json, CRED_KEY_OS_VERSION, credInfo->softwareVersion, CRED_INFO_SOFTVERSION_LEN);
506 (void)GetDataFromJson(json, CRED_KEY_UDID, credInfo->udid, CRED_INFO_UDID_LEN);
507 (void)GetDataFromJson(json, CRED_KEY_SIGN_TIME, credInfo->signTime, CRED_INFO_SIGNTIME_LEN);
508 (void)GetDataFromJson(json, CRED_KEY_SECURITY_LEVEL, credInfo->securityLevel, CRED_INFO_LEVEL_LEN);
509
510 if (verified) {
511 if (sscanf_s(credInfo->securityLevel, "SL%u", &credInfo->credLevel) <= 0) {
512 SECURITY_LOG_ERROR("formatting securityLevel string failed");
513 }
514 }
515
516 FREE(buffer);
517 DestroyJson(json);
518 }
519
EcdsaVerify(const struct DataBuffer * srcData,const struct DataBuffer * sigData,const struct DataBuffer * pbkData,uint32_t algorithm)520 int32_t EcdsaVerify(const struct DataBuffer *srcData, const struct DataBuffer *sigData,
521 const struct DataBuffer *pbkData, uint32_t algorithm)
522 {
523 if (srcData == NULL || sigData == NULL || pbkData == NULL) {
524 return ERR_INVALID_PARA;
525 }
526 if (srcData->data == NULL || sigData->data == NULL || pbkData->data == NULL || srcData->length == 0 ||
527 sigData->length == 0 || pbkData->length == 0) {
528 return ERR_INVALID_PARA;
529 }
530 if ((algorithm != TYPE_ECDSA_SHA_256) && (algorithm != TYPE_ECDSA_SHA_384)) {
531 return ERR_INVALID_PARA;
532 }
533
534 const unsigned char *publicKey = (const unsigned char *)pbkData->data;
535 const EVP_MD *type = (algorithm == TYPE_ECDSA_SHA_256) ? EVP_sha256() : EVP_sha384();
536 EVP_PKEY *pkey = d2i_PUBKEY(NULL, &publicKey, pbkData->length);
537 if (pkey == NULL) {
538 SECURITY_LOG_ERROR("d2i_PUBKEY failed, length = %{public}d", pbkData->length);
539 return ERR_ECC_VERIFY_ERR;
540 }
541 EVP_MD_CTX *ctx = EVP_MD_CTX_new();
542 if (ctx == NULL) {
543 SECURITY_LOG_ERROR("EVP_MD_CTX_new failed");
544 EVP_PKEY_free(pkey);
545 return ERR_ECC_VERIFY_ERR;
546 }
547
548 int32_t result = ERR_ECC_VERIFY_ERR;
549 do {
550 if (EVP_DigestVerifyInit(ctx, NULL, type, NULL, pkey) <= 0) {
551 SECURITY_LOG_ERROR("EVP_DigestVerifyInit failed");
552 break;
553 }
554
555 if (EVP_DigestUpdate(ctx, srcData->data, srcData->length) <= 0) {
556 SECURITY_LOG_ERROR("EVP_DigestUpdate failed");
557 break;
558 }
559
560 if (EVP_DigestVerifyFinal(ctx, sigData->data, sigData->length) <= 0) {
561 SECURITY_LOG_ERROR("EVP_DigestVerifyFinal failed");
562 break;
563 }
564
565 result = SUCCESS;
566 } while (0);
567
568 EVP_PKEY_free(pkey);
569 EVP_MD_CTX_free(ctx);
570 return result;
571 }
572