1 /*
2  * Copyright (c) 2020-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 "app_verify_hap.h"
17 #include <stdbool.h>
18 #include <sys/mman.h>
19 #include <unistd.h>
20 #include "app_centraldirectory.h"
21 #include "app_common.h"
22 #include "app_verify.h"
23 #include "securec.h"
24 
GetDigestAlgorithmId(uint32_t signAlgorithm)25 int32_t GetDigestAlgorithmId(uint32_t signAlgorithm)
26 {
27     switch (signAlgorithm & ALGORITHM_MASK) {
28         case ALGORITHM_SHA256:
29         case ALGORITHM_PKCS1_SHA256:
30             return HASH_ALG_SHA256;
31         case ALGORITHM_SHA384:
32         case ALGORITHM_PKCS1_SHA384:
33             return HASH_ALG_SHA384;
34         case ALGORITHM_SHA512:
35         case ALGORITHM_PKCS1_SHA512:
36             return HASH_ALG_SHA512;
37         default:
38             LOG_ERROR("signAlgorithm: %u error", signAlgorithm);
39             return V_ERR;
40     }
41 }
42 
ComputeBlockHash(const char * block,int32_t blockLen,int32_t alg,const HapBuf * result,int32_t * offset)43 static int32_t ComputeBlockHash(const char *block, int32_t blockLen, int32_t alg, const HapBuf *result, int32_t *offset)
44 {
45     const mbedtls_md_info_t *mdInfo = mbedtls_md_info_from_type((mbedtls_md_type_t)alg);
46     P_NULL_RETURN_WTTH_LOG(mdInfo);
47     int32_t pos = 0;
48     int32_t rawBufLen = blockLen;
49     mbedtls_md_context_t *mdCtx = APPV_MALLOC(sizeof(mbedtls_md_context_t));
50     P_NULL_RETURN_WTTH_LOG(mdCtx);
51     LOG_INFO("alg: %d wholelen: %d", alg, rawBufLen);
52     while (rawBufLen > 0) {
53         mbedtls_md_init(mdCtx);
54         int32_t readLen = (rawBufLen > HASH_BLOB_LEN) ? HASH_BLOB_LEN : rawBufLen;
55         int32_t ret = mbedtls_md_setup(mdCtx, mdInfo, 0);
56         P_ERR_GOTO_WTTH_LOG(ret);
57         size_t hlen = mbedtls_md_get_size(mdInfo);
58         if (hlen == 0 || hlen > MAX_HASH_SIZE) {
59             goto EXIT;
60         }
61         ret = mbedtls_md_starts(mdCtx);
62         P_ERR_GOTO_WTTH_LOG(ret);
63         unsigned char chunkContentPrefix[HAP_DIGEST_PRIFIX_LEN] = {HAP_SECOND_LEVEL_CHUNK_PREFIX, 0, 0, 0, 0};
64         if (memcpy_s((chunkContentPrefix + 1), HAP_DIGEST_PRIFIX_LEN - 1, (&readLen), sizeof(int)) != EOK) {
65             LOG_ERROR("memcpy_s fail");
66             goto EXIT;
67         }
68         ret = mbedtls_md_update(mdCtx, chunkContentPrefix, HAP_DIGEST_PRIFIX_LEN);
69         P_ERR_GOTO_WTTH_LOG(ret);
70         LOG_INFO("content: %d, %d", rawBufLen, pos);
71         ret = mbedtls_md_update(mdCtx, (unsigned char *)block + pos, readLen);
72         P_ERR_GOTO_WTTH_LOG(ret);
73         rawBufLen -= readLen;
74         pos += readLen;
75         unsigned char *outbuf = APPV_MALLOC(hlen);
76         P_NULL_GOTO_WTTH_LOG(outbuf);
77         ret = mbedtls_md_finish(mdCtx, outbuf);
78         HapPutData(result, *offset, outbuf, hlen);
79         *offset += hlen;
80         (void)memset_s(outbuf, hlen, 0, hlen);
81         APPV_FREE(outbuf);
82         P_ERR_GOTO_WTTH_LOG(ret);
83         mbedtls_md_free(mdCtx);
84     }
85     APPV_FREE(mdCtx);
86     return V_OK;
87 EXIT:
88     mbedtls_md_free(mdCtx);
89     APPV_FREE(mdCtx);
90     return V_ERR;
91 }
92 
GetChunkSumCount(int32_t fileSize,int32_t coreDirectorySize,int32_t eocdSize,int32_t rootHashLen)93 static int32_t GetChunkSumCount(int32_t fileSize, int32_t coreDirectorySize, int32_t eocdSize, int32_t rootHashLen)
94 {
95     int32_t chunkSize = HASH_BLOB_LEN;
96     int32_t maxSize = INT_MAX - chunkSize;
97     if (fileSize > maxSize || coreDirectorySize > maxSize || eocdSize > maxSize) {
98         return 0;
99     }
100     int32_t count = ((fileSize - 1 + chunkSize) / chunkSize) + ((coreDirectorySize - 1 + chunkSize) / chunkSize) +
101         ((eocdSize - 1 + chunkSize) / chunkSize);
102     if (rootHashLen < 0 || (((INT_MAX - HAP_DIGEST_PRIFIX_LEN) / count) < rootHashLen)) {
103         LOG_ERROR("overflow count: %d, chunkDigestLen: %d", count, rootHashLen);
104         return 0;
105     }
106     LOG_INFO("get sum count %d", count);
107     return count;
108 }
109 
ComputeDigestsWithOptionalBlock(const int32_t digestAlgorithm,int32_t fp,const SignatureInfo * signInfo,const HapBuf * chunkDigest,const HapBuf * fianlDigest)110 static int32_t ComputeDigestsWithOptionalBlock(const int32_t digestAlgorithm, int32_t fp, const SignatureInfo *signInfo,
111     const HapBuf *chunkDigest, const HapBuf *fianlDigest)
112 {
113     int32_t rst = V_ERR;
114     char *rawBuf = NULL;
115     unsigned char* outbuf = NULL;
116     int32_t rootHashLen = GetHashUnitLen(digestAlgorithm);
117     LOG_INFO("rootHashLen %d", rootHashLen);
118     if (rootHashLen <= 0 || rootHashLen > MAX_HASH_SIZE) {
119         return rst;
120     }
121     const mbedtls_md_info_t *mdInfo = mbedtls_md_info_from_type((mbedtls_md_type_t)digestAlgorithm);
122     P_NULL_RETURN_WTTH_LOG(mdInfo);
123     mbedtls_md_context_t *mdCtx = APPV_MALLOC(sizeof(mbedtls_md_context_t));
124     P_NULL_RETURN_WTTH_LOG(mdCtx);
125     mbedtls_md_init(mdCtx);
126     int32_t ret = mbedtls_md_setup(mdCtx, mdInfo, 0);
127     int32_t rawLen = 0;
128     BlockHead blockHead = {0};
129 
130     P_ERR_GOTO_WTTH_LOG(ret);
131     ret = mbedtls_md_starts(mdCtx);
132     P_ERR_GOTO_WTTH_LOG(ret);
133     int32_t readLen = chunkDigest->len;
134     LOG_INFO("readLen %d", readLen);
135     ret = mbedtls_md_update(mdCtx, chunkDigest->buffer, readLen);
136     P_ERR_GOTO_WTTH_LOG(ret);
137 
138     rawBuf = GetSignBlockByType(signInfo, fp, PROFILE_BLOCK_WITHSIGN_TYPE, &rawLen, &blockHead);
139     P_NULL_GOTO_WTTH_LOG(rawBuf);
140     readLen = rawLen;
141     LOG_INFO("signBuf %0x %d", rawBuf[0], readLen);
142     ret = mbedtls_md_update(mdCtx, (unsigned char *)rawBuf, readLen);
143     P_ERR_GOTO_WTTH_LOG(ret);
144     outbuf = (unsigned char *)APPV_MALLOC(rootHashLen);
145     P_NULL_GOTO_WTTH_LOG(outbuf);
146     ret = mbedtls_md_finish(mdCtx, outbuf);
147     P_ERR_GOTO_WTTH_LOG(ret);
148     HapPutData(fianlDigest, 0, outbuf, rootHashLen);
149     (void)memset_s(outbuf, rootHashLen, 0, rootHashLen);
150     rst = V_OK;
151 EXIT:
152     mbedtls_md_free(mdCtx);
153     APPV_FREE(mdCtx);
154     APPV_FREE(rawBuf);
155     APPV_FREE(outbuf);
156     return rst;
157 }
158 
HapUpdateDigistHead(int32_t digestAlgorithm,mbedtls_md_context_t * mdCtx,const mbedtls_md_info_t * mdInfo,int32_t readLen,size_t * hlen)159 static int32_t HapUpdateDigistHead(
160     int32_t digestAlgorithm, mbedtls_md_context_t *mdCtx,
161     const mbedtls_md_info_t *mdInfo, int32_t readLen, size_t *hlen)
162 {
163     mbedtls_md_init(mdCtx);
164     int32_t ret = mbedtls_md_setup(mdCtx, mdInfo, 0);
165     if (ret != 0) {
166         return V_ERR;
167     }
168     *hlen = mbedtls_md_get_size(mdInfo);
169     if (*hlen == 0 || *hlen > MAX_HASH_SIZE) {
170         return V_ERR;
171     }
172     ret = mbedtls_md_starts(mdCtx);
173     if (ret != 0) {
174         return V_ERR;
175     }
176     unsigned char chunkContentPrefix[HAP_DIGEST_PRIFIX_LEN] = {HAP_SECOND_LEVEL_CHUNK_PREFIX, 0, 0, 0, 0};
177     if (memcpy_s((chunkContentPrefix + 1), HAP_DIGEST_PRIFIX_LEN - 1, (&readLen), sizeof(int)) != EOK) {
178         return V_ERR;
179     }
180     ret = mbedtls_md_update(mdCtx, chunkContentPrefix, HAP_DIGEST_PRIFIX_LEN);
181     if (ret != 0) {
182         return V_ERR;
183     }
184     return V_OK;
185 }
186 
UpdateSmallBlock(int32_t readLen,const int32_t fp,mbedtls_md_context_t * mdCtx)187 static int32_t UpdateSmallBlock(int32_t readLen, const int32_t fp, mbedtls_md_context_t *mdCtx)
188 {
189     int32_t readLenLeft = readLen;
190     while (readLenLeft > 0) {
191         int32_t onceRead = (readLenLeft > ONCE_READ_LEN) ? ONCE_READ_LEN : readLenLeft;
192         unsigned char *onceBuf = APPV_MALLOC(onceRead);
193         P_NULL_RETURN_WTTH_LOG(onceBuf);
194         int32_t len = read(fp, onceBuf, sizeof(char) * onceRead);
195         if (len != onceRead) {
196             LOG_ERROR("fread err: %d, %d", len, onceRead);
197             APPV_FREE(onceBuf);
198             return V_ERR;
199         }
200         int32_t ret = mbedtls_md_update(mdCtx, onceBuf, onceRead);
201         APPV_FREE(onceBuf);
202         P_ERR_RETURN_WTTH_LOG(ret);
203         readLenLeft -= onceRead;
204     }
205     return V_OK;
206 }
207 
ComputerFileHash(const SignatureInfo * signInfo,int32_t digestAlgorithm,const int32_t fp,const HapBuf * chunkDigest,int32_t * offset)208 static int32_t ComputerFileHash(const SignatureInfo *signInfo, int32_t digestAlgorithm, const int32_t fp,
209     const HapBuf *chunkDigest, int32_t *offset)
210 {
211     mbedtls_md_context_t *mdCtx = APPV_MALLOC(sizeof(mbedtls_md_context_t));
212     P_NULL_RETURN_WTTH_LOG(mdCtx);
213     lseek(fp, 0, SEEK_SET);
214     int32_t pos = 0;
215     int32_t rawBufLen = signInfo->fullSignBlockOffset;
216     while (rawBufLen > 0) {
217         size_t hlen = 0;
218         int32_t readLen = (rawBufLen > HASH_BLOB_LEN) ? HASH_BLOB_LEN : rawBufLen;
219         const mbedtls_md_info_t *mdInfo = mbedtls_md_info_from_type((mbedtls_md_type_t)digestAlgorithm);
220         if (mdInfo == NULL) {
221             APPV_FREE(mdCtx);
222             return V_ERR;
223         }
224         int32_t ret = HapUpdateDigistHead(digestAlgorithm, mdCtx, mdInfo, readLen, &hlen);
225         P_ERR_GOTO_WTTH_LOG(ret);
226         LOG_INFO("content: %d, %d", rawBufLen, pos);
227         ret = UpdateSmallBlock(readLen, fp, mdCtx);
228         P_ERR_GOTO_WTTH_LOG(ret);
229         rawBufLen -= readLen;
230         pos += readLen;
231         unsigned char *outbuf = APPV_MALLOC(hlen);
232         P_NULL_GOTO_WTTH_LOG(outbuf);
233         ret = mbedtls_md_finish(mdCtx, outbuf);
234         HapPutData(chunkDigest, *offset, outbuf, hlen);
235         (void)memset_s(outbuf, hlen, 0, hlen);
236         *offset += hlen;
237         APPV_FREE(outbuf);
238         P_ERR_GOTO_WTTH_LOG(ret);
239         mbedtls_md_free(mdCtx);
240     }
241     APPV_FREE(mdCtx);
242     return V_OK;
243 EXIT:
244     mbedtls_md_free(mdCtx);
245     APPV_FREE(mdCtx);
246     return V_ERR;
247 }
248 
ComputerCoreDirHash(const SignatureInfo * signInfo,int32_t digestAlgorithm,const int32_t fp,const HapBuf * chunkDigest,int32_t * offset)249 static int32_t ComputerCoreDirHash(const SignatureInfo *signInfo, int32_t digestAlgorithm, const int32_t fp,
250     const HapBuf *chunkDigest, int32_t *offset)
251 {
252     int32_t centralDirSize = signInfo->hapEocdOffset - signInfo->hapCoreDirOffset;
253     if (centralDirSize <= 0) {
254         return V_ERR;
255     }
256     char *dirBuf = APPV_MALLOC(centralDirSize);
257     P_NULL_RETURN_WTTH_LOG(dirBuf);
258     lseek(fp, signInfo->hapCoreDirOffset, SEEK_SET);
259     int32_t len = read(fp, dirBuf, sizeof(char) * centralDirSize);
260     if (len != centralDirSize) {
261         LOG_ERROR("fread err: %d, %d", len, centralDirSize);
262         APPV_FREE(dirBuf);
263         return V_ERR;
264     }
265     int32_t ret = ComputeBlockHash(dirBuf, centralDirSize, digestAlgorithm, chunkDigest, offset);
266     (void)memset_s(dirBuf, centralDirSize, 0, centralDirSize);
267     APPV_FREE(dirBuf);
268     P_ERR_RETURN_WTTH_LOG(ret);
269     return V_OK;
270 }
271 
ComputerEocdHash(const SignatureInfo * signInfo,int32_t digestAlgorithm,const int32_t fp,const HapBuf * chunkDigest,int32_t * offset)272 static int32_t ComputerEocdHash(const SignatureInfo *signInfo, int32_t digestAlgorithm, const int32_t fp,
273     const HapBuf *chunkDigest, int32_t *offset)
274 {
275     if (signInfo->hapEocdSize <= 0) {
276         return V_ERR;
277     }
278     HapEocd *eocdBuf = APPV_MALLOC(signInfo->hapEocdSize);
279     P_NULL_RETURN_WTTH_LOG(eocdBuf);
280     lseek(fp, signInfo->hapEocdOffset, SEEK_SET);
281     int32_t len = read(fp, eocdBuf, signInfo->hapEocdSize);
282     if (len != signInfo->hapEocdSize) {
283         LOG_ERROR("fread err: %d, %d", len, signInfo->hapEocdSize);
284         APPV_FREE(eocdBuf);
285         return V_ERR;
286     }
287     HapPutInt32((unsigned char*)(&(eocdBuf->eocdHead.coreDirOffset)), sizeof(int), signInfo->fullSignBlockOffset);
288     int32_t ret = ComputeBlockHash((char *)(eocdBuf), len, digestAlgorithm, chunkDigest, offset);
289     (void)memset_s(eocdBuf, signInfo->hapEocdSize, 0, signInfo->hapEocdSize);
290     APPV_FREE(eocdBuf);
291     P_ERR_RETURN_WTTH_LOG(ret);
292     return V_OK;
293 }
294 
VerifyIntegrityChunk(int32_t digestAlgorithm,const int32_t fp,const SignatureInfo * signInfo,const HapBuf * actualDigest)295 bool VerifyIntegrityChunk(int32_t digestAlgorithm, const int32_t fp,
296     const SignatureInfo *signInfo, const HapBuf *actualDigest)
297 {
298     if (signInfo == NULL || actualDigest == NULL || actualDigest->buffer == NULL) {
299         return false;
300     }
301     int32_t centralDirSize = signInfo->hapEocdOffset - signInfo->hapCoreDirOffset;
302     int32_t rootHashLen = GetHashUnitLen(digestAlgorithm);
303     if (rootHashLen < 0) {
304         LOG_ERROR("alg error");
305         return false;
306     }
307     int32_t sumCount = GetChunkSumCount(
308         signInfo->fullSignBlockOffset, centralDirSize, signInfo->hapEocdSize, rootHashLen);
309     if (sumCount == 0) {
310         LOG_ERROR("sum count error");
311         return false;
312     }
313     int32_t sumOfChunksLen = HAP_DIGEST_PRIFIX_LEN + sumCount * rootHashLen;
314     HapBuf chunkDigest = {0};
315     if (!CreateHapBuffer(&chunkDigest, sumOfChunksLen)) {
316         return false;
317     }
318     LOG_INFO("alg: %d", digestAlgorithm);
319     HapPutByte(&chunkDigest, 0, HAP_FIRST_LEVEL_CHUNK_PREFIX);
320     HapSetInt32(&chunkDigest, 1, sumCount);
321     int32_t offset = HAP_DIGEST_PRIFIX_LEN;
322     int32_t ret;
323     ret = ComputerFileHash(signInfo, digestAlgorithm, fp, &chunkDigest, &offset);
324     P_ERR_GOTO_WTTH_LOG(ret);
325     ret = ComputerCoreDirHash(signInfo, digestAlgorithm, fp, &chunkDigest, &offset);
326     P_ERR_GOTO_WTTH_LOG(ret);
327     ret = ComputerEocdHash(signInfo, digestAlgorithm, fp, &chunkDigest, &offset);
328     P_ERR_GOTO_WTTH_LOG(ret);
329     ret = ComputeDigestsWithOptionalBlock(digestAlgorithm, fp, signInfo, &chunkDigest, actualDigest);
330     P_ERR_GOTO_WTTH_LOG(ret);
331     ClearHapBuffer(&chunkDigest);
332     LOG_INFO("finish");
333     return true;
334 EXIT:
335     LOG_ERROR("exit");
336     ClearHapBuffer(&chunkDigest);
337     return false;
338 }
339