1 /* 2 * Copyright (c) 2023-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.codesigning.utils; 17 18 import com.ohos.hapsigntool.codesigning.exception.CodeSignErrMsg; 19 20 import org.bouncycastle.cert.X509CertificateHolder; 21 import org.bouncycastle.cms.CMSException; 22 import org.bouncycastle.cms.CMSProcessableByteArray; 23 import org.bouncycastle.cms.CMSSignedData; 24 import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder; 25 import org.bouncycastle.jce.provider.BouncyCastleProvider; 26 import org.bouncycastle.operator.OperatorCreationException; 27 28 import java.security.Security; 29 import java.security.cert.CertificateException; 30 import java.util.Collection; 31 32 /** 33 * CMS utils class 34 * 35 * @since 2023/06/05 36 */ 37 public class CmsUtils { 38 static { 39 if (Security.getProvider("BC") == null) { Security.addProvider(new BouncyCastleProvider())40 Security.addProvider(new BouncyCastleProvider()); 41 } 42 } 43 44 /** 45 * Private constructor 46 */ CmsUtils()47 private CmsUtils() { 48 } 49 isCollectionValid(Collection<X509CertificateHolder> collection)50 private static void isCollectionValid(Collection<X509CertificateHolder> collection) 51 throws OperatorCreationException { 52 if (collection == null) { 53 throw new OperatorCreationException( 54 CodeSignErrMsg.CODE_SIGN_INTERNAL_ERROR.toString("No matched cert")); 55 } 56 if (collection.size() != 1) { 57 throw new OperatorCreationException(CodeSignErrMsg.CODE_SIGN_INTERNAL_ERROR.toString( 58 "More than one matched certs, matched certs size: " + collection.size())); 59 } 60 } 61 62 @SuppressWarnings("unchecked") verifyCmsSignedData(CMSSignedData cmsSignedData)63 private static boolean verifyCmsSignedData(CMSSignedData cmsSignedData) throws CMSException { 64 return cmsSignedData.verifySignatures(signId -> { 65 Collection<X509CertificateHolder> collection = cmsSignedData.getCertificates().getMatches(signId); 66 isCollectionValid(collection); 67 X509CertificateHolder cert = collection.iterator().next(); 68 try { 69 return new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert); 70 } catch (CertificateException e) { 71 throw new OperatorCreationException( 72 CodeSignErrMsg.CODE_SIGN_INTERNAL_ERROR.toString("Verify BC signatures failed: " + e.getMessage()), 73 e); 74 } 75 }); 76 } 77 78 /** 79 * Verify signed data using an unsigned data digest 80 * 81 * @param unsignedDataDigest unsigned data digest 82 * @param signedData signed data 83 * @return true if verify success 84 * @throws CMSException if error 85 */ verifySignDataWithUnsignedDataDigest(byte[] unsignedDataDigest, byte[] signedData)86 public static boolean verifySignDataWithUnsignedDataDigest(byte[] unsignedDataDigest, byte[] signedData) 87 throws CMSException { 88 CMSSignedData cmsSignedData = new CMSSignedData(new CMSProcessableByteArray(unsignedDataDigest), signedData); 89 return verifyCmsSignedData(cmsSignedData); 90 } 91 } 92