• 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.VerifyCodeSignException;
19 
20 import java.nio.ByteBuffer;
21 import java.nio.ByteOrder;
22 import java.util.Locale;
23 
24 /**
25  * Code sign block header
26  * <p>
27  * Structure:
28  * 1) u64 magic: magic number
29  * 2) u32 version: sign tool version
30  * 3) u32 blockSize: size of code sign block
31  * 4) u32 segmentNum: number of segments, i.e. FsVerityInfoSegment, HapInfoSegment, SoInfoSegment
32  * 5) u32 flags
33  * 6) u8[8] reserved: for reservation
34  * <p>
35  * The Size of Code sign Block header if fixed, getBlockLength() method returns the size.
36  *
37  * @since 2023/09/08
38  */
39 public class CodeSignBlockHeader {
40     /**
41      * Flag indicating that merkle tree is included in code sign block
42      */
43     public static final int FLAG_MERKLE_TREE_INLINED = 0x1;
44 
45     /**
46      * Flag indicating that native lib is included in code sign block
47      */
48     public static final int FLAG_NATIVE_LIB_INCLUDED = 0x2;
49 
50     // code signing version
51     private static final int CODE_SIGNING_VERSION = 1;
52 
53     // byte size of magic number
54     private static final byte MAGIC_BYTE_ARRAY_LENGTH = Long.BYTES;
55 
56     // lower 8 bytes of MD5 result of string "hap code sign block" (E046 C8C6 5389 FCCD)
57     private static final long MAGIC_NUM = ((0xE046C8C6L << 32) + 0x5389FCCDL);
58 
59     // size of byte[8] reserved
60     private static final byte RESERVED_BYTE_ARRAY_LENGTH = 8;
61 
62     // At all times three segment are always included in code sign block, update this if new segments are created.
63     private static final int SEGMENT_NUM = 3;
64 
65     private long magic;
66 
67     private int version;
68 
69     private int blockSize;
70 
71     private int segmentNum;
72 
73     private int flags;
74 
75     private byte[] reserved;
76 
77     /**
78      * Construct of CodeSignBlockHeader
79      *
80      * @param builder builder
81      */
CodeSignBlockHeader(Builder builder)82     private CodeSignBlockHeader(Builder builder) {
83         this.magic = builder.magic;
84         this.version = builder.version;
85         this.blockSize = builder.blockSize;
86         this.segmentNum = builder.segmentNum;
87         this.flags = builder.flags;
88         this.reserved = builder.reserved;
89     }
90 
setSegmentNum(int num)91     public void setSegmentNum(int num) {
92         this.segmentNum = num;
93     }
94 
getSegmentNum()95     public int getSegmentNum() {
96         return segmentNum;
97     }
98 
setBlockSize(long size)99     public void setBlockSize(long size) {
100         this.blockSize = (int) size;
101     }
102 
getBlockSize()103     public int getBlockSize() {
104         return blockSize;
105     }
106 
setFlags(int flags)107     public void setFlags(int flags) {
108         this.flags = flags;
109     }
110 
111     /**
112      * Converts code sign block headers to a newly created byte array
113      *
114      * @return Byte array representation of a code sign block header
115      */
toByteArray()116     public byte[] toByteArray() {
117         ByteBuffer bf = ByteBuffer.allocate(size()).order(ByteOrder.LITTLE_ENDIAN);
118         bf.putLong(magic);
119         bf.putInt(version);
120         bf.putInt(blockSize);
121         bf.putInt(segmentNum);
122         bf.putInt(flags);
123         bf.put(reserved);
124         return bf.array();
125     }
126 
127     /**
128      * Init the CodeSignBlockHeader by a byte array
129      *
130      * @param bytes Byte array representation of a CodeSignBlockHeader object
131      * @return a newly created CodeSignBlockHeader object
132      * @throws VerifyCodeSignException parse result invalid
133      */
fromByteArray(byte[] bytes)134     public static CodeSignBlockHeader fromByteArray(byte[] bytes) throws VerifyCodeSignException {
135         if (bytes.length != size()) {
136             throw new VerifyCodeSignException("Invalid size of CodeSignBlockHeader");
137         }
138         ByteBuffer bf = ByteBuffer.allocate(bytes.length).order(ByteOrder.LITTLE_ENDIAN);
139         bf.put(bytes);
140         // after put, rewind is mandatory before get
141         bf.rewind();
142         long inMagic = bf.getLong();
143         if (inMagic != MAGIC_NUM) {
144             throw new VerifyCodeSignException("Invalid magic num of CodeSignBlockHeader");
145         }
146         int inVersion = bf.getInt();
147         if (inVersion != CODE_SIGNING_VERSION) {
148             throw new VerifyCodeSignException("Invalid version of CodeSignBlockHeader");
149         }
150         int inBlockSize = bf.getInt();
151         int inSegmentNum = bf.getInt();
152         if (inSegmentNum != SEGMENT_NUM) {
153             throw new VerifyCodeSignException("Invalid segmentNum of CodeSignBlockHeader");
154         }
155         int inFlags = bf.getInt();
156         if (inFlags < 0 || inFlags > (FLAG_MERKLE_TREE_INLINED + FLAG_NATIVE_LIB_INCLUDED)) {
157             throw new VerifyCodeSignException("Invalid flags of CodeSignBlockHeader");
158         }
159         byte[] inReserved = new byte[RESERVED_BYTE_ARRAY_LENGTH];
160         bf.get(inReserved);
161         return new Builder().setMagic(inMagic).setVersion(inVersion).setBlockSize(inBlockSize)
162             .setSegmentNum(inSegmentNum).setFlags(inFlags).setReserved(inReserved).build();
163     }
164 
165     /**
166      * Return the byte size of code sign block header
167      *
168      * @return byte size of code sign block header
169      */
size()170     public static int size() {
171         return MAGIC_BYTE_ARRAY_LENGTH + Integer.BYTES * 4 + RESERVED_BYTE_ARRAY_LENGTH;
172     }
173 
174     /**
175      * Return a string representation of the object
176      *
177      * @return string representation of the object
178      */
toString()179     public String toString() {
180         return String.format(Locale.ROOT,
181             "CodeSignBlockHeader{magic: %d, version: %d, blockSize: %d, segmentNum: %d, flags: %d}", this.magic,
182             this.version, this.blockSize, this.segmentNum, this.flags);
183     }
184 
185     /**
186      * Builder of CodeSignBlockHeader class
187      */
188     public static class Builder {
189         private long magic = MAGIC_NUM;
190 
191         private int version = CODE_SIGNING_VERSION;
192 
193         private int blockSize;
194 
195         private int segmentNum;
196 
197         private int flags;
198 
199         private byte[] reserved = new byte[RESERVED_BYTE_ARRAY_LENGTH];
200 
setMagic(long magic)201         public Builder setMagic(long magic) {
202             this.magic = magic;
203             return this;
204         }
205 
setVersion(int version)206         public Builder setVersion(int version) {
207             this.version = version;
208             return this;
209         }
210 
setBlockSize(int blockSize)211         public Builder setBlockSize(int blockSize) {
212             this.blockSize = blockSize;
213             return this;
214         }
215 
setSegmentNum(int segmentNum)216         public Builder setSegmentNum(int segmentNum) {
217             this.segmentNum = segmentNum;
218             return this;
219         }
220 
setFlags(int flags)221         public Builder setFlags(int flags) {
222             this.flags = flags;
223             return this;
224         }
225 
setReserved(byte[] reserved)226         public Builder setReserved(byte[] reserved) {
227             this.reserved = reserved;
228             return this;
229         }
230 
231         /**
232          * Create a CodeSignBlockHeader object
233          *
234          * @return a CodeSignBlockHeader object
235          */
build()236         public CodeSignBlockHeader build() {
237             return new CodeSignBlockHeader(this);
238         }
239     }
240 }
241