• 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.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