1fb299fa2Sopenharmony_ci/*
2fb299fa2Sopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd.
3fb299fa2Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4fb299fa2Sopenharmony_ci * you may not use this file except in compliance with the License.
5fb299fa2Sopenharmony_ci * You may obtain a copy of the License at
6fb299fa2Sopenharmony_ci *
7fb299fa2Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8fb299fa2Sopenharmony_ci *
9fb299fa2Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10fb299fa2Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11fb299fa2Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12fb299fa2Sopenharmony_ci * See the License for the specific language governing permissions and
13fb299fa2Sopenharmony_ci * limitations under the License.
14fb299fa2Sopenharmony_ci */
15fb299fa2Sopenharmony_ci
16fb299fa2Sopenharmony_ci#include "zip_pkg_parse.h"
17fb299fa2Sopenharmony_ci#include <vector>
18fb299fa2Sopenharmony_ci#include "dump.h"
19fb299fa2Sopenharmony_ci#include "pkg_utils.h"
20fb299fa2Sopenharmony_ci
21fb299fa2Sopenharmony_cinamespace Hpackage {
22fb299fa2Sopenharmony_cistruct Footer {
23fb299fa2Sopenharmony_ci    uint16_t signDataStart;
24fb299fa2Sopenharmony_ci    uint16_t signDataFlag;
25fb299fa2Sopenharmony_ci    uint16_t signDataSize;
26fb299fa2Sopenharmony_ci};
27fb299fa2Sopenharmony_ci
28fb299fa2Sopenharmony_cinamespace {
29fb299fa2Sopenharmony_ciconstexpr uint32_t ZIP_EOCD_LEN_EXCLUDE_COMMENT = 20;
30fb299fa2Sopenharmony_ciconstexpr uint32_t ZIP_EOCD_FIXED_PART_LEN = 22;
31fb299fa2Sopenharmony_ciconstexpr uint32_t PKG_FOOTER_SIZE = 6;
32fb299fa2Sopenharmony_ciconstexpr uint32_t PKG_ZIP_EOCD_MIN_LEN = ZIP_EOCD_FIXED_PART_LEN + PKG_FOOTER_SIZE;
33fb299fa2Sopenharmony_ciconstexpr uint32_t ZIP_EOCD_SIGNATURE = 0x06054b50;
34fb299fa2Sopenharmony_ciconstexpr uint16_t PKG_ZIP_EOCD_FOOTER_FLAG = 0xFFFF;
35fb299fa2Sopenharmony_ciconst uint8_t ZIP_EOCD_SIGNATURE_BIG_ENDIAN[4] = {0x50, 0x4b, 0x05, 0x06};
36fb299fa2Sopenharmony_ci}
37fb299fa2Sopenharmony_ci
38fb299fa2Sopenharmony_ci/*
39fb299fa2Sopenharmony_ci * ZIP:  File Entry(1..n) + CD(1..n) + EOCD(1)
40fb299fa2Sopenharmony_ci *
41fb299fa2Sopenharmony_ci * EOCD: FLAG(4 bytes) + FIX PART1(16 bytes) + comment length(2 bytes) + comment('comment length' bytes)
42fb299fa2Sopenharmony_ci *
43fb299fa2Sopenharmony_ci * EOCD comment: RESERVED(18 bytes) + SIGNATYRE(variable size) + FOOTER (6 bytes)
44fb299fa2Sopenharmony_ci *
45fb299fa2Sopenharmony_ci * FOOTER                           6 bytes (little endian)
46fb299fa2Sopenharmony_ci *     append signed result length  2 bytes (SIGNATYRE's length + FOOTER's length) = SIGNATYRE reversed offset
47fb299fa2Sopenharmony_ci *     0xFFFF                       2 bytes
48fb299fa2Sopenharmony_ci *     = .ZIP file comment length   2 bytes
49fb299fa2Sopenharmony_ci */
50fb299fa2Sopenharmony_ci
51fb299fa2Sopenharmony_ciint32_t ZipPkgParse::DoParseZipPkg(PkgStreamPtr pkgStream, PkgSignComment &pkgSignComment,
52fb299fa2Sopenharmony_ci    size_t &readLen, const uint16_t &signCommentAppendLen, uint16_t &signCommentTotalLen) const
53fb299fa2Sopenharmony_ci{
54fb299fa2Sopenharmony_ci    size_t fileLen = pkgStream->GetFileLength();
55fb299fa2Sopenharmony_ci    size_t eocdTotalLen = ZIP_EOCD_FIXED_PART_LEN + signCommentTotalLen;
56fb299fa2Sopenharmony_ci    if (fileLen <= eocdTotalLen) {
57fb299fa2Sopenharmony_ci        PKG_LOGE("Invalid eocd len[%zu]", eocdTotalLen);
58fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(PKG_INVALID_PKG_FORMAT);
59fb299fa2Sopenharmony_ci        return PKG_INVALID_PKG_FORMAT;
60fb299fa2Sopenharmony_ci    }
61fb299fa2Sopenharmony_ci
62fb299fa2Sopenharmony_ci    size_t zipEocdStart = fileLen - eocdTotalLen;
63fb299fa2Sopenharmony_ci    PkgBuffer zipEocd(eocdTotalLen);
64fb299fa2Sopenharmony_ci    int32_t ret = pkgStream->Read(zipEocd, zipEocdStart, eocdTotalLen, readLen);
65fb299fa2Sopenharmony_ci    if (ret != PKG_SUCCESS) {
66fb299fa2Sopenharmony_ci        PKG_LOGE("read zip eocd failed %s", pkgStream->GetFileName().c_str());
67fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(PKG_INVALID_PKG_FORMAT);
68fb299fa2Sopenharmony_ci        return ret;
69fb299fa2Sopenharmony_ci    }
70fb299fa2Sopenharmony_ci
71fb299fa2Sopenharmony_ci    ret = CheckZipEocd(zipEocd.buffer, eocdTotalLen, signCommentTotalLen);
72fb299fa2Sopenharmony_ci    if (ret != PKG_SUCCESS) {
73fb299fa2Sopenharmony_ci        PKG_LOGE("CheckZipEocd() error, ret[%d]", ret);
74fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(PKG_INVALID_PKG_FORMAT);
75fb299fa2Sopenharmony_ci        return ret;
76fb299fa2Sopenharmony_ci    }
77fb299fa2Sopenharmony_ci
78fb299fa2Sopenharmony_ci    if (fileLen <= signCommentTotalLen) {
79fb299fa2Sopenharmony_ci        PKG_LOGE("file len[%zu] < signCommentTotalLen[%zu]", fileLen, signCommentTotalLen);
80fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(PKG_INVALID_PKG_FORMAT, fileLen, signCommentTotalLen);
81fb299fa2Sopenharmony_ci        return PKG_INVALID_FILE;
82fb299fa2Sopenharmony_ci    }
83fb299fa2Sopenharmony_ci    pkgSignComment.signCommentTotalLen = signCommentTotalLen;
84fb299fa2Sopenharmony_ci    pkgSignComment.signCommentAppendLen = signCommentAppendLen;
85fb299fa2Sopenharmony_ci
86fb299fa2Sopenharmony_ci    return PKG_SUCCESS;
87fb299fa2Sopenharmony_ci}
88fb299fa2Sopenharmony_ci
89fb299fa2Sopenharmony_ciint32_t ZipPkgParse::ParseZipPkg(PkgStreamPtr pkgStream, PkgSignComment &pkgSignComment) const
90fb299fa2Sopenharmony_ci{
91fb299fa2Sopenharmony_ci    if (pkgStream == nullptr) {
92fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(PKG_INVALID_PARAM);
93fb299fa2Sopenharmony_ci        return PKG_INVALID_PARAM;
94fb299fa2Sopenharmony_ci    }
95fb299fa2Sopenharmony_ci    size_t fileLen = pkgStream->GetFileLength();
96fb299fa2Sopenharmony_ci    size_t footerSize = PKG_FOOTER_SIZE;
97fb299fa2Sopenharmony_ci    if (fileLen <= footerSize) {
98fb299fa2Sopenharmony_ci        PKG_LOGE("file len[%zu] < footerSize.", pkgStream->GetFileLength());
99fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(PKG_INVALID_FILE, fileLen);
100fb299fa2Sopenharmony_ci        return PKG_INVALID_FILE;
101fb299fa2Sopenharmony_ci    }
102fb299fa2Sopenharmony_ci    size_t footerStart = fileLen - footerSize;
103fb299fa2Sopenharmony_ci    size_t readLen = 0;
104fb299fa2Sopenharmony_ci    PkgBuffer footer(footerSize);
105fb299fa2Sopenharmony_ci    int32_t ret = pkgStream->Read(footer, footerStart, footerSize, readLen);
106fb299fa2Sopenharmony_ci    if (ret != PKG_SUCCESS) {
107fb299fa2Sopenharmony_ci        PKG_LOGE("read FOOTER struct failed %s", pkgStream->GetFileName().c_str());
108fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(ret);
109fb299fa2Sopenharmony_ci        return ret;
110fb299fa2Sopenharmony_ci    }
111fb299fa2Sopenharmony_ci
112fb299fa2Sopenharmony_ci    uint16_t signCommentAppendLen = 0;
113fb299fa2Sopenharmony_ci    uint16_t signCommentTotalLen = 0;
114fb299fa2Sopenharmony_ci    ret = ParsePkgFooter(footer.buffer, PKG_FOOTER_SIZE, signCommentAppendLen, signCommentTotalLen);
115fb299fa2Sopenharmony_ci    if (ret != PKG_SUCCESS) {
116fb299fa2Sopenharmony_ci        PKG_LOGE("ParsePkgFooter() error, ret[%d]", ret);
117fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(ret);
118fb299fa2Sopenharmony_ci        return ret;
119fb299fa2Sopenharmony_ci    }
120fb299fa2Sopenharmony_ci    return DoParseZipPkg(pkgStream, pkgSignComment, readLen, signCommentAppendLen, signCommentTotalLen);
121fb299fa2Sopenharmony_ci}
122fb299fa2Sopenharmony_ci
123fb299fa2Sopenharmony_ciint32_t ZipPkgParse::ParsePkgFooter(const uint8_t *footer, size_t length,
124fb299fa2Sopenharmony_ci    uint16_t &signCommentAppendLen, uint16_t &signCommentTotalLen) const
125fb299fa2Sopenharmony_ci{
126fb299fa2Sopenharmony_ci    Updater::UPDATER_INIT_RECORD;
127fb299fa2Sopenharmony_ci    if (length < PKG_FOOTER_SIZE) {
128fb299fa2Sopenharmony_ci        PKG_LOGE("length[%d] < Footer Size[%d]", length, PKG_FOOTER_SIZE);
129fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(PKG_INVALID_PARAM, length);
130fb299fa2Sopenharmony_ci        return PKG_INVALID_PARAM;
131fb299fa2Sopenharmony_ci    }
132fb299fa2Sopenharmony_ci
133fb299fa2Sopenharmony_ci    Footer signFooter = {0};
134fb299fa2Sopenharmony_ci    size_t offset = 0;
135fb299fa2Sopenharmony_ci    signFooter.signDataStart = ReadLE16(footer);
136fb299fa2Sopenharmony_ci    offset += sizeof(uint16_t);
137fb299fa2Sopenharmony_ci    signFooter.signDataFlag = ReadLE16(footer + offset);
138fb299fa2Sopenharmony_ci    offset += sizeof(uint16_t);
139fb299fa2Sopenharmony_ci    signFooter.signDataSize = ReadLE16(footer + offset);
140fb299fa2Sopenharmony_ci    if (signFooter.signDataFlag != PKG_ZIP_EOCD_FOOTER_FLAG) {
141fb299fa2Sopenharmony_ci        PKG_LOGE("error FooterFlag[0x%04X]", signFooter.signDataFlag);
142fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(PKG_INVALID_PKG_FORMAT, signFooter.signDataFlag);
143fb299fa2Sopenharmony_ci        return PKG_INVALID_PKG_FORMAT;
144fb299fa2Sopenharmony_ci    }
145fb299fa2Sopenharmony_ci
146fb299fa2Sopenharmony_ci    signCommentAppendLen = signFooter.signDataStart;
147fb299fa2Sopenharmony_ci    signCommentTotalLen = signFooter.signDataSize;
148fb299fa2Sopenharmony_ci    if ((signCommentAppendLen < PKG_FOOTER_SIZE) || (signCommentTotalLen < PKG_FOOTER_SIZE) ||
149fb299fa2Sopenharmony_ci        (signCommentAppendLen > signCommentTotalLen)) {
150fb299fa2Sopenharmony_ci        PKG_LOGE("bad footer length: append[0x%04X], total[0x%04X]",
151fb299fa2Sopenharmony_ci            signCommentAppendLen, signCommentTotalLen);
152fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(PKG_INVALID_PKG_FORMAT, signCommentAppendLen, signCommentTotalLen);
153fb299fa2Sopenharmony_ci        return PKG_INVALID_PKG_FORMAT;
154fb299fa2Sopenharmony_ci    }
155fb299fa2Sopenharmony_ci
156fb299fa2Sopenharmony_ci    return PKG_SUCCESS;
157fb299fa2Sopenharmony_ci}
158fb299fa2Sopenharmony_ci
159fb299fa2Sopenharmony_ciint32_t ZipPkgParse::CheckZipEocd(const uint8_t *eocd, size_t length,
160fb299fa2Sopenharmony_ci    uint16_t signCommentTotalLen) const
161fb299fa2Sopenharmony_ci{
162fb299fa2Sopenharmony_ci    Updater::UPDATER_INIT_RECORD;
163fb299fa2Sopenharmony_ci    if (length < PKG_ZIP_EOCD_MIN_LEN) {
164fb299fa2Sopenharmony_ci        PKG_LOGE("bad eocd length: append[0x%04X]", length);
165fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(PKG_INVALID_PKG_FORMAT);
166fb299fa2Sopenharmony_ci        return PKG_INVALID_PKG_FORMAT;
167fb299fa2Sopenharmony_ci    }
168fb299fa2Sopenharmony_ci
169fb299fa2Sopenharmony_ci    uint32_t eocdSignature = ReadLE32(eocd);
170fb299fa2Sopenharmony_ci    if (eocdSignature != ZIP_EOCD_SIGNATURE) {
171fb299fa2Sopenharmony_ci        PKG_LOGE("bad zip eocd flag[%zu]", eocdSignature);
172fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(PKG_INVALID_PKG_FORMAT);
173fb299fa2Sopenharmony_ci        return PKG_INVALID_PKG_FORMAT;
174fb299fa2Sopenharmony_ci    }
175fb299fa2Sopenharmony_ci
176fb299fa2Sopenharmony_ci    /* the beginning 4 chars are already checked before, so begin with i = 4; (length - 3) in case for overflow */
177fb299fa2Sopenharmony_ci    for (size_t i = 4; i < length - 3; i++) {
178fb299fa2Sopenharmony_ci        /* every 4 byte check if eocd, if eocd[i] = 0x50, eocd[i + 1] = 0x4b, eocd[i + 2] = 0x05, eocd[i + 3] = 0x06 */
179fb299fa2Sopenharmony_ci        /* the zip contain another ecod, we can consider it's invalid zip */
180fb299fa2Sopenharmony_ci        if (eocd[i] == ZIP_EOCD_SIGNATURE_BIG_ENDIAN[0] &&
181fb299fa2Sopenharmony_ci            eocd[i + 1] == ZIP_EOCD_SIGNATURE_BIG_ENDIAN[1] &&
182fb299fa2Sopenharmony_ci            eocd[i + 2] == ZIP_EOCD_SIGNATURE_BIG_ENDIAN[2] && /* eocd[i + 2] = 0x05 */
183fb299fa2Sopenharmony_ci            eocd[i + 3] == ZIP_EOCD_SIGNATURE_BIG_ENDIAN[3]) { /* eocd[i + 3] = 0x06 */
184fb299fa2Sopenharmony_ci            PKG_LOGE("EOCD marker occurs after start of EOCD");
185fb299fa2Sopenharmony_ci            UPDATER_LAST_WORD(PKG_INVALID_PKG_FORMAT);
186fb299fa2Sopenharmony_ci            return PKG_INVALID_PKG_FORMAT;
187fb299fa2Sopenharmony_ci        }
188fb299fa2Sopenharmony_ci    }
189fb299fa2Sopenharmony_ci
190fb299fa2Sopenharmony_ci    const uint8_t *zipSignCommentAddr = eocd + ZIP_EOCD_LEN_EXCLUDE_COMMENT;
191fb299fa2Sopenharmony_ci    uint16_t tempLen = ReadLE16(zipSignCommentAddr);
192fb299fa2Sopenharmony_ci    if (signCommentTotalLen != tempLen) {
193fb299fa2Sopenharmony_ci        PKG_LOGE("compare sign comment length: eocd[0x%04X], footer[0x%04X] error", tempLen, signCommentTotalLen);
194fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(PKG_INVALID_PKG_FORMAT);
195fb299fa2Sopenharmony_ci        return PKG_INVALID_PKG_FORMAT;
196fb299fa2Sopenharmony_ci    }
197fb299fa2Sopenharmony_ci
198fb299fa2Sopenharmony_ci    return PKG_SUCCESS;
199fb299fa2Sopenharmony_ci}
200fb299fa2Sopenharmony_ci} // namespace Hpackage
201