mirror of
				https://git.proxmox.com/git/efi-boot-shim
				synced 2025-10-31 12:59:56 +00:00 
			
		
		
		
	 e571428e21
			
		
	
	
		e571428e21
		
	
	
	
	
		
			
			Also update Cryptlib to edk2 r19218 - Undefine NO_BUILTIN_VA_FUNCS in Cryptlib/OpenSSL/ for x86_64 to use the gcc builtins and remove all EFIAPI from the functions - Move the most of defines into the headers instead of Makefile - Remove the global variable 'timeval' - Remove the unused code: crypto/pqueue/* and crypto/ts/* - Include bn.h in MokManager.c due to the changes in openssl Signed-off-by: Gary Lin <glin@suse.com>
		
			
				
	
	
		
			658 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			658 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 - 2015, Intel Corporation. All rights reserved.<BR>
 | |
| This program and the accompanying materials
 | |
| are licensed and made available under the terms and conditions of the BSD License
 | |
| which accompanies this distribution.  The full text of the license may be found at
 | |
| http://opensource.org/licenses/bsd-license.php
 | |
| 
 | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #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 convertion 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, 0, sizeof (EFI_TIME));
 | |
| 
 | |
|   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;
 | |
| 
 | |
|   //
 | |
|   // -- 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;
 | |
|   }
 | |
|   EVP_DigestInit (&MdCtx, Md);
 | |
|   EVP_DigestUpdate (&MdCtx, TimestampedData, DataSize);
 | |
|   EVP_DigestFinal (&MdCtx, HashedMsg, NULL);
 | |
|   if ((MdSize == (UINTN)ASN1_STRING_length (Imprint->HashedMessage)) &&
 | |
|       (CompareMem (HashedMsg, ASN1_STRING_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);
 | |
|   if (HashedMsg != NULL) {
 | |
|     FreePool (HashedMsg);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Verifies the validility 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 validility 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;
 | |
| }
 |