• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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