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 23namespace OHOS { 24namespace SignatureTools { 25const std::regex INTEGER_PATTERN = std::regex("\\d{1,10}"); 26 27bool 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 42static 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 74static 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 108static 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 132static 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 155bool 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 196bool 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 225static 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 239static 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 259static 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 280static 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 302static 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 328int 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 348bool 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 387bool 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 418bool 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 427bool 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 436bool 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 */ 450bool 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 */ 481bool 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 499bool 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