def Decode(self, Buffer):
        if len(Buffer) < self._StructSize:
            raise ValueError
        (CapsuleGuid, HeaderSize, Flags, CapsuleImageSize,
         Reserved) = struct.unpack(self._StructFormat,
                                   Buffer[0:self._StructSize])
        if HeaderSize < self._StructSize:
            raise ValueError
        if CapsuleImageSize != len(Buffer):
            raise ValueError
        self.CapsuleGuid = uuid.UUID(bytes_le=CapsuleGuid)
        self.HeaderSize = HeaderSize
        self.OemFlags = Flags & 0xffff
        self.PersistAcrossReset = (
            Flags & self._CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0
        self.PopulateSystemTable = (
            Flags & self._CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0
        self.InitiateReset = (Flags & self._CAPSULE_FLAGS_INITIATE_RESET) != 0
        self.CapsuleImageSize = CapsuleImageSize
        self.Payload = Buffer[self.HeaderSize:]
        if len(
                self.Payload
        ) > 0 and self.CapsuleGuid == self.EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID:
            self.FmpCapsuleHeader = FmpCapsuleHeaderClass()
            self.FmpCapsuleHeader.Decode(self.Payload)

        return self.Payload
예제 #2
0
 def test_payload_item_count_should_track_additions(self):
     test_header = FmpCapsuleHeaderClass()
     self.assertEqual(test_header.PayloadItemCount, 0)
     test_header.AddFmpCapsuleImageHeader(b'dummyheader')
     self.assertEqual(test_header.PayloadItemCount, 1)
     test_header.AddFmpCapsuleImageHeader(b'dummyheader2')
     self.assertEqual(test_header.PayloadItemCount, 2)
예제 #3
0
 def test_embedded_driver_count_should_track_additions(self):
     test_header = FmpCapsuleHeaderClass()
     self.assertEqual(test_header.EmbeddedDriverCount, 0)
     test_header.AddEmbeddedDriver(b'dummydriver')
     self.assertEqual(test_header.EmbeddedDriverCount, 1)
     test_header.AddEmbeddedDriver(b'dummydriver2')
     self.assertEqual(test_header.EmbeddedDriverCount, 2)
예제 #4
0
def build_capsule(capsule_data, capsule_options, signer_module, signer_options):
    '''
    goes through all of the steps of capsule generation for a single-payload FMP capsule

    takes in capsule_data as a byte string, a signer module, and capsule and signer options,
    and produces all of the headers necessary. Will use the signer module to produce the cert data
    for the FMP Auth header.

    NOTE: Uses a fixed MonotonicCount of 1.

    capsule_data - a byte string for the innermost payload
    capsule_options - a dictionary that will be used for all the capsule payload fields. Must include
                        'fw_version', 'lsv_version', and 'esrt_guid' at a minimum. These should all be
                        strings and the two versions should be strings of hex number (e.g. 0x12345)
    signer_module - a capsule signer module that implements the sign() function (see pyopenssl_signer or
                        signtool_signer built-in modules for examples)
    signer_options - a dictionary of options that will be passed to the signer_module. The required values
                        depend on the expectations of the signer_module provided

    returns a UefiCapsuleHeaderClass object containing all of the provided data
    '''
    # Start building the capsule as we go.
    # Create the FMP Payload and set all the necessary options.
    fmp_payload_header = FmpPayloadHeaderClass()
    fmp_payload_header.FwVersion = int(capsule_options['fw_version'], 16)
    fmp_payload_header.LowestSupportedVersion = int(capsule_options['lsv_version'], 16)
    fmp_payload_header.Payload = capsule_data

    # Create the auth header and get ready to sign the data.
    fmp_auth_header = FmpAuthHeaderClass()
    fmp_auth_header.MonotonicCount = 1
    fmp_auth_header.FmpPayloadHeader = fmp_payload_header

    data_to_sign = fmp_payload_header.Encode()
    data_to_sign = data_to_sign + struct.pack("<Q", fmp_auth_header.MonotonicCount)

    # Sign the data and assign it to the cert data.
    signature_options = {
        'sign_alg': 'pkcs12',
        'hash_alg': 'sha256'
    }
    # Set or override OID.
    signer_options['oid'] = PKCS7_SIGNED_DATA_OID
    fmp_auth_header.AuthInfo.CertData = signer_module.sign(data_to_sign, signature_options, signer_options)

    fmp_capsule_image_header = FmpCapsuleImageHeaderClass()
    fmp_capsule_image_header.UpdateImageTypeId = uuid.UUID(capsule_options['esrt_guid'])
    fmp_capsule_image_header.UpdateImageIndex = 1
    fmp_capsule_image_header.FmpAuthHeader = fmp_auth_header

    fmp_capsule_header = FmpCapsuleHeaderClass()
    fmp_capsule_header.AddFmpCapsuleImageHeader(fmp_capsule_image_header)

    uefi_capsule_header = UefiCapsuleHeaderClass()
    uefi_capsule_header.FmpCapsuleHeader = fmp_capsule_header
    uefi_capsule_header.PersistAcrossReset = True
    uefi_capsule_header.InitiateReset = True

    return uefi_capsule_header
    def test_should_be_able_to_save_a_capsule(self):
        fmp_capsule_image_header = FmpCapsuleImageHeaderClass()
        fmp_capsule_image_header.UpdateImageTypeId = uuid.UUID(
            DUMMY_OPTIONS['capsule']['esrt_guid'])
        fmp_capsule_image_header.UpdateImageIndex = 1

        fmp_capsule_header = FmpCapsuleHeaderClass()
        fmp_capsule_header.AddFmpCapsuleImageHeader(fmp_capsule_image_header)

        uefi_capsule_header = UefiCapsuleHeaderClass()
        uefi_capsule_header.FmpCapsuleHeader = fmp_capsule_header
        uefi_capsule_header.PersistAcrossReset = True
        uefi_capsule_header.InitiateReset = True

        capsule_file_path = capsule_helper.save_capsule(
            uefi_capsule_header, DUMMY_OPTIONS['capsule'], self.temp_dir)

        # Now read the data and check for the GUID.
        with open(capsule_file_path, 'rb') as capsule_file:
            capsule_bytes = capsule_file.read()

        self.assertTrue(
            uuid.UUID(DUMMY_OPTIONS['capsule']['esrt_guid']).bytes_le in
            capsule_bytes)
class UefiCapsuleHeaderClass(object):
    # typedef struct {
    #   ///
    #   /// A GUID that defines the contents of a capsule.
    #   ///
    #   EFI_GUID          CapsuleGuid;
    #   ///
    #   /// The size of the capsule header. This may be larger than the size of
    #   /// the EFI_CAPSULE_HEADER since CapsuleGuid may imply
    #   /// extended header entries
    #   ///
    #   UINT32            HeaderSize;
    #   ///
    #   /// Bit-mapped list describing the capsule attributes. The Flag values
    #   /// of 0x0000 - 0xFFFF are defined by CapsuleGuid. Flag values
    #   /// of 0x10000 - 0xFFFFFFFF are defined by this specification
    #   ///
    #   UINT32            Flags;
    #   ///
    #   /// Size in bytes of the capsule.
    #   ///
    #   UINT32            CapsuleImageSize;
    # } EFI_CAPSULE_HEADER;
    #
    # #define CAPSULE_FLAGS_PERSIST_ACROSS_RESET          0x00010000
    # #define CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE         0x00020000
    # #define CAPSULE_FLAGS_INITIATE_RESET                0x00040000
    #
    _StructFormat = '<16sIIII'
    _StructSize = struct.calcsize(_StructFormat)

    EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID = uuid.UUID(
        '6DCBD5ED-E82D-4C44-BDA1-7194199AD92A')

    _CAPSULE_FLAGS_PERSIST_ACROSS_RESET = 0x00010000
    _CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE = 0x00020000
    _CAPSULE_FLAGS_INITIATE_RESET = 0x00040000

    def __init__(self):
        self.CapsuleGuid = self.EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID
        self.HeaderSize = self._StructSize
        self.OemFlags = 0x0000
        self.PersistAcrossReset = False
        self.PopulateSystemTable = False
        self.InitiateReset = False
        self.CapsuleImageSize = self.HeaderSize
        self.Payload = b''
        self.FmpCapsuleHeader = None

    def Encode(self):
        Flags = self.OemFlags
        if self.PersistAcrossReset:
            Flags = Flags | self._CAPSULE_FLAGS_PERSIST_ACROSS_RESET
        if self.PopulateSystemTable:
            Flags = Flags | self._CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE
        if self.InitiateReset:
            Flags = Flags | self._CAPSULE_FLAGS_INITIATE_RESET

        # If we have an FmpCapsuleHeader, let's collapse that now.
        if self.FmpCapsuleHeader is not None:
            self.Payload = self.FmpCapsuleHeader.Encode()

        self.CapsuleImageSize = self.HeaderSize + len(self.Payload)

        UefiCapsuleHeader = struct.pack(self._StructFormat,
                                        self.CapsuleGuid.bytes_le,
                                        self.HeaderSize, Flags,
                                        self.CapsuleImageSize, 0)

        return UefiCapsuleHeader + self.Payload

    def Decode(self, Buffer):
        if len(Buffer) < self._StructSize:
            raise ValueError
        (CapsuleGuid, HeaderSize, Flags, CapsuleImageSize,
         Reserved) = struct.unpack(self._StructFormat,
                                   Buffer[0:self._StructSize])
        if HeaderSize < self._StructSize:
            raise ValueError
        if CapsuleImageSize != len(Buffer):
            raise ValueError
        self.CapsuleGuid = uuid.UUID(bytes_le=CapsuleGuid)
        self.HeaderSize = HeaderSize
        self.OemFlags = Flags & 0xffff
        self.PersistAcrossReset = (
            Flags & self._CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0
        self.PopulateSystemTable = (
            Flags & self._CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0
        self.InitiateReset = (Flags & self._CAPSULE_FLAGS_INITIATE_RESET) != 0
        self.CapsuleImageSize = CapsuleImageSize
        self.Payload = Buffer[self.HeaderSize:]
        if len(
                self.Payload
        ) > 0 and self.CapsuleGuid == self.EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID:
            self.FmpCapsuleHeader = FmpCapsuleHeaderClass()
            self.FmpCapsuleHeader.Decode(self.Payload)

        return self.Payload

    def DumpInfo(self):
        Flags = self.OemFlags
        if self.PersistAcrossReset:
            Flags = Flags | self._CAPSULE_FLAGS_PERSIST_ACROSS_RESET
        if self.PopulateSystemTable:
            Flags = Flags | self._CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE
        if self.InitiateReset:
            Flags = Flags | self._CAPSULE_FLAGS_INITIATE_RESET
        print('EFI_CAPSULE_HEADER.CapsuleGuid      = {Guid}'.format(
            Guid=str(self.CapsuleGuid).upper()))
        print('EFI_CAPSULE_HEADER.HeaderSize       = {Size:08X}'.format(
            Size=self.HeaderSize))
        print('EFI_CAPSULE_HEADER.Flags            = {Flags:08X}'.format(
            Flags=Flags))
        print('  OEM Flags                         = {Flags:04X}'.format(
            Flags=self.OemFlags))
        if self.PersistAcrossReset:
            print('  CAPSULE_FLAGS_PERSIST_ACROSS_RESET')
        if self.PopulateSystemTable:
            print('  CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE')
        if self.InitiateReset:
            print('  CAPSULE_FLAGS_INITIATE_RESET')
        print('EFI_CAPSULE_HEADER.CapsuleImageSize = {Size:08X}'.format(
            Size=self.CapsuleImageSize))
        print('sizeof (Payload)                    = {Size:08X}'.format(
            Size=len(self.Payload)))
        if self.FmpCapsuleHeader is not None:
            self.FmpCapsuleHeader.DumpInfo()
예제 #7
0
 def test_encoding_twice_should_yield_identical_results(self):
     test_header = FmpCapsuleHeaderClass()
     test_header.AddEmbeddedDriver(b'dummydriver')
     encode_1 = test_header.Encode()
     encode_2 = test_header.Encode()
     self.assertEqual(encode_1, encode_2)