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 * segment header has three field: 26 * <p> 27 * u32 type: indicates the type of segment: fs-verity/so/hap info segment 28 * <p> 29 * u32 segment offset: the segment position based on the start of code sign block 30 * <p> 31 * u32 segment size: byte size of the segment 32 * 33 * @since 2023/09/08 34 */ 35 public class SegmentHeader { 36 /** 37 * Byte size of SegmentHeader 38 */ 39 public static final int SEGMENT_HEADER_LENGTH = 12; 40 41 /** 42 * Fs-verity segment type 43 */ 44 public static final int CSB_FSVERITY_INFO_SEG = 0x1; 45 46 /** 47 * Hap info segment type 48 */ 49 public static final int CSB_HAP_META_SEG = 0x2; 50 51 /** 52 * So info segment type 53 */ 54 public static final int CSB_NATIVE_LIB_INFO_SEG = 0x3; 55 56 private final int type; 57 58 private int segmentOffset; 59 60 private final int segmentSize; 61 62 /** 63 * Constructor for SegmentHeader 64 * 65 * @param type segment type 66 * @param segmentSize byte size of the segment 67 */ SegmentHeader(int type, int segmentSize)68 public SegmentHeader(int type, int segmentSize) { 69 this(type, 0, segmentSize); 70 } 71 72 /** 73 * Constructor for SegmentHeader 74 * 75 * @param type segment type 76 * @param segmentOffset segment offset based on the start of code sign block 77 * @param segmentSize byte size of segment 78 */ SegmentHeader(int type, int segmentOffset, int segmentSize)79 public SegmentHeader(int type, int segmentOffset, int segmentSize) { 80 this.type = type; 81 this.segmentOffset = segmentOffset; 82 this.segmentSize = segmentSize; 83 } 84 getType()85 public int getType() { 86 return type; 87 } 88 setSegmentOffset(int offset)89 public void setSegmentOffset(int offset) { 90 this.segmentOffset = offset; 91 } 92 getSegmentOffset()93 public int getSegmentOffset() { 94 return segmentOffset; 95 } 96 getSegmentSize()97 public int getSegmentSize() { 98 return segmentSize; 99 } 100 101 /** 102 * Converts SegmentHeader to a newly created byte array 103 * 104 * @return Byte array representation of SegmentHeader 105 */ toByteArray()106 public byte[] toByteArray() { 107 ByteBuffer bf = ByteBuffer.allocate(SEGMENT_HEADER_LENGTH).order(ByteOrder.LITTLE_ENDIAN); 108 bf.putInt(type); 109 bf.putInt(segmentOffset); 110 bf.putInt(segmentSize); 111 return bf.array(); 112 } 113 114 /** 115 * Init the SegmentHeader by a byte array 116 * 117 * @param bytes Byte array representation of a SegmentHeader object 118 * @return a newly created SegmentHeader object 119 * @throws VerifyCodeSignException parsing result invalid 120 */ fromByteArray(byte[] bytes)121 public static SegmentHeader fromByteArray(byte[] bytes) throws VerifyCodeSignException { 122 if (bytes.length != SEGMENT_HEADER_LENGTH) { 123 throw new VerifyCodeSignException("Invalid size of SegmentHeader"); 124 } 125 ByteBuffer bf = ByteBuffer.allocate(SEGMENT_HEADER_LENGTH).order(ByteOrder.LITTLE_ENDIAN); 126 bf.put(bytes); 127 bf.rewind(); 128 int inType = bf.getInt(); 129 if ((inType != CSB_FSVERITY_INFO_SEG) && (inType != CSB_HAP_META_SEG) && (inType != CSB_NATIVE_LIB_INFO_SEG)) { 130 throw new VerifyCodeSignException("Invalid type of SegmentHeader"); 131 } 132 int inSegmentOffset = bf.getInt(); 133 // segment offset is always larger than the size of CodeSignBlockHeader 134 if (inSegmentOffset < CodeSignBlockHeader.size()) { 135 throw new VerifyCodeSignException("Invalid segmentOffset of SegmentHeader"); 136 } 137 int inSegmentSize = bf.getInt(); 138 if (inSegmentSize < 0) { 139 throw new VerifyCodeSignException("Invalid segmentSize of SegmentHeader"); 140 } 141 if ((inType == CSB_FSVERITY_INFO_SEG) && (inSegmentSize != FsVerityInfoSegment.FS_VERITY_INFO_SEGMENT_SIZE)) { 142 throw new VerifyCodeSignException("Invalid segmentSize of fs-verity SegmentHeader"); 143 } 144 return new SegmentHeader(inType, inSegmentOffset, inSegmentSize); 145 } 146 147 /** 148 * Return a string representation of the object 149 * 150 * @return string representation of the object 151 */ toString()152 public String toString() { 153 return String.format(Locale.ROOT, "Segment Header: type=%d, seg_offset = %d, seg_size = %d", this.type, 154 this.segmentOffset, this.segmentSize); 155 } 156 } 157