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