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