1 /*
2 * Copyright (c) 2025-2025 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_elf.h"
17 #include <unistd.h>
18
19 #include "file_utils.h"
20 #include "string_utils.h"
21 #include "constant.h"
22 #include "code_signing.h"
23 #include "param_constants.h"
24 #include "profile_sign_tool.h"
25
26 namespace OHOS {
27 namespace SignatureTools {
28
29 const std::string SignElf::codesignSec = ".codesign";
30 const std::string SignElf::profileSec = ".profile";
31 const std::string SignElf::permissionSec = ".permission";
32 constexpr size_t MAX_SECTION_SIZE = static_cast<size_t>(0xFFFFFFFF);
33
Sign(SignerConfig & signerConfig,std::map<std::string,std::string> & signParams)34 bool SignElf::Sign(SignerConfig& signerConfig, std::map<std::string, std::string>& signParams)
35 {
36 std::string inputFile = signParams.at(ParamConstants::PARAM_BASIC_INPUT_FILE);
37 ELFIO::elfio elfReader;
38 if (!elfReader.load(inputFile)) {
39 SIGNATURE_TOOLS_LOGE("[SignElf] Failed to load input ELF file");
40 return false;
41 }
42 bool writeProfilFlag = WriteSecDataToFile(elfReader, signerConfig, signParams);
43 if (!writeProfilFlag) {
44 SIGNATURE_TOOLS_LOGE("[SignElf] WriteSecDataToFile error");
45 return false;
46 }
47 std::string outputFile = signParams.at(ParamConstants::PARAM_BASIC_OUTPUT_FILE);
48 std::string tmpOutputFile = outputFile;
49 if (outputFile == inputFile) {
50 tmpOutputFile = "tmp-signed-elf";
51 }
52 uint64_t csOffset = 0;
53 bool writeCodeSignFlag = WriteCodeSignBlock(elfReader, tmpOutputFile, csOffset);
54 if (!writeCodeSignFlag) {
55 SIGNATURE_TOOLS_LOGE("[SignElf] WriteCodeSignBlock error");
56 return false;
57 }
58 // cs offset > 0 and 4K alignment
59 if (csOffset == 0 || (csOffset % PAGE_SIZE) != 0) {
60 SIGNATURE_TOOLS_LOGE("[SignElf] csOffset is not 4K alignment");
61 return false;
62 }
63 std::string selfSign = signParams.at(ParamConstants::PARAM_SELF_SIGN);
64 bool generateCodeSignFlag = GenerateCodeSignByte(signerConfig, tmpOutputFile, csOffset, selfSign);
65 if (!generateCodeSignFlag) {
66 return false;
67 }
68 return FileUtils::CopyTmpFileAndDel(tmpOutputFile, outputFile);
69 }
70
loadModule(std::map<std::string,std::string> & signParams,std::string & moduleContent)71 bool SignElf::loadModule(std::map<std::string, std::string>& signParams, std::string& moduleContent)
72 {
73 if (signParams.find(ParamConstants::PARAM_MODULE_FILE) != signParams.end()) {
74 std::string modulefilePath = signParams.at(ParamConstants::PARAM_MODULE_FILE);
75 if (FileUtils::ReadFile(modulefilePath, moduleContent) < 0) {
76 SIGNATURE_TOOLS_LOGE("[SignElf] Failed to open module file");
77 return false;
78 }
79 } else {
80 SIGNATURE_TOOLS_LOGI("[SignElf] No module file");
81 }
82 if (moduleContent.size() > MAX_SECTION_SIZE) {
83 SIGNATURE_TOOLS_LOGE("[SignElf] moduleContent size exceeds maximum allowed section size (4GB)");
84 return false;
85 }
86 return true;
87 }
88
loadProfileAndSign(SignerConfig & signerConfig,std::map<std::string,std::string> & signParams,std::string & p7b)89 bool SignElf::loadProfileAndSign(SignerConfig& signerConfig, std::map<std::string, std::string>& signParams,
90 std::string& p7b)
91 {
92 std::string profileContent;
93 if (signParams.find(ParamConstants::PARAM_BASIC_PROFILE) != signParams.end()) {
94 std::string profilefilePath = signParams.at(ParamConstants::PARAM_BASIC_PROFILE);
95 if (FileUtils::ReadFile(profilefilePath, profileContent) < 0) {
96 SIGNATURE_TOOLS_LOGE("[SignElf] Failed to open profile file");
97 return false;
98 }
99 } else {
100 return true;
101 }
102 std::string profileSigned = signParams.at(ParamConstants::PARAM_BASIC_PROFILE_SIGNED);
103 if (profileSigned == DEFAULT_PROFILE_SIGNED_0) {
104 std::string alg = signParams.at(ParamConstants::PARAM_BASIC_SIGANTURE_ALG);
105 if (ProfileSignTool::SignProfile(profileContent, signerConfig.GetSigner(), alg, p7b) < 0) {
106 SIGNATURE_TOOLS_LOGE("[SignElf] SignProfile error");
107 return false;
108 }
109 } else {
110 p7b = profileContent;
111 }
112 if (p7b.size() > MAX_SECTION_SIZE) {
113 SIGNATURE_TOOLS_LOGE("[SignElf] profileContent size exceeds maximum allowed section size (4GB)");
114 return false;
115 }
116 return true;
117 }
118
isExecElf(ELFIO::elfio & reader)119 bool SignElf::isExecElf(ELFIO::elfio& reader)
120 {
121 ELFIO::Elf64_Half eType = reader.get_type();
122 if (eType == ELFIO::ET_EXEC) {
123 return true;
124 }
125 if (eType == ELFIO::ET_DYN && reader.get_entry() > 0) {
126 return true;
127 }
128 return false;
129 }
130
WriteCodeSignBlock(ELFIO::elfio & reader,std::string & outputFile,uint64_t & csOffset)131 bool SignElf::WriteCodeSignBlock(ELFIO::elfio& reader, std::string& outputFile, uint64_t& csOffset)
132 {
133 ELFIO::section* sec = reader.sections[codesignSec];
134 if (sec) {
135 SIGNATURE_TOOLS_LOGE("[SignElf] .codesign section already exists");
136 return false;
137 }
138 sec = reader.sections.add(codesignSec);
139 if (!sec) {
140 SIGNATURE_TOOLS_LOGE("[SignElf] Failed to create .codesign section");
141 return false;
142 }
143 sec->set_type(ELFIO::SHT_PROGBITS);
144 sec->set_flags(ELFIO::SHF_ALLOC);
145 sec->set_addr_align(PAGE_SIZE);
146 char codesignData[PAGE_SIZE];
147 sec->set_data(codesignData, PAGE_SIZE);
148
149 if (!reader.save(outputFile)) {
150 SIGNATURE_TOOLS_LOGE("[SignElf] Failed to save 4K data to .codesign section");
151 return false;
152 }
153 ELFIO::Elf64_Off secOff = sec->get_offset();
154 csOffset = secOff;
155 PrintMsg("add codesign section success");
156 SIGNATURE_TOOLS_LOGD("[SignElf] .codesign section offset: %lu, size: %lu", secOff, sec->get_size());
157 return true;
158 }
159
WriteSection(ELFIO::elfio & reader,const std::string & content,const std::string & secName)160 bool SignElf::WriteSection(ELFIO::elfio& reader, const std::string& content, const std::string& secName)
161 {
162 ELFIO::section* sec = reader.sections[secName];
163 if (sec) {
164 SIGNATURE_TOOLS_LOGE("[SignElf] %s section already exists", secName.c_str());
165 return false;
166 }
167 sec = reader.sections.add(secName);
168 if (!sec) {
169 SIGNATURE_TOOLS_LOGE("[SignElf] Failed to create %s section", secName.c_str());
170 return false;
171 }
172 sec->set_type(ELFIO::SHT_PROGBITS);
173 sec->set_flags(ELFIO::SHF_ALLOC);
174 sec->set_addr_align(1);
175 sec->set_data(content);
176 return true;
177 }
178
WriteSecDataToFile(ELFIO::elfio & reader,SignerConfig & signerConfig,std::map<std::string,std::string> & signParams)179 bool SignElf::WriteSecDataToFile(ELFIO::elfio& reader, SignerConfig& signerConfig,
180 std::map<std::string, std::string>& signParams)
181 {
182 if (signParams.at(ParamConstants::PARAM_SELF_SIGN) == ParamConstants::SELF_SIGN_TYPE_1) {
183 return true;
184 }
185 // check elf bin or so
186 if (!isExecElf(reader)) {
187 return true;
188 }
189 std::string p7b;
190 if (!loadProfileAndSign(signerConfig, signParams, p7b)) {
191 return false;
192 }
193 if (!p7b.empty()) {
194 if (WriteSection(reader, p7b, profileSec)) {
195 PrintMsg("add profile section success");
196 } else {
197 return false;
198 }
199 }
200 std::string moduleContent;
201 if (!loadModule(signParams, moduleContent)) {
202 return false;
203 }
204
205 if (!moduleContent.empty()) {
206 if (WriteSection(reader, moduleContent, permissionSec)) {
207 PrintMsg("add permission section success");
208 } else {
209 return false;
210 }
211 }
212 return true;
213 }
214
GenerateCodeSignByte(SignerConfig & signerConfig,const std::string & inputFile,uint64_t & csOffset,const std::string & selfSign)215 bool SignElf::GenerateCodeSignByte(SignerConfig& signerConfig, const std::string& inputFile, uint64_t& csOffset,
216 const std::string& selfSign)
217 {
218 CodeSigning codeSigning(&signerConfig, (selfSign == ParamConstants::SELF_SIGN_TYPE_1));
219 std::vector<int8_t> codesignData;
220 bool getElfCodeSignBlockFlag = codeSigning.GetElfCodeSignBlock(inputFile, csOffset, codesignData);
221 if (!getElfCodeSignBlockFlag) {
222 SIGNATURE_TOOLS_LOGE("[SignElf] get elf code sign block error.");
223 return false;
224 }
225 SIGNATURE_TOOLS_LOGD("[SignElf] elf code sign block off %lu: ,len: %lu .", csOffset, codesignData.size());
226
227 if (codesignData.size() > PAGE_SIZE) {
228 SIGNATURE_TOOLS_LOGE("[SignElf] signature size is too large.");
229 return false;
230 }
231
232 if (!ReplaceDataOffset(inputFile, csOffset, codesignData)) {
233 SIGNATURE_TOOLS_LOGE("[SignElf] Failed to replace code sign data in file.");
234 return false;
235 }
236 PrintMsg("write code sign data success");
237 return true;
238 }
239
ReplaceDataOffset(const std::string & filePath,uint64_t & csOffset,const std::vector<int8_t> & csData)240 bool SignElf::ReplaceDataOffset(const std::string& filePath, uint64_t& csOffset, const std::vector<int8_t>& csData)
241 {
242 std::fstream fileStream(filePath, std::ios::in | std::ios::out | std::ios::binary);
243 if (!fileStream) {
244 SIGNATURE_TOOLS_LOGE("[SignElf] Failed to open file: %s", filePath.c_str());
245 return false;
246 }
247
248 fileStream.seekp(csOffset, std::ios::beg);
249 if (!fileStream) {
250 SIGNATURE_TOOLS_LOGE("[SignElf] Failed to seek to offset: %lu", csOffset);
251 return false;
252 }
253
254 fileStream.write(reinterpret_cast<const char*>(csData.data()), csData.size());
255 if (!fileStream) {
256 SIGNATURE_TOOLS_LOGE("[SignElf] Failed to write data at offset: %lu", csOffset);
257 return false;
258 }
259 fileStream.flush();
260 fileStream.close();
261 return true;
262 }
263 } // namespace SignatureTools
264 } // namespace OHOS