cros payload: --signatures flag shows the metadata signatures
The existing --signatures flag now dumps the metadata signatures
embedded in the payload.
BUG=None
TEST=Added unittests; manually check a signed payload.
Change-Id: I4e2eb5cafeabbafd40af31716840d405a79b1023
Reviewed-on: https://chromium-review.googlesource.com/310654
Commit-Ready: Alex Deymo <deymo@chromium.org>
Tested-by: Alex Deymo <deymo@chromium.org>
Reviewed-by: Sen Jiang <senj@chromium.org>
diff --git a/cli/cros/cros_payload.py b/cli/cros/cros_payload.py
index 61c4141..9581b59 100644
--- a/cli/cros/cros_payload.py
+++ b/cli/cros/cros_payload.py
@@ -8,7 +8,6 @@
import itertools
import os
-import string
import sys
import textwrap
@@ -37,7 +36,7 @@
' '.join('%.2x' % ord(c) for c in chunk) +
' ' * (16 - len(chunk)) +
' | ' +
- ''.join(c if c in string.printable else '.' for c in chunk))
+ ''.join(c if 32 <= ord(c) and ord(c) < 127 else '.' for c in chunk))
@command.CommandDecorator('payload')
@@ -101,22 +100,38 @@
def _DisplaySignatures(self):
"""Show information about the signatures from the manifest."""
+ header = self.payload.header
+ if header.metadata_signature_len:
+ offset = header.size + header.manifest_len
+ DisplayValue('Metadata signatures blob',
+ 'file_offset=%d (%d bytes)' %
+ (offset, header.metadata_signature_len))
+ signatures_blob = self.payload.ReadDataBlob(
+ -header.metadata_signature_len,
+ header.metadata_signature_len)
+ self._DisplaySignaturesBlob('Metadata', signatures_blob)
+ else:
+ print('No metadata signatures stored in the payload')
+
manifest = self.payload.manifest
- if not manifest.HasField('signatures_offset'):
- print('No signatures stored in the payload')
- return
+ if manifest.HasField('signatures_offset'):
+ signature_msg = 'blob_offset=%d' % manifest.signatures_offset
+ if manifest.signatures_size:
+ signature_msg += ' (%d bytes)' % manifest.signatures_size
+ DisplayValue('Payload signatures blob', signature_msg)
+ signatures_blob = self.payload.ReadDataBlob(manifest.signatures_offset,
+ manifest.signatures_size)
+ self._DisplaySignaturesBlob('Payload', signatures_blob)
+ else:
+ print('No payload signatures stored in the payload')
- signature_msg = 'offset=%d' % manifest.signatures_offset
- if manifest.signatures_size:
- signature_msg += ' (%d bytes)' % manifest.signatures_size
- DisplayValue('Signature blob', signature_msg)
- signatures_blob = self.payload.ReadDataBlob(manifest.signatures_offset,
- manifest.signatures_size)
-
+ @staticmethod
+ def _DisplaySignaturesBlob(signature_name, signatures_blob):
from dev.host.lib.update_payload import update_metadata_pb2
signatures = update_metadata_pb2.Signatures()
signatures.ParseFromString(signatures_blob)
- print('Payload signatures: (%d entries)' % len(signatures.signatures))
+ print('%s signatures: (%d entries)' %
+ (signature_name, len(signatures.signatures)))
for signature in signatures.signatures:
print(' version=%s, hex_data: (%d bytes)' %
(signature.version if signature.HasField('version') else None,
diff --git a/cli/cros/cros_payload_unittest.py b/cli/cros/cros_payload_unittest.py
index f8fd78d..36f4749 100644
--- a/cli/cros/cros_payload_unittest.py
+++ b/cli/cros/cros_payload_unittest.py
@@ -93,19 +93,32 @@
"""Fake HasField method based on the python members."""
return hasattr(self, field_name) and getattr(self, field_name) is not None
+class FakeHeader(object):
+ """Fake payload header for testing."""
+
+ def __init__(self, version, manifest_len, metadata_signature_len):
+ self.version = version
+ self.manifest_len = manifest_len
+ self.metadata_signature_len = metadata_signature_len
+
+ @property
+ def size(self):
+ return (20 if self.version == cros_payload.MAJOR_PAYLOAD_VERSION_CHROMEOS
+ else 24)
+
+
class FakePayload(object):
"""Fake payload for testing."""
def __init__(self, major_version):
- FakeHeader = collections.namedtuple('FakeHeader',
- ['version', 'manifest_len'])
- self._header = FakeHeader(major_version, 222)
+ self._header = FakeHeader(major_version, 222, 0)
self.header = None
self._manifest = FakeManifest(major_version)
self.manifest = None
self._blobs = {}
- self._signatures = update_metadata_pb2.Signatures()
+ self._payload_signatures = update_metadata_pb2.Signatures()
+ self._metadata_signatures = update_metadata_pb2.Signatures()
def Init(self):
"""Fake Init that sets header and manifest.
@@ -126,15 +139,28 @@
'actual: %d)' % (len(blob), length))
return blob
- def AddSignature(self, **kwargs):
- new_signature = self._signatures.signatures.add()
+ @staticmethod
+ def _AddSignatureToProto(proto, **kwargs):
+ """Add a new Signature element to the passed proto."""
+ new_signature = proto.signatures.add()
for key, val in kwargs.iteritems():
setattr(new_signature, key, val)
- blob = self._signatures.SerializeToString()
+
+ def AddPayloadSignature(self, **kwargs):
+ self._AddSignatureToProto(self._payload_signatures, **kwargs)
+ blob = self._payload_signatures.SerializeToString()
self._manifest.signatures_offset = 1234
self._manifest.signatures_size = len(blob)
self._blobs[self._manifest.signatures_offset] = blob
+ def AddMetadataSignature(self, **kwargs):
+ self._AddSignatureToProto(self._metadata_signatures, **kwargs)
+ if self._header.metadata_signature_len:
+ del self._blobs[-self._header.metadata_signature_len]
+ blob = self._metadata_signatures.SerializeToString()
+ self._header.metadata_signature_len = len(blob)
+ self._blobs[-len(blob)] = blob
+
class PayloadCommandTest(cros_test_lib.MockOutputTestCase):
"""Test class for our PayloadCommand class."""
@@ -298,7 +324,8 @@
Number of kernel ops: 1
Block size: 4096
Minor version: 4
-No signatures stored in the payload
+No metadata signatures stored in the payload
+No payload signatures stored in the payload
"""
self.assertEquals(stdout, expected_out)
@@ -307,22 +334,29 @@
"""Verify that the --signatures option shows the present signatures."""
payload_cmd = cros_payload.PayloadCommand(
FakeOption(action='show', signatures=True))
- payload = FakePayload(cros_payload.MAJOR_PAYLOAD_VERSION_CHROMEOS)
- payload.AddSignature(version=1, data='12345678abcdefgh\x00\x01\x02\x03')
- payload.AddSignature(data='I am a signature so access is yes.')
+ payload = FakePayload(cros_payload.MAJOR_PAYLOAD_VERSION_BRILLO)
+ payload.AddPayloadSignature(version=1,
+ data='12345678abcdefgh\x00\x01\x02\x03')
+ payload.AddPayloadSignature(data='I am a signature so access is yes.')
+ payload.AddMetadataSignature(data='\x00\x0a\x0c')
self.PatchObject(update_payload, 'Payload', return_value=payload)
with self.OutputCapturer() as output:
payload_cmd.Run()
stdout = output.GetStdout()
- expected_out = """Payload version: 1
+ expected_out = """Payload version: 2
Manifest length: 222
-Number of operations: 1
-Number of kernel ops: 1
+Number of partitions: 2
+ Number of "rootfs" ops: 1
+ Number of "kernel" ops: 1
Block size: 4096
Minor version: 4
-Signature blob: offset=1234 (64 bytes)
+Metadata signatures blob: file_offset=246 (7 bytes)
+Metadata signatures: (1 entries)
+ version=None, hex_data: (3 bytes)
+ 00 0a 0c | ...
+Payload signatures blob: blob_offset=1234 (64 bytes)
Payload signatures: (2 entries)
version=1, hex_data: (20 bytes)
31 32 33 34 35 36 37 38 61 62 63 64 65 66 67 68 | 12345678abcdefgh