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
24namespace OHOS {
25namespace SignatureTools {
26const std::string ParamsRunTool::VERSION = "1.0.0";
27
28std::vector<std::string> ParamsRunTool::InformList = {
29    "bin",
30    "elf",
31    "zip"
32};
33
34static 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
42static 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
53bool 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
88bool 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
102bool 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
148bool 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
171bool 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
184bool 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
215bool 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
251bool 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
295bool 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
312bool 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
329bool 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
353bool 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
381bool 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
422bool 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
449void ParamsRunTool::PrintHelp()
450{
451    PrintMsg(HELP_TXT);
452}
453
454void  ParamsRunTool::Version()
455{
456    PrintMsg(ParamsRunTool::VERSION);
457}
458
459bool 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