• 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.entity.RetMsg;
19 import com.ohos.entity.SignAppParameters;
20 import com.ohos.entity.SignProfileParameters;
21 import com.ohos.entity.VerifyAppParameters;
22 import com.ohos.entity.VerifyProfileParameters;
23 import com.ohos.hapsigntool.api.ServiceApi;
24 import com.ohos.hapsigntool.api.SignToolServiceImpl;
25 import com.ohos.hapsigntool.entity.Options;
26 import com.ohos.hapsigntool.error.CustomException;
27 import com.ohos.hapsigntool.error.ERROR;
28 import com.ohos.hapsigntool.error.ParamException;
29 import com.ohos.hapsigntool.error.SignToolErrMsg;
30 import com.ohos.hapsigntool.utils.FileUtils;
31 import com.ohos.hapsigntool.utils.LogUtils;
32 import com.ohos.hapsigntool.utils.StringUtils;
33 import com.ohos.hapsigntoolcmd.CmdUtil;
34 import com.ohos.hapsigntoolcmd.CmdUtil.Method;
35 import com.ohos.hapsigntoolcmd.HelpDocument;
36 import com.ohos.hapsigntoolcmd.Params;
37 
38 import java.util.ArrayList;
39 import java.util.List;
40 
41 /**
42  * HapSignTool.
43  *
44  * @since 2021/12/28
45  */
46 public final class HapSignTool {
47     /**
48      * Add log info.
49      */
50     private static final LogUtils LOGGER = new LogUtils(HapSignTool.class);
51 
52     /**
53      * Tool version.
54      */
55     private static final String VERSION = "1.0.0";
56 
57     /**
58      * Local sign.
59      */
60     private static final String LOCAL_SIGN = "localSign";
61 
62     /**
63      * Remote sign.
64      */
65     private static final String REMOTE_SIGN = "remoteSign";
66 
67     /**
68      * Signed.
69      */
70     private static final String SIGNED = "1";
71 
72     /**
73      * No signed.
74      */
75     private static final String NOT_SIGNED = "0";
76 
77     private static final List<String> informList = new ArrayList<>();
78 
79     static {
80         informList.add("bin");
81         informList.add("elf");
82         informList.add("zip");
83     }
84 
HapSignTool()85     private HapSignTool() {
86     }
87 
88     /**
89      * Main entry.
90      *
91      * @param args arguments
92      */
main(String[] args)93     public static void main(String[] args) {
94         try {
95             boolean isSuccess = processCmd(args);
96             if (!isSuccess) {
97                 System.exit(1);
98             }
99         } catch (CustomException e) {
100             LOGGER.error(e.getMessage());
101             System.exit(1);
102         } catch (Exception e) {
103             LOGGER.error(SignToolErrMsg.UNKNOWN_ERROR.toString(e.getMessage()));
104             System.exit(1);
105         }
106     }
107 
108     /**
109      * Process command.
110      *
111      * @param args arguments
112      * @return command processing result
113      * @throws CustomException custom exception for command execution failure
114      */
processCmd(String[] args)115     public static boolean processCmd(String[] args) throws CustomException {
116         if (args.length == 0 || StringUtils.isEmpty(args[0])) {
117             help();
118         } else if ("-h".equals(args[0]) || "-help".equals(args[0])) {
119             help();
120         } else if ("-v".equals(args[0]) || "-version".equals(args[0])) {
121             version();
122         } else {
123             ServiceApi api = new SignToolServiceImpl();
124             Params params = CmdUtil.convert2Params(args);
125             LOGGER.debug(params.toString());
126             LOGGER.info("Start {}", params.getMethod());
127             boolean isSuccess = dispatchParams(params, api);
128             if (isSuccess) {
129                 LOGGER.info(String.format("%s %s", params.getMethod(), "success"));
130             } else {
131                 LOGGER.info(String.format("%s %s", params.getMethod(), "failed"));
132             }
133             return isSuccess;
134         }
135         return true;
136     }
137 
callGenerators(Params params, ServiceApi api)138     private static boolean callGenerators(Params params, ServiceApi api) {
139         boolean isSuccess = false;
140         String method = params.getMethod();
141         switch (method) {
142             case Method.GENERATE_APP_CERT:
143                 isSuccess = runAppCert(params.getOptions(), api);
144                 break;
145             case Method.GENERATE_CA:
146                 isSuccess = runCa(params.getOptions(), api);
147                 break;
148             case Method.GENERATE_CERT:
149                 isSuccess = runCert(params.getOptions(), api);
150                 break;
151             case Method.GENERATE_CSR:
152                 isSuccess = runCsr(params.getOptions(), api);
153                 break;
154             case Method.GENERATE_KEYPAIR:
155                 isSuccess = runKeypair(params.getOptions(), api);
156                 break;
157             case Method.GENERATE_PROFILE_CERT:
158                 isSuccess = runProfileCert(params.getOptions(), api);
159                 break;
160             default:
161                 CustomException.throwException(ERROR.COMMAND_ERROR, SignToolErrMsg.UNSUPPORTED_METHOD.toString(method));
162                 break;
163         }
164         return isSuccess;
165     }
166 
dispatchParams(Params params, ServiceApi api)167     private static boolean dispatchParams(Params params, ServiceApi api) {
168         boolean isSuccess;
169         switch (params.getMethod()) {
170             case Method.SIGN_APP:
171                 isSuccess = runSignApp(params.getOptions(), api);
172                 break;
173             case Method.SIGN_PROFILE:
174                 isSuccess = runSignProfile(params.getOptions(), api);
175                 break;
176             case Method.VERIFY_APP:
177                 isSuccess = runVerifyApp(params.getOptions(), api);
178                 break;
179             case Method.VERIFY_PROFILE:
180                 isSuccess = runVerifyProfile(params.getOptions(), api);
181                 break;
182             default:
183                 isSuccess = callGenerators(params, api);
184                 break;
185         }
186         return isSuccess;
187     }
188 
checkEndCertArguments(Options params)189     private static void checkEndCertArguments(Options params) {
190         params.required(Options.KEY_ALIAS, Options.ISSUER, Options.ISSUER_KEY_ALIAS, Options.SUBJECT,
191                 Options.SIGN_ALG, Options.KEY_STORE_FILE);
192         String signAlg = params.getString(Options.SIGN_ALG);
193         CmdUtil.judgeEndSignAlgType(signAlg);
194         String outForm = params.getString(Options.OUT_FORM);
195         if (!StringUtils.isEmpty(outForm)) {
196             CmdUtil.verifyType(outForm, Options.OUT_FORM_SCOPE);
197         }
198         if (StringUtils.isEmpty(outForm) || "certChain".equals(outForm)) {
199             params.required(Options.SUB_CA_CERT_FILE, Options.CA_CERT_FILE);
200             FileUtils.validFileType(params.getString(Options.SUB_CA_CERT_FILE), "cer");
201             FileUtils.validFileType(params.getString(Options.CA_CERT_FILE), "cer");
202         }
203         String keyStoreFile = params.getString(Options.KEY_STORE_FILE);
204         FileUtils.validFileType(keyStoreFile, "p12", "jks");
205 
206         if (params.containsKey(Options.ISSUER_KEY_STORE_FILE)) {
207             String issuerKeyStoreFile = params.getString(Options.ISSUER_KEY_STORE_FILE);
208             FileUtils.validFileType(issuerKeyStoreFile, "p12", "jks");
209         }
210 
211         String outFile = params.getString(Options.OUT_FILE);
212         if (!StringUtils.isEmpty(outFile)) {
213             FileUtils.validFileType(outFile, "cer", "pem");
214         }
215     }
216 
runAppCert(Options params, ServiceApi api)217     private static boolean runAppCert(Options params, ServiceApi api) {
218         checkEndCertArguments(params);
219         return api.generateAppCert(params);
220     }
221 
runCa(Options params, ServiceApi api)222     private static boolean runCa(Options params, ServiceApi api) {
223         params.required(Options.KEY_ALIAS, Options.KEY_ALG, Options.KEY_SIZE, Options.SUBJECT,
224                 Options.SIGN_ALG, Options.KEY_STORE_FILE);
225         String keyAlg = params.getString(Options.KEY_ALG);
226         CmdUtil.judgeAlgType(keyAlg);
227         String size = params.getString(Options.KEY_SIZE);
228         CmdUtil.judgeSize(size, keyAlg);
229         String signAlg = params.getString(Options.SIGN_ALG);
230         CmdUtil.judgeSignAlgType(signAlg);
231         FileUtils.validFileType(params.getString(Options.KEY_STORE_FILE), "p12", "jks");
232         params.put(Options.KEY_SIZE, CmdUtil.convertAlgSize(size));
233         return api.generateCA(params);
234     }
235 
runCert(Options params, ServiceApi api)236     private static boolean runCert(Options params, ServiceApi api) {
237         params.required(Options.KEY_ALIAS, Options.ISSUER, Options.ISSUER_KEY_ALIAS, Options.SUBJECT,
238                 Options.KEY_USAGE, Options.SIGN_ALG, Options.KEY_STORE_FILE);
239         String keyUsage = params.getString(Options.KEY_USAGE);
240         CmdUtil.verifyType(keyUsage, Options.KEY_USAGE_SCOPE);
241         String extKeyUsage = params.getString(Options.EXT_KEY_USAGE);
242         CmdUtil.verifyType(extKeyUsage, Options.EXT_KEY_USAGE_SCOPE);
243         String signAlg = params.getString(Options.SIGN_ALG);
244         CmdUtil.judgeSignAlgType(signAlg);
245         FileUtils.validFileType(params.getString(Options.KEY_STORE_FILE), "p12", "jks");
246         if (params.containsKey(Options.ISSUER_KEY_STORE_FILE)) {
247             String issuerKeyStoreFile = params.getString(Options.ISSUER_KEY_STORE_FILE);
248             FileUtils.validFileType(issuerKeyStoreFile, "p12", "jks");
249         }
250         return api.generateCert(params);
251     }
252 
runCsr(Options params, ServiceApi api)253     private static boolean runCsr(Options params, ServiceApi api) {
254         params.required(Options.KEY_ALIAS, Options.SUBJECT, Options.SIGN_ALG, Options.KEY_STORE_FILE);
255         String signAlg = params.getString(Options.SIGN_ALG);
256         CmdUtil.judgeSignAlgType(signAlg);
257         FileUtils.validFileType(params.getString(Options.KEY_STORE_FILE), "p12", "jks");
258         if (!StringUtils.isEmpty(params.getString(Options.OUT_FILE))) {
259             FileUtils.validFileType(params.getString(Options.OUT_FILE), "csr");
260         }
261 
262         return api.generateCsr(params);
263     }
264 
runKeypair(Options params, ServiceApi api)265     private static boolean runKeypair(Options params, ServiceApi api) {
266         params.required(Options.KEY_ALIAS, Options.KEY_ALG, Options.KEY_SIZE, Options.KEY_STORE_FILE);
267         String keyAlg = params.getString(Options.KEY_ALG);
268         CmdUtil.judgeAlgType(keyAlg);
269         String size = params.getString(Options.KEY_SIZE);
270         CmdUtil.judgeSize(size, keyAlg);
271         params.put(Options.KEY_SIZE, CmdUtil.convertAlgSize(size));
272         FileUtils.validFileType(params.getString(Options.KEY_STORE_FILE), "p12", "jks");
273 
274         return api.generateKeyStore(params);
275     }
276 
runProfileCert(Options params, ServiceApi api)277     private static boolean runProfileCert(Options params, ServiceApi api) {
278         checkEndCertArguments(params);
279         return api.generateProfileCert(params);
280     }
281 
runSignApp(Options params, ServiceApi api)282     private static boolean runSignApp(Options params, ServiceApi api) {
283         params.required(Options.MODE, Options.IN_FILE, Options.OUT_FILE, Options.SIGN_ALG);
284         String mode = params.getString(Options.MODE);
285         if (!LOCAL_SIGN.equalsIgnoreCase(mode)
286                 && !REMOTE_SIGN.equalsIgnoreCase(mode)
287                 && !"remoteResign".equalsIgnoreCase(mode)) {
288             CustomException.throwException(ERROR.COMMAND_ERROR, SignToolErrMsg.PARAM_CHECK_FAILED
289                     .toString(Options.MODE, "value must be localSign/remoteSign/remoteResign"));
290         }
291 
292         if (LOCAL_SIGN.equalsIgnoreCase(mode)) {
293             params.required(Options.KEY_STORE_FILE, Options.KEY_ALIAS, Options.APP_CERT_FILE);
294             FileUtils.validFileType(params.getString(Options.KEY_STORE_FILE), "p12", "jks");
295         }
296         checkProfile(params);
297         String inForm = params.getString(Options.IN_FORM, "zip");
298         if (!StringUtils.isEmpty(inForm) && !containsIgnoreCase(inForm)) {
299             CustomException.throwException(ERROR.COMMAND_ERROR, SignToolErrMsg.PARAM_CHECK_FAILED
300                     .toString(Options.IN_FORM, "value must be " + informList));
301         }
302         String signAlg = params.getString(Options.SIGN_ALG);
303         CmdUtil.judgeEndSignAlgType(signAlg);
304 
305         return api.signHap(params);
306     }
307 
checkProfile(Options params)308     private static void checkProfile(Options params) {
309         String inForm = params.getString(Options.IN_FORM);
310         String profileFile = params.getString(Options.PROFILE_FILE);
311         String profileSigned = params.getString(Options.PROFILE_SIGNED, SIGNED);
312 
313         if ("elf".equalsIgnoreCase(inForm) && StringUtils.isEmpty(profileFile)) {
314             return;
315         }
316         if (!SIGNED.equals(profileSigned) && !NOT_SIGNED.equals(profileSigned)) {
317             CustomException.throwException(ERROR.COMMAND_ERROR, SignToolErrMsg.PARAM_CHECK_FAILED
318                     .toString(Options.PROFILE_SIGNED, "value must be 1/0"));
319         }
320         if (SIGNED.equals(profileSigned)) {
321             FileUtils.validFileType(profileFile, "p7b");
322         } else {
323             FileUtils.validFileType(profileFile, "json");
324         }
325     }
326 
runSignProfile(Options params, ServiceApi api)327     private static boolean runSignProfile(Options params, ServiceApi api) {
328         params.required(Options.MODE, Options.SIGN_ALG, Options.OUT_FILE, Options.IN_FILE);
329         String mode = params.getString(Options.MODE);
330         if (!LOCAL_SIGN.equalsIgnoreCase(mode) && !REMOTE_SIGN.equalsIgnoreCase(mode)) {
331             CustomException.throwException(ERROR.COMMAND_ERROR, SignToolErrMsg.PARAM_CHECK_FAILED
332                     .toString(Options.MODE, "value must be localSign/remoteSign/remoteResign"));
333         }
334         if (LOCAL_SIGN.equalsIgnoreCase(mode)) {
335             params.required(Options.KEY_STORE_FILE, Options.KEY_ALIAS, Options.PROFILE_CERT_FILE);
336             FileUtils.validFileType(params.getString(Options.KEY_STORE_FILE), "p12", "jks");
337         }
338 
339         String signAlg = params.getString(Options.SIGN_ALG);
340         CmdUtil.judgeEndSignAlgType(signAlg);
341         String outFile = params.getString(Options.OUT_FILE);
342         FileUtils.validFileType(outFile, "p7b");
343 
344         return api.signProfile(params);
345     }
346 
runVerifyApp(Options params, ServiceApi api)347     private static boolean runVerifyApp(Options params, ServiceApi api) {
348         params.required(Options.IN_FILE, Options.OUT_CERT_CHAIN,
349                 Options.OUT_PROFILE);
350         String inForm = params.getString(Options.IN_FORM, "zip");
351         if (!containsIgnoreCase(inForm)) {
352             CustomException.throwException(ERROR.COMMAND_ERROR, SignToolErrMsg.PARAM_CHECK_FAILED
353                     .toString(Options.IN_FORM, "value must be " + informList));
354         }
355         FileUtils.validFileType(params.getString(Options.OUT_CERT_CHAIN), "cer");
356         FileUtils.validFileType(params.getString(Options.OUT_PROFILE), "p7b");
357         return api.verifyHap(params);
358     }
359 
runVerifyProfile(Options params, ServiceApi api)360     private static boolean runVerifyProfile(Options params, ServiceApi api) {
361         params.required(Options.IN_FILE);
362         FileUtils.validFileType(params.getString(Options.IN_FILE), "p7b");
363         String outFile = params.getString(Options.OUT_FILE);
364         if (!StringUtils.isEmpty(outFile)) {
365             FileUtils.validFileType(outFile, "json");
366         }
367 
368         return api.verifyProfile(params);
369     }
370 
371     /**
372      * Software version.
373      */
version()374     public static void version() {
375         LOGGER.info(VERSION);
376     }
377 
378     /**
379      * Print help to console.
380      */
help()381     public static void help() {
382         HelpDocument.printHelp(LOGGER);
383     }
384 
containsIgnoreCase(String inForm)385     private static boolean containsIgnoreCase(String inForm) {
386         for (String s : informList) {
387             if (s.equalsIgnoreCase(inForm)) {
388                 return true;
389             }
390         }
391         return false;
392     }
393 
394     /**
395      * sign App
396      *
397      * @param signAppParameters verifyProfileParameters
398      * @return RetMsg
399      */
signApp(SignAppParameters signAppParameters)400     public static RetMsg signApp(SignAppParameters signAppParameters) {
401         try {
402             if (signAppParameters == null) {
403                 throw new ParamException("params is null");
404             }
405             Options options = signAppParameters.toOptions();
406             ServiceApi api = new SignToolServiceImpl();
407             if (runSignApp(options, api)) {
408                 return new RetMsg(ERROR.SUCCESS_CODE, "sign app success");
409             }
410             return new RetMsg(ERROR.SIGN_ERROR, "sign app failed");
411         } catch (CustomException e) {
412             return new RetMsg(e.getError(), e.getMessage());
413         } catch (ParamException e) {
414             return new RetMsg(ERROR.COMMAND_PARAM_ERROR, "paramException : " + e.getMessage());
415         } catch (Exception e) {
416             return new RetMsg(ERROR.UNKNOWN_ERROR, "unknownException : " + e.getMessage());
417         }
418     }
419 
420     /**
421      * verify App
422      *
423      * @param verifyAppParameters verifyProfileParameters
424      * @return RetMsg
425      */
verifyApp(VerifyAppParameters verifyAppParameters)426     public static RetMsg verifyApp(VerifyAppParameters verifyAppParameters) {
427         try {
428             if (verifyAppParameters == null) {
429                 throw new ParamException("params is null");
430             }
431             Options options = verifyAppParameters.toOptions();
432             ServiceApi api = new SignToolServiceImpl();
433             if (runVerifyApp(options, api)) {
434                 return new RetMsg(ERROR.SUCCESS_CODE, "verify app success");
435             }
436             return new RetMsg(ERROR.VERIFY_ERROR, "verify app failed");
437         } catch (CustomException e) {
438             return new RetMsg(e.getError(), e.getMessage());
439         } catch (ParamException e) {
440             return new RetMsg(ERROR.COMMAND_PARAM_ERROR, "paramException : " + e.getMessage());
441         } catch (Exception e) {
442             return new RetMsg(ERROR.UNKNOWN_ERROR, "unknownException : " + e.getMessage());
443         }
444     }
445 
446     /**
447      * sign Profile
448      *
449      * @param signProfileParameters verifyProfileParameters
450      * @return RetMsg
451      */
signProfile(SignProfileParameters signProfileParameters)452     public static RetMsg signProfile(SignProfileParameters signProfileParameters) {
453         try {
454             if (signProfileParameters == null) {
455                 throw new ParamException("params is null");
456             }
457             Options options = signProfileParameters.toOptions();
458             ServiceApi api = new SignToolServiceImpl();
459             if (runSignProfile(options, api)) {
460                 return new RetMsg(ERROR.SUCCESS_CODE, "sign profile success");
461             }
462             return new RetMsg(ERROR.SIGN_ERROR, "sign profile failed");
463         } catch (CustomException e) {
464             return new RetMsg(e.getError(), e.getMessage());
465         } catch (ParamException e) {
466             return new RetMsg(ERROR.COMMAND_PARAM_ERROR, "paramException : " + e.getMessage());
467         } catch (Exception e) {
468             return new RetMsg(ERROR.UNKNOWN_ERROR, "unknownException : " + e.getMessage());
469         }
470     }
471 
472     /**
473      * verify Profile
474      *
475      * @param verifyProfileParameters verifyProfileParameters
476      * @return RetMsg
477      */
verifyProfile(VerifyProfileParameters verifyProfileParameters)478     public static RetMsg verifyProfile(VerifyProfileParameters verifyProfileParameters) {
479         try {
480             if (verifyProfileParameters == null) {
481                 throw new ParamException("params is null");
482             }
483             Options options = verifyProfileParameters.toOptions();
484             ServiceApi api = new SignToolServiceImpl();
485             if (runVerifyProfile(options, api)) {
486                 return new RetMsg(ERROR.SUCCESS_CODE, "verify profile success");
487             }
488             return new RetMsg(ERROR.VERIFY_ERROR, "verify profile failed");
489         } catch (CustomException e) {
490             return new RetMsg(e.getError(), e.getMessage());
491         } catch (ParamException e) {
492             return new RetMsg(ERROR.COMMAND_PARAM_ERROR, "paramException : " + e.getMessage());
493         } catch (Exception e) {
494             return new RetMsg(ERROR.UNKNOWN_ERROR, "unknownException : " + e.getMessage());
495         }
496     }
497 }
498