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