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