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 "params_run_tool.h"
17 #include <unistd.h>
18 #include <memory>
19 #include <filesystem>
20 
21 #include "constant.h"
22 #include "help.h"
23 
24 namespace OHOS {
25 namespace SignatureTools {
26 const std::string ParamsRunTool::VERSION = "1.0.0";
27 
28 std::vector<std::string> ParamsRunTool::InformList = {
29     "bin",
30     "elf",
31     "zip"
32 };
33 
34 static std::unordered_map <std::string,
35                            std::function<bool(Options* params, SignToolServiceImpl& api)>> DISPATCH_RUN_METHOD {
36     {SIGN_APP, ParamsRunTool::RunSignApp},
37     {SIGN_PROFILE, ParamsRunTool::RunSignProfile},
38     {VERIFY_APP, ParamsRunTool::RunVerifyApp},
39     {VERIFY_PROFILE, ParamsRunTool::RunVerifyProfile}
40 };
41 
42 static std::unordered_map <std::string,
43                            std::function<bool(Options* params, SignToolServiceImpl& api)>> GENERATOR_RUN_METHOD {
44     {GENERATE_KEYPAIR, ParamsRunTool::RunKeypair},
45     {GENERATE_CSR, ParamsRunTool::RunCsr},
46     {GENERATE_CA, ParamsRunTool::RunCa},
47     {GENERATE_APP_CERT, ParamsRunTool::RunAppCert},
48     {GENERATE_PROFILE_CERT, ParamsRunTool::RunProfileCert},
49     {GENERATE_CERT, ParamsRunTool::RunCert},
50 };
51 
52 
ProcessCmd(char** args, size_t size)53 bool ParamsRunTool::ProcessCmd(char** args, size_t size)
54 {
55     if (size < CmdUtil::ARGS_MIN_LEN) {
56         PrintHelp();
57         return true;
58     }
59     if (args == nullptr || strcmp(args[1], "") == 0) {
60         PrintHelp();
61         return true;
62     } else if (strcmp(args[1], "-h") == 0 || strcmp(args[1], "-help") == 0) {
63         PrintHelp();
64         return true;
65     } else if (strcmp(args[1], "-v") == 0 || strcmp(args[1], "-version") == 0) {
66         Version();
67         return true;
68     } else {
69         std::shared_ptr<SignToolServiceImpl> serviceApi = std::make_shared<SignToolServiceImpl>();
70         ParamsSharedPtr param = std::make_shared<Params>();
71         if (!CmdUtil::Convert2Params(args, size, param)) {
72             PrintMsg(param->GetMethod() + " failed");
73             return false;
74         }
75         PrintMsg("Start " + param->GetMethod());
76         SIGNATURE_TOOLS_LOGD("%s run start time  ", param->GetMethod().c_str());
77         if (!DispatchParams(param, *serviceApi)) {
78             SIGNATURE_TOOLS_LOGD("%s run end time  ", param->GetMethod().c_str());
79             PrintMsg(param->GetMethod() + " failed");
80             return false;
81         }
82         PrintMsg(param->GetMethod() + " success");
83         SIGNATURE_TOOLS_LOGD("%s run end time  ", param->GetMethod().c_str());
84     }
85     return true;
86 }
87 
CallGenerators(const ParamsSharedPtr& params, SignToolServiceImpl& api)88 bool ParamsRunTool::CallGenerators(const ParamsSharedPtr& params, SignToolServiceImpl& api)
89 {
90     bool isSuccess = false;
91     std::string method = params->GetMethod();
92     auto it = GENERATOR_RUN_METHOD.find(method);
93     if (it == GENERATOR_RUN_METHOD.end()) {
94         PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR, "Unsupported method: " + method);
95         return false;
96     } else {
97         isSuccess = it->second(params->GetOptions(), api);
98     }
99     return isSuccess;
100 }
101 
RunSignApp(Options* params, SignToolServiceImpl& api)102 bool ParamsRunTool::RunSignApp(Options* params, SignToolServiceImpl& api)
103 {
104     if (!params->Required({Options::MODE, Options::IN_FILE, Options::OUT_FILE, Options::SIGN_ALG})) {
105         return false;
106     }
107 
108     if (!CmdUtil::UpdateParamForCheckInFile(params, {Options::IN_FILE, Options::APP_CERT_FILE,
109                                             Options::PROFILE_FILE, Options::KEY_STORE_FILE,
110                                             ParamConstants::PARAM_REMOTE_SIGNERPLUGIN})) {
111         return false;
112     }
113 
114     if (!CmdUtil::UpdateParamForCheckOutFile(params, {Options::OUT_FILE})) {
115         return false;
116     }
117 
118     std::string mode = params->GetString(Options::MODE);
119     if (!StringUtils::CaseCompare(mode, LOCAL_SIGN) &&
120         !StringUtils::CaseCompare(mode, REMOTE_SIGN)) {
121         PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR, "not support command param '" + mode + "'");
122         return false;
123     }
124     if (StringUtils::CaseCompare(mode, LOCAL_SIGN)) {
125         if (!params->Required({Options::KEY_STORE_FILE, Options::KEY_ALIAS, Options::APP_CERT_FILE})) {
126             return false;
127         }
128         if (!FileUtils::ValidFileType(params->GetString(Options::KEY_STORE_FILE), {"p12", "jks"})) {
129             return false;
130         }
131     }
132     if (!CheckProfile(*params)) {
133         return false;
134     }
135     std::string inForm = params->GetString(Options::INFORM, ZIP);
136     if (!StringUtils::IsEmpty(inForm) && !StringUtils::ContainsCase(InformList, inForm)) {
137         PrintErrorNumberMsg("NOT_SUPPORT_ERROR", NOT_SUPPORT_ERROR, "parameter '" + inForm
138                             + "' format error, Inform only support zip/elf/bin");
139         return false;
140     }
141     std::string signAlg = params->GetString(Options::SIGN_ALG);
142     if (!CmdUtil::JudgeSignAlgType(signAlg)) {
143         return false;
144     }
145     return api.SignHap(params);
146 }
147 
CheckProfile(Options& params)148 bool ParamsRunTool::CheckProfile(Options& params)
149 {
150     std::string inForm = params.GetString(Options::INFORM);
151     std::string profileFile = params.GetString(Options::PROFILE_FILE);
152 
153     std::string profileSigned = params.GetString(Options::PROFILE_SIGNED);
154     if (StringUtils::CaseCompare(inForm, ELF) && FileUtils::IsEmpty(profileFile)) {
155         return true;
156     }
157 
158     if (profileSigned == "1") {
159         if (!FileUtils::ValidFileType(profileFile, {"p7b"})) {
160             return false;
161         }
162     } else {
163         if (!FileUtils::ValidFileType(profileFile, {"json"})) {
164             return false;
165         }
166     }
167 
168     return true;
169 }
170 
DispatchParams(const ParamsSharedPtr& params, SignToolServiceImpl& api)171 bool ParamsRunTool::DispatchParams(const ParamsSharedPtr& params, SignToolServiceImpl& api)
172 {
173     bool isSuccess = false;
174     std::string method = params->GetMethod();
175     auto it = DISPATCH_RUN_METHOD.find(method);
176     if (it == DISPATCH_RUN_METHOD.end()) {
177         isSuccess = ParamsRunTool::CallGenerators(params, api);
178     } else {
179         isSuccess = it->second(params->GetOptions(), api);
180     }
181     return isSuccess;
182 }
183 
RunCa(Options* params, SignToolServiceImpl& api)184 bool ParamsRunTool::RunCa(Options* params, SignToolServiceImpl& api)
185 {
186     if (!params->Required({Options::KEY_ALIAS, Options::KEY_ALG,
187         Options::KEY_SIZE, Options::SUBJECT, Options::SIGN_ALG, Options::KEY_STORE_FILE})) {
188         return false;
189     }
190 
191     if (!CmdUtil::UpdateParamForCheckOutFile(params, {Options::OUT_FILE, Options::KEY_STORE_FILE,
192                                              Options::ISSUER_KEY_STORE_FILE})) {
193         return false;
194     }
195 
196     std::string keyAlg = params->GetString(Options::KEY_ALG);
197     if (!CmdUtil::JudgeAlgType(keyAlg)) {
198         return false;
199     }
200     int keySize = params->GetInt(Options::KEY_SIZE);
201     if (!CmdUtil::JudgeSize(keySize)) {
202         return false;
203     }
204     std::string signAlg = params->GetString(Options::SIGN_ALG);
205     if (!CmdUtil::JudgeSignAlgType(signAlg)) {
206         return false;
207     }
208     if (!FileUtils::ValidFileType(params->GetString(Options::KEY_STORE_FILE), {"p12", "jks"})) {
209         return false;
210     }
211 
212     return api.GenerateCA(params);
213 }
214 
RunCert(Options* params, SignToolServiceImpl& api)215 bool ParamsRunTool::RunCert(Options* params, SignToolServiceImpl& api)
216 {
217     if (!params->Required({Options::KEY_ALIAS, Options::ISSUER,
218         Options::ISSUER_KEY_ALIAS, Options::SUBJECT, Options::KEY_USAGE,
219         Options::SIGN_ALG, Options::KEY_STORE_FILE})) {
220         return false;
221     }
222 
223     if (!CmdUtil::UpdateParamForCheckInFile(params, {Options::KEY_STORE_FILE, Options::ISSUER_KEY_STORE_FILE})) {
224         return false;
225     }
226 
227     if (!CmdUtil::UpdateParamForCheckOutFile(params, {Options::OUT_FILE})) {
228         return false;
229     }
230 
231     std::string keyusage = params->GetString(Options::KEY_USAGE);
232     if (!CmdUtil::VerifyTypes(keyusage)) {
233         return false;
234     }
235     std::string extkeyusage = params->GetString(Options::EXT_KEY_USAGE);
236     if (!extkeyusage.empty()) {
237         if (!CmdUtil::VerifyType(extkeyusage)) {
238             return false;
239         }
240     }
241     std::string signAlg = params->GetString(Options::SIGN_ALG);
242     if (!CmdUtil::JudgeSignAlgType(signAlg)) {
243         return false;
244     }
245     if (!FileUtils::ValidFileType(params->GetString(Options::KEY_STORE_FILE), {"p12", "jks"})) {
246         return false;
247     }
248     return api.GenerateCert(params);
249 }
250 
CheckEndCertArguments(Options& params)251 bool ParamsRunTool::CheckEndCertArguments(Options& params)
252 {
253     if (!params.Required({Options::KEY_ALIAS, Options::ISSUER, Options::ISSUER_KEY_ALIAS,
254                         Options::SUBJECT, Options::SIGN_ALG, Options::KEY_STORE_FILE})) {
255         return false;
256     }
257     std::string signAlg = params.GetString(Options::SIGN_ALG);
258     if (!CmdUtil::JudgeSignAlgType(signAlg)) {
259         return false;
260     }
261     std::string outForm = params.GetString(Options::OUT_FORM);
262     if (!outForm.empty()) {
263         if (!CmdUtil::VerifyType(outForm, Options::OUT_FORM_SCOPE)) {
264             return false;
265         }
266     }
267     if (!outForm.empty() && "certChain" == outForm) {
268         if (!params.Required({Options::SUB_CA_CERT_FILE, Options::CA_CERT_FILE})) {
269             return false;
270         }
271         if (!FileUtils::ValidFileType(params.GetString(Options::SUB_CA_CERT_FILE), {"cer"}) ||
272             !FileUtils::ValidFileType(params.GetString(Options::CA_CERT_FILE), {"cer"})) {
273             return false;
274         }
275     }
276     std::string keyStoreFile = params.GetString(Options::KEY_STORE_FILE);
277     if (!FileUtils::ValidFileType(keyStoreFile, {"p12", "jks"})) {
278         return false;
279     }
280     if (params.find(Options::ISSUER_KEY_STORE_FILE) != params.end()) {
281         std::string issuerKeyStoreFile = params.GetString(Options::ISSUER_KEY_STORE_FILE);
282         if (!FileUtils::ValidFileType(issuerKeyStoreFile, {"p12", "jks"})) {
283             return false;
284         }
285     }
286     std::string outFile = params.GetString(Options::OUT_FILE);
287     if (!outFile.empty()) {
288         if (!FileUtils::ValidFileType(outFile, {"cer", "pem"})) {
289             return false;
290         }
291     }
292     return true;
293 }
294 
RunAppCert(Options* params, SignToolServiceImpl& api)295 bool ParamsRunTool::RunAppCert(Options* params, SignToolServiceImpl& api)
296 {
297     if (!CmdUtil::UpdateParamForCheckInFile(params, {Options::KEY_STORE_FILE, Options::ISSUER_KEY_STORE_FILE,
298                                             Options::CA_CERT_FILE, Options::SUB_CA_CERT_FILE})) {
299         return false;
300     }
301 
302     if (!CmdUtil::UpdateParamForCheckOutFile(params, {Options::OUT_FILE})) {
303         return false;
304     }
305 
306     if (!ParamsRunTool::CheckEndCertArguments(*params)) {
307         return false;
308     }
309     return api.GenerateAppCert(params);
310 }
311 
RunProfileCert(Options* params, SignToolServiceImpl& api)312 bool ParamsRunTool::RunProfileCert(Options* params, SignToolServiceImpl& api)
313 {
314     if (!CmdUtil::UpdateParamForCheckInFile(params, {Options::KEY_STORE_FILE, Options::ISSUER_KEY_STORE_FILE,
315                                             Options::CA_CERT_FILE, Options::SUB_CA_CERT_FILE})) {
316         return false;
317     }
318 
319     if (!CmdUtil::UpdateParamForCheckOutFile(params, {Options::OUT_FILE})) {
320         return false;
321     }
322 
323     if (!ParamsRunTool::CheckEndCertArguments(*params)) {
324         return false;
325     }
326     return api.GenerateProfileCert(params);
327 }
328 
RunKeypair(Options* params, SignToolServiceImpl& api)329 bool ParamsRunTool::RunKeypair(Options* params, SignToolServiceImpl& api)
330 {
331     if (!params->Required({Options::KEY_ALIAS, Options::KEY_ALG, Options::KEY_SIZE, Options::KEY_STORE_FILE})) {
332         return false;
333     }
334 
335     if (!CmdUtil::UpdateParamForCheckOutFile(params, {Options::KEY_STORE_FILE})) {
336         return false;
337     }
338 
339     std::string keyAlgorithm = params->GetString(Options::KEY_ALG);
340     if (!CmdUtil::JudgeAlgType(keyAlgorithm)) {
341         return false;
342     }
343     int keyAlgorithmSize = params->GetInt(Options::KEY_SIZE);
344     if (!CmdUtil::JudgeSize(keyAlgorithmSize)) {
345         return false;
346     }
347     if (!FileUtils::ValidFileType(params->GetString(Options::KEY_STORE_FILE), {"p12", "jks"})) {
348         return false;
349     }
350     return api.GenerateKeyStore(params);
351 }
352 
RunCsr(Options* params, SignToolServiceImpl& api)353 bool ParamsRunTool::RunCsr(Options* params, SignToolServiceImpl& api)
354 {
355     if (!params->Required({Options::KEY_ALIAS, Options::SUBJECT, Options::SIGN_ALG, Options::KEY_STORE_FILE})) {
356         return false;
357     }
358     if (!CmdUtil::UpdateParamForCheckInFile(params, {Options::KEY_STORE_FILE})) {
359         return false;
360     }
361 
362     if (!CmdUtil::UpdateParamForCheckOutFile(params, {Options::OUT_FILE})) {
363         return false;
364     }
365 
366     std::string signAlg = params->GetString(Options::SIGN_ALG);
367     if (!CmdUtil::JudgeSignAlgType(signAlg)) {
368         return false;
369     }
370     if (!FileUtils::ValidFileType(params->GetString(Options::KEY_STORE_FILE), {"p12", "jks"})) {
371         return false;
372     }
373     if (params->count(Options::OUT_FILE)) {
374         if (!FileUtils::ValidFileType(params->GetString(Options::OUT_FILE), {"csr"})) {
375             return false;
376         }
377     }
378     return api.GenerateCsr(params);
379 }
380 
RunSignProfile(Options* params, SignToolServiceImpl& api)381 bool ParamsRunTool::RunSignProfile(Options* params, SignToolServiceImpl& api)
382 {
383     if (!params->Required({params->MODE, params->SIGN_ALG, params->OUT_FILE, params->IN_FILE})) {
384         return false;
385     }
386 
387     if (!CmdUtil::UpdateParamForCheckInFile(params, {Options::KEY_STORE_FILE, Options::PROFILE_CERT_FILE,
388                                             Options::IN_FILE})) {
389         return false;
390     }
391 
392     if (!CmdUtil::UpdateParamForCheckOutFile(params, {Options::OUT_FILE})) {
393         return false;
394     }
395 
396     std::string mode = params->GetString(Options::MODE);
397     if (!StringUtils::CaseCompare(mode, LOCAL_SIGN) &&
398         !StringUtils::CaseCompare(mode, REMOTE_SIGN)) {
399         PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR, "not support command param '" + mode + "'");
400         return false;
401     }
402     if (StringUtils::CaseCompare(mode, LOCAL_SIGN)) {
403         if (!params->Required({params->KEY_STORE_FILE, params->KEY_ALIAS, params->PROFILE_CERT_FILE})) {
404             return false;
405         }
406 
407         if (!FileUtils::ValidFileType(params->GetString(Options::KEY_STORE_FILE), {"p12", "jks"})) {
408             return false;
409         }
410     }
411     std::string signAlg = params->GetString(Options::SIGN_ALG);
412     if (!CmdUtil::JudgeSignAlgType(signAlg)) {
413         return false;
414     }
415     std::string outFile = params->GetString(Options::OUT_FILE);
416     if (FileUtils::ValidFileType(outFile, {"p7b"}) == false) {
417         return false;
418     }
419     return api.SignProfile(params);
420 }
421 
RunVerifyProfile(Options* params, SignToolServiceImpl& api)422 bool ParamsRunTool::RunVerifyProfile(Options* params, SignToolServiceImpl& api)
423 {
424     if (!params->Required({Options::IN_FILE})) {
425         return false;
426     }
427 
428     if (!CmdUtil::UpdateParamForCheckInFile(params, {Options::IN_FILE})) {
429         return false;
430     }
431 
432     if (!CmdUtil::UpdateParamForCheckOutFile(params, {Options::OUT_FILE})) {
433         return false;
434     }
435 
436     if (!FileUtils::ValidFileType(params->GetString(Options::IN_FILE), {"p7b"})) {
437         return false;
438     }
439 
440     std::string outFile = params->GetString(Options::OUT_FILE);
441     if (!outFile.empty()) {
442         if (!FileUtils::ValidFileType(outFile, {"json"})) {
443             return false;
444         }
445     }
446     return api.VerifyProfile(params);
447 }
448 
PrintHelp()449 void ParamsRunTool::PrintHelp()
450 {
451     PrintMsg(HELP_TXT);
452 }
453 
Version()454 void  ParamsRunTool::Version()
455 {
456     PrintMsg(ParamsRunTool::VERSION);
457 }
458 
RunVerifyApp(Options* params, SignToolServiceImpl& api)459 bool ParamsRunTool::RunVerifyApp(Options* params, SignToolServiceImpl& api)
460 {
461     if (!params->Required({Options::IN_FILE, Options::OUT_CERT_CHAIN, Options::OUT_PROFILE})) {
462         return false;
463     }
464 
465     if (!CmdUtil::UpdateParamForCheckInFile(params, {Options::IN_FILE})) {
466         return false;
467     }
468 
469     if (!CmdUtil::UpdateParamForCheckOutFile(params, {Options::OUT_CERT_CHAIN, Options::OUT_PROFILE})) {
470         return false;
471     }
472 
473     std::string inForm = params->GetString(Options::INFORM, ZIP);
474     if (!StringUtils::ContainsCase(InformList, inForm)) {
475         PrintErrorNumberMsg("NOT_SUPPORT_ERROR", NOT_SUPPORT_ERROR, "parameter '" + inForm
476                             + "' format error, Inform only support zip/elf/bin");
477         return false;
478     }
479     if (!FileUtils::ValidFileType(params->GetString(Options::OUT_CERT_CHAIN), {"cer"})) {
480         return false;
481     }
482     if (!FileUtils::ValidFileType(params->GetString(Options::OUT_PROFILE), {"p7b"})) {
483         return false;
484     }
485     return api.VerifyHapSigner(params);
486 }
487 } // namespace SignatureTools
488 } // namespace OHOS