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 #include <libgen.h>
16 #include <set>
17 #include <unistd.h>
18 #include "cmd_util.h"
19 #include "params_run_tool.h"
20 #include "constant.h"
21 #include "param_constants.h"
22
23 namespace OHOS {
24 namespace SignatureTools {
25 const std::regex INTEGER_PATTERN = std::regex("\\d{1,10}");
26
String2Bool(Options * options,const std::string & option)27 bool CmdUtil::String2Bool(Options* options, const std::string& option)
28 {
29 std::string val = options->GetString(option);
30 if (val == "1" || val == "true" || val == "TRUE") {
31 (*options)[option] = true;
32 } else if (val == "0" || val == "false" || val == "FALSE") {
33 (*options)[option] = false;
34 } else {
35 PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR,
36 val + " is not valid value for " + "-" + option);
37 return false;
38 }
39 return true;
40 }
41
UpdateParamForVariantCertInt(const ParamsSharedPtr & param)42 static bool UpdateParamForVariantCertInt(const ParamsSharedPtr& param)
43 {
44 int defaultValidity = 0;
45 Options* options = param->GetOptions();
46 if (options->count(Options::VALIDITY)) {
47 int validity = 0;
48 std::string val = options->GetString(Options::VALIDITY);
49 for (char x : val) {
50 if (!isdigit(x)) {
51 PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR, "Invalid parameter '"
52 + val + "', You should fill in the numbers");
53 return false;
54 }
55 }
56 if (!StringUtils::CheckStringToint(val, validity)) {
57 PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR, "Invalid parameter '"
58 + val + "'");
59 return false;
60 }
61 validity *= ONE_DAY_TIME;
62 (*options)[Options::VALIDITY] = validity;
63 } else if (param->GetMethod() == GENERATE_CA || param->GetMethod() == GENERATE_APP_CERT ||
64 param->GetMethod() == GENERATE_PROFILE_CERT) {
65 defaultValidity = DEFAULT_VALIDITY_DAYS * ONE_DAY_TIME;
66 (*options)[Options::VALIDITY] = defaultValidity;
67 } else if (param->GetMethod() == GENERATE_CERT) {
68 defaultValidity = DEFAULT_CUSTOM_VALIDITY_DAYS * ONE_DAY_TIME;
69 (*options)[Options::VALIDITY] = defaultValidity;
70 }
71 return true;
72 }
73
UpdateParamForVariantInt(const ParamsSharedPtr & param)74 static bool UpdateParamForVariantInt(const ParamsSharedPtr& param)
75 {
76 Options* options = param->GetOptions();
77 // general
78 if (options->count(Options::KEY_SIZE)) {
79 std::string keySize = options->GetString(Options::KEY_SIZE);
80 if (keySize == "NIST-P-256") {
81 (*options)[Options::KEY_SIZE] = NIST_P_256;
82 } else if (keySize == "NIST-P-384") {
83 (*options)[Options::KEY_SIZE] = NIST_P_384;
84 } else {
85 PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR, "not supported '" + keySize
86 + "' Key algorithms length");
87 return false;
88 }
89 }
90 if (!UpdateParamForVariantCertInt(param)) {
91 return false;
92 }
93 return true;
94 }
95
UpdateParamForVariantBoolKeyUsage(const ParamsSharedPtr & param)96 static bool UpdateParamForVariantBoolKeyUsage(const ParamsSharedPtr& param)
97 {
98 Options* options = param->GetOptions();
99
100 // The bool type is used only by the "generate-cert" module
101 if (options->count(Options::KEY_USAGE_CRITICAL)) {
102 if (!CmdUtil::String2Bool(options, Options::KEY_USAGE_CRITICAL)) {
103 return false;
104 }
105 } else if (param->GetMethod() == GENERATE_CERT) {
106 (*options)[Options::KEY_USAGE_CRITICAL] = DEFAULT_KEY_USAGE_CRITICAL;
107 }
108
109 // The bool type is used only by the "generate-cert" module
110 if (options->count(Options::EXT_KEY_USAGE_CRITICAL)) {
111 if (!CmdUtil::String2Bool(options, Options::EXT_KEY_USAGE_CRITICAL)) {
112 return false;
113 }
114 } else if (param->GetMethod() == GENERATE_CERT) {
115 (*options)[Options::EXT_KEY_USAGE_CRITICAL] = DEFAULT_EXT_KEY_USAGE_CRITICAL;
116 }
117 return true;
118 }
119
UpdateParamForVariantBoolProfileSigned(const ParamsSharedPtr & param)120 static bool UpdateParamForVariantBoolProfileSigned(const ParamsSharedPtr& param)
121 {
122 Options* options = param->GetOptions();
123
124 // The bool type is used only by the "sign-elf" module
125 if (options->count(Options::PROFILE_SIGNED)) {
126 std::string val = options->GetString(Options::PROFILE_SIGNED);
127 if (val == "1" || val == "true" || val == "TRUE") {
128 (*options)[Options::PROFILE_SIGNED] = DEFAULT_PROFILE_SIGNED_1;
129 } else if (val == "0" || val == "false" || val == "FALSE") {
130 (*options)[Options::PROFILE_SIGNED] = DEFAULT_PROFILE_SIGNED_0;
131 } else {
132 PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR,
133 val + " is not valid value for "+"-" + Options::PROFILE_SIGNED);
134 return false;
135 }
136 } else if (param->GetMethod() == SIGN_ELF) {
137 (*options)[Options::PROFILE_SIGNED] = DEFAULT_PROFILE_SIGNED_1;
138 }
139
140 return true;
141 }
142
UpdateParamForVariantBoolSelfSign(const ParamsSharedPtr & param)143 static bool UpdateParamForVariantBoolSelfSign(const ParamsSharedPtr& param)
144 {
145 Options* options = param->GetOptions();
146 // The bool type is used only by the "sign-elf" module
147 if (options->count(Options::SELF_SIGN)) {
148 std::string val = options->GetString(Options::SELF_SIGN);
149 if (val == "1" || val == "true" || val == "TRUE") {
150 (*options)[Options::SELF_SIGN] = ParamConstants::SELF_SIGN_TYPE_1;
151 } else if (val == "0" || val == "false" || val == "FALSE") {
152 (*options)[Options::SELF_SIGN] = ParamConstants::SELF_SIGN_TYPE_0;
153 } else {
154 PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR,
155 val + " is not valid value for "+"-" + Options::SELF_SIGN);
156 return false;
157 }
158 } else if (param->GetMethod() == SIGN_ELF) {
159 (*options)[Options::SELF_SIGN] = ParamConstants::SELF_SIGN_TYPE_0;
160 }
161
162 return true;
163 }
164
GetParentPath(const std::string & outFilePath)165 static std::string GetParentPath(const std::string &outFilePath)
166 {
167 if (outFilePath.size() == 0) {
168 PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR,
169 "get_parent_path realpath error, empty input");
170 return "";
171 }
172
173 if (outFilePath.size() > PATH_MAX) {
174 PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR,
175 "get_parent_path realpath error, input too long");
176 return "";
177 }
178
179 char resolvedPath[PATH_MAX + 1] = {0x00};
180 if (realpath(outFilePath.c_str(), resolvedPath) == nullptr) {
181 SIGNATURE_TOOLS_LOGI("Get realpath from %s may failed", resolvedPath);
182 return "";
183 }
184 resolvedPath[PATH_MAX] = '\0';
185 SIGNATURE_TOOLS_LOGI("GetParentPath, resolvedPath:%s", resolvedPath);
186 char *parentPath = dirname(resolvedPath);
187 if (parentPath == nullptr) {
188 SIGNATURE_TOOLS_LOGI("Get parentPath of %s may failed", resolvedPath);
189 return "";
190 }
191
192 SIGNATURE_TOOLS_LOGI("GetParentPath :%s", parentPath);
193 return std::string(parentPath);
194 }
195
GetFileName(const std::string & path)196 static std::string GetFileName(const std::string &path)
197 {
198 size_t lastSlash = path.find_last_of('/');
199 if (lastSlash == std::string::npos) {
200 return path;
201 }
202
203 return path.substr(lastSlash + 1);
204 }
205
UpdateParamForCheckOutFile(Options * options,const std::initializer_list<std::string> & outFileKeys)206 bool CmdUtil::UpdateParamForCheckOutFile(Options* options, const std::initializer_list<std::string>& outFileKeys)
207 {
208 for (auto& key : outFileKeys) {
209 if (options->count(key)) {
210 std::string outFilePath = options->GetString(key);
211 std::string parentPath = GetParentPath(outFilePath);
212
213 // Purpose: To prevent the user output path from passing an empty string. eg " "
214 std::string tmpOutFilePath = outFilePath;
215 tmpOutFilePath.erase(std::remove_if(tmpOutFilePath.begin(),
216 tmpOutFilePath.end(), ::isspace), tmpOutFilePath.end());
217
218 if (parentPath.empty() && !tmpOutFilePath.empty()) {
219 parentPath = "./";
220 }
221 char realFilePath[PATH_MAX + 1] = {0x00};
222 if (parentPath.size() > PATH_MAX) {
223 PrintErrorNumberMsg("FILE_NOT_FOUND", FILE_NOT_FOUND, "'" + outFilePath + "' File path longer than '"
224 + std::to_string(PATH_MAX) + "' characters");
225 return false;
226 }
227 if (realpath(parentPath.c_str(), realFilePath) == nullptr) {
228 PrintErrorNumberMsg("FILE_NOT_FOUND", FILE_NOT_FOUND, "The '" + outFilePath +
229 "' file does not exist or the path is invalid"
230 + ", parameter name '-" + key + "'");
231 return false;
232 }
233 std::string charStr(realFilePath);
234 std::string fileName = GetFileName(outFilePath);
235 if (fileName.empty()) {
236 PrintErrorNumberMsg("FILE_NOT_FOUND", FILE_NOT_FOUND, "The file name cannot be empty '"
237 + outFilePath + "', parameter name '-" + key + "'");
238 return false;
239 } else {
240 SIGNATURE_TOOLS_LOGI("UpdateParamForCheckOutFile GetFileName:%s", fileName.c_str());
241 }
242 (*options)[key] = charStr + "/" + fileName;
243 }
244 }
245 return true;
246 }
247
UpdateParamForCheckInFile(Options * options,const std::initializer_list<std::string> & inFileKeys)248 bool CmdUtil::UpdateParamForCheckInFile(Options* options, const std::initializer_list<std::string>& inFileKeys)
249 {
250 for (auto& key : inFileKeys) {
251 if (options->count(key)) {
252 std::string inFilePath = options->GetString(key);
253 char realFilePath[PATH_MAX + 1] = {0x00};
254 if (inFilePath.size() > PATH_MAX) {
255 PrintErrorNumberMsg("FILE_NOT_FOUND", FILE_NOT_FOUND, "'" + inFilePath + "' File path longer than '"
256 + std::to_string(PATH_MAX) + "' characters");
257 return false;
258 }
259 if (realpath(inFilePath.c_str(), realFilePath) == nullptr) {
260 PrintErrorNumberMsg("FILE_NOT_FOUND", FILE_NOT_FOUND, "The '" + inFilePath +
261 "' file does not exist or the path is invalid"
262 + ", parameter name '-" + key + "'");
263 return false;
264 }
265 std::string charStr(realFilePath);
266 (*options)[key] = charStr;
267
268 if (!FileUtils::IsValidFile(inFilePath)) {
269 return false;
270 }
271 }
272 }
273
274 return true;
275 }
276
UpdateParamForCheckSignAlg(const ParamsSharedPtr & param)277 static bool UpdateParamForCheckSignAlg(const ParamsSharedPtr& param)
278 {
279 // check signAlg
280 Options* options = param->GetOptions();
281 if (options->count(Options::SIGN_ALG)) {
282 std::string signAlg = options->GetString(Options::SIGN_ALG);
283 if (signAlg != SIGN_ALG_SHA256 && signAlg != SIGN_ALG_SHA384) {
284 PrintErrorNumberMsg("NOT_SUPPORT_ERROR", NOT_SUPPORT_ERROR, "'" + signAlg + "' parameter is incorrect");
285 return false;
286 }
287 }
288 return true;
289 }
290
UpdateParamForOutform(const ParamsSharedPtr & param)291 static bool UpdateParamForOutform(const ParamsSharedPtr& param)
292 {
293 // check generate_app_cert generate_profile_cert
294 Options* options = param->GetOptions();
295 if (param->GetMethod() == GENERATE_APP_CERT ||
296 param->GetMethod() == GENERATE_PROFILE_CERT) {
297 if (options->count(Options::OUT_FORM)) {
298 std::string outForm = options->GetString(Options::OUT_FORM);
299 if (outForm != OUT_FORM_CERT && outForm != OUT_FORM_CERT_CHAIN) {
300 PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR, "parameter '" + outForm
301 + "' format error, Outform only supprot cert/cerChain");
302 return false;
303 }
304 } else {
305 (*options)[Options::OUT_FORM] = OUT_FORM_CERT_CHAIN;
306 }
307 }
308 return true;
309 }
310
UpdateParam(const ParamsSharedPtr & param)311 static bool UpdateParam(const ParamsSharedPtr& param)
312 {
313 if (!UpdateParamForVariantInt(param)) {
314 return false;
315 }
316 if (!UpdateParamForVariantBoolKeyUsage(param)) {
317 return false;
318 }
319 if (!UpdateParamForVariantBoolProfileSigned(param)) {
320 return false;
321 }
322 if (!UpdateParamForVariantBoolSelfSign(param)) {
323 return false;
324 }
325 if (!UpdateParamForCheckSignAlg(param)) {
326 return false;
327 }
328 if (!UpdateParamForOutform(param)) {
329 return false;
330 }
331 return true;
332 }
333
GetCommandParameterKey(const char strChar,std::string & strChars,std::vector<std::string> & trustList,std::string & keyStandBy)334 int CmdUtil::GetCommandParameterKey(const char strChar, std::string& strChars, std::vector<std::string>& trustList,
335 std::string& keyStandBy)
336 {
337 if (strChar == '-') {
338 bool isTrust = std::find(trustList.begin(), trustList.end(), strChars) != trustList.end();
339 if (!isTrust) {
340 PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR, "There is no '"
341 + strChars + "' command for the trust list");
342 return RET_FAILED;
343 }
344 keyStandBy = strChars.substr(1);
345 } else {
346 PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR, "'" + strChars
347 + "' Parameters error, Param key - value must in pairs");
348 return RET_FAILED;
349 }
350
351 return RET_OK;
352 }
353
Convert2Params(char ** args,const size_t size,const ParamsSharedPtr & param)354 bool CmdUtil::Convert2Params(char** args, const size_t size, const ParamsSharedPtr& param)
355 {
356 param->SetMethod(args[1]);
357 std::string keyStandBy = "";
358 bool readKey = true;
359 std::vector<std::string> trustList = ParamsTrustList::GetInstance().GetTrustList(args[1]);
360 if (trustList.empty()) {
361 return false;
362 }
363 std::string strChars;
364 for (size_t i = 2; i < size; i++) {
365 if (readKey) {
366 strChars = args[i];
367 if (GetCommandParameterKey(args[i][0], strChars, trustList, keyStandBy) == RET_OK) {
368 readKey = false;
369 } else {
370 return false;
371 }
372 } else {
373 bool success = ValidAndPutParam(param, keyStandBy, args[i]);
374 if (success) {
375 keyStandBy = "";
376 readKey = true;
377 } else {
378 return false;
379 }
380 }
381 }
382 param->GetOptions()->emplace(Options::MODE, LOCAL_SIGN);
383 if (!readKey) {
384 PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR,
385 "The last value of parameter cannot be omitted");
386 return false;
387 }
388 if (!UpdateParam(param)) {
389 return false;
390 }
391 return true;
392 }
393
ValidAndPutParam(const ParamsSharedPtr & params,const std::string & key,char * value)394 bool CmdUtil::ValidAndPutParam(const ParamsSharedPtr& params, const std::string& key, char* value)
395 {
396 std::string str = "Pwd";
397 bool result = true;
398 if (key.empty()) {
399 PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR,
400 "The command-line parameter key cannot be empty");
401 result = false;
402 } else if (strlen(value) == 0) {
403 PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR,
404 "The command-line parameter value cannot be empty");
405 result = false;
406 } else if (params->GetOptions()->count(key)) {
407 PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR,
408 "Duplicate command parameter are not allowed '" + key + "'");
409 result = false;
410 } else if (key.length() >= str.length() && key.substr(key.length() - INVALIDCHAR) == str) {
411 params->GetOptions()->emplace(key, value);
412 } else {
413 if (key == Options::KEY_ALIAS || key == Options::ISSUER_KEY_ALIAS) {
414 std::string keyAlias = value;
415 std::transform(keyAlias.begin(), keyAlias.end(), keyAlias.begin(),
416 [](unsigned char c) { return std::tolower(c); });
417 params->GetOptions()->emplace(key, keyAlias);
418 } else {
419 params->GetOptions()->emplace(key, std::string(value));
420 }
421 }
422 return result;
423 }
424
JudgeSignAlgType(const std::string & signAlg)425 bool CmdUtil::JudgeSignAlgType(const std::string& signAlg)
426 {
427 if (signAlg != SIGN_ALG_SHA256 && signAlg != SIGN_ALG_SHA384) {
428 PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR, "not supported '" + signAlg + "' signature algorithm");
429 return false;
430 }
431 return true;
432 }
433 } // namespace SignatureTools
434 } // namespace OHOS
435