REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3737 Apply uncrustify changes to .c/.h files in the CryptoPkg package Cc: Andrew Fish <afish@apple.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Jian J Wang <jian.j.wang@intel.com>
		
			
				
	
	
		
			684 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			684 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  RFC3161 Timestamp Countersignature Verification over OpenSSL.
 | 
						|
  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.
 | 
						|
 | 
						|
Copyright (c) 2014 - 2017, Intel Corporation. All rights reserved.<BR>
 | 
						|
SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "InternalCryptLib.h"
 | 
						|
 | 
						|
#include <openssl/asn1.h>
 | 
						|
#include <openssl/asn1t.h>
 | 
						|
#include <openssl/x509.h>
 | 
						|
#include <openssl/x509v3.h>
 | 
						|
#include <openssl/pkcs7.h>
 | 
						|
 | 
						|
//
 | 
						|
// OID ASN.1 Value for SPC_RFC3161_OBJID ("1.3.6.1.4.1.311.3.3.1")
 | 
						|
//
 | 
						|
UINT8  mSpcRFC3161OidValue[] = {
 | 
						|
  0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x03, 0x03, 0x01
 | 
						|
};
 | 
						|
 | 
						|
///
 | 
						|
/// The messageImprint field SHOULD contain the hash of the datum to be
 | 
						|
/// time-stamped.  The hash is represented as an OCTET STRING.  Its
 | 
						|
/// length MUST match the length of the hash value for that algorithm
 | 
						|
/// (e.g., 20 bytes for SHA-1 or 16 bytes for MD5).
 | 
						|
///
 | 
						|
/// MessageImprint ::= SEQUENCE  {
 | 
						|
///   hashAlgorithm                AlgorithmIdentifier,
 | 
						|
///   hashedMessage                OCTET STRING  }
 | 
						|
///
 | 
						|
typedef struct {
 | 
						|
  X509_ALGOR           *HashAlgorithm;
 | 
						|
  ASN1_OCTET_STRING    *HashedMessage;
 | 
						|
} TS_MESSAGE_IMPRINT;
 | 
						|
 | 
						|
//
 | 
						|
// ASN.1 Functions for TS_MESSAGE_IMPRINT
 | 
						|
//
 | 
						|
DECLARE_ASN1_FUNCTIONS (TS_MESSAGE_IMPRINT)
 | 
						|
ASN1_SEQUENCE (TS_MESSAGE_IMPRINT) = {
 | 
						|
  ASN1_SIMPLE (TS_MESSAGE_IMPRINT, HashAlgorithm, X509_ALGOR),
 | 
						|
  ASN1_SIMPLE (TS_MESSAGE_IMPRINT, HashedMessage, ASN1_OCTET_STRING)
 | 
						|
} ASN1_SEQUENCE_END (TS_MESSAGE_IMPRINT)
 | 
						|
IMPLEMENT_ASN1_FUNCTIONS (TS_MESSAGE_IMPRINT)
 | 
						|
 | 
						|
///
 | 
						|
/// Accuracy represents the time deviation around the UTC time contained
 | 
						|
/// in GeneralizedTime of time-stamp token.
 | 
						|
///
 | 
						|
/// Accuracy ::= SEQUENCE {
 | 
						|
///       seconds        INTEGER              OPTIONAL,
 | 
						|
///       millis     [0] INTEGER  (1..999)    OPTIONAL,
 | 
						|
///       micros     [1] INTEGER  (1..999)    OPTIONAL  }
 | 
						|
///
 | 
						|
typedef struct {
 | 
						|
  ASN1_INTEGER    *Seconds;
 | 
						|
  ASN1_INTEGER    *Millis;
 | 
						|
  ASN1_INTEGER    *Micros;
 | 
						|
} TS_ACCURACY;
 | 
						|
 | 
						|
//
 | 
						|
// ASN.1 Functions for TS_ACCURACY
 | 
						|
//
 | 
						|
DECLARE_ASN1_FUNCTIONS (TS_ACCURACY)
 | 
						|
ASN1_SEQUENCE (TS_ACCURACY) = {
 | 
						|
  ASN1_OPT (TS_ACCURACY,     Seconds, ASN1_INTEGER),
 | 
						|
  ASN1_IMP_OPT (TS_ACCURACY, Millis,  ASN1_INTEGER, 0),
 | 
						|
  ASN1_IMP_OPT (TS_ACCURACY, Micros,  ASN1_INTEGER, 1)
 | 
						|
} ASN1_SEQUENCE_END (TS_ACCURACY)
 | 
						|
IMPLEMENT_ASN1_FUNCTIONS (TS_ACCURACY)
 | 
						|
 | 
						|
///
 | 
						|
/// The timestamp token info resulting from a successful timestamp request,
 | 
						|
/// as defined in RFC 3161.
 | 
						|
///
 | 
						|
///  TSTInfo ::= SEQUENCE  {
 | 
						|
///     version                      INTEGER  { v1(1) },
 | 
						|
///     policy                       TSAPolicyId,
 | 
						|
///     messageImprint               MessageImprint,
 | 
						|
///       -- MUST have the same value as the similar field in
 | 
						|
///       -- TimeStampReq
 | 
						|
///     serialNumber                 INTEGER,
 | 
						|
///       -- Time-Stamping users MUST be ready to accommodate integers
 | 
						|
///       -- up to 160 bits.
 | 
						|
///     genTime                      GeneralizedTime,
 | 
						|
///     accuracy                     Accuracy                 OPTIONAL,
 | 
						|
///     ordering                     BOOLEAN             DEFAULT FALSE,
 | 
						|
///     nonce                        INTEGER                  OPTIONAL,
 | 
						|
///       -- MUST be present if the similar field was present
 | 
						|
///       -- in TimeStampReq.  In that case it MUST have the same value.
 | 
						|
///     tsa                          [0] GeneralName          OPTIONAL,
 | 
						|
///     extensions                   [1] IMPLICIT Extensions   OPTIONAL  }
 | 
						|
///
 | 
						|
typedef struct {
 | 
						|
  ASN1_INTEGER            *Version;
 | 
						|
  ASN1_OBJECT             *Policy;
 | 
						|
  TS_MESSAGE_IMPRINT      *MessageImprint;
 | 
						|
  ASN1_INTEGER            *SerialNumber;
 | 
						|
  ASN1_GENERALIZEDTIME    *GenTime;
 | 
						|
  TS_ACCURACY             *Accuracy;
 | 
						|
  ASN1_BOOLEAN            Ordering;
 | 
						|
  ASN1_INTEGER            *Nonce;
 | 
						|
  GENERAL_NAME            *Tsa;
 | 
						|
  STACK_OF (X509_EXTENSION)  *Extensions;
 | 
						|
} TS_TST_INFO;
 | 
						|
 | 
						|
//
 | 
						|
// ASN.1 Functions for TS_TST_INFO
 | 
						|
//
 | 
						|
DECLARE_ASN1_FUNCTIONS (TS_TST_INFO)
 | 
						|
ASN1_SEQUENCE (TS_TST_INFO) = {
 | 
						|
  ASN1_SIMPLE (TS_TST_INFO,              Version,        ASN1_INTEGER),
 | 
						|
  ASN1_SIMPLE (TS_TST_INFO,              Policy,         ASN1_OBJECT),
 | 
						|
  ASN1_SIMPLE (TS_TST_INFO,              MessageImprint, TS_MESSAGE_IMPRINT),
 | 
						|
  ASN1_SIMPLE (TS_TST_INFO,              SerialNumber,   ASN1_INTEGER),
 | 
						|
  ASN1_SIMPLE (TS_TST_INFO,              GenTime,        ASN1_GENERALIZEDTIME),
 | 
						|
  ASN1_OPT (TS_TST_INFO,                 Accuracy,       TS_ACCURACY),
 | 
						|
  ASN1_OPT (TS_TST_INFO,                 Ordering,       ASN1_FBOOLEAN),
 | 
						|
  ASN1_OPT (TS_TST_INFO,                 Nonce,          ASN1_INTEGER),
 | 
						|
  ASN1_EXP_OPT (TS_TST_INFO,             Tsa,            GENERAL_NAME,         0),
 | 
						|
  ASN1_IMP_SEQUENCE_OF_OPT (TS_TST_INFO, Extensions,     X509_EXTENSION,       1)
 | 
						|
} ASN1_SEQUENCE_END (TS_TST_INFO)
 | 
						|
IMPLEMENT_ASN1_FUNCTIONS (TS_TST_INFO)
 | 
						|
 | 
						|
/**
 | 
						|
  Convert ASN.1 GeneralizedTime to EFI Time.
 | 
						|
 | 
						|
  @param[in]  Asn1Time         Pointer to the ASN.1 GeneralizedTime to be converted.
 | 
						|
  @param[out] SigningTime      Return the corresponding EFI Time.
 | 
						|
 | 
						|
  @retval  TRUE   The time conversion succeeds.
 | 
						|
  @retval  FALSE  Invalid parameters.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
ConvertAsn1TimeToEfiTime (
 | 
						|
  IN  ASN1_TIME  *Asn1Time,
 | 
						|
  OUT EFI_TIME   *EfiTime
 | 
						|
  )
 | 
						|
{
 | 
						|
  CONST CHAR8  *Str;
 | 
						|
  UINTN        Index;
 | 
						|
 | 
						|
  if ((Asn1Time == NULL) || (EfiTime == NULL)) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  Str = (CONST CHAR8 *)Asn1Time->data;
 | 
						|
  SetMem (EfiTime, sizeof (EFI_TIME), 0);
 | 
						|
 | 
						|
  Index = 0;
 | 
						|
  if (Asn1Time->type == V_ASN1_UTCTIME) {
 | 
						|
    /* two digit year */
 | 
						|
    EfiTime->Year  = (Str[Index++] - '0') * 10;
 | 
						|
    EfiTime->Year += (Str[Index++] - '0');
 | 
						|
    if (EfiTime->Year < 70) {
 | 
						|
      EfiTime->Year += 100;
 | 
						|
    }
 | 
						|
  } else if (Asn1Time->type == V_ASN1_GENERALIZEDTIME) {
 | 
						|
    /* four digit year */
 | 
						|
    EfiTime->Year  = (Str[Index++] - '0') * 1000;
 | 
						|
    EfiTime->Year += (Str[Index++] - '0') * 100;
 | 
						|
    EfiTime->Year += (Str[Index++] - '0') * 10;
 | 
						|
    EfiTime->Year += (Str[Index++] - '0');
 | 
						|
    if ((EfiTime->Year < 1900) || (EfiTime->Year > 9999)) {
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  EfiTime->Month  = (Str[Index++] - '0') * 10;
 | 
						|
  EfiTime->Month += (Str[Index++] - '0');
 | 
						|
  if ((EfiTime->Month < 1) || (EfiTime->Month > 12)) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  EfiTime->Day  = (Str[Index++] - '0') * 10;
 | 
						|
  EfiTime->Day += (Str[Index++] - '0');
 | 
						|
  if ((EfiTime->Day < 1) || (EfiTime->Day > 31)) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  EfiTime->Hour  = (Str[Index++] - '0') * 10;
 | 
						|
  EfiTime->Hour += (Str[Index++] - '0');
 | 
						|
  if (EfiTime->Hour > 23) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  EfiTime->Minute  = (Str[Index++] - '0') * 10;
 | 
						|
  EfiTime->Minute += (Str[Index++] - '0');
 | 
						|
  if (EfiTime->Minute > 59) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  EfiTime->Second  = (Str[Index++] - '0') * 10;
 | 
						|
  EfiTime->Second += (Str[Index++] - '0');
 | 
						|
  if (EfiTime->Second > 59) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Note: we did not adjust the time based on time zone information */
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Check the validity of TimeStamp Token Information.
 | 
						|
 | 
						|
  @param[in]  TstInfo          Pointer to the TS_TST_INFO structure.
 | 
						|
  @param[in]  TimestampedData  Pointer to the data to be time-stamped.
 | 
						|
  @param[in]  DataSize         Size of timestamped data in bytes.
 | 
						|
 | 
						|
  @retval  TRUE   The TimeStamp Token Information is valid.
 | 
						|
  @retval  FALSE  Invalid TimeStamp Token Information.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
CheckTSTInfo (
 | 
						|
  IN  CONST TS_TST_INFO  *TstInfo,
 | 
						|
  IN  CONST UINT8        *TimestampedData,
 | 
						|
  IN  UINTN              DataSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  BOOLEAN             Status;
 | 
						|
  TS_MESSAGE_IMPRINT  *Imprint;
 | 
						|
  X509_ALGOR          *HashAlgo;
 | 
						|
  CONST EVP_MD        *Md;
 | 
						|
  EVP_MD_CTX          *MdCtx;
 | 
						|
  UINTN               MdSize;
 | 
						|
  UINT8               *HashedMsg;
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialization
 | 
						|
  //
 | 
						|
  Status    = FALSE;
 | 
						|
  HashAlgo  = NULL;
 | 
						|
  HashedMsg = NULL;
 | 
						|
  MdCtx     = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // -- Check version number of Timestamp:
 | 
						|
  //   The version field (currently v1) describes the version of the time-stamp token.
 | 
						|
  //   Conforming time-stamping servers MUST be able to provide version 1 time-stamp tokens.
 | 
						|
  //
 | 
						|
  if ((ASN1_INTEGER_get (TstInfo->Version)) != 1) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // -- Check Policies
 | 
						|
  //   The policy field MUST indicate the TSA's policy under which the response was produced.
 | 
						|
  //
 | 
						|
  if (TstInfo->Policy == NULL) {
 | 
						|
    /// NOTE: Need to check if the requested and returned policies.
 | 
						|
    ///       We have no information about the Requested TSA Policy.
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // -- Compute & Check Message Imprint
 | 
						|
  //
 | 
						|
  Imprint  = TstInfo->MessageImprint;
 | 
						|
  HashAlgo = X509_ALGOR_dup (Imprint->HashAlgorithm);
 | 
						|
 | 
						|
  Md = EVP_get_digestbyobj (HashAlgo->algorithm);
 | 
						|
  if (Md == NULL) {
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  MdSize    = EVP_MD_size (Md);
 | 
						|
  HashedMsg = AllocateZeroPool (MdSize);
 | 
						|
  if (HashedMsg == NULL) {
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  MdCtx = EVP_MD_CTX_new ();
 | 
						|
  if (MdCtx == NULL) {
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((EVP_DigestInit_ex (MdCtx, Md, NULL) != 1) ||
 | 
						|
      (EVP_DigestUpdate (MdCtx, TimestampedData, DataSize) != 1) ||
 | 
						|
      (EVP_DigestFinal (MdCtx, HashedMsg, NULL) != 1))
 | 
						|
  {
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((MdSize == (UINTN)ASN1_STRING_length (Imprint->HashedMessage)) &&
 | 
						|
      (CompareMem (HashedMsg, ASN1_STRING_get0_data (Imprint->HashedMessage), MdSize) != 0))
 | 
						|
  {
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // -- Check Nonces
 | 
						|
  //
 | 
						|
  if (TstInfo->Nonce != NULL) {
 | 
						|
    //
 | 
						|
    // Nonces is optional, No error if no nonce is returned;
 | 
						|
    //
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // -- Check if the TSA name and signer certificate is matched.
 | 
						|
  //
 | 
						|
  if (TstInfo->Tsa != NULL) {
 | 
						|
    //
 | 
						|
    //  Ignored the optional Tsa field checking.
 | 
						|
    //
 | 
						|
  }
 | 
						|
 | 
						|
  Status = TRUE;
 | 
						|
 | 
						|
_Exit:
 | 
						|
  X509_ALGOR_free (HashAlgo);
 | 
						|
  EVP_MD_CTX_free (MdCtx);
 | 
						|
  if (HashedMsg != NULL) {
 | 
						|
    FreePool (HashedMsg);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Verifies the validity of a TimeStamp Token as described in RFC 3161 ("Internet
 | 
						|
  X.509 Public Key Infrastructure Time-Stamp Protocol (TSP)").
 | 
						|
 | 
						|
  If TSToken is NULL, then return FALSE.
 | 
						|
  If TimestampedData is NULL, then return FALSE.
 | 
						|
 | 
						|
  @param[in]  TSToken          Pointer to the RFC3161 TimeStamp Token, which is generated
 | 
						|
                               by a TSA and located in the software publisher's SignerInfo
 | 
						|
                               structure.
 | 
						|
  @param[in]  TokenSize        Size of the TimeStamp Token in bytes.
 | 
						|
  @param[in]  TsaCert          Pointer to a trusted/root TSA certificate encoded in DER.
 | 
						|
  @param[in]  CertSize         Size of the trusted TSA certificate in bytes.
 | 
						|
  @param[in]  TimestampedData  Pointer to the data to be time-stamped.
 | 
						|
  @param[in]  DataSize         Size of timestamped data in bytes.
 | 
						|
  @param[out] SigningTime      Return the time of timestamp generation time if the timestamp
 | 
						|
                               signature is valid.
 | 
						|
 | 
						|
  @retval  TRUE   The specified timestamp token is valid.
 | 
						|
  @retval  FALSE  Invalid timestamp token.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
TimestampTokenVerify (
 | 
						|
  IN  CONST UINT8  *TSToken,
 | 
						|
  IN  UINTN        TokenSize,
 | 
						|
  IN  CONST UINT8  *TsaCert,
 | 
						|
  IN  UINTN        CertSize,
 | 
						|
  IN  CONST UINT8  *TimestampedData,
 | 
						|
  IN  UINTN        DataSize,
 | 
						|
  OUT EFI_TIME     *SigningTime
 | 
						|
  )
 | 
						|
{
 | 
						|
  BOOLEAN      Status;
 | 
						|
  CONST UINT8  *TokenTemp;
 | 
						|
  PKCS7        *Pkcs7;
 | 
						|
  X509         *Cert;
 | 
						|
  CONST UINT8  *CertTemp;
 | 
						|
  X509_STORE   *CertStore;
 | 
						|
  BIO          *OutBio;
 | 
						|
  UINT8        *TstData;
 | 
						|
  UINTN        TstSize;
 | 
						|
  CONST UINT8  *TstTemp;
 | 
						|
  TS_TST_INFO  *TstInfo;
 | 
						|
 | 
						|
  Status = FALSE;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check input parameters
 | 
						|
  //
 | 
						|
  if ((TSToken == NULL) || (TsaCert == NULL) || (TimestampedData == NULL) ||
 | 
						|
      (TokenSize > INT_MAX) || (CertSize > INT_MAX) || (DataSize > INT_MAX))
 | 
						|
  {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Initializations
 | 
						|
  //
 | 
						|
  if (SigningTime != NULL) {
 | 
						|
    SetMem (SigningTime, sizeof (EFI_TIME), 0);
 | 
						|
  }
 | 
						|
 | 
						|
  Pkcs7     = NULL;
 | 
						|
  Cert      = NULL;
 | 
						|
  CertStore = NULL;
 | 
						|
  OutBio    = NULL;
 | 
						|
  TstData   = NULL;
 | 
						|
  TstInfo   = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // TimeStamp Token should contain one valid DER-encoded ASN.1 PKCS#7 structure.
 | 
						|
  //
 | 
						|
  TokenTemp = TSToken;
 | 
						|
  Pkcs7     = d2i_PKCS7 (NULL, (const unsigned char **)&TokenTemp, (int)TokenSize);
 | 
						|
  if (Pkcs7 == NULL) {
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // The timestamp signature (TSA's response) will be one PKCS#7 signed data.
 | 
						|
  //
 | 
						|
  if (!PKCS7_type_is_signed (Pkcs7)) {
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Read the trusted TSA certificate (DER-encoded), and Construct X509 Certificate.
 | 
						|
  //
 | 
						|
  CertTemp = TsaCert;
 | 
						|
  Cert     = d2i_X509 (NULL, &CertTemp, (long)CertSize);
 | 
						|
  if (Cert == NULL) {
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Setup X509 Store for trusted certificate.
 | 
						|
  //
 | 
						|
  CertStore = X509_STORE_new ();
 | 
						|
  if ((CertStore == NULL) || !(X509_STORE_add_cert (CertStore, Cert))) {
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Allow partial certificate chains, terminated by a non-self-signed but
 | 
						|
  // still trusted intermediate certificate. Also disable time checks.
 | 
						|
  //
 | 
						|
  X509_STORE_set_flags (
 | 
						|
    CertStore,
 | 
						|
    X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_NO_CHECK_TIME
 | 
						|
    );
 | 
						|
 | 
						|
  X509_STORE_set_purpose (CertStore, X509_PURPOSE_ANY);
 | 
						|
 | 
						|
  //
 | 
						|
  // Verifies the PKCS#7 signedData structure, and output the signed contents.
 | 
						|
  //
 | 
						|
  OutBio = BIO_new (BIO_s_mem ());
 | 
						|
  if (OutBio == NULL) {
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!PKCS7_verify (Pkcs7, NULL, CertStore, NULL, OutBio, PKCS7_BINARY)) {
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Read the signed contents detached in timestamp signature.
 | 
						|
  //
 | 
						|
  TstData = AllocateZeroPool (2048);
 | 
						|
  if (TstData == NULL) {
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  TstSize = BIO_read (OutBio, (void *)TstData, 2048);
 | 
						|
 | 
						|
  //
 | 
						|
  // Construct TS_TST_INFO structure from the signed contents.
 | 
						|
  //
 | 
						|
  TstTemp = TstData;
 | 
						|
  TstInfo = d2i_TS_TST_INFO (
 | 
						|
              NULL,
 | 
						|
              (const unsigned char **)&TstTemp,
 | 
						|
              (int)TstSize
 | 
						|
              );
 | 
						|
  if (TstInfo == NULL) {
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check TS_TST_INFO structure.
 | 
						|
  //
 | 
						|
  Status = CheckTSTInfo (TstInfo, TimestampedData, DataSize);
 | 
						|
  if (!Status) {
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Retrieve the signing time from TS_TST_INFO structure.
 | 
						|
  //
 | 
						|
  if (SigningTime != NULL) {
 | 
						|
    SetMem (SigningTime, sizeof (EFI_TIME), 0);
 | 
						|
    Status = ConvertAsn1TimeToEfiTime (TstInfo->GenTime, SigningTime);
 | 
						|
  }
 | 
						|
 | 
						|
_Exit:
 | 
						|
  //
 | 
						|
  // Release Resources
 | 
						|
  //
 | 
						|
  PKCS7_free (Pkcs7);
 | 
						|
  X509_free (Cert);
 | 
						|
  X509_STORE_free (CertStore);
 | 
						|
  BIO_free (OutBio);
 | 
						|
  TS_TST_INFO_free (TstInfo);
 | 
						|
 | 
						|
  if (TstData != NULL) {
 | 
						|
    FreePool (TstData);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Verifies the validity of a RFC3161 Timestamp CounterSignature embedded in PE/COFF Authenticode
 | 
						|
  signature.
 | 
						|
 | 
						|
  If AuthData is NULL, then return FALSE.
 | 
						|
 | 
						|
  @param[in]  AuthData     Pointer to the Authenticode Signature retrieved from signed
 | 
						|
                           PE/COFF image to be verified.
 | 
						|
  @param[in]  DataSize     Size of the Authenticode Signature in bytes.
 | 
						|
  @param[in]  TsaCert      Pointer to a trusted/root TSA certificate encoded in DER, which
 | 
						|
                           is used for TSA certificate chain verification.
 | 
						|
  @param[in]  CertSize     Size of the trusted certificate in bytes.
 | 
						|
  @param[out] SigningTime  Return the time of timestamp generation time if the timestamp
 | 
						|
                           signature is valid.
 | 
						|
 | 
						|
  @retval  TRUE   The specified Authenticode includes a valid RFC3161 Timestamp CounterSignature.
 | 
						|
  @retval  FALSE  No valid RFC3161 Timestamp CounterSignature in the specified Authenticode data.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
ImageTimestampVerify (
 | 
						|
  IN  CONST UINT8  *AuthData,
 | 
						|
  IN  UINTN        DataSize,
 | 
						|
  IN  CONST UINT8  *TsaCert,
 | 
						|
  IN  UINTN        CertSize,
 | 
						|
  OUT EFI_TIME     *SigningTime
 | 
						|
  )
 | 
						|
{
 | 
						|
  BOOLEAN      Status;
 | 
						|
  PKCS7        *Pkcs7;
 | 
						|
  CONST UINT8  *Temp;
 | 
						|
 | 
						|
  STACK_OF (PKCS7_SIGNER_INFO)  *SignerInfos;
 | 
						|
  PKCS7_SIGNER_INFO  *SignInfo;
 | 
						|
  UINTN              Index;
 | 
						|
 | 
						|
  STACK_OF (X509_ATTRIBUTE)     *Sk;
 | 
						|
  X509_ATTRIBUTE     *Xa;
 | 
						|
  ASN1_OBJECT        *XaObj;
 | 
						|
  ASN1_TYPE          *Asn1Type;
 | 
						|
  ASN1_OCTET_STRING  *EncDigest;
 | 
						|
  UINT8              *TSToken;
 | 
						|
  UINTN              TokenSize;
 | 
						|
 | 
						|
  //
 | 
						|
  // Input Parameters Checking.
 | 
						|
  //
 | 
						|
  if ((AuthData == NULL) || (TsaCert == NULL)) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((DataSize > INT_MAX) || (CertSize > INT_MAX)) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Register & Initialize necessary digest algorithms for PKCS#7 Handling.
 | 
						|
  //
 | 
						|
  if ((EVP_add_digest (EVP_md5 ()) == 0) || (EVP_add_digest (EVP_sha1 ()) == 0) ||
 | 
						|
      (EVP_add_digest (EVP_sha256 ()) == 0) || ((EVP_add_digest_alias (SN_sha1WithRSAEncryption, SN_sha1WithRSA)) == 0))
 | 
						|
  {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialization.
 | 
						|
  //
 | 
						|
  Status   = FALSE;
 | 
						|
  Pkcs7    = NULL;
 | 
						|
  SignInfo = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Decode ASN.1-encoded Authenticode data into PKCS7 structure.
 | 
						|
  //
 | 
						|
  Temp  = AuthData;
 | 
						|
  Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **)&Temp, (int)DataSize);
 | 
						|
  if (Pkcs7 == NULL) {
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check if there is one and only one signer.
 | 
						|
  //
 | 
						|
  SignerInfos = PKCS7_get_signer_info (Pkcs7);
 | 
						|
  if (!SignerInfos || (sk_PKCS7_SIGNER_INFO_num (SignerInfos) != 1)) {
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Locate the TimeStamp CounterSignature.
 | 
						|
  //
 | 
						|
  SignInfo = sk_PKCS7_SIGNER_INFO_value (SignerInfos, 0);
 | 
						|
  if (SignInfo == NULL) {
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Locate Message Digest which will be the data to be time-stamped.
 | 
						|
  //
 | 
						|
  EncDigest = SignInfo->enc_digest;
 | 
						|
  if (EncDigest == NULL) {
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // The RFC3161 timestamp counterSignature is contained in unauthenticatedAttributes field
 | 
						|
  // of SignerInfo.
 | 
						|
  //
 | 
						|
  Sk = SignInfo->unauth_attr;
 | 
						|
  if (Sk == NULL) {
 | 
						|
    // No timestamp counterSignature.
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  Asn1Type = NULL;
 | 
						|
  for (Index = 0; Index < (UINTN)sk_X509_ATTRIBUTE_num (Sk); Index++) {
 | 
						|
    //
 | 
						|
    // Search valid RFC3161 timestamp counterSignature based on OBJID.
 | 
						|
    //
 | 
						|
    Xa = sk_X509_ATTRIBUTE_value (Sk, (int)Index);
 | 
						|
    if (Xa == NULL) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    XaObj = X509_ATTRIBUTE_get0_object (Xa);
 | 
						|
    if (XaObj == NULL) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    if ((OBJ_length (XaObj) != sizeof (mSpcRFC3161OidValue)) ||
 | 
						|
        (CompareMem (OBJ_get0_data (XaObj), mSpcRFC3161OidValue, sizeof (mSpcRFC3161OidValue)) != 0))
 | 
						|
    {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    Asn1Type = X509_ATTRIBUTE_get0_type (Xa, 0);
 | 
						|
  }
 | 
						|
 | 
						|
  if (Asn1Type == NULL) {
 | 
						|
    Status = FALSE;
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  TSToken   = Asn1Type->value.octet_string->data;
 | 
						|
  TokenSize = Asn1Type->value.octet_string->length;
 | 
						|
 | 
						|
  //
 | 
						|
  // TimeStamp counterSignature (Token) verification.
 | 
						|
  //
 | 
						|
  Status = TimestampTokenVerify (
 | 
						|
             TSToken,
 | 
						|
             TokenSize,
 | 
						|
             TsaCert,
 | 
						|
             CertSize,
 | 
						|
             EncDigest->data,
 | 
						|
             EncDigest->length,
 | 
						|
             SigningTime
 | 
						|
             );
 | 
						|
 | 
						|
_Exit:
 | 
						|
  //
 | 
						|
  // Release Resources
 | 
						|
  //
 | 
						|
  PKCS7_free (Pkcs7);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 |