• 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 
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