def test_Verify(self): zip_file = self.construct_zip_package_withValidPayload(with_metadata=True) property_files = AbOtaPropertyFiles() with zipfile.ZipFile(zip_file, 'r') as zip_fp: raw_metadata = property_files.GetPropertyFilesString( zip_fp, reserve_space=False) property_files.Verify(zip_fp, raw_metadata)
def test_Compute(self): zip_file = self.construct_zip_package_withValidPayload() property_files = AbOtaPropertyFiles() with zipfile.ZipFile(zip_file, 'r') as zip_fp: property_files_string = property_files.Compute(zip_fp) tokens = self._parse_property_files_string(property_files_string) # "6" indcludes the four entries above, one metadata entry, and one entry # for payload-metadata.bin. self.assertEqual(6, len(tokens)) self._verify_entries( zip_file, tokens, ('care_map.txt', 'compatibility.zip'))
def test_Finalize(self): zip_file = self.construct_zip_package_withValidPayload(with_metadata=True) property_files = AbOtaPropertyFiles() with zipfile.ZipFile(zip_file, 'r') as zip_fp: raw_metadata = property_files.GetPropertyFilesString( zip_fp, reserve_space=False) property_files_string = property_files.Finalize(zip_fp, len(raw_metadata)) tokens = self._parse_property_files_string(property_files_string) # "6" indcludes the four entries above, one metadata entry, and one entry # for payload-metadata.bin. self.assertEqual(6, len(tokens)) self._verify_entries( zip_file, tokens, ('care_map.txt', 'compatibility.zip'))
def test_GetPayloadMetadataOffsetAndSize(self): target_file = construct_target_files() payload = Payload() payload.Generate(target_file) payload_signer = PayloadSigner() payload.Sign(payload_signer) output_file = common.MakeTempFile(suffix='.zip') with zipfile.ZipFile(output_file, 'w') as output_zip: payload.WriteToZip(output_zip) # Find out the payload metadata offset and size. property_files = AbOtaPropertyFiles() with zipfile.ZipFile(output_file) as input_zip: # pylint: disable=protected-access payload_offset, metadata_total = ( property_files._GetPayloadMetadataOffsetAndSize(input_zip)) # Read in the metadata signature directly. with open(output_file, 'rb') as verify_fp: verify_fp.seek(payload_offset + metadata_total - self.SIGNATURE_SIZE) metadata_signature = verify_fp.read(self.SIGNATURE_SIZE) # Now we extract the metadata hash via brillo_update_payload script, which # will serve as the oracle result. payload_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin") metadata_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin") cmd = ['brillo_update_payload', 'hash', '--unsigned_payload', payload.payload_file, '--signature_size', str(self.SIGNATURE_SIZE), '--metadata_hash_file', metadata_sig_file, '--payload_hash_file', payload_sig_file] proc = common.Run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) stdoutdata, _ = proc.communicate() self.assertEqual( 0, proc.returncode, 'Failed to run brillo_update_payload: {}'.format(stdoutdata)) signed_metadata_sig_file = payload_signer.Sign(metadata_sig_file) # Finally we can compare the two signatures. with open(signed_metadata_sig_file, 'rb') as verify_fp: self.assertEqual(verify_fp.read(), metadata_signature)
def test_init(self): property_files = AbOtaPropertyFiles() self.assertEqual('ota-property-files', property_files.name) self.assertEqual( ( 'payload.bin', 'payload_properties.txt', ), property_files.required) self.assertEqual( ( 'care_map.txt', 'compatibility.zip', ), property_files.optional)
def test_GetPayloadMetadataOffsetAndSize(self): target_file = construct_target_files() payload = Payload() payload.Generate(target_file) payload_signer = PayloadSigner() payload.Sign(payload_signer) output_file = common.MakeTempFile(suffix='.zip') with zipfile.ZipFile(output_file, 'w') as output_zip: payload.WriteToZip(output_zip) # Find out the payload metadata offset and size. property_files = AbOtaPropertyFiles() with zipfile.ZipFile(output_file) as input_zip: # pylint: disable=protected-access payload_offset, metadata_total = ( property_files._GetPayloadMetadataOffsetAndSize(input_zip)) # The signature proto has the following format (details in # /platform/system/update_engine/update_metadata.proto): # message Signature { # optional uint32 version = 1; # optional bytes data = 2; # optional fixed32 unpadded_signature_size = 3; # } # # According to the protobuf encoding, the tail of the signature message will # be [signature string(256 bytes) + encoding of the fixed32 number 256]. And # 256 is encoded as 'x1d\x00\x01\x00\x00': # [3 (field number) << 3 | 5 (type) + byte reverse of 0x100 (256)]. # Details in (https://developers.google.com/protocol-buffers/docs/encoding) signature_tail_length = self.SIGNATURE_SIZE + 5 self.assertGreater(metadata_total, signature_tail_length) with open(output_file, 'rb') as verify_fp: verify_fp.seek(payload_offset + metadata_total - signature_tail_length) metadata_signature_proto_tail = verify_fp.read(signature_tail_length) self.assertEqual(b'\x1d\x00\x01\x00\x00', metadata_signature_proto_tail[-5:]) metadata_signature = metadata_signature_proto_tail[:-5] # Now we extract the metadata hash via brillo_update_payload script, which # will serve as the oracle result. payload_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin") metadata_sig_file = common.MakeTempFile(prefix="sig-", suffix=".bin") cmd = ['brillo_update_payload', 'hash', '--unsigned_payload', payload.payload_file, '--signature_size', str(self.SIGNATURE_SIZE), '--metadata_hash_file', metadata_sig_file, '--payload_hash_file', payload_sig_file] proc = common.Run(cmd) stdoutdata, _ = proc.communicate() self.assertEqual( 0, proc.returncode, 'Failed to run brillo_update_payload:\n{}'.format(stdoutdata)) signed_metadata_sig_file = payload_signer.Sign(metadata_sig_file) # Finally we can compare the two signatures. with open(signed_metadata_sig_file, 'rb') as verify_fp: self.assertEqual(verify_fp.read(), metadata_signature)