1 /* 2 * Copyright (c) 2021-2022 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.utils; 17 18 import com.ohos.hapsigntool.error.CustomException; 19 import com.ohos.hapsigntool.error.ERROR; 20 import org.apache.logging.log4j.LogManager; 21 import org.apache.logging.log4j.Logger; 22 23 import javax.security.auth.x500.X500Principal; 24 import java.io.IOException; 25 import java.math.BigInteger; 26 import java.security.InvalidAlgorithmParameterException; 27 import java.security.KeyStore; 28 import java.security.KeyStoreException; 29 import java.security.NoSuchAlgorithmException; 30 import java.security.cert.CertPath; 31 import java.security.cert.CertPathBuilder; 32 import java.security.cert.CertPathBuilderException; 33 import java.security.cert.CertPathValidator; 34 import java.security.cert.CertPathValidatorException; 35 import java.security.cert.CertPathValidatorResult; 36 import java.security.cert.CertStore; 37 import java.security.cert.CertificateException; 38 import java.security.cert.CertificateFactory; 39 import java.security.cert.CollectionCertStoreParameters; 40 import java.security.cert.PKIXBuilderParameters; 41 import java.security.cert.PKIXCertPathBuilderResult; 42 import java.security.cert.PKIXCertPathValidatorResult; 43 import java.security.cert.PKIXParameters; 44 import java.security.cert.X509CertSelector; 45 import java.security.cert.X509Certificate; 46 import java.time.LocalDateTime; 47 import java.time.ZoneId; 48 import java.util.Base64; 49 import java.util.Date; 50 import java.util.List; 51 52 /** 53 * Check cert list is cert chain. 54 */ 55 public class CertChainUtils { 56 private static final Logger LOGGER = LogManager.getLogger(CertUtils.class); 57 CertChainUtils()58 private CertChainUtils() { 59 } 60 getCertPath(List<X509Certificate> certificates, KeyStore trustStore, X500Principal issuer, BigInteger serial)61 private static CertPath getCertPath(List<X509Certificate> certificates, KeyStore trustStore, X500Principal issuer, 62 BigInteger serial) throws KeyStoreException, InvalidAlgorithmParameterException, 63 NoSuchAlgorithmException, CertPathBuilderException, CertificateException { 64 if (certificates.size() != 1 && (issuer != null || serial != null)) { 65 X509CertSelector targetCertSelector = new X509CertSelector(); 66 targetCertSelector.setIssuer(issuer); 67 targetCertSelector.setSerialNumber(serial); 68 PKIXBuilderParameters params = new PKIXBuilderParameters(trustStore, targetCertSelector); 69 CertStore certStore = CertStore.getInstance("Collection", 70 new CollectionCertStoreParameters(certificates)); 71 params.addCertStore(certStore); 72 params.setDate(Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant())); 73 params.setRevocationEnabled(false); 74 CertPathBuilder certPathBuilder = CertPathBuilder.getInstance("PKIX"); 75 PKIXCertPathBuilderResult result = (PKIXCertPathBuilderResult) certPathBuilder.build(params); 76 return result.getCertPath(); 77 } else { 78 CertificateFactory factory = CertificateFactory.getInstance("X.509"); 79 return factory.generateCertPath(certificates); 80 } 81 } 82 83 84 /** 85 * Check cert list is cert chain. 86 * 87 * @param certificates cert list to be verified 88 * @param issuer issuer 89 * @param serial serial number 90 * @param root root cert 91 */ verifyCertChain(List<X509Certificate> certificates, X500Principal issuer, BigInteger serial, X509Certificate root)92 public static void verifyCertChain(List<X509Certificate> certificates, X500Principal issuer, BigInteger serial, 93 X509Certificate root) { 94 try { 95 KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); 96 trustStore.load(null, null); 97 trustStore.setCertificateEntry("root", root); 98 CertPath certPath = getCertPath(certificates, trustStore, issuer, serial); 99 PKIXParameters params = new PKIXParameters(trustStore); 100 params.setRevocationEnabled(false); 101 params.setDate(Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant())); 102 CertStore certStore = CertStore.getInstance("Collection", new CollectionCertStoreParameters()); 103 params.addCertStore(certStore); 104 CertPathValidator validator = CertPathValidator.getInstance("PKIX"); 105 CertPathValidatorResult validatorResult = validator.validate(certPath, params); 106 ValidateUtils.throwIfNotMatches(validatorResult instanceof PKIXCertPathValidatorResult, 107 ERROR.VERIFY_ERROR, "Validator result not target type"); 108 if (validatorResult instanceof PKIXCertPathValidatorResult) { 109 PKIXCertPathValidatorResult pkixValidatorResult = (PKIXCertPathValidatorResult) validatorResult; 110 ValidateUtils.throwIfNotMatches(params.getTrustAnchors().contains(pkixValidatorResult.getTrustAnchor()), 111 ERROR.VERIFY_ERROR, "Anchor is not trusted: " + Base64.getEncoder().encodeToString( 112 pkixValidatorResult.getTrustAnchor().getTrustedCert().getEncoded())); 113 } else { 114 CustomException.throwException(ERROR.VERIFY_ERROR, "Validator result not target type"); 115 } 116 } catch (InvalidAlgorithmParameterException | NoSuchAlgorithmException | IOException | CertificateException 117 | KeyStoreException | CertPathBuilderException | CertPathValidatorException exception) { 118 LOGGER.debug(exception.getMessage(), exception); 119 CustomException.throwException(ERROR.VERIFY_ERROR, "Failed to verify signature: " + exception.getMessage()); 120 } 121 } 122 } 123