• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.sign;
17 
18 import com.ohos.hapsigntool.codesigning.datastructure.CodeSignBlock;
19 import com.ohos.hapsigntool.codesigning.datastructure.ElfSignBlock;
20 import com.ohos.hapsigntool.codesigning.datastructure.Extension;
21 import com.ohos.hapsigntool.codesigning.datastructure.FsVerityInfoSegment;
22 import com.ohos.hapsigntool.codesigning.datastructure.MerkleTreeExtension;
23 import com.ohos.hapsigntool.codesigning.datastructure.PageInfoExtension;
24 import com.ohos.hapsigntool.codesigning.datastructure.SignInfo;
25 import com.ohos.hapsigntool.codesigning.elf.ElfHeader;
26 import com.ohos.hapsigntool.codesigning.exception.CodeSignErrMsg;
27 import com.ohos.hapsigntool.codesigning.exception.CodeSignException;
28 import com.ohos.hapsigntool.codesigning.exception.FsVerityDigestException;
29 import com.ohos.hapsigntool.codesigning.exception.PageInfoException;
30 import com.ohos.hapsigntool.codesigning.fsverity.FsVerityDescriptor;
31 import com.ohos.hapsigntool.codesigning.fsverity.FsVerityDescriptorWithSign;
32 import com.ohos.hapsigntool.codesigning.fsverity.FsVerityGenerator;
33 import com.ohos.hapsigntool.codesigning.utils.HapUtils;
34 import com.ohos.hapsigntool.codesigning.utils.NumberUtils;
35 import com.ohos.hapsigntool.entity.Pair;
36 import com.ohos.hapsigntool.error.HapFormatException;
37 import com.ohos.hapsigntool.error.ProfileException;
38 import com.ohos.hapsigntool.hap.config.SignerConfig;
39 import com.ohos.hapsigntool.signer.LocalSigner;
40 import com.ohos.hapsigntool.utils.FileUtils;
41 import com.ohos.hapsigntool.utils.LogUtils;
42 import com.ohos.hapsigntool.utils.StringUtils;
43 import com.ohos.hapsigntool.zip.EntryType;
44 import com.ohos.hapsigntool.zip.Zip;
45 import com.ohos.hapsigntool.zip.ZipEntry;
46 import com.ohos.hapsigntool.zip.ZipEntryHeader;
47 
48 import java.io.File;
49 import java.io.FileInputStream;
50 import java.io.FileOutputStream;
51 import java.io.IOException;
52 import java.io.InputStream;
53 import java.util.ArrayList;
54 import java.util.Enumeration;
55 import java.util.List;
56 import java.util.Locale;
57 import java.util.Map;
58 import java.util.jar.JarEntry;
59 import java.util.jar.JarFile;
60 import java.util.stream.Collectors;
61 
62 /**
63  * core functions of code signing
64  *
65  * @since 2023/06/05
66  */
67 public class CodeSigning {
68     /**
69      * Only hap and hsp, hqf bundle supports code signing
70      */
71     public static final String[] SUPPORT_FILE_FORM = {"hap", "hsp", "hqf"};
72 
73     /**
74      * Only elf file supports bin code signing
75      */
76     public static final String SUPPORT_BIN_FILE_FORM = "elf";
77 
78     /**
79      * Defined entry name of hap file
80      */
81     public static final String HAP_SIGNATURE_ENTRY_NAME = "Hap";
82 
83     private static final LogUtils LOGGER = new LogUtils(CodeSigning.class);
84 
85     private final SignerConfig signConfig;
86 
87     private CodeSignBlock codeSignBlock;
88 
89     private PageInfoExtension pageInfoExtension;
90 
91     /**
92      * provide code sign functions to sign a hap
93      *
94      * @param signConfig configuration of sign
95      */
CodeSigning(SignerConfig signConfig)96     public CodeSigning(SignerConfig signConfig) {
97         this.signConfig = signConfig;
98     }
99 
100     /**
101      * Sign the given elf file, and pack all signature into output file
102      *
103      * @param input  file to sign
104      * @param offset position of codesign block based on start of the file
105      * @param inForm file's format
106      * @param profileContent profile of the elf
107      * @return byte array of code sign block
108      * @throws CodeSignException        code signing exception
109      * @throws IOException              io error
110      * @throws FsVerityDigestException  computing FsVerity digest error
111      * @throws ProfileException         profile of elf is invalid
112      */
getElfCodeSignBlock(File input, long offset, String inForm, String profileContent)113     public byte[] getElfCodeSignBlock(File input, long offset, String inForm, String profileContent)
114         throws CodeSignException, FsVerityDigestException, IOException, ProfileException {
115         LOGGER.info("Start to sign code.");
116         if (!SUPPORT_BIN_FILE_FORM.equalsIgnoreCase(inForm)) {
117             throw new CodeSignException(CodeSignErrMsg.FILE_FORMAT_UNSUPPORTED_ERROR.toString(SUPPORT_BIN_FILE_FORM));
118         }
119         long fileSize = input.length();
120         int paddingSize = ElfSignBlock.computeMerkleTreePaddingLength(offset);
121         long fsvTreeOffset = offset + Integer.BYTES * 2 + paddingSize;
122         try (FileInputStream inputStream = new FileInputStream(input)) {
123             FsVerityGenerator fsVerityGenerator = new FsVerityGenerator();
124             fsVerityGenerator.generateFsVerityDigest(inputStream, fileSize, fsvTreeOffset);
125             byte[] fsVerityDigest = fsVerityGenerator.getFsVerityDigest();
126             // ownerID should be DEBUG_LIB_ID while signing ELF
127             String ownerID = (profileContent == null)
128                 ? HapUtils.HAP_DEBUG_OWNER_ID
129                 : HapUtils.getAppIdentifier(profileContent);
130             byte[] signature = generateSignature(fsVerityDigest, ownerID);
131             // add fs-verify info
132             FsVerityDescriptor.Builder fsdbuilder = new FsVerityDescriptor.Builder().setFileSize(fileSize)
133                 .setHashAlgorithm(FsVerityGenerator.getFsVerityHashAlgorithm())
134                 .setLog2BlockSize(FsVerityGenerator.getLog2BlockSize())
135                 .setSaltSize((byte) fsVerityGenerator.getSaltSize())
136                 .setSignSize(signature.length)
137                 .setFileSize(fileSize)
138                 .setSalt(fsVerityGenerator.getSalt())
139                 .setRawRootHash(fsVerityGenerator.getRootHash())
140                 .setFlags(FsVerityDescriptor.FLAG_STORE_MERKLE_TREE_OFFSET)
141                 .setMerkleTreeOffset(fsvTreeOffset)
142                 .setCsVersion(FsVerityDescriptor.CODE_SIGN_VERSION);
143             FsVerityDescriptorWithSign fsVerityDescriptorWithSign = new FsVerityDescriptorWithSign(fsdbuilder.build(),
144                 signature);
145             byte[] treeBytes = fsVerityGenerator.getTreeBytes();
146             ElfSignBlock signBlock = new ElfSignBlock(paddingSize, treeBytes, fsVerityDescriptorWithSign);
147             LOGGER.info("Sign elf successfully.");
148             return signBlock.toByteArray();
149         } catch (PageInfoException e) {
150             throw new CodeSignException(e.getMessage());
151         }
152     }
153 
154     /**
155      * Sign the given hap file, and pack all signature into output file
156      *
157      * @param input  file to sign
158      * @param offset position of codesign block based on start of the file
159      * @param inForm file's format
160      * @param profileContent profile of the hap
161      * @param zip zip
162      * @return byte array of code sign block
163      * @throws CodeSignException        code signing exception
164      * @throws IOException              io error
165      * @throws HapFormatException       hap format invalid
166      * @throws FsVerityDigestException  computing FsVerity digest error
167      * @throws ProfileException         profile of the hap error
168      */
getCodeSignBlock(File input, long offset, String inForm, String profileContent, Zip zip)169     public byte[] getCodeSignBlock(File input, long offset, String inForm, String profileContent, Zip zip)
170         throws CodeSignException, IOException, HapFormatException, FsVerityDigestException, ProfileException {
171         LOGGER.info("Start to sign code.");
172         if (!StringUtils.containsIgnoreCase(SUPPORT_FILE_FORM, inForm)) {
173             throw new CodeSignException(
174                 CodeSignErrMsg.FILE_FORMAT_UNSUPPORTED_ERROR.toString(String.join(",", SUPPORT_FILE_FORM)));
175         }
176         long dataSize = computeDataSize(zip);
177         // generate CodeSignBlock
178         this.codeSignBlock = new CodeSignBlock();
179         // compute merkle tree offset, replace with computeMerkleTreeOffset if fs-verity descriptor supports
180         long fsvTreeOffset = this.codeSignBlock.computeMerkleTreeOffset(offset);
181         // update fs-verity segment
182         FsVerityInfoSegment fsVerityInfoSegment = new FsVerityInfoSegment(FsVerityDescriptor.VERSION,
183             FsVerityGenerator.getFsVerityHashAlgorithm(), FsVerityGenerator.getLog2BlockSize());
184         this.codeSignBlock.setFsVerityInfoSegment(fsVerityInfoSegment);
185 
186         LOGGER.debug("Sign hap.");
187         String ownerID = HapUtils.getAppIdentifier(profileContent);
188         try (FileInputStream inputStream = new FileInputStream(input)) {
189             Pair<SignInfo, byte[]> hapSignInfoAndMerkleTreeBytesPair = signFile(inputStream, dataSize, true,
190                 fsvTreeOffset, ownerID);
191             // update hap segment in CodeSignBlock
192             this.codeSignBlock.getHapInfoSegment().setSignInfo(hapSignInfoAndMerkleTreeBytesPair.getFirst());
193             // Insert merkle tree bytes into code sign block
194             this.codeSignBlock.addOneMerkleTree(HAP_SIGNATURE_ENTRY_NAME,
195                 hapSignInfoAndMerkleTreeBytesPair.getSecond());
196         }
197         // update native lib info segment in CodeSignBlock
198         List<Pair<String, SignInfo>> nativeLibInfoList = new ArrayList<>();
199         nativeLibInfoList.addAll(signNativeLibs(input, ownerID));
200         nativeLibInfoList.addAll(signNativeHnps(input, profileContent, ownerID));
201         // update SoInfoSegment in CodeSignBlock
202         this.codeSignBlock.getSoInfoSegment().setSoInfoList(nativeLibInfoList);
203 
204         // last update codeSignBlock before generating its byte array representation
205         updateCodeSignBlock(this.codeSignBlock);
206 
207         // complete code sign block byte array here
208         byte[] generated = this.codeSignBlock.generateCodeSignBlockByte(fsvTreeOffset);
209         LOGGER.info("Sign successfully.");
210         return generated;
211     }
212 
createPageInfoExtension(ZipEntry entry)213     private void createPageInfoExtension(ZipEntry entry) {
214         long bitmapOff = entry.getCentralDirectory().getOffset() + ZipEntryHeader.HEADER_LENGTH
215             + entry.getZipEntryData().getZipEntryHeader().getFileNameLength() + entry.getZipEntryData()
216             .getZipEntryHeader()
217             .getExtraLength();
218         long bitmapSize = bitmapOff / CodeSignBlock.PAGE_SIZE_4K * PageInfoExtension.DEFAULT_UNIT_SIZE;
219         pageInfoExtension = new PageInfoExtension(bitmapOff, bitmapSize);
220     }
221 
computeDataSize(Zip zip)222     private long computeDataSize(Zip zip) throws HapFormatException {
223         long dataSize = 0L;
224         for (ZipEntry entry : zip.getZipEntries()) {
225             ZipEntryHeader zipEntryHeader = entry.getZipEntryData().getZipEntryHeader();
226             EntryType type = entry.getZipEntryData().getType();
227             short method = zipEntryHeader.getMethod();
228             if ((EntryType.RUNNABLE_FILE.equals(type) && method == Zip.FILE_UNCOMPRESS_METHOD_FLAG)) {
229                 continue;
230             }
231             if (EntryType.BIT_MAP.equals(type)) {
232                 createPageInfoExtension(entry);
233                 continue;
234             }
235             // if the first file is not uncompressed abc or so, set dataSize to zero
236             if (entry.getCentralDirectory().getOffset() == 0) {
237                 break;
238             }
239             // the first entry which is not abc/so/an is found, return its data offset
240             dataSize = entry.getCentralDirectory().getOffset() + ZipEntryHeader.HEADER_LENGTH
241                     + zipEntryHeader.getFileNameLength() + zipEntryHeader.getExtraLength();
242             break;
243         }
244         if (!NumberUtils.isMultiple4K(dataSize)) {
245             throw new HapFormatException(CodeSignErrMsg.FILE_4K_ALIGNMENT_ERROR.toString(dataSize));
246         }
247         return dataSize;
248     }
249 
signNativeLibs(File input, String ownerID)250     private List<Pair<String, SignInfo>> signNativeLibs(File input, String ownerID)
251         throws IOException, FsVerityDigestException, CodeSignException {
252         // sign native files
253         try (JarFile inputJar = new JarFile(input, false)) {
254             List<String> entryNames = getNativeEntriesFromHap(inputJar);
255             if (entryNames.isEmpty()) {
256                 LOGGER.info("No native libs.");
257                 return new ArrayList<>();
258             }
259             return signFilesFromJar(entryNames, inputJar, ownerID);
260         }
261     }
262 
signNativeHnps(File input, String profileContent, String ownerID)263     private List<Pair<String, SignInfo>> signNativeHnps(File input, String profileContent, String ownerID)
264         throws IOException, CodeSignException, ProfileException {
265         List<Pair<String, SignInfo>> nativeLibInfoList = new ArrayList<>();
266         try (JarFile inputJar = new JarFile(input, false)) {
267             Map<String, String> hnpTypeMap = HapUtils.getHnpsFromJson(inputJar);
268             // get hnp entry
269             for (Enumeration<JarEntry> e = inputJar.entries(); e.hasMoreElements(); ) {
270                 JarEntry entry = e.nextElement();
271                 String entryName = entry.getName();
272                 if (entry.isDirectory() || !entryName.startsWith("hnp/") || !entryName.toLowerCase(Locale.ROOT)
273                     .endsWith(".hnp")) {
274                     continue;
275                 }
276                 String hnpFileName = HapUtils.parseHnpPath(entryName);
277                 if (!hnpTypeMap.containsKey(hnpFileName)) {
278                     throw new CodeSignException(CodeSignErrMsg.HNP_FILE_DESCRIPTION_ERROR.toString(entryName));
279                 }
280                 LOGGER.debug("Sign hnp name = {}", entryName);
281                 String type = hnpTypeMap.get(hnpFileName);
282                 String hnpOwnerId = ownerID;
283                 if ("public".equals(type)) {
284                     hnpOwnerId = HapUtils.getPublicHnpOwnerId(profileContent);
285                 }
286                 nativeLibInfoList.addAll(signHnpLibs(inputJar, entry, hnpOwnerId));
287             }
288         }
289         return nativeLibInfoList;
290     }
291 
signHnpLibs(JarFile inputJar, JarEntry hnpEntry, String ownerID)292     private List<Pair<String, SignInfo>> signHnpLibs(JarFile inputJar, JarEntry hnpEntry, String ownerID)
293         throws IOException, CodeSignException {
294         File tempHnp = File.createTempFile("tmp-", ".hnp");
295         writeTempHnpFile(inputJar, hnpEntry, tempHnp);
296         if (!tempHnp.exists() || tempHnp.length() == 0) {
297             throw new CodeSignException(CodeSignErrMsg.EXTRACT_HNP_FILE_ERROR.toString(hnpEntry.getName()));
298         }
299         try (JarFile hnp = new JarFile(tempHnp, false)) {
300             List<JarEntry> elfEntries = getHnpLibEntries(hnp);
301             LOGGER.debug("{} elf num : {}", hnpEntry.getName(), elfEntries.size());
302             List<Pair<String, SignInfo>> nativeLibInfoList = elfEntries.stream().parallel().map(entry -> {
303                 String hnpElfPath = hnpEntry.getName() + "!/" + entry.getName();
304                 try (InputStream inputStream = hnp.getInputStream(entry)) {
305                     // We don't store merkle tree in code signing of native libs
306                     // Therefore, the second value of pair returned is ignored
307                     Pair<SignInfo, byte[]> pairSignInfoAndMerkleTreeBytes = signFile(inputStream, entry.getSize(),
308                         false, 0, ownerID);
309                     return (Pair.create(hnpElfPath, pairSignInfoAndMerkleTreeBytes.getFirst()));
310                 } catch (IOException | FsVerityDigestException | CodeSignException e) {
311                     LOGGER.error("Sign hnp lib error msg : {} AT entry : {}" + System.lineSeparator(), e.getMessage(),
312                         hnpElfPath);
313                 }
314                 return null;
315             }).collect(Collectors.toList());
316             if (nativeLibInfoList.contains(null)) {
317                 throw new CodeSignException("Sign hnp lib error");
318             }
319             return nativeLibInfoList;
320         } catch (IOException e) {
321             throw new CodeSignException(CodeSignErrMsg.EXTRACT_HNP_FILE_ERROR.toString(hnpEntry.getName()), e);
322         } finally {
323             if (tempHnp.exists()) {
324                 if (tempHnp.delete()) {
325                     LOGGER.debug("delete temp hnp file {}", tempHnp.getName());
326                 } else {
327                     LOGGER.error("delete temp hnp file error {}", tempHnp.getName());
328                 }
329             }
330         }
331     }
332 
getHnpLibEntries(JarFile hnp)333     private List<JarEntry> getHnpLibEntries(JarFile hnp) throws IOException {
334         List<JarEntry> elfEntries = new ArrayList<>();
335         for (Enumeration<JarEntry> e = hnp.entries(); e.hasMoreElements(); ) {
336             JarEntry entry = e.nextElement();
337             try (InputStream inputStream = hnp.getInputStream(entry)) {
338                 byte[] bytes = new byte[4];
339                 inputStream.read(bytes);
340                 if (ElfHeader.isElfFile(bytes)) {
341                     elfEntries.add(entry);
342                 }
343             }
344         }
345         return elfEntries;
346     }
347 
writeTempHnpFile(JarFile inputJar, JarEntry hnpEntry, File tempHnp)348     private void writeTempHnpFile(JarFile inputJar, JarEntry hnpEntry, File tempHnp) {
349         try (InputStream inputStream = inputJar.getInputStream(hnpEntry);
350             FileOutputStream fos = new FileOutputStream(tempHnp)) {
351             int read;
352             // buffered 64k
353             byte[] bytes = new byte[1024 * 64];
354             while ((read = inputStream.read(bytes)) != -1) {
355                 fos.write(bytes, 0, read);
356             }
357         } catch (IOException e) {
358             LOGGER.error("write temp hnp file error ", e);
359         }
360     }
361 
362     /**
363      * Get entry name of all native files in hap
364      *
365      * @param hap the given hap
366      * @return list of entry name
367      */
getNativeEntriesFromHap(JarFile hap)368     private List<String> getNativeEntriesFromHap(JarFile hap) {
369         List<String> result = new ArrayList<>();
370         for (Enumeration<JarEntry> e = hap.entries(); e.hasMoreElements();) {
371             JarEntry entry = e.nextElement();
372             if (!entry.isDirectory()) {
373                 if (!isNativeFile(entry.getName())) {
374                     continue;
375                 }
376                 result.add(entry.getName());
377             }
378         }
379         return result;
380     }
381 
382     /**
383      * Check whether the entry is a native file
384      *
385      * @param entryName the name of entry
386      * @return true if it is a native file, and false otherwise
387      */
isNativeFile(String entryName)388     private boolean isNativeFile(String entryName) {
389         if (StringUtils.isEmpty(entryName)) {
390             return false;
391         }
392         if (entryName.endsWith(FileUtils.NATIVE_LIB_AN_SUFFIX)) {
393             return true;
394         }
395         if (entryName.startsWith(FileUtils.LIBS_PATH_PREFIX)) {
396             return true;
397         }
398         return false;
399     }
400 
401     /**
402      * Sign specific entries in a hap
403      *
404      * @param entryNames list of entries which need to be signed
405      * @param hap        input hap
406      * @param ownerID    app-id in signature to identify
407      * @return sign info and merkle tree of each file
408      * @throws CodeSignException       sign error
409      */
signFilesFromJar(List<String> entryNames, JarFile hap, String ownerID)410     private List<Pair<String, SignInfo>> signFilesFromJar(List<String> entryNames, JarFile hap, String ownerID)
411         throws CodeSignException {
412         List<Pair<String, SignInfo>> nativeLibInfoList = entryNames.stream().parallel().map(name -> {
413             LOGGER.debug("Sign entry name = {}", name);
414             JarEntry inEntry = hap.getJarEntry(name);
415             try (InputStream inputStream = hap.getInputStream(inEntry)) {
416                 long fileSize = inEntry.getSize();
417                 // We don't store merkle tree in code signing of native libs
418                 // Therefore, the second value of pair returned is ignored
419                 Pair<SignInfo, byte[]> pairSignInfoAndMerkleTreeBytes = signFile(inputStream, fileSize, false, 0,
420                     ownerID);
421                 return Pair.create(name, pairSignInfoAndMerkleTreeBytes.getFirst());
422             } catch (FsVerityDigestException | CodeSignException | IOException e) {
423                 LOGGER.error("Sign lib error msg : {} AT entry : {}" + System.lineSeparator(), e.getMessage(), name);
424             }
425             return null;
426         }).collect(Collectors.toList());
427         if (nativeLibInfoList.contains(null)) {
428             throw new CodeSignException("Sign lib error");
429         }
430         return nativeLibInfoList;
431     }
432 
433     /**
434      * Sign a file from input stream
435      *
436      * @param inputStream   input stream of a file
437      * @param fileSize      size of the file
438      * @param storeTree     whether to store merkle tree in signed info
439      * @param fsvTreeOffset merkle tree raw bytes offset based on the start of file
440      * @param ownerID       app-id in signature to identify
441      * @return pair of signature and tree
442      * @throws FsVerityDigestException computing FsVerity Digest error
443      * @throws CodeSignException       signing error
444      */
signFile(InputStream inputStream, long fileSize, boolean storeTree, long fsvTreeOffset, String ownerID)445     public Pair<SignInfo, byte[]> signFile(InputStream inputStream, long fileSize, boolean storeTree,
446         long fsvTreeOffset, String ownerID) throws FsVerityDigestException, CodeSignException {
447         FsVerityGenerator fsVerityGenerator = new FsVerityGenerator();
448         fsVerityGenerator.setPageInfoExtension(pageInfoExtension);
449         try {
450             fsVerityGenerator.generateFsVerityDigest(inputStream, fileSize, fsvTreeOffset);
451         } catch (PageInfoException e) {
452             throw new CodeSignException(e.getMessage());
453         }
454         byte[] fsVerityDigest = fsVerityGenerator.getFsVerityDigest();
455         byte[] signature = generateSignature(fsVerityDigest, ownerID);
456         int flags = 0;
457         if (storeTree) {
458             flags = SignInfo.FLAG_MERKLE_TREE_INCLUDED;
459         }
460         SignInfo signInfo = new SignInfo(fsVerityGenerator.getSaltSize(), flags, fileSize, fsVerityGenerator.getSalt(),
461             signature);
462         // if store merkle tree in sign info
463         if (storeTree) {
464             int merkleTreeSize = fsVerityGenerator.getTreeBytes() == null ? 0 : fsVerityGenerator.getTreeBytes().length;
465             Extension merkleTreeExtension = new MerkleTreeExtension(merkleTreeSize, fsvTreeOffset,
466                 fsVerityGenerator.getRootHash());
467             signInfo.addExtension(merkleTreeExtension);
468             if (pageInfoExtension != null) {
469                 byte[] fsVerityDigestV2 = fsVerityGenerator.getFsVerityDigestV2();
470                 byte[] signatureV2 = generateSignature(fsVerityDigestV2, ownerID);
471                 pageInfoExtension.setSignature(signatureV2);
472                 signInfo.addExtension(pageInfoExtension);
473                 LOGGER.debug(pageInfoExtension.toString());
474             }
475         }
476         return Pair.create(signInfo, fsVerityGenerator.getTreeBytes());
477     }
478 
generateSignature(byte[] signedData, String ownerID)479     private byte[] generateSignature(byte[] signedData, String ownerID) throws CodeSignException {
480         SignerConfig copiedConfig = signConfig;
481         // signConfig is created by SignerFactory
482         if ((copiedConfig.getSigner() instanceof LocalSigner)) {
483             if (copiedConfig.getCertificates().isEmpty()) {
484                 throw new CodeSignException(
485                     CodeSignErrMsg.CERTIFICATES_CONFIGURE_ERROR.toString("No certificate is configured for sign"));
486             }
487             BcSignedDataGenerator bcSignedDataGenerator = new BcSignedDataGenerator();
488             bcSignedDataGenerator.setOwnerID(ownerID);
489             return bcSignedDataGenerator.generateSignedData(signedData, copiedConfig);
490         } else {
491             copiedConfig = signConfig.copy();
492             BcSignedDataGenerator bcSignedDataGenerator = new BcSignedDataGenerator();
493             bcSignedDataGenerator.setOwnerID(ownerID);
494             return bcSignedDataGenerator.generateSignedData(signedData, copiedConfig);
495         }
496     }
497 
498     /**
499      * At here, segment header, fsverity info/hap/so info segment, merkle tree
500      * segment should all be generated.
501      * code sign block size, segment number, offset is not updated.
502      * Try to update whatever could be updated here.
503      *
504      * @param codeSignBlock CodeSignBlock
505      */
updateCodeSignBlock(CodeSignBlock codeSignBlock)506     private void updateCodeSignBlock(CodeSignBlock codeSignBlock) {
507         // construct segment header list
508         codeSignBlock.setSegmentHeaders();
509         // Compute and set segment number
510         codeSignBlock.setSegmentNum();
511         // update code sign block header flag
512         codeSignBlock.setCodeSignBlockFlag();
513         // compute segment offset
514         codeSignBlock.computeSegmentOffset();
515     }
516 
517 }
518