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.profile; 17 18 import com.ohos.hapsigntool.api.LocalizationAdapter; 19 import com.ohos.hapsigntool.error.CustomException; 20 import com.ohos.hapsigntool.error.ERROR; 21 import com.ohos.hapsigntool.profile.model.VerificationResult; 22 import com.ohos.hapsigntool.signer.ISigner; 23 import com.ohos.hapsigntool.signer.SignerFactory; 24 import com.ohos.hapsigntool.utils.ValidateUtils; 25 import org.apache.logging.log4j.LogManager; 26 import org.apache.logging.log4j.Logger; 27 import org.bouncycastle.asn1.ASN1EncodableVector; 28 import org.bouncycastle.asn1.ASN1Set; 29 import org.bouncycastle.asn1.BERSet; 30 import org.bouncycastle.asn1.DEROctetString; 31 import org.bouncycastle.asn1.DERSet; 32 import org.bouncycastle.asn1.cms.Attribute; 33 import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; 34 import org.bouncycastle.asn1.cms.ContentInfo; 35 import org.bouncycastle.asn1.cms.IssuerAndSerialNumber; 36 import org.bouncycastle.asn1.cms.SignedData; 37 import org.bouncycastle.asn1.cms.SignerIdentifier; 38 import org.bouncycastle.asn1.cms.SignerInfo; 39 import org.bouncycastle.asn1.cms.Time; 40 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; 41 import org.bouncycastle.asn1.x509.AlgorithmIdentifier; 42 import org.bouncycastle.cert.jcajce.JcaX509CRLHolder; 43 import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder; 44 import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder; 45 import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder; 46 import org.bouncycastle.operator.DigestCalculator; 47 import org.bouncycastle.operator.DigestCalculatorProvider; 48 import org.bouncycastle.operator.OperatorCreationException; 49 import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder; 50 51 import java.io.IOException; 52 import java.security.cert.CRLException; 53 import java.security.cert.CertificateEncodingException; 54 import java.security.cert.X509CRL; 55 import java.security.cert.X509Certificate; 56 import java.time.LocalDateTime; 57 import java.time.ZoneId; 58 import java.util.Date; 59 import java.util.List; 60 61 /** 62 * To sign and verify profile. 63 * 64 * @since 2021/12/28 65 */ 66 public final class ProfileSignTool { 67 /** 68 * Empty byte array. 69 */ 70 private static final byte[] NO_BYTE = {}; 71 72 /** 73 * logger 74 */ 75 private static final Logger LOGGER = LogManager.getLogger(ProfileSignTool.class); 76 ProfileSignTool()77 private ProfileSignTool() { 78 } 79 80 /** 81 * generateP7b. 82 * 83 * @param adapter local adapter with params 84 * @param content content to sign 85 * @return signed content 86 */ generateP7b(LocalizationAdapter adapter, byte[] content)87 public static byte[] generateP7b(LocalizationAdapter adapter, byte[] content) { 88 ISigner signer = new SignerFactory().getSigner(adapter); 89 byte[] p7b = signProfile(content, signer, adapter.getSignAlg()); 90 VerifyHelper verifyHelper = new VerifyHelper(); 91 VerificationResult verificationResult = verifyHelper.verify(p7b); 92 ValidateUtils.throwIfNotMatches(verificationResult.isVerifiedPassed(), ERROR.SIGN_ERROR, 93 verificationResult.getMessage()); 94 return p7b; 95 } 96 97 /** 98 * signProfile. 99 * 100 * @param content content to sign 101 * @param signer signer 102 * @param sigAlg sign algorithm 103 * @return signed data 104 */ signProfile(byte[] content, ISigner signer, String sigAlg)105 public static byte[] signProfile(byte[] content, ISigner signer, String sigAlg) { 106 try { 107 AlgorithmIdentifier sigAlgId = (new DefaultSignatureAlgorithmIdentifierFinder()).find(sigAlg); 108 ASN1EncodableVector digestAlgIds = new ASN1EncodableVector(); 109 AlgorithmIdentifier digestAlgId = (new DefaultDigestAlgorithmIdentifierFinder()).find(sigAlgId); 110 digestAlgIds.add(digestAlgId); 111 byte[] digest = getContentDigest(content, digestAlgId); 112 ASN1Set signedAttr = generatePKCS9Attributes(digest); 113 byte[] signature = signer.getSignature(signedAttr.getEncoded("DER"), sigAlg, null); 114 // To validate cert(public key) and private key 115 VerifyHelper.verifySignature(signer.getCertificates().get(0), signature, 116 signedAttr.getEncoded("DER"), sigAlg); 117 SignerIdentifier signerIdentifier = generateSignerIdentifier(signer.getCertificates().get(0)); 118 SignerInfo signerInfo = new SignerInfo(signerIdentifier, digestAlgId, signedAttr, sigAlgId, 119 new DEROctetString(signature), null); 120 ASN1EncodableVector signerInfos = new ASN1EncodableVector(); 121 signerInfos.add(signerInfo); 122 ASN1Set certList = createBerSetFromCerts(signer.getCertificates()); 123 List<X509CRL> crls = signer.getCrls(); 124 ASN1Set crlList = createBerSetFromCrls(crls); 125 ContentInfo encryptInfo = new ContentInfo(CMSObjectIdentifiers.data, new DEROctetString(content)); 126 SignedData sd = new SignedData(new DERSet(digestAlgIds), encryptInfo, certList, crlList, 127 new DERSet(signerInfos)); 128 ContentInfo contentInfo = new ContentInfo(CMSObjectIdentifiers.signedData, sd); 129 return contentInfo.getEncoded("DER"); 130 } catch (OperatorCreationException | IOException | CertificateEncodingException | CRLException e) { 131 LOGGER.debug(e.getMessage(), e); 132 CustomException.throwException(ERROR.SIGN_ERROR, e.getMessage()); 133 } 134 return NO_BYTE; 135 } 136 generateSignerIdentifier(X509Certificate certificate)137 private static SignerIdentifier generateSignerIdentifier(X509Certificate certificate) 138 throws CertificateEncodingException { 139 return new SignerIdentifier(new IssuerAndSerialNumber( 140 (new JcaX509CertificateHolder(certificate)).toASN1Structure())); 141 } 142 generatePKCS9Attributes(byte[] digest)143 private static ASN1Set generatePKCS9Attributes(byte[] digest) { 144 ASN1EncodableVector vector = new ASN1EncodableVector(); 145 Attribute signTime = new Attribute(PKCSObjectIdentifiers.pkcs_9_at_signingTime, 146 new DERSet(new Time(Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant())))); 147 Attribute contentType = new Attribute(PKCSObjectIdentifiers.pkcs_9_at_contentType, 148 new DERSet(PKCSObjectIdentifiers.data)); 149 Attribute digestAtt = new Attribute(PKCSObjectIdentifiers.pkcs_9_at_messageDigest, 150 new DERSet(new DEROctetString(digest))); 151 vector.add(signTime); 152 vector.add(contentType); 153 vector.add(digestAtt); 154 return new DERSet(vector); 155 } 156 getContentDigest(byte[] content, AlgorithmIdentifier digestAlgorithmIdentifier)157 private static byte[] getContentDigest(byte[] content, AlgorithmIdentifier digestAlgorithmIdentifier) 158 throws OperatorCreationException, IOException { 159 DigestCalculatorProvider digestCalculatorProvider = (new JcaDigestCalculatorProviderBuilder()).build(); 160 DigestCalculator digestCalculator = digestCalculatorProvider.get(digestAlgorithmIdentifier); 161 digestCalculator.getOutputStream().write(content); 162 return digestCalculator.getDigest(); 163 } 164 createBerSetFromCrls(List<X509CRL> crls)165 private static ASN1Set createBerSetFromCrls(List<X509CRL> crls) throws CRLException { 166 if (crls != null && crls.size() != 0) { 167 ASN1EncodableVector vector = new ASN1EncodableVector(crls.size()); 168 for (X509CRL crl : crls) { 169 vector.add((new JcaX509CRLHolder(crl)).toASN1Structure()); 170 } 171 return new BERSet(vector); 172 } else { 173 return null; 174 } 175 } 176 createBerSetFromCerts(List<X509Certificate> certs)177 private static ASN1Set createBerSetFromCerts(List<X509Certificate> certs) throws CertificateEncodingException { 178 if (certs != null && certs.size() != 0) { 179 ASN1EncodableVector vector = new ASN1EncodableVector(certs.size()); 180 for (X509Certificate cert : certs) { 181 vector.add((new JcaX509CertificateHolder(cert)).toASN1Structure()); 182 } 183 return new BERSet(vector); 184 } else { 185 return null; 186 } 187 } 188 } 189