• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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