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