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.datastructure; 17 18 import com.ohos.hapsigntool.codesigning.exception.FsVerityDigestException; 19 import com.ohos.hapsigntool.codesigning.exception.VerifyCodeSignException; 20 import com.ohos.hapsigntool.codesigning.fsverity.FsVerityDescriptor; 21 import com.ohos.hapsigntool.codesigning.fsverity.FsVerityDescriptorWithSign; 22 23 import java.nio.ByteBuffer; 24 import java.nio.ByteOrder; 25 26 /** 27 * elf sign block is a chunk of bytes attached to elf file. 28 * 1) u32 type: 0x2 merkle tree 29 * 2) u32 length: merkle tree with padding size 30 * 3) u8[] merkle tree data 31 * 4) u32 type: 0x1 fsverity descriptor 32 * 5) u32 length: fsverity descriptor size 33 * 6) u8 version: fs-verity version 34 * 7) u8 hashAlgorithm: hash algorithm to use for the Merkle tree 35 * 8) u8 log2BlockSize: log2 of size of data and tree blocks 36 * 9) u8 saltSize: byte size of salt 37 * 10) u32 signSize: byte size of signature 38 * 11) u64 dataSize: byte size of data being signed 39 * 12) u8[64] rootHash: merkle tree root hash 40 * 13) u8[32] salt: salt used in signing 41 * 14) u32 flags 42 * 15) u32 reserved 43 * 16) u64 treeOffset: merkle tree offset 44 * 17) u8[127] reserved 45 * 18) u8 csVersion: code sign version 46 * 19) u8[] signature: signature after signing the data in byte array representation 47 * 48 * @since 2023/09/08 49 */ 50 public class ElfSignBlock { 51 /** 52 * page size in bytes 53 */ 54 public static final int PAGE_SIZE_4K = 4096; 55 56 /** 57 * Type of MerkleTree 58 */ 59 public static final int MERKLE_TREE_INLINED = 0x2; 60 61 private int type = MERKLE_TREE_INLINED; 62 63 private int treeLength; 64 65 private byte[] merkleTreeWithPadding; 66 67 private FsVerityDescriptorWithSign descriptorWithSign; 68 69 /** 70 * Constructor of ElfSignBlock 71 * 72 * @param paddingSize padding size before merkle tree 73 * @param merkleTreeData merkle tree data 74 * @param descriptorWithSign FsVerityDescriptorWithSign object 75 */ ElfSignBlock(int paddingSize, byte[] merkleTreeData, FsVerityDescriptorWithSign descriptorWithSign)76 public ElfSignBlock(int paddingSize, byte[] merkleTreeData, FsVerityDescriptorWithSign descriptorWithSign) { 77 byte[] inMerkleTreeData = new byte[0]; 78 if (merkleTreeData != null) { 79 inMerkleTreeData = merkleTreeData; 80 } 81 this.treeLength = paddingSize + inMerkleTreeData.length; 82 this.merkleTreeWithPadding = new byte[this.treeLength]; 83 System.arraycopy(inMerkleTreeData, 0, merkleTreeWithPadding, paddingSize, inMerkleTreeData.length); 84 this.descriptorWithSign = descriptorWithSign; 85 } 86 ElfSignBlock(int type, int treeLength, byte[] merkleTreeWithPadding, FsVerityDescriptorWithSign descriptorWithSign)87 private ElfSignBlock(int type, int treeLength, byte[] merkleTreeWithPadding, 88 FsVerityDescriptorWithSign descriptorWithSign) { 89 this.type = type; 90 this.treeLength = treeLength; 91 this.merkleTreeWithPadding = merkleTreeWithPadding; 92 this.descriptorWithSign = descriptorWithSign; 93 } 94 95 /** 96 * Return the byte size of code sign block 97 * 98 * @return byte size of code sign block 99 */ size()100 public int size() { 101 return Integer.BYTES * 2 + merkleTreeWithPadding.length + descriptorWithSign.size(); 102 } 103 104 /** 105 * return padding length by the sign block offset 106 * 107 * @param signBlockOffset sign block offset based on the start of file 108 * @return merkle tree raw bytes offset based on the start of file 109 */ computeMerkleTreePaddingLength(long signBlockOffset)110 public static int computeMerkleTreePaddingLength(long signBlockOffset) { 111 return (int) (PAGE_SIZE_4K - (signBlockOffset + Integer.BYTES * 2) % PAGE_SIZE_4K) % PAGE_SIZE_4K; 112 } 113 getMerkleTreeWithPadding()114 public byte[] getMerkleTreeWithPadding() { 115 return merkleTreeWithPadding; 116 } 117 118 /** 119 * get DataSize 120 * 121 * @return DataSize 122 */ getDataSize()123 public long getDataSize() { 124 return descriptorWithSign.getFsVerityDescriptor().getFileSize(); 125 } 126 127 /** 128 * get TreeOffset 129 * 130 * @return TreeOffset 131 */ getTreeOffset()132 public long getTreeOffset() { 133 return descriptorWithSign.getFsVerityDescriptor().getMerkleTreeOffset(); 134 } 135 136 /** 137 * get Signature 138 * 139 * @return Signature 140 */ getSignature()141 public byte[] getSignature() { 142 return descriptorWithSign.getSignature(); 143 } 144 145 /** 146 * Return a string representation of the object 147 * 148 * @return string representation of the object 149 * @throws FsVerityDigestException if error 150 */ toByteArray()151 public byte[] toByteArray() throws FsVerityDigestException { 152 ByteBuffer bf = ByteBuffer.allocate(size()).order(ByteOrder.LITTLE_ENDIAN); 153 bf.putInt(type); 154 bf.putInt(merkleTreeWithPadding.length); 155 bf.put(merkleTreeWithPadding); 156 bf.put(descriptorWithSign.toByteArray()); 157 return bf.array(); 158 } 159 160 /** 161 * Init the ElfSignBlock by a byte array 162 * 163 * @param bytes Byte array representation of a ElfSignBlock object 164 * @return a newly created ElfSignBlock object 165 * @throws VerifyCodeSignException parse result invalid 166 */ fromByteArray(byte[] bytes)167 public static ElfSignBlock fromByteArray(byte[] bytes) throws VerifyCodeSignException { 168 ByteBuffer bf = ByteBuffer.allocate(bytes.length).order(ByteOrder.LITTLE_ENDIAN); 169 bf.put(bytes); 170 // after put, rewind is mandatory before get 171 bf.rewind(); 172 int inTreeType = bf.getInt(); 173 if (MERKLE_TREE_INLINED != inTreeType) { 174 throw new VerifyCodeSignException("Invalid merkle tree type of ElfSignBlock"); 175 } 176 int inTreeLength = bf.getInt(); 177 byte[] treeWithPadding = new byte[inTreeLength]; 178 bf.get(treeWithPadding); 179 int inFsdType = bf.getInt(); 180 if (FsVerityDescriptor.FS_VERITY_DESCRIPTOR_TYPE != inFsdType) { 181 throw new VerifyCodeSignException("Invalid fs-verify descriptor type of ElfSignBlock"); 182 } 183 int inFsdLength = bf.getInt(); 184 if (bytes.length != Integer.BYTES * 2 + inTreeLength + Integer.BYTES * 2 + inFsdLength) { 185 throw new VerifyCodeSignException("Invalid fs-verify descriptor with signature length of ElfSignBlock"); 186 } 187 byte[] fsdArray = new byte[FsVerityDescriptor.DESCRIPTOR_SIZE]; 188 bf.get(fsdArray); 189 FsVerityDescriptor fsd = FsVerityDescriptor.fromByteArray(fsdArray); 190 if (inFsdLength != fsd.getSignSize() + FsVerityDescriptor.DESCRIPTOR_SIZE) { 191 throw new VerifyCodeSignException("Invalid sign size of ElfSignBlock"); 192 } 193 byte[] inSignature = new byte[inFsdLength - FsVerityDescriptor.DESCRIPTOR_SIZE]; 194 bf.get(inSignature); 195 FsVerityDescriptorWithSign fsVerityDescriptorWithSign = new FsVerityDescriptorWithSign(inFsdType, inFsdLength, 196 fsd, inSignature); 197 return new ElfSignBlock(inTreeType, inTreeLength, treeWithPadding, fsVerityDescriptorWithSign); 198 } 199 } 200