1 /*
2 * Copyright (c) 2024-2024 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 "sign_bin.h"
17 #include "param_constants.h"
18 #include "file_utils.h"
19 #include "block_head.h"
20 #include "signature_block_types.h"
21 #include "signature_block_tags.h"
22 #include "hash_utils.h"
23 #include "sign_content_info.h"
24 #include "sign_head.h"
25 #include "bc_pkcs7_generator.h"
26 #include "params.h"
27
28 namespace OHOS {
29 namespace SignatureTools {
30
Sign(SignerConfig & signerConfig,const std::map<std::string,std::string> & signParams)31 bool SignBin::Sign(SignerConfig& signerConfig, const std::map<std::string, std::string>& signParams)
32 {
33 /* 1. Make block head, write to output file. */
34 std::string signCode = signParams.at(ParamConstants::PARAM_SIGN_CODE);
35 if (ParamConstants::ENABLE_SIGN_CODE == signCode) {
36 SIGNATURE_TOOLS_LOGW("can not sign bin with codesign.\n");
37 }
38 std::string inputFile = signParams.at(ParamConstants::PARAM_BASIC_INPUT_FILE);
39 std::string outputFile = signParams.at(ParamConstants::PARAM_BASIC_OUTPUT_FILE);
40 std::string profileFile = signParams.at(ParamConstants::PARAM_BASIC_PROFILE);
41 std::string profileSigned = signParams.at(ParamConstants::PARAM_BASIC_PROFILE_SIGNED);
42 bool writeBlockOk = WriteBlockDataToFile(inputFile, outputFile, profileFile, profileSigned);
43 if (!writeBlockOk) {
44 SIGNATURE_TOOLS_LOGE("The block head data made failed.");
45 FileUtils::DelDir(outputFile);
46 return false;
47 }
48 /* 2. Make sign data, and append write to output file */
49 std::string signAlg = signParams.at(ParamConstants::PARAM_BASIC_SIGANTURE_ALG);
50 bool writeSignDataOk = WriteSignDataToOutputFile(signerConfig, outputFile, signAlg);
51 if (!writeSignDataOk) {
52 SIGNATURE_TOOLS_LOGE("The sign data made failed.");
53 FileUtils::DelDir(outputFile);
54 return false;
55 }
56 /* 3. Make sign head data, and write to output file */
57 bool writeSignHeadDataOk = WriteSignHeadDataToOutputFile(inputFile, outputFile);
58 if (!writeSignHeadDataOk) {
59 SIGNATURE_TOOLS_LOGE("The sign head data made failed.");
60 FileUtils::DelDir(outputFile);
61 return false;
62 }
63 return true;
64 }
65
WriteBlockDataToFile(const std::string & inputFile,const std::string & outputFile,const std::string & profileFile,const std::string & profileSigned)66 bool SignBin::WriteBlockDataToFile(const std::string& inputFile, const std::string& outputFile,
67 const std::string& profileFile, const std::string& profileSigned)
68 {
69 int64_t binFileLen = FileUtils::GetFileLen(inputFile);
70 int64_t profileDataLen = FileUtils::GetFileLen(profileFile);
71 bool isValid = CheckBinAndProfileLengthIsValid(binFileLen, profileDataLen);
72 if (!isValid) {
73 PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR,
74 "file length is invalid, binFileLen: " + std::to_string(binFileLen) +
75 "lld, profileDataLen: " + std::to_string(profileDataLen) + "lld");
76 return false;
77 }
78 int64_t offset = binFileLen + BlockHead::GetBlockLen() + BlockHead::GetBlockLen();
79 bool isOver = IsLongOverflowInteger(offset);
80 if (isOver) {
81 PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR,
82 "The profile block head offset is overflow interger range in sign bin, offset: "
83 + std::to_string(offset));
84 return false;
85 }
86 char isSigned = SignatureBlockTypes::GetProfileBlockTypes(profileSigned);
87 std::string proBlockByte =
88 BlockHead::GetBlockHead(isSigned, SignatureBlockTags::DEFAULT, (short)profileDataLen, (int)offset);
89 offset += profileDataLen;
90 isOver = IsLongOverflowInteger(offset);
91 if (isOver) {
92 PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR,
93 "The profile block head offset is overflow interger range in sign bin, offset: "
94 + std::to_string(offset));
95 return false;
96 }
97 std::string signBlockByte = BlockHead::GetBlockHead(
98 SignatureBlockTypes::SIGNATURE_BLOCK, SignatureBlockTags::DEFAULT, (short)0, (int)offset);
99 return WriteSignedBin(inputFile, proBlockByte, signBlockByte, profileFile, outputFile);
100 }
101
GenerateFileDigest(const std::string & outputFile,const std::string & signAlg)102 std::vector<int8_t> SignBin::GenerateFileDigest(const std::string& outputFile,
103 const std::string& signAlg)
104 {
105 SignatureAlgorithmHelper signatureAlgorithmClass;
106 bool getAlgOk = Params::GetSignatureAlgorithm(signAlg, signatureAlgorithmClass);
107 if (!getAlgOk) {
108 PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "[SignHap] get Signature Algorithm failed.");
109 return std::vector<int8_t>();
110 }
111 std::string alg = signatureAlgorithmClass.m_contentDigestAlgorithm.GetDigestAlgorithm();
112 std::vector<int8_t> data = HashUtils::GetFileDigest(outputFile, alg);
113 if (data.empty()) {
114 SIGNATURE_TOOLS_LOGE("GetFileDigest failed.");
115 return std::vector<int8_t>();
116 }
117 SignContentInfo contentInfo;
118 contentInfo.AddContentHashData(0, SignatureBlockTags::HASH_ROOT_4K, HashUtils::GetHashAlgsId(alg),
119 data.size(), data);
120 return contentInfo.GetByteContent();
121 }
122
WriteSignDataToOutputFile(SignerConfig & SignerConfig,const std::string & outputFile,const std::string & signAlg)123 bool SignBin::WriteSignDataToOutputFile(SignerConfig& SignerConfig, const std::string& outputFile,
124 const std::string& signAlg)
125 {
126 std::vector<int8_t> dig = GenerateFileDigest(outputFile, signAlg);
127 if (dig.empty()) {
128 SIGNATURE_TOOLS_LOGE("generateSignature verity digest is null.");
129 return false;
130 }
131 std::string retStr;
132 std::string signedData(dig.begin(), dig.end());
133 std::unique_ptr<Pkcs7Generator> generator = std::make_unique<BCPkcs7Generator>();
134 if (generator->GenerateSignedData(signedData, &SignerConfig, retStr)) {
135 SIGNATURE_TOOLS_LOGE("failed to GenerateSignedData!");
136 return false;
137 }
138 bool writeByteToOutFile = FileUtils::AppendWriteByteToFile(retStr, outputFile);
139 if (!writeByteToOutFile) {
140 SIGNATURE_TOOLS_LOGE("write signedData to outputFile failed!");
141 return false;
142 }
143 return true;
144 }
145
WriteSignHeadDataToOutputFile(const std::string & inputFile,const std::string & outputFile)146 bool SignBin::WriteSignHeadDataToOutputFile(const std::string& inputFile, const std::string& outputFile)
147 {
148 int64_t size = FileUtils::GetFileLen(outputFile) - FileUtils::GetFileLen(inputFile) + SignHead::SIGN_HEAD_LEN;
149 bool isOver = IsLongOverflowInteger(size);
150 if (isOver) {
151 PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR,
152 "File size is Overflow integer range, size: " + std::to_string(size));
153 return false;
154 }
155 SignHead signHeadData;
156 std::vector<int8_t> signHeadByte = signHeadData.GetSignHead(size);
157 if (signHeadByte.empty()) {
158 SIGNATURE_TOOLS_LOGE("Failed to get sign head data!");
159 return false;
160 }
161 bool writeByteToOutFile =
162 FileUtils::AppendWriteByteToFile(std::string(signHeadByte.begin(), signHeadByte.end()), outputFile);
163 if (!writeByteToOutFile) {
164 SIGNATURE_TOOLS_LOGE("Failed to WriteByteToOutFile!");
165 return false;
166 }
167 return true;
168 }
169
CheckBinAndProfileLengthIsValid(int64_t binFileLen,int64_t profileDataLen)170 bool SignBin::CheckBinAndProfileLengthIsValid(int64_t binFileLen, int64_t profileDataLen)
171 {
172 return binFileLen != -1 && profileDataLen != -1 && !IsLongOverflowShort(profileDataLen);
173 }
174
IsLongOverflowInteger(int64_t num)175 bool SignBin::IsLongOverflowInteger(int64_t num)
176 {
177 return (num - (num & 0xffffffffL)) != 0;
178 }
179
IsLongOverflowShort(int64_t num)180 bool SignBin::IsLongOverflowShort(int64_t num)
181 {
182 return (num - (num & 0xffff)) != 0;
183 }
184
WriteSignedBin(const std::string & inputFile,const std::string & proBlockByte,const std::string & signBlockByte,const std::string & profileFile,const std::string & outputFile)185 bool SignBin::WriteSignedBin(const std::string& inputFile, const std::string& proBlockByte,
186 const std::string& signBlockByte, const std::string& profileFile,
187 const std::string& outputFile)
188 {
189 // 1. write the input file to the output file.
190 bool writeInputOk = FileUtils::WriteInputToOutPut(inputFile, outputFile);
191 // 2. append write profile block head to the output file.
192 bool appendProfileHeadOk = FileUtils::AppendWriteByteToFile(proBlockByte, outputFile);
193 // 3. append write sign block head to the output file.
194 bool appendBlockHeadOk = FileUtils::AppendWriteByteToFile(signBlockByte, outputFile);
195 // 4. write profile src file to the output file.
196 bool appendProfileSrcOk = FileUtils::AppendWriteFileToFile(profileFile, outputFile);
197 if (!writeInputOk || !appendProfileHeadOk || !appendBlockHeadOk || !appendProfileSrcOk) {
198 PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "Failed to write signed bin");
199 return false;
200 }
201 return true;
202 }
203
204 } // namespace SignatureTools
205 } // namespace OHOS