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 "cmd_util.h"
16 #include <set>
17 #include <filesystem>
18
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 (options->count(Options::BASIC_CONSTRAINTS_PATH_LEN)) {
91 int basicConstraintsPathLen = 0;
92 std::string val = options->GetString(Options::BASIC_CONSTRAINTS_PATH_LEN);
93 if (!StringUtils::CheckStringToint(val, basicConstraintsPathLen)) {
94 PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR, "Invalid parameter '"
95 + val + "', You should fill in the numbers");
96 return false;
97 }
98 (*options)[Options::BASIC_CONSTRAINTS_PATH_LEN] = basicConstraintsPathLen;
99 } else if (param->GetMethod() == GENERATE_CA || param->GetMethod() == GENERATE_CERT) {
100 (*options)[Options::BASIC_CONSTRAINTS_PATH_LEN] = DEFAULT_BASIC_CONSTRAINTS_PATH_LEN;
101 }
102 if (!UpdateParamForVariantCertInt(param)) {
103 return false;
104 }
105 return true;
106 }
107
UpdateParamForVariantBoolKeyUsage(const ParamsSharedPtr& param)108 static bool UpdateParamForVariantBoolKeyUsage(const ParamsSharedPtr& param)
109 {
110 Options* options = param->GetOptions();
111
112 //The bool type is used only by the "generate-cert" module
113 if (options->count(Options::KEY_USAGE_CRITICAL)) {
114 if (!CmdUtil::String2Bool(options, Options::KEY_USAGE_CRITICAL)) {
115 return false;
116 }
117 } else if (param->GetMethod() == GENERATE_CERT) {
118 (*options)[Options::KEY_USAGE_CRITICAL] = DEFAULT_KEY_USAGE_CRITICAL;
119 }
120
121 //The bool type is used only by the "generate-cert" module
122 if (options->count(Options::EXT_KEY_USAGE_CRITICAL)) {
123 if (!CmdUtil::String2Bool(options, Options::EXT_KEY_USAGE_CRITICAL)) {
124 return false;
125 }
126 } else if (param->GetMethod() == GENERATE_CERT) {
127 (*options)[Options::EXT_KEY_USAGE_CRITICAL] = DEFAULT_EXT_KEY_USAGE_CRITICAL;
128 }
129 return true;
130 }
131
UpdateParamForVariantBoolProfileSigned(const ParamsSharedPtr& param)132 static bool UpdateParamForVariantBoolProfileSigned(const ParamsSharedPtr& param)
133 {
134 Options* options = param->GetOptions();
135
136 //The bool type is used only by the "sign-app" module
137 if (options->count(Options::PROFILE_SIGNED)) {
138 std::string val = options->GetString(Options::PROFILE_SIGNED);
139 if (val == "1" || val == "true" || val == "TRUE") {
140 (*options)[Options::PROFILE_SIGNED] = DEFAULT_PROFILE_SIGNED_1;
141 } else if (val == "0" || val == "false" || val == "FALSE") {
142 (*options)[Options::PROFILE_SIGNED] = DEFAULT_PROFILE_SIGNED_0;
143 } else {
144 PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR,
145 val + "is not valid value for "+"-" + Options::PROFILE_SIGNED);
146 return false;
147 }
148 } else if (param->GetMethod() == SIGN_APP) {
149 (*options)[Options::PROFILE_SIGNED] = DEFAULT_PROFILE_SIGNED_1;
150 }
151
152 return true;
153 }
154
UpdateParamForCheckOutFile(Options* options, const std::initializer_list<std::string>& outFileKeys)155 bool CmdUtil::UpdateParamForCheckOutFile(Options* options, const std::initializer_list<std::string>& outFileKeys)
156 {
157 for (auto& key : outFileKeys) {
158 if (options->count(key)) {
159 std::string outFilePath = options->GetString(key);
160 std::filesystem::path filePath = outFilePath;
161 std::string parentPath = filePath.parent_path();
162
163 //Purpose: To prevent the user output path from passing an empty string. eg " "
164 std::string tmpOutFilePath = outFilePath;
165 tmpOutFilePath.erase(std::remove_if(tmpOutFilePath.begin(),
166 tmpOutFilePath.end(), ::isspace), tmpOutFilePath.end());
167
168 if (parentPath.empty() && !tmpOutFilePath.empty()) {
169 parentPath = "./";
170 }
171 char realFilePath[PATH_MAX + 1] = {0x00};
172 if (parentPath.size() > PATH_MAX) {
173 PrintErrorNumberMsg("FILE_NOT_FOUND", FILE_NOT_FOUND, "'" + outFilePath + "' File path longer than '"
174 + std::to_string(PATH_MAX) + "' characters");
175 return false;
176 }
177 if (realpath(parentPath.c_str(), realFilePath) == nullptr) {
178 PrintErrorNumberMsg("FILE_NOT_FOUND", FILE_NOT_FOUND, "The '" + outFilePath +
179 "' file does not exist or the path is invalid"
180 + "', parameter name '-" + key + "'");
181 return false;
182 }
183 std::string charStr(realFilePath);
184 std::string fileName = filePath.filename();
185 if (fileName.empty()) {
186 PrintErrorNumberMsg("FILE_NOT_FOUND", FILE_NOT_FOUND, "The file name cannot be empty '"
187 + outFilePath + "', parameter name '-" + key + "'");
188 return false;
189 }
190 (*options)[key] = charStr + "/" + fileName;
191 }
192 }
193 return true;
194 }
195
UpdateParamForCheckInFile(Options* options, const std::initializer_list<std::string>& inFileKeys)196 bool CmdUtil::UpdateParamForCheckInFile(Options* options, const std::initializer_list<std::string>& inFileKeys)
197 {
198 for (auto& key : inFileKeys) {
199 if (options->count(key)) {
200 std::string inFilePath = options->GetString(key);
201 char realFilePath[PATH_MAX + 1] = {0x00};
202 if (inFilePath.size() > PATH_MAX) {
203 PrintErrorNumberMsg("FILE_NOT_FOUND", FILE_NOT_FOUND, "'" + inFilePath + "' File path longer than '"
204 + std::to_string(PATH_MAX) + "' characters");
205 return false;
206 }
207 if (realpath(inFilePath.c_str(), realFilePath) == nullptr) {
208 PrintErrorNumberMsg("FILE_NOT_FOUND", FILE_NOT_FOUND, "The '" + inFilePath +
209 "' file does not exist or the path is invalid"
210 + "', parameter name '-" + key + "'");
211 return false;
212 }
213 std::string charStr(realFilePath);
214 (*options)[key] = charStr;
215
216 if (!FileUtils::IsValidFile(inFilePath)) {
217 return false;
218 }
219 }
220 }
221
222 return true;
223 }
224
UpdateParamForCheckSignAlg(const ParamsSharedPtr& param)225 static bool UpdateParamForCheckSignAlg(const ParamsSharedPtr& param)
226 {
227 // check signAlg
228 Options* options = param->GetOptions();
229 if (options->count(Options::SIGN_ALG)) {
230 std::string signAlg = options->GetString(Options::SIGN_ALG);
231 if (signAlg != SIGN_ALG_SHA256 && signAlg != SIGN_ALG_SHA384) {
232 PrintErrorNumberMsg("NOT_SUPPORT_ERROR", NOT_SUPPORT_ERROR, "'" + signAlg + "' parameter is incorrect");
233 return false;
234 }
235 }
236 return true;
237 }
238
UpdateParamForInform(const ParamsSharedPtr& param)239 static bool UpdateParamForInform(const ParamsSharedPtr& param)
240 {
241 // check sign_app verify_app inform
242 Options* options = param->GetOptions();
243 if (param->GetMethod() == SIGN_APP ||
244 param->GetMethod() == VERIFY_APP) {
245 if (options->count(Options::INFORM)) {
246 std::string inForm = options->GetString(Options::INFORM);
247 if (!StringUtils::ContainsCase(ParamsRunTool::InformList, inForm)) {
248 PrintErrorNumberMsg("NOT_SUPPORT_ERROR", NOT_SUPPORT_ERROR, "parameter '"
249 + inForm + "' format error, Inform only support zip/elf/bin");
250 return false;
251 }
252 } else {
253 (*options)[Options::INFORM] = ZIP;
254 }
255 }
256 return true;
257 }
258
UpdateParamForOutform(const ParamsSharedPtr& param)259 static bool UpdateParamForOutform(const ParamsSharedPtr& param)
260 {
261 // check generate_app_cert generate_profile_cert
262 Options* options = param->GetOptions();
263 if (param->GetMethod() == GENERATE_APP_CERT ||
264 param->GetMethod() == GENERATE_PROFILE_CERT) {
265 if (options->count(Options::OUT_FORM)) {
266 std::string outForm = options->GetString(Options::OUT_FORM);
267 if (outForm != OUT_FORM_CERT && outForm != OUT_FORM_CERT_CHAIN) {
268 PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR, "parameter '" + outForm
269 + "' format error, Outform only supprot cert/cerChain");
270 return false;
271 }
272 } else {
273 (*options)[Options::OUT_FORM] = OUT_FORM_CERT_CHAIN;
274 }
275 }
276 return true;
277 }
278
279 //Check "remoteSign" additional parameters are required
UpdateParamForCheckRemoteSignProfile(const ParamsSharedPtr& param)280 static bool UpdateParamForCheckRemoteSignProfile(const ParamsSharedPtr& param)
281 {
282 Options* options = param->GetOptions();
283 std::set<std::string> signProfileRemoteParams{ParamConstants::PARAM_REMOTE_SERVER,
284 ParamConstants::PARAM_REMOTE_USERNAME,
285 ParamConstants::PARAM_REMOTE_USERPWD,
286 ParamConstants::PARAM_REMOTE_ONLINEAUTHMODE,
287 ParamConstants::PARAM_REMOTE_SIGNERPLUGIN};
288
289 if (param->GetMethod() == SIGN_PROFILE && options->count(Options::MODE) &&
290 options->GetString(Options::MODE) == REMOTE_SIGN) {
291 for (const std::string& key : signProfileRemoteParams) {
292 if (options->count(key) == 0) {
293 PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR, "sign profile RemoteSign absence param '"
294 + key + "'");
295 return false;
296 }
297 }
298 }
299 return true;
300 }
301
UpdateParam(const ParamsSharedPtr& param)302 static bool UpdateParam(const ParamsSharedPtr& param)
303 {
304 if (!UpdateParamForVariantInt(param)) {
305 return false;
306 }
307 if (!UpdateParamForVariantBoolKeyUsage(param)) {
308 return false;
309 }
310 if (!UpdateParamForVariantBoolProfileSigned(param)) {
311 return false;
312 }
313 if (!UpdateParamForCheckSignAlg(param)) {
314 return false;
315 }
316 if (!UpdateParamForInform(param)) {
317 return false;
318 }
319 if (!UpdateParamForOutform(param)) {
320 return false;
321 }
322 if (!UpdateParamForCheckRemoteSignProfile(param)) {
323 return false;
324 }
325 return true;
326 }
327
GetCommandParameterKey(const char strChar, std::string& strChars, std::vector<std::string>& trustList, std::string& keyStandBy)328 int CmdUtil::GetCommandParameterKey(const char strChar, std::string& strChars, std::vector<std::string>& trustList,
329 std::string& keyStandBy)
330 {
331 if (strChar == '-') {
332 bool isTrust = std::find(trustList.begin(), trustList.end(), strChars) != trustList.end();
333 if (!isTrust) {
334 PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR, "There is no '"
335 + strChars + "' command for the trust list");
336 return RET_FAILED;
337 }
338 keyStandBy = strChars.substr(1);
339 } else {
340 PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR, "'" + strChars
341 + "' Parameters error, Param key - value must in pairs");
342 return RET_FAILED;
343 }
344
345 return RET_OK;
346 }
347
Convert2Params(char** args, const size_t size, const ParamsSharedPtr& param)348 bool CmdUtil::Convert2Params(char** args, const size_t size, const ParamsSharedPtr& param)
349 {
350 param->SetMethod(args[1]);
351 std::string keyStandBy = "";
352 bool readKey = true;
353 std::vector<std::string> trustList = ParamsTrustList::GetInstance().GetTrustList(args[1]);
354 if (trustList.empty()) {
355 return false;
356 }
357 std::string strChars;
358 for (size_t i = 2; i < size; i++) {
359 if (readKey) {
360 strChars = args[i];
361 if (GetCommandParameterKey(args[i][0], strChars, trustList, keyStandBy) == RET_OK) {
362 readKey = false;
363 } else {
364 return false;
365 }
366 } else {
367 bool success = ValidAndPutParam(param, keyStandBy, args[i]);
368 if (success) {
369 keyStandBy = "";
370 readKey = true;
371 } else {
372 return false;
373 }
374 }
375 }
376 if (!readKey) {
377 PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR,
378 "The last value of parameter cannot be omitted");
379 return false;
380 }
381 if (!UpdateParam(param)) {
382 return false;
383 }
384 return true;
385 }
386
ValidAndPutParam(const ParamsSharedPtr& params, const std::string& key, char* value)387 bool CmdUtil::ValidAndPutParam(const ParamsSharedPtr& params, const std::string& key, char* value)
388 {
389 std::string str = "Pwd";
390 bool result = true;
391 if (key.empty()) {
392 PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR,
393 "The command-line parameter key cannot be empty");
394 result = false;
395 } else if (strlen(value) == 0) {
396 PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR,
397 "The command-line parameter value cannot be empty");
398 result = false;
399 } else if (params->GetOptions()->count(key)) {
400 PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR,
401 "Duplicate command parameter are not allowed '" + key + "'");
402 result = false;
403 } else if (key.length() >= str.length() && key.substr(key.length() - INVALIDCHAR) == str) {
404 params->GetOptions()->emplace(key, value);
405 } else {
406 if (key == Options::KEY_ALIAS || key == Options::ISSUER_KEY_ALIAS) {
407 std::string keyAlias = value;
408 std::transform(keyAlias.begin(), keyAlias.end(), keyAlias.begin(),
409 [](unsigned char c) { return std::tolower(c); });
410 params->GetOptions()->emplace(key, keyAlias);
411 } else {
412 params->GetOptions()->emplace(key, std::string(value));
413 }
414 }
415 return result;
416 }
417
JudgeAlgType(const std::string& keyAlg)418 bool CmdUtil::JudgeAlgType(const std::string& keyAlg)
419 {
420 if (keyAlg != "ECC") {
421 PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR, "not supported '" + keyAlg + "' Key algorithms");
422 return false;
423 }
424 return true;
425 }
426
JudgeSize(const int size)427 bool CmdUtil::JudgeSize(const int size)
428 {
429 if (size != NIST_P_256 && size != NIST_P_384) {
430 PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR, "Keysize params is incorrect, Support only 256 or 384");
431 return false;
432 }
433 return true;
434 }
435
JudgeSignAlgType(const std::string& signAlg)436 bool CmdUtil::JudgeSignAlgType(const std::string& signAlg)
437 {
438 if (signAlg != SIGN_ALG_SHA256 && signAlg != SIGN_ALG_SHA384) {
439 PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR, "not supported '" + signAlg + "' signature algorithm");
440 return false;
441 }
442 return true;
443 }
444
445 /**
446 * @tc.name: Test parameter function
447 * @tc.desc: Pass more than one parameter,but it needs to be in the parameter list.
448 * @tc.type: FUNC
449 */
VerifyTypes(const std::string& inputType)450 bool CmdUtil::VerifyTypes(const std::string& inputType)
451 {
452 if (inputType.size() == 0) {
453 return false;
454 }
455 std::vector<std::string> vecs = StringUtils::SplitString(inputType.c_str(), ',');
456 std::set<std::string> sets;
457 sets.insert("digitalSignature");
458 sets.insert("nonRepudiation");
459 sets.insert("keyEncipherment");
460 sets.insert("dataEncipherment");
461 sets.insert("keyAgreement");
462 sets.insert("certificateSignature");
463 sets.insert("crlSignature");
464 sets.insert("encipherOnly");
465 sets.insert("decipherOnly");
466 for (const auto& val : vecs) {
467 if (sets.count(val) == 0) {
468 PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR,
469 "Not support command param '" + val + "'");
470 return false;
471 }
472 }
473 return true;
474 }
475
476 /**
477 * @tc.name: Test parameter function
478 * @tc.desc: Pass one parameter,but it needs to be in the parameter list.
479 * @tc.type: FUNC
480 */
VerifyType(const std::string& inputType)481 bool CmdUtil::VerifyType(const std::string& inputType)
482 {
483 std::set<std::string> sets;
484 sets.insert("clientAuthentication");
485 sets.insert("serverAuthentication");
486 sets.insert("codeSignature");
487 sets.insert("emailProtection");
488 sets.insert("smartCardLogin");
489 sets.insert("timestamp");
490 sets.insert("ocspSignature");
491 if (sets.count(inputType) == 0) {
492 PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR,
493 "Not support command param '" + inputType + "'");
494 return false;
495 }
496 return true;
497 }
498
VerifyType(const std::string& inputType, const std::string& supportTypes)499 bool CmdUtil::VerifyType(const std::string& inputType, const std::string& supportTypes)
500 {
501 std::string firstStr = supportTypes.substr(0, supportTypes.find_last_of(","));
502 std::string secondStr = supportTypes.substr(supportTypes.find_first_of(",") + 1,
503 supportTypes.size() - supportTypes.find_first_of(","));
504 if (inputType == firstStr || inputType == secondStr) {
505 return true;
506 }
507 PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR, "Not support command param '" + inputType + "'");
508
509 return false;
510 }
511 } // namespace SignatureTools
512 } // namespace OHOS