• 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 #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 
382     TransformKeyAliasWhenLocalSign(param);
383     if (!UpdateParam(param)) {
384         return false;
385     }
386     return true;
387 }
388 
TransformKeyAliasWhenLocalSign(const ParamsSharedPtr & params)389 void CmdUtil::TransformKeyAliasWhenLocalSign(const ParamsSharedPtr& params)
390 {
391     Options* options = params->GetOptions();
392     std::string mode = options->GetString(Options::MODE);
393     if (mode == REMOTE_SIGN) {
394         return;
395     }
396 
397     std::string keyAlias = options->GetString(Options::KEY_ALIAS);
398     if (!keyAlias.empty()) {
399         std::transform(keyAlias.begin(), keyAlias.end(), keyAlias.begin(),
400             [](unsigned char c) { return std::tolower(c); });
401         (*options)[Options::KEY_ALIAS] = keyAlias;
402     }
403 
404     keyAlias = options->GetString(Options::ISSUER_KEY_ALIAS);
405     if (!keyAlias.empty()) {
406         std::transform(keyAlias.begin(), keyAlias.end(), keyAlias.begin(),
407             [](unsigned char c) { return std::tolower(c); });
408         (*options)[Options::ISSUER_KEY_ALIAS] = keyAlias;
409     }
410 }
411 
ValidAndPutParam(const ParamsSharedPtr & params,const std::string & key,char * value)412 bool CmdUtil::ValidAndPutParam(const ParamsSharedPtr& params, const std::string& key, char* value)
413 {
414     std::string  str = "Pwd";
415     bool result = true;
416     if (key.empty()) {
417         PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR,
418                             "The command-line parameter key cannot be empty");
419         result = false;
420     } else if (strlen(value) == 0) {
421         PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR,
422                             "The command-line parameter value cannot be empty");
423         result = false;
424     } else if (params->GetOptions()->count(key)) {
425         PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR,
426                             "Duplicate command parameter are not allowed '" + key + "'");
427         result = false;
428     } else if (key.length() >= str.length() && key.substr(key.length() - INVALIDCHAR) == str) {
429         params->GetOptions()->emplace(key, value);
430     } else {
431         params->GetOptions()->emplace(key, std::string(value));
432     }
433     return result;
434 }
435 
JudgeAlgType(const std::string & keyAlg)436 bool CmdUtil::JudgeAlgType(const std::string& keyAlg)
437 {
438     if (keyAlg != "ECC") {
439         PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR, "not supported '" + keyAlg + "' Key algorithms");
440         return false;
441     }
442     return true;
443 }
444 
JudgeSize(const int size)445 bool CmdUtil::JudgeSize(const int size)
446 {
447     if (size != NIST_P_256 && size != NIST_P_384) {
448         PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR, "Keysize params is incorrect, Support only 256 or 384");
449         return false;
450     }
451     return true;
452 }
453 
JudgeSignAlgType(const std::string & signAlg)454 bool CmdUtil::JudgeSignAlgType(const std::string& signAlg)
455 {
456     if (signAlg != SIGN_ALG_SHA256 && signAlg != SIGN_ALG_SHA384) {
457         PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR, "not supported '" + signAlg + "' signature algorithm");
458         return  false;
459     }
460     return true;
461 }
462 
463 /**
464  * @tc.name: Test parameter function
465  * @tc.desc: Pass more than one parameter,but it needs to be in the parameter list.
466  * @tc.type: FUNC
467  */
VerifyTypes(const std::string & inputType)468 bool CmdUtil::VerifyTypes(const std::string& inputType)
469 {
470     if (inputType.size() == 0) {
471         return false;
472     }
473     std::vector<std::string> vecs = StringUtils::SplitString(inputType.c_str(), ',');
474     std::set<std::string> sets;
475     sets.insert("digitalSignature");
476     sets.insert("nonRepudiation");
477     sets.insert("keyEncipherment");
478     sets.insert("dataEncipherment");
479     sets.insert("keyAgreement");
480     sets.insert("certificateSignature");
481     sets.insert("crlSignature");
482     sets.insert("encipherOnly");
483     sets.insert("decipherOnly");
484     for (const auto& val : vecs) {
485         if (sets.count(val) == 0) {
486             PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR,
487                                 "Not support command param '" + val + "'");
488             return false;
489         }
490     }
491     return true;
492 }
493 
494 /**
495  * @tc.name: Test parameter function
496  * @tc.desc: Pass one parameter,but it needs to be in the parameter list.
497  * @tc.type: FUNC
498  */
VerifyType(const std::string & inputType)499 bool CmdUtil::VerifyType(const std::string& inputType)
500 {
501     std::set<std::string> sets;
502     sets.insert("clientAuthentication");
503     sets.insert("serverAuthentication");
504     sets.insert("codeSignature");
505     sets.insert("emailProtection");
506     sets.insert("smartCardLogin");
507     sets.insert("timestamp");
508     sets.insert("ocspSignature");
509     if (sets.count(inputType) == 0) {
510         PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR,
511                             "Not support command param '" + inputType + "'");
512         return false;
513     }
514     return true;
515 }
516 
VerifyType(const std::string & inputType,const std::string & supportTypes)517 bool CmdUtil::VerifyType(const std::string& inputType, const std::string& supportTypes)
518 {
519     std::string firstStr = supportTypes.substr(0, supportTypes.find_last_of(","));
520     std::string secondStr = supportTypes.substr(supportTypes.find_first_of(",") + 1,
521                                                 supportTypes.size() - supportTypes.find_first_of(","));
522     if (inputType == firstStr || inputType == secondStr) {
523         return true;
524     }
525     PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR, "Not support command param '" + inputType + "'");
526 
527     return false;
528 }
529 } // namespace SignatureTools
530 } // namespace OHOS