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