1*5a923131SAndroid Build Coastguard Worker# 2*5a923131SAndroid Build Coastguard Worker# Copyright (C) 2013 The Android Open Source Project 3*5a923131SAndroid Build Coastguard Worker# 4*5a923131SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 5*5a923131SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 6*5a923131SAndroid Build Coastguard Worker# You may obtain a copy of the License at 7*5a923131SAndroid Build Coastguard Worker# 8*5a923131SAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 9*5a923131SAndroid Build Coastguard Worker# 10*5a923131SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 11*5a923131SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 12*5a923131SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*5a923131SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 14*5a923131SAndroid Build Coastguard Worker# limitations under the License. 15*5a923131SAndroid Build Coastguard Worker# 16*5a923131SAndroid Build Coastguard Worker 17*5a923131SAndroid Build Coastguard Worker"""Tools for reading, verifying and applying Chrome OS update payloads.""" 18*5a923131SAndroid Build Coastguard Worker 19*5a923131SAndroid Build Coastguard Workerfrom __future__ import absolute_import 20*5a923131SAndroid Build Coastguard Workerfrom __future__ import print_function 21*5a923131SAndroid Build Coastguard Workerimport binascii 22*5a923131SAndroid Build Coastguard Worker 23*5a923131SAndroid Build Coastguard Workerimport hashlib 24*5a923131SAndroid Build Coastguard Workerimport io 25*5a923131SAndroid Build Coastguard Workerimport mmap 26*5a923131SAndroid Build Coastguard Workerimport struct 27*5a923131SAndroid Build Coastguard Workerimport zipfile 28*5a923131SAndroid Build Coastguard Worker 29*5a923131SAndroid Build Coastguard Workerimport update_metadata_pb2 30*5a923131SAndroid Build Coastguard Worker 31*5a923131SAndroid Build Coastguard Workerfrom update_payload import checker 32*5a923131SAndroid Build Coastguard Workerfrom update_payload import common 33*5a923131SAndroid Build Coastguard Workerfrom update_payload.error import PayloadError 34*5a923131SAndroid Build Coastguard Worker 35*5a923131SAndroid Build Coastguard Worker 36*5a923131SAndroid Build Coastguard Worker# 37*5a923131SAndroid Build Coastguard Worker# Helper functions. 38*5a923131SAndroid Build Coastguard Worker# 39*5a923131SAndroid Build Coastguard Workerdef _ReadInt(file_obj, size, is_unsigned, hasher=None): 40*5a923131SAndroid Build Coastguard Worker """Reads a binary-encoded integer from a file. 41*5a923131SAndroid Build Coastguard Worker 42*5a923131SAndroid Build Coastguard Worker It will do the correct conversion based on the reported size and whether or 43*5a923131SAndroid Build Coastguard Worker not a signed number is expected. Assumes a network (big-endian) byte 44*5a923131SAndroid Build Coastguard Worker ordering. 45*5a923131SAndroid Build Coastguard Worker 46*5a923131SAndroid Build Coastguard Worker Args: 47*5a923131SAndroid Build Coastguard Worker file_obj: a file object 48*5a923131SAndroid Build Coastguard Worker size: the integer size in bytes (2, 4 or 8) 49*5a923131SAndroid Build Coastguard Worker is_unsigned: whether it is signed or not 50*5a923131SAndroid Build Coastguard Worker hasher: an optional hasher to pass the value through 51*5a923131SAndroid Build Coastguard Worker 52*5a923131SAndroid Build Coastguard Worker Returns: 53*5a923131SAndroid Build Coastguard Worker An "unpacked" (Python) integer value. 54*5a923131SAndroid Build Coastguard Worker 55*5a923131SAndroid Build Coastguard Worker Raises: 56*5a923131SAndroid Build Coastguard Worker PayloadError if an read error occurred. 57*5a923131SAndroid Build Coastguard Worker """ 58*5a923131SAndroid Build Coastguard Worker return struct.unpack(common.IntPackingFmtStr(size, is_unsigned), 59*5a923131SAndroid Build Coastguard Worker common.Read(file_obj, size, hasher=hasher))[0] 60*5a923131SAndroid Build Coastguard Worker 61*5a923131SAndroid Build Coastguard Worker 62*5a923131SAndroid Build Coastguard Worker# 63*5a923131SAndroid Build Coastguard Worker# Update payload. 64*5a923131SAndroid Build Coastguard Worker# 65*5a923131SAndroid Build Coastguard Workerclass Payload(object): 66*5a923131SAndroid Build Coastguard Worker """Chrome OS update payload processor.""" 67*5a923131SAndroid Build Coastguard Worker 68*5a923131SAndroid Build Coastguard Worker class _PayloadHeader(object): 69*5a923131SAndroid Build Coastguard Worker """Update payload header struct.""" 70*5a923131SAndroid Build Coastguard Worker 71*5a923131SAndroid Build Coastguard Worker # Header constants; sizes are in bytes. 72*5a923131SAndroid Build Coastguard Worker _MAGIC = b'CrAU' 73*5a923131SAndroid Build Coastguard Worker _VERSION_SIZE = 8 74*5a923131SAndroid Build Coastguard Worker _MANIFEST_LEN_SIZE = 8 75*5a923131SAndroid Build Coastguard Worker _METADATA_SIGNATURE_LEN_SIZE = 4 76*5a923131SAndroid Build Coastguard Worker 77*5a923131SAndroid Build Coastguard Worker def __init__(self): 78*5a923131SAndroid Build Coastguard Worker self.version = None 79*5a923131SAndroid Build Coastguard Worker self.manifest_len = None 80*5a923131SAndroid Build Coastguard Worker self.metadata_signature_len = None 81*5a923131SAndroid Build Coastguard Worker self.size = None 82*5a923131SAndroid Build Coastguard Worker 83*5a923131SAndroid Build Coastguard Worker def ReadFromPayload(self, payload_file, hasher=None): 84*5a923131SAndroid Build Coastguard Worker """Reads the payload header from a file. 85*5a923131SAndroid Build Coastguard Worker 86*5a923131SAndroid Build Coastguard Worker Reads the payload header from the |payload_file| and updates the |hasher| 87*5a923131SAndroid Build Coastguard Worker if one is passed. The parsed header is stored in the _PayloadHeader 88*5a923131SAndroid Build Coastguard Worker instance attributes. 89*5a923131SAndroid Build Coastguard Worker 90*5a923131SAndroid Build Coastguard Worker Args: 91*5a923131SAndroid Build Coastguard Worker payload_file: a file object 92*5a923131SAndroid Build Coastguard Worker hasher: an optional hasher to pass the value through 93*5a923131SAndroid Build Coastguard Worker 94*5a923131SAndroid Build Coastguard Worker Returns: 95*5a923131SAndroid Build Coastguard Worker None. 96*5a923131SAndroid Build Coastguard Worker 97*5a923131SAndroid Build Coastguard Worker Raises: 98*5a923131SAndroid Build Coastguard Worker PayloadError if a read error occurred or the header is invalid. 99*5a923131SAndroid Build Coastguard Worker """ 100*5a923131SAndroid Build Coastguard Worker # Verify magic 101*5a923131SAndroid Build Coastguard Worker magic = common.Read(payload_file, len(self._MAGIC), hasher=hasher) 102*5a923131SAndroid Build Coastguard Worker if magic != self._MAGIC: 103*5a923131SAndroid Build Coastguard Worker raise PayloadError('invalid payload magic: %s' % magic) 104*5a923131SAndroid Build Coastguard Worker 105*5a923131SAndroid Build Coastguard Worker self.version = _ReadInt(payload_file, self._VERSION_SIZE, True, 106*5a923131SAndroid Build Coastguard Worker hasher=hasher) 107*5a923131SAndroid Build Coastguard Worker self.manifest_len = _ReadInt(payload_file, self._MANIFEST_LEN_SIZE, True, 108*5a923131SAndroid Build Coastguard Worker hasher=hasher) 109*5a923131SAndroid Build Coastguard Worker self.size = (len(self._MAGIC) + self._VERSION_SIZE + 110*5a923131SAndroid Build Coastguard Worker self._MANIFEST_LEN_SIZE) 111*5a923131SAndroid Build Coastguard Worker self.metadata_signature_len = 0 112*5a923131SAndroid Build Coastguard Worker 113*5a923131SAndroid Build Coastguard Worker if self.version == common.BRILLO_MAJOR_PAYLOAD_VERSION: 114*5a923131SAndroid Build Coastguard Worker self.size += self._METADATA_SIGNATURE_LEN_SIZE 115*5a923131SAndroid Build Coastguard Worker self.metadata_signature_len = _ReadInt( 116*5a923131SAndroid Build Coastguard Worker payload_file, self._METADATA_SIGNATURE_LEN_SIZE, True, 117*5a923131SAndroid Build Coastguard Worker hasher=hasher) 118*5a923131SAndroid Build Coastguard Worker 119*5a923131SAndroid Build Coastguard Worker def __init__(self, payload_file, payload_file_offset=0): 120*5a923131SAndroid Build Coastguard Worker """Initialize the payload object. 121*5a923131SAndroid Build Coastguard Worker 122*5a923131SAndroid Build Coastguard Worker Args: 123*5a923131SAndroid Build Coastguard Worker payload_file: update payload file object open for reading 124*5a923131SAndroid Build Coastguard Worker payload_file_offset: the offset of the actual payload 125*5a923131SAndroid Build Coastguard Worker """ 126*5a923131SAndroid Build Coastguard Worker if zipfile.is_zipfile(payload_file): 127*5a923131SAndroid Build Coastguard Worker self.name = payload_file 128*5a923131SAndroid Build Coastguard Worker with zipfile.ZipFile(payload_file) as zfp: 129*5a923131SAndroid Build Coastguard Worker if "payload.bin" not in zfp.namelist(): 130*5a923131SAndroid Build Coastguard Worker raise ValueError(f"payload.bin missing in archive {payload_file}") 131*5a923131SAndroid Build Coastguard Worker self.payload_file = zfp.open("payload.bin", "r") 132*5a923131SAndroid Build Coastguard Worker elif isinstance(payload_file, str): 133*5a923131SAndroid Build Coastguard Worker self.name = payload_file 134*5a923131SAndroid Build Coastguard Worker payload_fp = open(payload_file, "rb") 135*5a923131SAndroid Build Coastguard Worker payload_bytes = mmap.mmap( 136*5a923131SAndroid Build Coastguard Worker payload_fp.fileno(), 0, access=mmap.ACCESS_READ) 137*5a923131SAndroid Build Coastguard Worker self.payload_file = io.BytesIO(payload_bytes) 138*5a923131SAndroid Build Coastguard Worker else: 139*5a923131SAndroid Build Coastguard Worker self.name = payload_file.name 140*5a923131SAndroid Build Coastguard Worker self.payload_file = payload_file 141*5a923131SAndroid Build Coastguard Worker self.payload_file_size = self.payload_file.seek(0, io.SEEK_END) 142*5a923131SAndroid Build Coastguard Worker self.payload_file.seek(0, io.SEEK_SET) 143*5a923131SAndroid Build Coastguard Worker self.payload_file_offset = payload_file_offset 144*5a923131SAndroid Build Coastguard Worker self.manifest_hasher = None 145*5a923131SAndroid Build Coastguard Worker self.is_init = False 146*5a923131SAndroid Build Coastguard Worker self.header = None 147*5a923131SAndroid Build Coastguard Worker self.manifest = None 148*5a923131SAndroid Build Coastguard Worker self.data_offset = None 149*5a923131SAndroid Build Coastguard Worker self.metadata_signature = None 150*5a923131SAndroid Build Coastguard Worker self.payload_signature = None 151*5a923131SAndroid Build Coastguard Worker self.metadata_size = None 152*5a923131SAndroid Build Coastguard Worker self.Init() 153*5a923131SAndroid Build Coastguard Worker 154*5a923131SAndroid Build Coastguard Worker @property 155*5a923131SAndroid Build Coastguard Worker def metadata_hash(self): 156*5a923131SAndroid Build Coastguard Worker return self.manifest_hasher.digest() 157*5a923131SAndroid Build Coastguard Worker 158*5a923131SAndroid Build Coastguard Worker @property 159*5a923131SAndroid Build Coastguard Worker def payload_hash(self): 160*5a923131SAndroid Build Coastguard Worker hasher = hashlib.sha256() 161*5a923131SAndroid Build Coastguard Worker self.payload_file.seek(0) 162*5a923131SAndroid Build Coastguard Worker hasher.update(self.payload_file.read(self.metadata_size)) 163*5a923131SAndroid Build Coastguard Worker self.payload_file.seek(self.header.metadata_signature_len, io.SEEK_CUR) 164*5a923131SAndroid Build Coastguard Worker hasher.update(self.payload_file.read(self.total_data_length)) 165*5a923131SAndroid Build Coastguard Worker return hasher.digest() 166*5a923131SAndroid Build Coastguard Worker 167*5a923131SAndroid Build Coastguard Worker @property 168*5a923131SAndroid Build Coastguard Worker def is_incremental(self): 169*5a923131SAndroid Build Coastguard Worker return any([part.HasField("old_partition_info") for part in self.manifest.partitions]) 170*5a923131SAndroid Build Coastguard Worker 171*5a923131SAndroid Build Coastguard Worker @property 172*5a923131SAndroid Build Coastguard Worker def is_partial(self): 173*5a923131SAndroid Build Coastguard Worker return self.manifest.partial_update 174*5a923131SAndroid Build Coastguard Worker 175*5a923131SAndroid Build Coastguard Worker @property 176*5a923131SAndroid Build Coastguard Worker def total_data_length(self): 177*5a923131SAndroid Build Coastguard Worker """Return the total data length of this payload, excluding payload 178*5a923131SAndroid Build Coastguard Worker signature at the very end. 179*5a923131SAndroid Build Coastguard Worker """ 180*5a923131SAndroid Build Coastguard Worker # Operations are sorted in ascending data_offset order, so iterating 181*5a923131SAndroid Build Coastguard Worker # backwards and find the first one with non zero data_offset will tell 182*5a923131SAndroid Build Coastguard Worker # us total data length 183*5a923131SAndroid Build Coastguard Worker for partition in reversed(self.manifest.partitions): 184*5a923131SAndroid Build Coastguard Worker for op in reversed(partition.operations): 185*5a923131SAndroid Build Coastguard Worker if op.data_length > 0: 186*5a923131SAndroid Build Coastguard Worker return op.data_offset + op.data_length 187*5a923131SAndroid Build Coastguard Worker return 0 188*5a923131SAndroid Build Coastguard Worker 189*5a923131SAndroid Build Coastguard Worker def _ReadHeader(self): 190*5a923131SAndroid Build Coastguard Worker """Reads and returns the payload header. 191*5a923131SAndroid Build Coastguard Worker 192*5a923131SAndroid Build Coastguard Worker Returns: 193*5a923131SAndroid Build Coastguard Worker A payload header object. 194*5a923131SAndroid Build Coastguard Worker 195*5a923131SAndroid Build Coastguard Worker Raises: 196*5a923131SAndroid Build Coastguard Worker PayloadError if a read error occurred. 197*5a923131SAndroid Build Coastguard Worker """ 198*5a923131SAndroid Build Coastguard Worker header = self._PayloadHeader() 199*5a923131SAndroid Build Coastguard Worker header.ReadFromPayload(self.payload_file, self.manifest_hasher) 200*5a923131SAndroid Build Coastguard Worker return header 201*5a923131SAndroid Build Coastguard Worker 202*5a923131SAndroid Build Coastguard Worker def _ReadManifest(self): 203*5a923131SAndroid Build Coastguard Worker """Reads and returns the payload manifest. 204*5a923131SAndroid Build Coastguard Worker 205*5a923131SAndroid Build Coastguard Worker Returns: 206*5a923131SAndroid Build Coastguard Worker A string containing the payload manifest in binary form. 207*5a923131SAndroid Build Coastguard Worker 208*5a923131SAndroid Build Coastguard Worker Raises: 209*5a923131SAndroid Build Coastguard Worker PayloadError if a read error occurred. 210*5a923131SAndroid Build Coastguard Worker """ 211*5a923131SAndroid Build Coastguard Worker if not self.header: 212*5a923131SAndroid Build Coastguard Worker raise PayloadError('payload header not present') 213*5a923131SAndroid Build Coastguard Worker 214*5a923131SAndroid Build Coastguard Worker return common.Read(self.payload_file, self.header.manifest_len, 215*5a923131SAndroid Build Coastguard Worker hasher=self.manifest_hasher) 216*5a923131SAndroid Build Coastguard Worker 217*5a923131SAndroid Build Coastguard Worker def _ReadMetadataSignature(self): 218*5a923131SAndroid Build Coastguard Worker """Reads and returns the metadata signatures. 219*5a923131SAndroid Build Coastguard Worker 220*5a923131SAndroid Build Coastguard Worker Returns: 221*5a923131SAndroid Build Coastguard Worker A string containing the metadata signatures protobuf in binary form or 222*5a923131SAndroid Build Coastguard Worker an empty string if no metadata signature found in the payload. 223*5a923131SAndroid Build Coastguard Worker 224*5a923131SAndroid Build Coastguard Worker Raises: 225*5a923131SAndroid Build Coastguard Worker PayloadError if a read error occurred. 226*5a923131SAndroid Build Coastguard Worker """ 227*5a923131SAndroid Build Coastguard Worker if not self.header: 228*5a923131SAndroid Build Coastguard Worker raise PayloadError('payload header not present') 229*5a923131SAndroid Build Coastguard Worker 230*5a923131SAndroid Build Coastguard Worker return common.Read( 231*5a923131SAndroid Build Coastguard Worker self.payload_file, self.header.metadata_signature_len, 232*5a923131SAndroid Build Coastguard Worker offset=self.payload_file_offset + self.header.size + 233*5a923131SAndroid Build Coastguard Worker self.header.manifest_len) 234*5a923131SAndroid Build Coastguard Worker 235*5a923131SAndroid Build Coastguard Worker def ReadDataBlob(self, offset, length): 236*5a923131SAndroid Build Coastguard Worker """Reads and returns a single data blob from the update payload. 237*5a923131SAndroid Build Coastguard Worker 238*5a923131SAndroid Build Coastguard Worker Args: 239*5a923131SAndroid Build Coastguard Worker offset: offset to the beginning of the blob from the end of the manifest 240*5a923131SAndroid Build Coastguard Worker length: the blob's length 241*5a923131SAndroid Build Coastguard Worker 242*5a923131SAndroid Build Coastguard Worker Returns: 243*5a923131SAndroid Build Coastguard Worker A string containing the raw blob data. 244*5a923131SAndroid Build Coastguard Worker 245*5a923131SAndroid Build Coastguard Worker Raises: 246*5a923131SAndroid Build Coastguard Worker PayloadError if a read error occurred. 247*5a923131SAndroid Build Coastguard Worker """ 248*5a923131SAndroid Build Coastguard Worker return common.Read(self.payload_file, length, 249*5a923131SAndroid Build Coastguard Worker offset=self.payload_file_offset + self.data_offset + 250*5a923131SAndroid Build Coastguard Worker offset) 251*5a923131SAndroid Build Coastguard Worker 252*5a923131SAndroid Build Coastguard Worker def Init(self): 253*5a923131SAndroid Build Coastguard Worker """Initializes the payload object. 254*5a923131SAndroid Build Coastguard Worker 255*5a923131SAndroid Build Coastguard Worker This is a prerequisite for any other public API call. 256*5a923131SAndroid Build Coastguard Worker 257*5a923131SAndroid Build Coastguard Worker Raises: 258*5a923131SAndroid Build Coastguard Worker PayloadError if object already initialized or fails to initialize 259*5a923131SAndroid Build Coastguard Worker correctly. 260*5a923131SAndroid Build Coastguard Worker """ 261*5a923131SAndroid Build Coastguard Worker if self.is_init: 262*5a923131SAndroid Build Coastguard Worker return 263*5a923131SAndroid Build Coastguard Worker 264*5a923131SAndroid Build Coastguard Worker self.manifest_hasher = hashlib.sha256() 265*5a923131SAndroid Build Coastguard Worker 266*5a923131SAndroid Build Coastguard Worker # Read the file header. 267*5a923131SAndroid Build Coastguard Worker self.payload_file.seek(self.payload_file_offset) 268*5a923131SAndroid Build Coastguard Worker self.header = self._ReadHeader() 269*5a923131SAndroid Build Coastguard Worker 270*5a923131SAndroid Build Coastguard Worker # Read the manifest. 271*5a923131SAndroid Build Coastguard Worker manifest_raw = self._ReadManifest() 272*5a923131SAndroid Build Coastguard Worker self.manifest = update_metadata_pb2.DeltaArchiveManifest() 273*5a923131SAndroid Build Coastguard Worker self.manifest.ParseFromString(manifest_raw) 274*5a923131SAndroid Build Coastguard Worker 275*5a923131SAndroid Build Coastguard Worker # Read the metadata signature (if any). 276*5a923131SAndroid Build Coastguard Worker metadata_signature_raw = self._ReadMetadataSignature() 277*5a923131SAndroid Build Coastguard Worker if metadata_signature_raw: 278*5a923131SAndroid Build Coastguard Worker self.metadata_signature = update_metadata_pb2.Signatures() 279*5a923131SAndroid Build Coastguard Worker self.metadata_signature.ParseFromString(metadata_signature_raw) 280*5a923131SAndroid Build Coastguard Worker 281*5a923131SAndroid Build Coastguard Worker self.metadata_size = self.header.size + self.header.manifest_len 282*5a923131SAndroid Build Coastguard Worker self.data_offset = self.metadata_size + self.header.metadata_signature_len 283*5a923131SAndroid Build Coastguard Worker 284*5a923131SAndroid Build Coastguard Worker if self.manifest.signatures_offset and self.manifest.signatures_size and self.manifest.signatures_offset + self.manifest.signatures_size <= self.payload_file_size: 285*5a923131SAndroid Build Coastguard Worker payload_signature_blob = self.ReadDataBlob( 286*5a923131SAndroid Build Coastguard Worker self.manifest.signatures_offset, self.manifest.signatures_size) 287*5a923131SAndroid Build Coastguard Worker payload_signature = update_metadata_pb2.Signatures() 288*5a923131SAndroid Build Coastguard Worker payload_signature.ParseFromString(payload_signature_blob) 289*5a923131SAndroid Build Coastguard Worker self.payload_signature = payload_signature 290*5a923131SAndroid Build Coastguard Worker 291*5a923131SAndroid Build Coastguard Worker self.is_init = True 292*5a923131SAndroid Build Coastguard Worker 293*5a923131SAndroid Build Coastguard Worker def _AssertInit(self): 294*5a923131SAndroid Build Coastguard Worker """Raises an exception if the object was not initialized.""" 295*5a923131SAndroid Build Coastguard Worker if not self.is_init: 296*5a923131SAndroid Build Coastguard Worker raise PayloadError('payload object not initialized') 297*5a923131SAndroid Build Coastguard Worker 298*5a923131SAndroid Build Coastguard Worker def ResetFile(self): 299*5a923131SAndroid Build Coastguard Worker """Resets the offset of the payload file to right past the manifest.""" 300*5a923131SAndroid Build Coastguard Worker self.payload_file.seek(self.payload_file_offset + self.data_offset) 301*5a923131SAndroid Build Coastguard Worker 302*5a923131SAndroid Build Coastguard Worker def IsDelta(self): 303*5a923131SAndroid Build Coastguard Worker """Returns True iff the payload appears to be a delta.""" 304*5a923131SAndroid Build Coastguard Worker self._AssertInit() 305*5a923131SAndroid Build Coastguard Worker return (any(partition.HasField('old_partition_info') 306*5a923131SAndroid Build Coastguard Worker for partition in self.manifest.partitions)) 307*5a923131SAndroid Build Coastguard Worker 308*5a923131SAndroid Build Coastguard Worker def IsFull(self): 309*5a923131SAndroid Build Coastguard Worker """Returns True iff the payload appears to be a full.""" 310*5a923131SAndroid Build Coastguard Worker return not self.IsDelta() 311*5a923131SAndroid Build Coastguard Worker 312*5a923131SAndroid Build Coastguard Worker def Check(self, pubkey_file_name=None, metadata_sig_file=None, 313*5a923131SAndroid Build Coastguard Worker metadata_size=0, report_out_file=None, assert_type=None, 314*5a923131SAndroid Build Coastguard Worker block_size=0, part_sizes=None, allow_unhashed=False, 315*5a923131SAndroid Build Coastguard Worker disabled_tests=()): 316*5a923131SAndroid Build Coastguard Worker """Checks the payload integrity. 317*5a923131SAndroid Build Coastguard Worker 318*5a923131SAndroid Build Coastguard Worker Args: 319*5a923131SAndroid Build Coastguard Worker pubkey_file_name: public key used for signature verification 320*5a923131SAndroid Build Coastguard Worker metadata_sig_file: metadata signature, if verification is desired 321*5a923131SAndroid Build Coastguard Worker metadata_size: metadata size, if verification is desired 322*5a923131SAndroid Build Coastguard Worker report_out_file: file object to dump the report to 323*5a923131SAndroid Build Coastguard Worker assert_type: assert that payload is either 'full' or 'delta' 324*5a923131SAndroid Build Coastguard Worker block_size: expected filesystem / payload block size 325*5a923131SAndroid Build Coastguard Worker part_sizes: map of partition label to (physical) size in bytes 326*5a923131SAndroid Build Coastguard Worker allow_unhashed: allow unhashed operation blobs 327*5a923131SAndroid Build Coastguard Worker disabled_tests: list of tests to disable 328*5a923131SAndroid Build Coastguard Worker 329*5a923131SAndroid Build Coastguard Worker Raises: 330*5a923131SAndroid Build Coastguard Worker PayloadError if payload verification failed. 331*5a923131SAndroid Build Coastguard Worker """ 332*5a923131SAndroid Build Coastguard Worker self._AssertInit() 333*5a923131SAndroid Build Coastguard Worker 334*5a923131SAndroid Build Coastguard Worker # Create a short-lived payload checker object and run it. 335*5a923131SAndroid Build Coastguard Worker helper = checker.PayloadChecker( 336*5a923131SAndroid Build Coastguard Worker self, assert_type=assert_type, block_size=block_size, 337*5a923131SAndroid Build Coastguard Worker allow_unhashed=allow_unhashed, disabled_tests=disabled_tests) 338*5a923131SAndroid Build Coastguard Worker helper.Run(pubkey_file_name=pubkey_file_name, 339*5a923131SAndroid Build Coastguard Worker metadata_sig_file=metadata_sig_file, 340*5a923131SAndroid Build Coastguard Worker metadata_size=metadata_size, 341*5a923131SAndroid Build Coastguard Worker part_sizes=part_sizes, 342*5a923131SAndroid Build Coastguard Worker report_out_file=report_out_file) 343*5a923131SAndroid Build Coastguard Worker 344*5a923131SAndroid Build Coastguard Worker def CheckDataHash(self): 345*5a923131SAndroid Build Coastguard Worker for part in self.manifest.partitions: 346*5a923131SAndroid Build Coastguard Worker for op in part.operations: 347*5a923131SAndroid Build Coastguard Worker if op.data_length == 0: 348*5a923131SAndroid Build Coastguard Worker continue 349*5a923131SAndroid Build Coastguard Worker if not op.data_sha256_hash: 350*5a923131SAndroid Build Coastguard Worker raise PayloadError( 351*5a923131SAndroid Build Coastguard Worker f"Operation {op} in partition {part.partition_name} missing data_sha256_hash") 352*5a923131SAndroid Build Coastguard Worker blob = self.ReadDataBlob(op.data_offset, op.data_length) 353*5a923131SAndroid Build Coastguard Worker blob_hash = hashlib.sha256(blob) 354*5a923131SAndroid Build Coastguard Worker if blob_hash.digest() != op.data_sha256_hash: 355*5a923131SAndroid Build Coastguard Worker raise PayloadError( 356*5a923131SAndroid Build Coastguard Worker f"Operation {op} in partition {part.partition_name} has unexpected hash, expected: {binascii.hexlify(op.data_sha256_hash)}, actual: {blob_hash.hexdigest()}") 357