CloverBootloader/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py
2019-09-03 12:58:42 +03:00

191 lines
7.7 KiB
Python

## @file
# Module that encodes and decodes a EFI_FIRMWARE_IMAGE_AUTHENTICATION with
# certificate data and payload data.
#
# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
'''
FmpAuthHeader
'''
import struct
import uuid
class FmpAuthHeaderClass (object):
# ///
# /// Image Attribute -Authentication Required
# ///
# typedef struct {
# ///
# /// It is included in the signature of AuthInfo. It is used to ensure freshness/no replay.
# /// It is incremented during each firmware image operation.
# ///
# UINT64 MonotonicCount;
# ///
# /// Provides the authorization for the firmware image operations. It is a signature across
# /// the image data and the Monotonic Count value. Caller uses the private key that is
# /// associated with a public key that has been provisioned via the key exchange.
# /// Because this is defined as a signature, WIN_CERTIFICATE_UEFI_GUID.CertType must
# /// be EFI_CERT_TYPE_PKCS7_GUID.
# ///
# WIN_CERTIFICATE_UEFI_GUID AuthInfo;
# } EFI_FIRMWARE_IMAGE_AUTHENTICATION;
#
# ///
# /// Certificate which encapsulates a GUID-specific digital signature
# ///
# typedef struct {
# ///
# /// This is the standard WIN_CERTIFICATE header, where
# /// wCertificateType is set to WIN_CERT_TYPE_EFI_GUID.
# ///
# WIN_CERTIFICATE Hdr;
# ///
# /// This is the unique id which determines the
# /// format of the CertData. .
# ///
# EFI_GUID CertType;
# ///
# /// The following is the certificate data. The format of
# /// the data is determined by the CertType.
# /// If CertType is EFI_CERT_TYPE_RSA2048_SHA256_GUID,
# /// the CertData will be EFI_CERT_BLOCK_RSA_2048_SHA256 structure.
# ///
# UINT8 CertData[1];
# } WIN_CERTIFICATE_UEFI_GUID;
#
# ///
# /// The WIN_CERTIFICATE structure is part of the PE/COFF specification.
# ///
# typedef struct {
# ///
# /// The length of the entire certificate,
# /// including the length of the header, in bytes.
# ///
# UINT32 dwLength;
# ///
# /// The revision level of the WIN_CERTIFICATE
# /// structure. The current revision level is 0x0200.
# ///
# UINT16 wRevision;
# ///
# /// The certificate type. See WIN_CERT_TYPE_xxx for the UEFI
# /// certificate types. The UEFI specification reserves the range of
# /// certificate type values from 0x0EF0 to 0x0EFF.
# ///
# UINT16 wCertificateType;
# ///
# /// The following is the actual certificate. The format of
# /// the certificate depends on wCertificateType.
# ///
# /// UINT8 bCertificate[ANYSIZE_ARRAY];
# ///
# } WIN_CERTIFICATE;
#
# #define WIN_CERT_TYPE_EFI_GUID 0x0EF1
#
# ///
# /// This identifies a signature containing a DER-encoded PKCS #7 version 1.5 [RFC2315]
# /// SignedData value.
# ///
# #define EFI_CERT_TYPE_PKCS7_GUID \
# { \
# 0x4aafd29d, 0x68df, 0x49ee, {0x8a, 0xa9, 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7} \
# }
_StructFormat = '<QIHH16s'
_StructSize = struct.calcsize (_StructFormat)
_MonotonicCountFormat = '<Q'
_MonotonicCountSize = struct.calcsize (_MonotonicCountFormat)
_StructAuthInfoFormat = '<IHH16s'
_StructAuthInfoSize = struct.calcsize (_StructAuthInfoFormat)
_WIN_CERT_REVISION = 0x0200
_WIN_CERT_TYPE_EFI_GUID = 0x0EF1
_EFI_CERT_TYPE_PKCS7_GUID = uuid.UUID ('4aafd29d-68df-49ee-8aa9-347d375665a7')
def __init__ (self):
self._Valid = False
self.MonotonicCount = 0
self.dwLength = self._StructAuthInfoSize
self.wRevision = self._WIN_CERT_REVISION
self.wCertificateType = self._WIN_CERT_TYPE_EFI_GUID
self.CertType = self._EFI_CERT_TYPE_PKCS7_GUID
self.CertData = b''
self.Payload = b''
def Encode (self):
if self.wRevision != self._WIN_CERT_REVISION:
raise ValueError
if self.wCertificateType != self._WIN_CERT_TYPE_EFI_GUID:
raise ValueError
if self.CertType != self._EFI_CERT_TYPE_PKCS7_GUID:
raise ValueError
self.dwLength = self._StructAuthInfoSize + len (self.CertData)
FmpAuthHeader = struct.pack (
self._StructFormat,
self.MonotonicCount,
self.dwLength,
self.wRevision,
self.wCertificateType,
self.CertType.bytes_le
)
self._Valid = True
return FmpAuthHeader + self.CertData + self.Payload
def Decode (self, Buffer):
if len (Buffer) < self._StructSize:
raise ValueError
(MonotonicCount, dwLength, wRevision, wCertificateType, CertType) = \
struct.unpack (
self._StructFormat,
Buffer[0:self._StructSize]
)
if dwLength < self._StructAuthInfoSize:
raise ValueError
if wRevision != self._WIN_CERT_REVISION:
raise ValueError
if wCertificateType != self._WIN_CERT_TYPE_EFI_GUID:
raise ValueError
if CertType != self._EFI_CERT_TYPE_PKCS7_GUID.bytes_le:
raise ValueError
self.MonotonicCount = MonotonicCount
self.dwLength = dwLength
self.wRevision = wRevision
self.wCertificateType = wCertificateType
self.CertType = uuid.UUID (bytes_le = CertType)
self.CertData = Buffer[self._StructSize:self._MonotonicCountSize + self.dwLength]
self.Payload = Buffer[self._MonotonicCountSize + self.dwLength:]
self._Valid = True
return self.Payload
def IsSigned (self, Buffer):
if len (Buffer) < self._StructSize:
return False
(MonotonicCount, dwLength, wRevision, wCertificateType, CertType) = \
struct.unpack (
self._StructFormat,
Buffer[0:self._StructSize]
)
if CertType != self._EFI_CERT_TYPE_PKCS7_GUID.bytes_le:
return False
return True
def DumpInfo (self):
if not self._Valid:
raise ValueError
print ('EFI_FIRMWARE_IMAGE_AUTHENTICATION.MonotonicCount = {MonotonicCount:016X}'.format (MonotonicCount = self.MonotonicCount))
print ('EFI_FIRMWARE_IMAGE_AUTHENTICATION.AuthInfo.Hdr.dwLength = {dwLength:08X}'.format (dwLength = self.dwLength))
print ('EFI_FIRMWARE_IMAGE_AUTHENTICATION.AuthInfo.Hdr.wRevision = {wRevision:04X}'.format (wRevision = self.wRevision))
print ('EFI_FIRMWARE_IMAGE_AUTHENTICATION.AuthInfo.Hdr.wCertificateType = {wCertificateType:04X}'.format (wCertificateType = self.wCertificateType))
print ('EFI_FIRMWARE_IMAGE_AUTHENTICATION.AuthInfo.CertType = {Guid}'.format (Guid = str(self.CertType).upper()))
print ('sizeof (EFI_FIRMWARE_IMAGE_AUTHENTICATION.AuthInfo.CertData) = {Size:08X}'.format (Size = len (self.CertData)))
print ('sizeof (Payload) = {Size:08X}'.format (Size = len (self.Payload)))