1

In a Windows portable executable (PE) file the certificate directory points to an offset to a WIN_CERTIFICATE structure. My understanding is that while the field is named bCertificate, it actually contains an array of certificates in ASN.1 format in order to support multiple signatures.

Having extracted the bCertificate data from a number of signed Microsoft executables, I can see that the data within is an ASN.1 SEQUENCE structure containing one or more objects with OID 1.2.840.113549.1.7.2, corresponding to PKCS#7 signedData. It is unclear to me whether this structure is itself hashed (is a PKCS#7 signedData structure a certificate?) as part of authenticode, or even if multiple certificates are encoded as sequential ASN.1 structures with no parent ASN.1 sequence (i.e. concatenated ASN.1 certificates), or as ASN.1 elements inside a parent SEQUENCE element.

The documented process for producing the authenticity hash talks about skipping some PE fields - the checksum, the certificate directory RVA/size, and the certificate entry itself. It is clear to me that the certificate itself does not need to be part of the hash, as its authenticity is already controlled via CA/intermediate signing. However it isn't clear to me whether the exclusion includes any wrapping structure, if one exists (see prior paragraph).

Can someone clarify this? Is the PKCS#7 signedData structure considered to be a certificate in the context of authenticode hashing? Is the certificate array simply a concatenation of ASN.1-encoded certificates, or is the array facilitated by a parent ASN.1 sequence? If it's the latter, is the ASN.1 sequence definition (type + size) part of the authenticode hash?

Polynomial
  • 132,208
  • 43
  • 298
  • 379

3 Answers3

2

I think most if not all of your questions can be answered by Microsoft's, Windows Authenticode Portable Executable Signature doc: http://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/authenticode_pe.docx

The data looks significantly cleaner in the doc but I've included the parts I believe to be relevant to your questions.

The Authenticode signature in a PE file is in a PKCS #7 SignedData structure. The signature asserts that: • The file originates from a specific software publisher. • The file has not been altered since it was signed.

The signature itself does not convey any information about the intent or quality of the software. However, signatures that are associated with programs such as the Windows Logo Program—that sign software only if it passes certain tests—can convey quality information. A PKCS #7 SignedData structure contains the PE file's hash value, a signature created by the software publisher’s private key, and the X.509 v3 certificates that bind the software publisher’s signing key to a legal entity. A PKCS #7 SignedData structure can optionally contain: • A description of the software publisher. • The software publisher's URL. • An Authenticode timestamp. The timestamp is generated by a timestamping authority (TSA) and asserts that a publisher’s signature existed before the specified time. The timestamp extends the lifetime of the signature when a signing certificate expires or is later revoked.

Authenticode signatures can be “embedded” in a Windows PE file, in a location specified by the Certificate Table entry in Optional Header Data Directories. When Authenticode is used to sign a Windows PE file, the algorithm that calculates the file's Authenticode hash value excludes certain PE fields. When embedding the signature in the file, the signing process can modify these fields without affecting the file's hash value. Figure 1 provides a simplified overview of how an Authenticode signature is included in a Windows PE file. It includes the location of the embedded Authenticode signature and specifies which PE fields are excluded when calculating the PE file's hash value. For details about the PE file structure, see ”Microsoft Portable Executable and Common Object File Format Specification” (PE/COFF specification). For details on the PKCS #7 portion of the Authenticode signature see the Abstract Syntax Notation version 1 (ASN.1) structure definitions later in this paper. For details on how the Authenticode PE hash value is calculated, see “Calculating the PE Image Hash” later in this paper.

authenticode_sig

Authenticode Profile of PKCS #7 SignedData This profile describes which PKCS #7 structures and values are used in the Authenticode signature. For more details on the PKCS #7 standard, see ”PKCS #7: Cryptographic Message Syntax Standard.” SignedData The PKCS #7 v1.5 specification defines the following ASN.1 structure for SignedData: SignedData ::= SEQUENCE { version Version, digestAlgorithms DigestAlgorithmIdentifiers, contentInfo ContentInfo, certificates [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL, Crls 1 IMPLICIT CertificateRevocationLists OPTIONAL, signerInfos SignerInfos }

DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier

ContentInfo ::= SEQUENCE { contentType ContentType, content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }

ContentType ::= OBJECT IDENTIFIER

SignerInfos ::= SET OF SignerInfo

The Authenticode profile of SignedData assigns the following values: version This field must be set to 1. digestAlgorithms This field contains the object identifiers (OIDs) of the digest algorithms that are used to sign the contents of the ContentInfo type, as defined by ”PKCS #7: Cryptographic Message Syntax Standard.” Because Authenticode signatures support only one signer, digestAlgorithms must contain only one digestAlgorithmIdentifier structure and the structure must match the value set in the SignerInfo structure's digestAlgorithm field. If not, the signature has been tampered with. contentInfo This field contains two fields: • contentType must be set to SPC_INDIRECT_DATA_OBJID (1.3.6.1.4.1.311.2.1.4). • content must be set to an SpcIndirectDataContent structure, which is described later. certificates This field contains a set of certificates. For Authenticode signatures, certificates contains the signer certificate and any intermediate certificates, but typically does not contain the root certificate. If the Authenticode signature is timestamped, certificates contains certificates that are used to verify the timestamp, which may include the root certificate. Authenticode certificate processing rules are described in “Authenticode Signature Verification” later in this paper. Note: This paper specifies only the signature format of PE files that are signed with X.509 v3 certificates. For more information on processing X.509 v3 certificate chains, see ”Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile.” crls This field is not used. signerInfos This field contains a set of SignerInfo structures, which contains information about the signatures. Because Authenticode supports only one signer, only one SignerInfo structure is in signerInfos. For details, see ”SignerInfo” later in this paper. SignerInfo For Authenticode signatures, SignerInfos contains one SignerInfo structure. The PKCS #7 v1.5 specification defines the following ASN.1 structure for SignerInfo: SignerInfo ::= SEQUENCE {
version Version, issuerAndSerialNumber IssuerAndSerialNumber,
digestAlgorithm DigestAlgorithmIdentifier, authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL, digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier, encryptedDigest EncryptedDigest, unauthenticatedAttributes 1 IMPLICIT Attributes OPTIONAL } IssuerAndSerialNumber ::= SEQUENCE { issuer Name, serialNumber CertificateSerialNumber } EncryptedDigest ::= OCTET STRING

The Authenticode profile for SignerInfo assigns the following values: version This field must be set to 1. issuerAndSerialNumber This field contains an issuerAndSerialNumber structure, which contains the issuer name and serial number of the signing certificate, as defined by ”PKCS

7: Cryptographic Message Syntax Standard.” digestAlgorithm This field contains the OID of the digest algorithm that is used to sign the

contents of ContentInfo, as defined by ”PKCS #7: Cryptographic Message Syntax Standard.” The digestAlgorithm value in the parent SignedData structure must match the digestAlgorithm value assigned in signerInfo. Algorithms supported by Authenticode include: • SHA1 (1.3.14.3.2.26) • MD5 (1.2.840.113549.2.5) This algorithm is supported only for backwards-compatibility requirements and should not be used to sign new content. authenticatedAttributes This field contains a set of signed attributes. The following attributes are always present: • contentType (1.2.840.113549.1.9.3) This attribute contains a messageDigest OID (1.2.840.113549.1.9.4) as defined in ”PKCS #9: Selected Attribute Types.” • messageDigest (1.2.840.113549.1.9.4) This attribute contains an octet string with a hash value that is calculated as defined in ”PKCS #7: Cryptographic Message Syntax Standard.” The follow signed attribute is always present in an Authenticode signature: • SPC_SP_OPUS_INFO_OBJID (1.3.6.1.4.1.311.2.1.12) This attribute contains an SpcSpOpusInfo structure. For details, see ”Authenticode-Specific Structures” later in this paper. digestEncryptionAlgorithm This field contains an OID that specifies the signature algorithm. Supported algorithms include: • RSA (1.2.840.113549.1.1.1) • DSA (1.2.840.10040.4.1) encryptedDigest This field contains the signature created by the signing certificate's private key, calculated as defined by the PKCS #7 specification. unauthenticatedAttributes If present, this field contains an Attributes object that in turn contains a set of Attribute objects. In Authenticode, this set contains only one Attribute object, which contains an Authenticode timestamp. The Authenticode timestamp is described in ”Authenticode-Specific Structures” later in this paper. Authenticode-Specific Structures This part of the paper describes the Authenticode-specific structures in an Authenticode signature’s PKCS

7 SignedData structure. Authenticode-Specific Structures in ContentInfo An Authenticode signature's ContentInfo structure contains

several structures that in turn contain the file's hash value, page hash values (if present), the file description, and various optional or legacy ASN.1 fields. The root structure is SpcIndirectDataContent. SpcIndirectDataContent The following is the ASN.1 definition of SpcIndirectDataContent: SpcIndirectDataContent ::= SEQUENCE { data SpcAttributeTypeAndOptionalValue, messageDigest DigestInfo } --#public—

SpcAttributeTypeAndOptionalValue ::= SEQUENCE { type ObjectID, value [0] EXPLICIT ANY OPTIONAL }

DigestInfo ::= SEQUENCE { digestAlgorithm AlgorithmIdentifier, digest OCTETSTRING }

AlgorithmIdentifier ::= SEQUENCE { algorithm ObjectID, parameters [0] EXPLICIT ANY OPTIONAL }

The SpcIndirectDataContent structure has two members: data This field is set to an SpcAttributeTypeAndOptionalValue structure. messageDigest This field is set to a DigestInfo structure. These structures are defined later. The SpcAttributeTypeAndOptionalValue structure has two fields, which are set as follows for an Authenticode-signed PE file: type This field is set to SPC_PE_IMAGE_DATAOBJ OID (1.3.6.1.4.1.311.2.1.15). value This field is set to an SpcPeImageData structure, which is defined later. The DigestInfo structure has two fields: digestAlgorithm This field specifies the digest algorithm that is used to hash the file. The value must match the digestAlgorithm value specified in SignerInfo and the parent PKCS #7 digestAlgorithms fields. digest This field is set to the message digest value of the file. For details, see “Calculating the PE Image Hash” later in the paper. SpcPeImageData The following is the ASN.1 definition of SpcPeImageData: SpcPeImageData ::= SEQUENCE { flags
SpcPeImageFlags DEFAULT { includeResources }, file
SpcLink } --#public--

SpcPeImageFlags ::= BIT STRING { includeResources (0), includeDebugInfo (1), includeImportAddressTable (2) }

SpcLink ::= CHOICE { url [0] IMPLICIT IA5STRING, moniker 1 IMPLICIT SpcSerializedObject, file [2] EXPLICIT SpcString } --#public--

SpcString ::= CHOICE { unicode [0] IMPLICIT BMPSTRING, ascii 1 IMPLICIT IA5STRING }

The SpcPeImageData structure has two fields: flags This field specifies which portions of the Windows PE file are hashed. It is a 2-bit value that is set to one of the SpcPeImageData flags. Although flags is always present, it is ignored when calculating the file hash for both signing and verification purposes. file This field is always set to an SPCLink structure, even though the ASN.1 definitions designate file as optional. SPCLink originally contained information that describes the software publisher, but it now has the following choices: url [0] This choice is not supported, but it does not affect signature verification if present. moniker 1 This choice is set to an SpcSerializedObject structure, which is described later. file [2] This is the default choice. It is set to an SpcString structure, which contains a Unicode string set to “<<>>”. Warning to Implementers: There is an optional instance of SpcString in the SignerInfo structure that, if present, contains an ASCII string set to the publisher's URL. Do not confuse these instances of SPCString. SpcSerializedObject The following is the ASN.1 definition of SpcSerializedObject: SpcSerializedObject ::= SEQUENCE { classId SpcUuid, serializedData OCTETSTRING }

SpcUuid ::= OCTETSTRING

SpcUuid The SpcUuid field is set to the following 10-byte octet string (a globally unique identifier—GUID) if SpcSerializedObject is present: a6 b5 86 d5 b4 a1 24 66 ae 05 a2 17 da 8e 60 d6

serializedData The serializedData field contains a binary structure. When present in an Authenticode signature generated in Windows Vista, serializedData contains a binary structure that contains page hashes. However, the definition of this binary structure is outside the scope of this paper. Authenticode-Specific SignerInfo UnauthenticatedAttributes Structures The following Authenticode-specific data structures are present in SignerInfo authenticated attributes. SpcSpOpusInfo SpcSpOpusInfo is identified by SPC_SP_OPUS_INFO_OBJID (1.3.6.1.4.1.311.2.1.12) and is defined as follows: SpcSpOpusInfo ::= SEQUENCE { programName [0] EXPLICIT SpcString OPTIONAL, moreInfo 1 EXPLICIT SpcLink OPTIONAL, } --#public--

SpcSpOpusInfo has two fields: programName This field contains the program description: • If publisher chooses not to specify a description, the SpcString structure contains a zero-length program name. • If the publisher chooses to specify a description, the SpcString structure contains a Unicode string. moreInfo This field is set to an SPCLink structure that contains a URL for a Web site with more information about the signer. The URL is an ASCII string. Authenticode-Specific SignerInfo UnsignedAttrs Structures The following Authenticode-specific data structures are present in SignerInfo unsigned attributes. Authenticode Timestamp The Authenticode timestamp is a PKCS #9 v1 countersignature located in the software publisher's SignerInfo unauthenticatedAttributes. The timestamp is generated by a TSA and signs both the hash value of the SignerInfo structure's encryptedDigest field and the Coordinated Universal Time (UTC) time at which the timestamp was generated. The timestamp asserts that the signature existed before the UTC time specified by the timestamp. The timestamp certificate chain—including the root certificate—is added to the PKCS #7 SignedData certificates structure, although the root certificate is not required. The following is the timestamp attribute's OID type: szOID_RSA_counterSign 1.2.840.113549.1.9.6

The timestamp attribute content contains a PKCS #9 countersignature. The values in the countersignature are set by the TSA in accordance with ”PKCS #9: Selected Attribute Types.” The ASN.1 definition of SignerInfo that the countersignature uses is the same as that discussed in ”SignerInfo” earlier in this paper. The Authenticode timestamp SignerInfo structure contains the following authenticatedAttributes values: • ContentType (1.2.840.113549.1.9.3) is set to PKCS #7 Data (1.2.840.113549.1.7.1). • Signing Time (1.2.840.113549.1.9.5) is set to the UTC time of timestamp generation time. • Message Digest (1.2.840.113549.1.9.4) is set to the hash value of the SignerInfo structure's encryptedDigest value. The hash algorithm that is used to calculate the hash value is the same as that specified in the SignerInfo structure’s digestAlgorithm value of the timestamp.

Authenticode Signature Verification The most common Authenticode verification policy is implemented by the Win32® WinVerifyTrust function with pgActionID set to WINTRUST_ACTION_GENERIC_VERIFY_V2. This section describes how Authenticode signatures are verified against this policy. Note: This portion of the paper refers to many PE structures described in the PE/COFF specification. You will find it helpful to have that document available for reference. Extracting and Verifying PKCS #7 The Authenticode signature is in a location that is specified by the Certificates Table entry in Optional Header Data Directories and the associated Attribute Certificate Table. Note: “Attribute Certificate” as used by the PE/COFF specification does not refer to X.509 attribute certificates, as used in a PKI context. This is an unfortunate name collision. The Authenticode signature is in a WIN_CERTIFICATE structure, which is declared in Wintrust.h as follows: typedef struct _WIN_CERTIFICATE { DWORD dwLength; WORD wRevision; WORD wCertificateType;
BYTE bCertificate[ANYSIZE_ARRAY]; } WIN_CERTIFICATE, *LPWIN_CERTIFICATE;

The fields in WIN_CERTIFICATE are set to the following values: • dwLength is set to the length of bCertificate. • wRevision is set to the WIN_CERTIFICATE version number. Value Name Notes 0x0100 WIN_CERT_REVISION_1_0 Version 1 is the legacy version of WIN_CERTIFICATE. It is supported only for verifying legacy Authenticode signatures. 0x0200 WIN_CERT_REVISION_2_0 Version 2 is the current version of WIN_CERTIFICATE.

• wCertificateType is set to 0x0002 for Authenticode signatures. This value is defined in Wintrust.h as WIN_CERT_TYPE_PKCS_SIGNED_DATA. • bCertificate is set to a variable-length binary array that contains the Authenticode PKCS #7 signedData. The PKCS #7 integrity is verified as described in ”PKCS #7: Cryptographic Message Syntax Standard.”

thepip3r
  • 633
  • 3
  • 8
2

Nope. The entire certificate entry table is excluded from the Authenticode digest.

The intuition for this is that, in the case of multiple certificates, the length and other metadata in the certificate entry table would cause problems for consistent hashing.

MSDN offers similar reasoning (link):

When included in a certificate, the image digest must exclude certain fields in the PE Image, such as the Checksum and Certificate Table entry in Optional Header Data Directories. This is because the act of adding a Certificate changes these fields and would cause a different hash value to be calculated.

yossarian
  • 121
  • 3
0

Basically, if you want Python/pseudocode from folks who have reproduced the algorithm without using MSFT tools:

raw_data = pe.__data__

hash_data = raw_data[:checksum_offset] + 
            raw_data[checksum_offset+0x04:certificate_table_offset]
# ^^ Skip OptionalHeader.CheckSum field and continue until IMAGE_DIRECTORY_ENTRY_SECURITY

hash_data += raw_data[certificate_table_offset+0x08:certificate_virtual_addr] +
             raw_data[certificate_virtual_addr+certificate_size:]
# ^^ Skip IMAGE_DIRECTORY_ENTRY_SECURITY and certificate

Unfortunately, I don't know of any MSFT tools that print that particular hash (used internally during signature verification), as opposed to one computed over the whole file. One thing that can be miffing, in practice, is that if you sign the same file twice it can have different signatures in some setups, due to the inclusion of a timestamp of the signing date/moment in the counter-signature(s). So whole-file hash will be different in that scenario, even if the payload hash relevant for the check is the same.

Fizz
  • 111
  • 5