• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2023 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 package com.ohos.hapsigntool;
17 
18 import com.ohos.hapsigntool.api.ServiceApi;
19 import com.ohos.hapsigntool.api.SignToolServiceImpl;
20 import com.ohos.hapsigntool.entity.Options;
21 import com.ohos.hapsigntool.error.CustomException;
22 import com.ohos.hapsigntool.error.ERROR;
23 import com.ohos.hapsigntool.utils.FileUtils;
24 import com.ohos.hapsigntool.utils.StringUtils;
25 import com.ohos.hapsigntoolcmd.CmdUtil;
26 import com.ohos.hapsigntoolcmd.CmdUtil.Method;
27 import com.ohos.hapsigntoolcmd.HelpDocument;
28 import com.ohos.hapsigntoolcmd.Params;
29 
30 import org.apache.logging.log4j.LogManager;
31 import org.apache.logging.log4j.Logger;
32 
33 import java.util.ArrayList;
34 import java.util.List;
35 
36 /**
37  * HapSignTool.
38  *
39  * @since 2021/12/28
40  */
41 public final class HapSignTool {
42     /**
43      * Add log info.
44      */
45     private static final Logger LOGGER = LogManager.getLogger(HapSignTool.class);
46 
47     /**
48      * Tool version.
49      */
50     private static final String VERSION = "1.0.0";
51 
52     /**
53      * Local sign.
54      */
55     private static final String LOCAL_SIGN = "localSign";
56 
57     /**
58      * Remote sign.
59      */
60     private static final String REMOTE_SIGN = "remoteSign";
61 
62     /**
63      * Signed.
64      */
65     private static final String SIGNED = "1";
66 
67     /**
68      * No signed.
69      */
70     private static final String NOT_SIGNED = "0";
71 
72     private static List<String> informList = new ArrayList<>();
73 
74     static {
75         informList.add("bin");
76         informList.add("elf");
77         informList.add("zip");
78     }
79 
HapSignTool()80     private HapSignTool() {
81     }
82 
83     /**
84      * Main entry.
85      *
86      * @param args arguments
87      */
main(String[] args)88     public static void main(String[] args) {
89         try {
90             boolean isSuccess = processCmd(args);
91             if (!isSuccess) {
92                 System.exit(1);
93             }
94         } catch (CustomException exception) {
95             LOGGER.debug(exception.getMessage(), exception);
96             LOGGER.error(exception.getMessage());
97             System.exit(1);
98         }
99     }
100 
101     /**
102      * Process command.
103      *
104      * @param args arguments
105      * @return command processing result
106      * @throws CustomException custom exception for command execution failure
107      */
processCmd(String[] args)108     public static boolean processCmd(String[] args) throws CustomException {
109         if (args.length == 0 || StringUtils.isEmpty(args[0])) {
110             help();
111         } else if ("-h".equals(args[0]) || "-help".equals(args[0])) {
112             help();
113         } else if ("-v".equals(args[0]) || "-version".equals(args[0])) {
114             version();
115         } else {
116             ServiceApi api = new SignToolServiceImpl();
117             Params params = CmdUtil.convert2Params(args);
118             LOGGER.debug(params.toString());
119             LOGGER.info("Start {}", params.getMethod());
120             boolean isSuccess = dispatchParams(params, api);
121             if (isSuccess) {
122                 LOGGER.info(String.format("%s %s", params.getMethod(), "success"));
123             } else {
124                 LOGGER.info(String.format("%s %s", params.getMethod(), "failed"));
125             }
126             return isSuccess;
127         }
128         return true;
129     }
130 
callGenerators(Params params, ServiceApi api)131     private static boolean callGenerators(Params params, ServiceApi api) {
132         boolean isSuccess = false;
133         switch (params.getMethod()) {
134             case Method.GENERATE_APP_CERT:
135                 isSuccess = runAppCert(params.getOptions(), api);
136                 break;
137             case Method.GENERATE_CA:
138                 isSuccess = runCa(params.getOptions(), api);
139                 break;
140             case Method.GENERATE_CERT:
141                 isSuccess = runCert(params.getOptions(), api);
142                 break;
143             case Method.GENERATE_CSR:
144                 isSuccess = runCsr(params.getOptions(), api);
145                 break;
146             case Method.GENERATE_KEYPAIR:
147                 isSuccess = runKeypair(params.getOptions(), api);
148                 break;
149             case Method.GENERATE_PROFILE_CERT:
150                 isSuccess = runProfileCert(params.getOptions(), api);
151                 break;
152             default:
153                 CustomException.throwException(ERROR.COMMAND_ERROR, "Unsupported cmd");
154                 break;
155         }
156         return isSuccess;
157     }
158 
dispatchParams(Params params, ServiceApi api)159     private static boolean dispatchParams(Params params, ServiceApi api) {
160         boolean isSuccess;
161         switch (params.getMethod()) {
162             case Method.SIGN_APP:
163                 isSuccess = runSignApp(params.getOptions(), api);
164                 break;
165             case Method.SIGN_PROFILE:
166                 isSuccess = runSignProfile(params.getOptions(), api);
167                 break;
168             case Method.VERIFY_APP:
169                 isSuccess = runVerifyApp(params.getOptions(), api);
170                 break;
171             case Method.VERIFY_PROFILE:
172                 isSuccess = runVerifyProfile(params.getOptions(), api);
173                 break;
174             default:
175                 isSuccess = callGenerators(params, api);
176                 break;
177         }
178         return isSuccess;
179     }
180 
checkEndCertArguments(Options params)181     private static void checkEndCertArguments(Options params) {
182         params.required(Options.KEY_ALIAS, Options.ISSUER, Options.ISSUER_KEY_ALIAS, Options.SUBJECT,
183                 Options.SIGN_ALG, Options.KEY_STORE_FILE);
184         String signAlg = params.getString(Options.SIGN_ALG);
185         CmdUtil.judgeEndSignAlgType(signAlg);
186         String outForm = params.getString(Options.OUT_FORM);
187         if (!StringUtils.isEmpty(outForm)) {
188             CmdUtil.verifyType(outForm, Options.OUT_FORM_SCOPE);
189         }
190         if (StringUtils.isEmpty(outForm) || "certChain".equals(outForm)) {
191             params.required(Options.SUB_CA_CERT_FILE, Options.CA_CERT_FILE);
192             FileUtils.validFileType(params.getString(Options.SUB_CA_CERT_FILE), "cer");
193             FileUtils.validFileType(params.getString(Options.CA_CERT_FILE), "cer");
194         }
195         String keyStoreFile = params.getString(Options.KEY_STORE_FILE);
196         FileUtils.validFileType(keyStoreFile, "p12", "jks");
197 
198         if (params.containsKey(Options.ISSUER_KEY_STORE_FILE)) {
199             String issuerKeyStoreFile = params.getString(Options.ISSUER_KEY_STORE_FILE);
200             FileUtils.validFileType(issuerKeyStoreFile, "p12", "jks");
201         }
202 
203         String outFile = params.getString(Options.OUT_FILE);
204         if (!StringUtils.isEmpty(outFile)) {
205             FileUtils.validFileType(outFile, "cer", "pem");
206         }
207     }
208 
runAppCert(Options params, ServiceApi api)209     private static boolean runAppCert(Options params, ServiceApi api) {
210         checkEndCertArguments(params);
211         return api.generateAppCert(params);
212     }
213 
runCa(Options params, ServiceApi api)214     private static boolean runCa(Options params, ServiceApi api) {
215         params.required(Options.KEY_ALIAS, Options.KEY_ALG, Options.KEY_SIZE, Options.SUBJECT,
216                 Options.SIGN_ALG, Options.KEY_STORE_FILE);
217         String keyAlg = params.getString(Options.KEY_ALG);
218         CmdUtil.judgeAlgType(keyAlg);
219         String size = params.getString(Options.KEY_SIZE);
220         CmdUtil.judgeSize(size, keyAlg);
221         String signAlg = params.getString(Options.SIGN_ALG);
222         CmdUtil.judgeSignAlgType(signAlg);
223         FileUtils.validFileType(params.getString(Options.KEY_STORE_FILE), "p12", "jks");
224         params.put(Options.KEY_SIZE, CmdUtil.convertAlgSize(size));
225         return api.generateCA(params);
226     }
227 
runCert(Options params, ServiceApi api)228     private static boolean runCert(Options params, ServiceApi api) {
229         params.required(Options.KEY_ALIAS, Options.ISSUER, Options.ISSUER_KEY_ALIAS, Options.SUBJECT,
230                 Options.KEY_USAGE, Options.SIGN_ALG, Options.KEY_STORE_FILE);
231         String keyUsage = params.getString(Options.KEY_USAGE);
232         CmdUtil.verifyType(keyUsage, Options.KEY_USAGE_SCOPE);
233         String extKeyUsage = params.getString(Options.EXT_KEY_USAGE);
234         CmdUtil.verifyType(extKeyUsage, Options.EXT_KEY_USAGE_SCOPE);
235         String signAlg = params.getString(Options.SIGN_ALG);
236         CmdUtil.judgeSignAlgType(signAlg);
237         FileUtils.validFileType(params.getString(Options.KEY_STORE_FILE), "p12", "jks");
238         if (params.containsKey(Options.ISSUER_KEY_STORE_FILE)) {
239             String issuerKeyStoreFile = params.getString(Options.ISSUER_KEY_STORE_FILE);
240             FileUtils.validFileType(issuerKeyStoreFile, "p12", "jks");
241         }
242         return api.generateCert(params);
243     }
244 
runCsr(Options params, ServiceApi api)245     private static boolean runCsr(Options params, ServiceApi api) {
246         params.required(Options.KEY_ALIAS, Options.SUBJECT, Options.SIGN_ALG, Options.KEY_STORE_FILE);
247         String signAlg = params.getString(Options.SIGN_ALG);
248         CmdUtil.judgeSignAlgType(signAlg);
249         FileUtils.validFileType(params.getString(Options.KEY_STORE_FILE), "p12", "jks");
250         if (!StringUtils.isEmpty(params.getString(Options.OUT_FILE))) {
251             FileUtils.validFileType(params.getString(Options.OUT_FILE), "csr");
252         }
253 
254         return api.generateCsr(params);
255     }
256 
runKeypair(Options params, ServiceApi api)257     private static boolean runKeypair(Options params, ServiceApi api) {
258         params.required(Options.KEY_ALIAS, Options.KEY_ALG, Options.KEY_SIZE, Options.KEY_STORE_FILE);
259         String keyAlg = params.getString(Options.KEY_ALG);
260         CmdUtil.judgeAlgType(keyAlg);
261         String size = params.getString(Options.KEY_SIZE);
262         CmdUtil.judgeSize(size, keyAlg);
263         params.put(Options.KEY_SIZE, CmdUtil.convertAlgSize(size));
264         FileUtils.validFileType(params.getString(Options.KEY_STORE_FILE), "p12", "jks");
265 
266         return api.generateKeyStore(params);
267     }
268 
runProfileCert(Options params, ServiceApi api)269     private static boolean runProfileCert(Options params, ServiceApi api) {
270         checkEndCertArguments(params);
271         return api.generateProfileCert(params);
272     }
273 
runSignApp(Options params, ServiceApi api)274     private static boolean runSignApp(Options params, ServiceApi api) {
275         params.required(Options.MODE, Options.IN_FILE, Options.OUT_FILE, Options.SIGN_ALG);
276         String mode = params.getString(Options.MODE);
277         if (!LOCAL_SIGN.equalsIgnoreCase(mode)
278                 && !REMOTE_SIGN.equalsIgnoreCase(mode)
279                 && !"remoteResign".equalsIgnoreCase(mode)) {
280             CustomException.throwException(ERROR.COMMAND_ERROR, "mode params is incorrect");
281         }
282 
283         if (LOCAL_SIGN.equalsIgnoreCase(mode)) {
284             params.required(Options.KEY_STORE_FILE, Options.KEY_ALIAS, Options.APP_CERT_FILE);
285             FileUtils.validFileType(params.getString(Options.KEY_STORE_FILE), "p12", "jks");
286         }
287         checkProfile(params);
288         String inForm = params.getString(Options.IN_FORM, "zip");
289         if (!StringUtils.isEmpty(inForm) && !containsIgnoreCase(inForm)) {
290             CustomException.throwException(ERROR.NOT_SUPPORT_ERROR, "inForm params is incorrect");
291         }
292         String signAlg = params.getString(Options.SIGN_ALG);
293         CmdUtil.judgeEndSignAlgType(signAlg);
294 
295         return api.signHap(params);
296     }
297 
checkProfile(Options params)298     private static void checkProfile(Options params) {
299         String inForm = params.getString(Options.IN_FORM);
300         String profileFile = params.getString(Options.PROFILE_FILE);
301         String profileSigned = params.getString(Options.PROFILE_SIGNED, SIGNED);
302 
303         if ("elf".equalsIgnoreCase(inForm) && StringUtils.isEmpty(profileFile)) {
304             return;
305         }
306         if (!SIGNED.equals(profileSigned) && !NOT_SIGNED.equals(profileSigned)) {
307             CustomException.throwException(ERROR.NOT_SUPPORT_ERROR, "profileSigned params is incorrect");
308         }
309         if (SIGNED.equals(profileSigned)) {
310             FileUtils.validFileType(profileFile, "p7b");
311         } else {
312             FileUtils.validFileType(profileFile, "json");
313         }
314     }
315 
runSignProfile(Options params, ServiceApi api)316     private static boolean runSignProfile(Options params, ServiceApi api) {
317         params.required(Options.MODE, Options.SIGN_ALG, Options.OUT_FILE, Options.IN_FILE);
318         String mode = params.getString(Options.MODE);
319         if (!LOCAL_SIGN.equalsIgnoreCase(mode) && !REMOTE_SIGN.equalsIgnoreCase(mode)) {
320             CustomException.throwException(ERROR.COMMAND_ERROR, "mode params is incorrect");
321         }
322         if (LOCAL_SIGN.equalsIgnoreCase(mode)) {
323             params.required(Options.KEY_STORE_FILE, Options.KEY_ALIAS, Options.PROFILE_CERT_FILE);
324             FileUtils.validFileType(params.getString(Options.KEY_STORE_FILE), "p12", "jks");
325         }
326 
327         String signAlg = params.getString(Options.SIGN_ALG);
328         CmdUtil.judgeEndSignAlgType(signAlg);
329         String outFile = params.getString(Options.OUT_FILE);
330         FileUtils.validFileType(outFile, "p7b");
331 
332         return api.signProfile(params);
333     }
334 
runVerifyApp(Options params, ServiceApi api)335     private static boolean runVerifyApp(Options params, ServiceApi api) {
336         params.required(Options.IN_FILE, Options.OUT_CERT_CHAIN,
337                 Options.OUT_PROFILE);
338         String inForm = params.getString(Options.IN_FORM, "zip");
339         if (!containsIgnoreCase(inForm)) {
340             CustomException.throwException(ERROR.NOT_SUPPORT_ERROR, "inForm params must is " + informList);
341         }
342         FileUtils.validFileType(params.getString(Options.OUT_CERT_CHAIN), "cer");
343         FileUtils.validFileType(params.getString(Options.OUT_PROFILE), "p7b");
344         return api.verifyHap(params);
345     }
346 
runVerifyProfile(Options params, ServiceApi api)347     private static boolean runVerifyProfile(Options params, ServiceApi api) {
348         params.required(Options.IN_FILE);
349         FileUtils.validFileType(params.getString(Options.IN_FILE), "p7b");
350         String outFile = params.getString(Options.OUT_FILE);
351         if (!StringUtils.isEmpty(outFile)) {
352             FileUtils.validFileType(outFile, "json");
353         }
354 
355         return api.verifyProfile(params);
356     }
357 
358     /**
359      * Software version.
360      */
version()361     public static void version() {
362         LOGGER.info(VERSION);
363     }
364 
365     /**
366      * Print help to console.
367      */
help()368     public static void help() {
369         HelpDocument.printHelp(LOGGER);
370     }
371 
containsIgnoreCase(String inForm)372     private static boolean containsIgnoreCase(String inForm) {
373         for (String s : informList) {
374             if (s.equalsIgnoreCase(inForm)) {
375                 return true;
376             }
377         }
378         return false;
379     }
380 }
381