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 #include <unistd.h>
16
17 #include "sign_elf.h"
18 #include "string_utils.h"
19 #include "code_signing.h"
20 #include "param_constants.h"
21 #include "block_head.h"
22 #include "sign_head.h"
23 #include "signature_block_types.h"
24 #include "signature_block_tags.h"
25
26 namespace OHOS {
27 namespace SignatureTools {
28
29 int SignElf::blockNum = 0;
30 const std::string SignElf::CODESIGN_OFF = "0";
31
Sign(SignerConfig& signerConfig, std::map<std::string, std::string>& signParams)32 bool SignElf::Sign(SignerConfig& signerConfig, std::map<std::string, std::string>& signParams)
33 {
34 std::string inputFile = signParams.at(ParamConstants::PARAM_BASIC_INPUT_FILE);
35 std::string tmpFile;
36 bool checkAlignFileBy4kBytesFlag = AlignFileBy4kBytes(inputFile, tmpFile);
37 if (!checkAlignFileBy4kBytesFlag) {
38 SIGNATURE_TOOLS_LOGE("[SignElf] AlignFileBy4kBytes error");
39 remove(tmpFile.c_str());
40 return false;
41 }
42 std::string outputFile = signParams.at(ParamConstants::PARAM_BASIC_OUTPUT_FILE);
43 std::string profileSigned = signParams.at(ParamConstants::PARAM_BASIC_PROFILE_SIGNED);
44 bool checkWriteBlockDataToFileFlag = WriteBlockDataToFile(signerConfig, tmpFile,
45 outputFile, profileSigned, signParams);
46 if (!checkWriteBlockDataToFileFlag) {
47 SIGNATURE_TOOLS_LOGE("[SignElf] WriteBlockDataToFile error");
48 remove(tmpFile.c_str());
49 return false;
50 }
51 bool checkWriteSignHeadDataToOutputFileFlag = WriteSignHeadDataToOutputFile(tmpFile, outputFile, blockNum);
52 if (!checkWriteSignHeadDataToOutputFileFlag) {
53 SIGNATURE_TOOLS_LOGE("[SignElf] WriteSignHeadDataToOutputFile error");
54 remove(tmpFile.c_str());
55 return false;
56 }
57 return (remove(tmpFile.c_str()) == 0);
58 ;
59 }
60
AlignFileBy4kBytes(const std::string& inputFile, std::string& tmpFile)61 bool SignElf::AlignFileBy4kBytes(const std::string& inputFile, std::string& tmpFile)
62 {
63 auto now = std::chrono::high_resolution_clock::now();
64 auto duration = now.time_since_epoch();
65 auto timeStamp = std::chrono::duration_cast<std::chrono::microseconds>(duration).count();
66 tmpFile = "tmpFile" + std::to_string(timeStamp);
67 std::ofstream output(tmpFile);
68 bool checkSpaceFlag = FileUtils::IsSpaceEnough(std::string("./"), FileUtils::GetFileLen(inputFile));
69 if (!checkSpaceFlag) {
70 char currentPath[FILE_PATH_LENGTH] = { 0 };
71 getcwd(currentPath, FILE_PATH_LENGTH);
72 PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "[SignElf] The available space of the current directory: "
73 + std::string(currentPath) + " is insufficient. Please check");
74 return false;
75 }
76 bool checkOutputFlag = output.is_open();
77 if (!checkOutputFlag) {
78 PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "[SignElf] open file: " + tmpFile + "failed");
79 return false;
80 }
81 std::ifstream input(inputFile);
82 bool checkInputFlag = input.is_open();
83 if (!checkInputFlag) {
84 PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "[SignElf] open file: " + inputFile + "failed");
85 return false;
86 }
87 char buffer[FILE_BUFFER_BLOCK];
88 std::streamsize bytesRead;
89 int64_t outputLength = 0;
90 while ((bytesRead = input.read(buffer, sizeof(buffer)).gcount()) > 0) {
91 output.write(buffer, bytesRead);
92 if (!output) {
93 PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "[SignElf] write data to " + tmpFile + "failed");
94 return false;
95 }
96 outputLength += bytesRead;
97 }
98 int64_t addLength = PAGE_SIZE - (outputLength % PAGE_SIZE);
99 std::vector<char> bytes(addLength, 0);
100 output.write(bytes.data(), addLength);
101 return true;
102 }
103
WriteBlockDataToFile(SignerConfig& signerConfig, const std::string &inputFile, std::string& outputFile, const std::string& profileSigned, const std::map<std::string, std::string>& signParams)104 bool SignElf::WriteBlockDataToFile(SignerConfig& signerConfig,
105 const std::string &inputFile, std::string& outputFile,
106 const std::string& profileSigned,
107 const std::map<std::string, std::string>& signParams)
108 {
109 std::string proFile;
110 if (signParams.find(ParamConstants::PARAM_BASIC_PROFILE) != signParams.end()) {
111 proFile = signParams.at(ParamConstants::PARAM_BASIC_PROFILE);
112 }
113 std::list<SignBlockData> signDataList;
114 int64_t binFileLen = FileUtils::GetFileLen(inputFile);
115 bool checkFlag = binFileLen < 0 || IsLongOverflowInteger(binFileLen);
116 if (checkFlag) {
117 PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "[SignElf] The length exceeds the maximum limit.");
118 return false;
119 }
120 bool checkIsEmptyFlag = StringUtils::IsEmpty(proFile);
121 if (!checkIsEmptyFlag) {
122 signDataList.push_front(GenerateProfileSignByte(proFile, profileSigned));
123 }
124 blockNum = signDataList.size() + 1;
125 SignBlockData* codeSign = nullptr;
126 bool checkGenerateCodeSignByteFlag = !GenerateCodeSignByte(signerConfig, signParams, inputFile, blockNum,
127 binFileLen, &codeSign) || !codeSign;
128 if (checkGenerateCodeSignByteFlag) {
129 SIGNATURE_TOOLS_LOGE("[SignElf] generate code sign byte error.");
130 if (codeSign) {
131 delete codeSign;
132 }
133 return false;
134 }
135 signDataList.push_front(*codeSign);
136 blockNum = signDataList.size();
137 bool checkGenerateSignBlockHeadFlag = GenerateSignBlockHead(signDataList);
138 if (!checkGenerateSignBlockHeadFlag) {
139 SIGNATURE_TOOLS_LOGE("[SignElf] generate sign block head error.");
140 delete codeSign;
141 return false;
142 }
143 delete codeSign;
144 return WriteSignedElf(inputFile, signDataList, outputFile);
145 }
146
147 bool SignElf::WriteSignedElf(const std::string &inputFile, std::list<SignBlockData>& signBlockList,
148 std::string &outputFile)
149 {
150 std::ifstream fileInputStream(inputFile, std::ios::binary);
151 std::ofstream fileOutputStream(outputFile, std::ios::binary);
152 bool checkFlag = !fileInputStream.is_open();
153 if (checkFlag) {
154 PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "[SignElf] open file: " + inputFile + "failed");
155 return false;
156 }
157 checkFlag = !fileOutputStream.is_open();
158 if (checkFlag) {
159 fileInputStream.close();
160 PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "[SignElf] open file: " + outputFile + "failed");
161 return false;
162 }
163 char buffer[FILE_BUFFER_BLOCK];
164 while (!fileInputStream.eof()) {
165 fileInputStream.read(buffer, sizeof(buffer));
166 fileOutputStream.write(buffer, fileInputStream.gcount());
167 }
168 bool writeFlag = WriteSignBlockData(signBlockList, fileOutputStream);
169 if (!writeFlag) {
170 SIGNATURE_TOOLS_LOGE("[SignElf] write signBlockList to file error");
171 fileInputStream.close();
172 fileOutputStream.close();
173 return false;
174 }
175 fileInputStream.close();
176 fileOutputStream.close();
177 return true;
178 }
179
180 bool SignElf::WriteSignBlockData(std::list<SignBlockData>& signBlockList, std::ofstream& fileOutputStream)
181 {
182 for (auto& signBlockData : signBlockList) {
183 bool checkWriteByteToOutFileFlag = FileUtils::WriteByteToOutFile(signBlockData.GetBlockHead(),
184 fileOutputStream);
185 if (!checkWriteByteToOutFileFlag) {
186 SIGNATURE_TOOLS_LOGE("[SignElf] write data to file error");
187 return false;
188 }
189 }
190 for (auto& signBlockData : signBlockList) {
191 bool isSuccess;
192 bool checkFlag = signBlockData.GetByte();
193 if (checkFlag) {
194 isSuccess = FileUtils::WriteByteToOutFile(signBlockData.GetSignData(), fileOutputStream);
195 } else {
196 std::ifstream InputSignFileStream(signBlockData.GetSignFile(), std::ios::binary);
197 bool checkFileFlag = !InputSignFileStream.is_open();
198 if (checkFileFlag) {
199 PrintErrorNumberMsg("IO_ERROR", IO_ERROR,
200 "[SignElf] open file: " + signBlockData.GetSignFile() + "failed");
201 return false;
202 }
203 int result = FileUtils::WriteInputToOutPut(InputSignFileStream, fileOutputStream,
204 (long)signBlockData.GetLen());
205 isSuccess = (result == 0 ? true : false);
206 }
207 if (!isSuccess) {
208 PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "write data to file error");
209 return false;
210 }
211 }
212 return true;
213 }
214
215 bool SignElf::GenerateSignBlockHead(std::list<SignBlockData>& signDataList)
216 {
217 int64_t offset = BlockHead::GetElfBlockLen() * signDataList.size();
218 for (std::list<SignBlockData>::iterator it = signDataList.begin(); it != signDataList.end(); ++it) {
219 std::vector<int8_t> tmp = BlockHead::GetBlockHeadLittleEndian(it->GetType(),
220 SignatureBlockTags::DEFAULT, it->GetLen(), offset);
221 it->SetBlockHead(tmp);
222 offset += it->GetLen();
223 bool checkIsLongOverflowIntegerFlag = IsLongOverflowInteger(offset);
224 if (checkIsLongOverflowIntegerFlag) {
225 PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "[SignElf] The length exceeds the maximum limit.");
226 return false;
227 }
228 }
229 return true;
230 }
231
GenerateProfileSignByte(std::string profileFile, std::string profileSigned)232 SignBlockData SignElf::GenerateProfileSignByte(std::string profileFile, std::string profileSigned)
233 {
234 int64_t profileDataLen = FileUtils::GetFileLen(profileFile);
235 if (profileDataLen < 0 || IsLongOverflowShort(profileDataLen)) {
236 PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR,
237 "[SignElf] The length exceeds the maximum limit.");
238 }
239 char isSigned = SignatureBlockTypes::GetProfileBlockTypes(profileSigned);
240 return SignBlockData(profileFile, isSigned);
241 }
242
GenerateCodeSignByte(SignerConfig& signerConfig, const std::map<std::string, std::string> &signParams, const std::string &inputFile, const int blockNum, const long binFileLen, SignBlockData** codeSign)243 bool SignElf::GenerateCodeSignByte(SignerConfig& signerConfig, const std::map<std::string, std::string> &signParams,
244 const std::string &inputFile, const int blockNum, const long binFileLen,
245 SignBlockData** codeSign)
246 {
247 if (signParams.at(ParamConstants::PARAM_SIGN_CODE) == CODESIGN_OFF) {
248 PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "[SignElf] check pamams signCode = 0 error.");
249 return false;
250 }
251 CodeSigning codeSigning(&signerConfig);
252 long offset = binFileLen + (long)BlockHead::GetElfBlockLen() * blockNum;
253 std::string profileContent;
254 if (signParams.find(ParamConstants::PARAM_PROFILE_JSON_CONTENT) != signParams.end()) {
255 profileContent = signParams.at(ParamConstants::PARAM_PROFILE_JSON_CONTENT);
256 }
257 std::vector<int8_t> codesignData;
258 bool checkGetElfCodeSignBlockFlag = codeSigning.GetElfCodeSignBlock(inputFile, offset,
259 signParams.at(ParamConstants::PARAM_IN_FORM),
260 profileContent, codesignData);
261 if (!checkGetElfCodeSignBlockFlag) {
262 SIGNATURE_TOOLS_LOGE("[SignElf] get elf code sign block error.");
263 return false;
264 }
265 *codeSign = new SignBlockData(codesignData, CODESIGN_BLOCK_TYPE);
266 return true;
267 }
268
WriteSignHeadDataToOutputFile(const std::string& inputFile, const std::string& outputFile, const int blockNum)269 bool SignElf::WriteSignHeadDataToOutputFile(const std::string& inputFile, const std::string& outputFile,
270 const int blockNum)
271 {
272 int64_t size = FileUtils::GetFileLen(outputFile) - FileUtils::GetFileLen(inputFile);
273 if (IsLongOverflowInteger(size)) {
274 PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR,
275 "[SignElf] The length exceeds the maximum limit.");
276 return false;
277 }
278 SignHead signHeadData;
279 std::vector<int8_t> signHeadByte = signHeadData.GetSignHeadLittleEndian((int)size, blockNum);
280 std::ofstream fileOutputStream(outputFile, std::ios::app | std::ios::binary);
281 return FileUtils::WriteByteToOutFile(signHeadByte, fileOutputStream);
282 }
283
IsLongOverflowInteger(const int64_t num)284 bool SignElf::IsLongOverflowInteger(const int64_t num)
285 {
286 return (num - (num & 0xffffffffL)) != 0;
287 }
288
IsLongOverflowShort(const int64_t num)289 bool SignElf::IsLongOverflowShort(const int64_t num)
290 {
291 return (num - (num & 0xffffL)) != 0;
292 }
293
294 } // namespace SignatureTools
295 } // namespace OHOS