• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   RFC3161 Timestamp Countersignature Verification over OpenSSL.
3   The timestamp is generated by a TimeStamping Authority (TSA) and asserts that a
4   publisher's signature existed before the specified time. The timestamp extends
5   the lifetime of the signature when a signing certificate expires or is later
6   revoked.
7 
8 Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>
9 This program and the accompanying materials
10 are licensed and made available under the terms and conditions of the BSD License
11 which accompanies this distribution.  The full text of the license may be found at
12 http://opensource.org/licenses/bsd-license.php
13 
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 
17 **/
18 
19 #include "InternalCryptLib.h"
20 
21 #include <openssl/asn1.h>
22 #include <openssl/asn1t.h>
23 #include <openssl/x509.h>
24 #include <openssl/x509v3.h>
25 #include <openssl/pkcs7.h>
26 
27 //
28 // OID ASN.1 Value for SPC_RFC3161_OBJID ("1.3.6.1.4.1.311.3.3.1")
29 //
30 UINT8 mSpcRFC3161OidValue[] = {
31   0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x03, 0x03, 0x01
32   };
33 
34 ///
35 /// The messageImprint field SHOULD contain the hash of the datum to be
36 /// time-stamped.  The hash is represented as an OCTET STRING.  Its
37 /// length MUST match the length of the hash value for that algorithm
38 /// (e.g., 20 bytes for SHA-1 or 16 bytes for MD5).
39 ///
40 /// MessageImprint ::= SEQUENCE  {
41 ///   hashAlgorithm                AlgorithmIdentifier,
42 ///   hashedMessage                OCTET STRING  }
43 ///
44 typedef struct {
45   X509_ALGOR         *HashAlgorithm;
46   ASN1_OCTET_STRING  *HashedMessage;
47 } TS_MESSAGE_IMPRINT;
48 
49 //
50 // ASN.1 Functions for TS_MESSAGE_IMPRINT
51 //
52 DECLARE_ASN1_FUNCTIONS (TS_MESSAGE_IMPRINT)
53 ASN1_SEQUENCE (TS_MESSAGE_IMPRINT) = {
54   ASN1_SIMPLE (TS_MESSAGE_IMPRINT, HashAlgorithm, X509_ALGOR),
55   ASN1_SIMPLE (TS_MESSAGE_IMPRINT, HashedMessage, ASN1_OCTET_STRING)
56 } ASN1_SEQUENCE_END (TS_MESSAGE_IMPRINT)
57 IMPLEMENT_ASN1_FUNCTIONS (TS_MESSAGE_IMPRINT)
58 
59 ///
60 /// Accuracy represents the time deviation around the UTC time contained
61 /// in GeneralizedTime of time-stamp token.
62 ///
63 /// Accuracy ::= SEQUENCE {
64 ///       seconds        INTEGER              OPTIONAL,
65 ///       millis     [0] INTEGER  (1..999)    OPTIONAL,
66 ///       micros     [1] INTEGER  (1..999)    OPTIONAL  }
67 ///
68 typedef struct {
69   ASN1_INTEGER  *Seconds;
70   ASN1_INTEGER  *Millis;
71   ASN1_INTEGER  *Micros;
72 } TS_ACCURACY;
73 
74 //
75 // ASN.1 Functions for TS_ACCURACY
76 //
77 DECLARE_ASN1_FUNCTIONS (TS_ACCURACY)
78 ASN1_SEQUENCE (TS_ACCURACY) = {
79   ASN1_OPT     (TS_ACCURACY, Seconds, ASN1_INTEGER),
80   ASN1_IMP_OPT (TS_ACCURACY, Millis,  ASN1_INTEGER, 0),
81   ASN1_IMP_OPT (TS_ACCURACY, Micros,  ASN1_INTEGER, 1)
82 } ASN1_SEQUENCE_END (TS_ACCURACY)
83 IMPLEMENT_ASN1_FUNCTIONS (TS_ACCURACY)
84 
85 ///
86 /// The timestamp token info resulting from a successful timestamp request,
87 /// as defined in RFC 3161.
88 ///
89 ///  TSTInfo ::= SEQUENCE  {
90 ///     version                      INTEGER  { v1(1) },
91 ///     policy                       TSAPolicyId,
92 ///     messageImprint               MessageImprint,
93 ///       -- MUST have the same value as the similar field in
94 ///       -- TimeStampReq
95 ///     serialNumber                 INTEGER,
96 ///       -- Time-Stamping users MUST be ready to accommodate integers
97 ///       -- up to 160 bits.
98 ///     genTime                      GeneralizedTime,
99 ///     accuracy                     Accuracy                 OPTIONAL,
100 ///     ordering                     BOOLEAN             DEFAULT FALSE,
101 ///     nonce                        INTEGER                  OPTIONAL,
102 ///       -- MUST be present if the similar field was present
103 ///       -- in TimeStampReq.  In that case it MUST have the same value.
104 ///     tsa                          [0] GeneralName          OPTIONAL,
105 ///     extensions                   [1] IMPLICIT Extensions   OPTIONAL  }
106 ///
107 typedef struct {
108   ASN1_INTEGER              *Version;
109   ASN1_OBJECT               *Policy;
110   TS_MESSAGE_IMPRINT        *MessageImprint;
111   ASN1_INTEGER              *SerialNumber;
112   ASN1_GENERALIZEDTIME      *GenTime;
113   TS_ACCURACY               *Accuracy;
114   ASN1_BOOLEAN              Ordering;
115   ASN1_INTEGER              *Nonce;
116   GENERAL_NAME              *Tsa;
117   STACK_OF(X509_EXTENSION)  *Extensions;
118 } TS_TST_INFO;
119 
120 //
121 // ASN.1 Functions for TS_TST_INFO
122 //
123 DECLARE_ASN1_FUNCTIONS (TS_TST_INFO)
124 ASN1_SEQUENCE (TS_TST_INFO) = {
125   ASN1_SIMPLE (TS_TST_INFO, Version, ASN1_INTEGER),
126   ASN1_SIMPLE (TS_TST_INFO, Policy, ASN1_OBJECT),
127   ASN1_SIMPLE (TS_TST_INFO, MessageImprint, TS_MESSAGE_IMPRINT),
128   ASN1_SIMPLE (TS_TST_INFO, SerialNumber, ASN1_INTEGER),
129   ASN1_SIMPLE (TS_TST_INFO, GenTime, ASN1_GENERALIZEDTIME),
130   ASN1_OPT    (TS_TST_INFO, Accuracy, TS_ACCURACY),
131   ASN1_OPT    (TS_TST_INFO, Ordering, ASN1_FBOOLEAN),
132   ASN1_OPT    (TS_TST_INFO, Nonce, ASN1_INTEGER),
133   ASN1_EXP_OPT(TS_TST_INFO, Tsa, GENERAL_NAME, 0),
134   ASN1_IMP_SEQUENCE_OF_OPT (TS_TST_INFO, Extensions, X509_EXTENSION, 1)
135 } ASN1_SEQUENCE_END (TS_TST_INFO)
136 IMPLEMENT_ASN1_FUNCTIONS (TS_TST_INFO)
137 
138 
139 /**
140   Convert ASN.1 GeneralizedTime to EFI Time.
141 
142   @param[in]  Asn1Time         Pointer to the ASN.1 GeneralizedTime to be converted.
143   @param[out] SigningTime      Return the corresponding EFI Time.
144 
145   @retval  TRUE   The time convertion succeeds.
146   @retval  FALSE  Invalid parameters.
147 
148 **/
149 BOOLEAN
150 EFIAPI
151 ConvertAsn1TimeToEfiTime (
152   IN  ASN1_TIME  *Asn1Time,
153   OUT EFI_TIME   *EfiTime
154   )
155 {
156   CONST CHAR8  *Str;
157   UINTN        Index;
158 
159   if ((Asn1Time == NULL) || (EfiTime == NULL)) {
160     return FALSE;
161   }
162 
163   Str = (CONST CHAR8*)Asn1Time->data;
164   SetMem (EfiTime, 0, sizeof (EFI_TIME));
165 
166   Index = 0;
167   if (Asn1Time->type == V_ASN1_UTCTIME) {               /* two digit year */
168     EfiTime->Year  = (Str[Index++] - '0') * 10;
169     EfiTime->Year += (Str[Index++] - '0');
170     if (EfiTime->Year < 70) {
171       EfiTime->Year += 100;
172     }
173   } else if (Asn1Time->type == V_ASN1_GENERALIZEDTIME) { /* four digit year */
174     EfiTime->Year  = (Str[Index++] - '0') * 1000;
175     EfiTime->Year += (Str[Index++] - '0') * 100;
176     EfiTime->Year += (Str[Index++] - '0') * 10;
177     EfiTime->Year += (Str[Index++] - '0');
178     if ((EfiTime->Year < 1900) || (EfiTime->Year > 9999)) {
179       return FALSE;
180     }
181   }
182 
183   EfiTime->Month   = (Str[Index++] - '0') * 10;
184   EfiTime->Month  += (Str[Index++] - '0');
185   if ((EfiTime->Month < 1) || (EfiTime->Month > 12)) {
186     return FALSE;
187   }
188 
189   EfiTime->Day     = (Str[Index++] - '0') * 10;
190   EfiTime->Day    += (Str[Index++] - '0');
191   if ((EfiTime->Day < 1) || (EfiTime->Day > 31)) {
192     return FALSE;
193   }
194 
195   EfiTime->Hour    = (Str[Index++] - '0') * 10;
196   EfiTime->Hour   += (Str[Index++] - '0');
197   if (EfiTime->Hour > 23) {
198     return FALSE;
199   }
200 
201   EfiTime->Minute  = (Str[Index++] - '0') * 10;
202   EfiTime->Minute += (Str[Index++] - '0');
203   if (EfiTime->Minute > 59) {
204     return FALSE;
205   }
206 
207   EfiTime->Second  = (Str[Index++] - '0') * 10;
208   EfiTime->Second += (Str[Index++] - '0');
209   if (EfiTime->Second > 59) {
210     return FALSE;
211   }
212 
213   /* Note: we did not adjust the time based on time zone information */
214 
215   return TRUE;
216 }
217 
218 /**
219 
220   Check the validity of TimeStamp Token Information.
221 
222   @param[in]  TstInfo          Pointer to the TS_TST_INFO structure.
223   @param[in]  TimestampedData  Pointer to the data to be time-stamped.
224   @param[in]  DataSize         Size of timestamped data in bytes.
225 
226   @retval  TRUE   The TimeStamp Token Information is valid.
227   @retval  FALSE  Invalid TimeStamp Token Information.
228 
229 **/
230 BOOLEAN
231 EFIAPI
CheckTSTInfo(IN CONST TS_TST_INFO * TstInfo,IN CONST UINT8 * TimestampedData,IN UINTN DataSize)232 CheckTSTInfo (
233   IN  CONST TS_TST_INFO  *TstInfo,
234   IN  CONST UINT8        *TimestampedData,
235   IN  UINTN              DataSize
236   )
237 {
238   BOOLEAN             Status;
239   TS_MESSAGE_IMPRINT  *Imprint;
240   X509_ALGOR          *HashAlgo;
241   CONST EVP_MD        *Md;
242   EVP_MD_CTX          MdCtx;
243   UINTN               MdSize;
244   UINT8               *HashedMsg;
245 
246   //
247   // Initialization
248   //
249   Status    = FALSE;
250   HashAlgo  = NULL;
251   HashedMsg = NULL;
252 
253   //
254   // -- Check version number of Timestamp:
255   //   The version field (currently v1) describes the version of the time-stamp token.
256   //   Conforming time-stamping servers MUST be able to provide version 1 time-stamp tokens.
257   //
258   if ((ASN1_INTEGER_get (TstInfo->Version)) != 1) {
259     return FALSE;
260   }
261 
262   //
263   // -- Check Policies
264   //   The policy field MUST indicate the TSA's policy under which the response was produced.
265   //
266   if (TstInfo->Policy == NULL) {
267     /// NOTE: Need to check if the requested and returned policies.
268     ///       We have no information about the Requested TSA Policy.
269     return FALSE;
270   }
271 
272   //
273   // -- Compute & Check Message Imprint
274   //
275   Imprint  = TstInfo->MessageImprint;
276   HashAlgo = X509_ALGOR_dup (Imprint->HashAlgorithm);
277 
278   Md = EVP_get_digestbyobj (HashAlgo->algorithm);
279   if (Md == NULL) {
280     goto _Exit;
281   }
282 
283   MdSize = EVP_MD_size (Md);
284   HashedMsg = AllocateZeroPool (MdSize);
285   if (HashedMsg == NULL) {
286     goto _Exit;
287   }
288   EVP_DigestInit (&MdCtx, Md);
289   EVP_DigestUpdate (&MdCtx, TimestampedData, DataSize);
290   EVP_DigestFinal (&MdCtx, HashedMsg, NULL);
291   if ((MdSize == (UINTN)ASN1_STRING_length (Imprint->HashedMessage)) &&
292       (CompareMem (HashedMsg, ASN1_STRING_data (Imprint->HashedMessage), MdSize) != 0)) {
293     goto _Exit;
294   }
295 
296   //
297   // -- Check Nonces
298   //
299   if (TstInfo->Nonce != NULL) {
300     //
301     // Nonces is optional, No error if no nonce is returned;
302     //
303   }
304 
305   //
306   // -- Check if the TSA name and signer certificate is matched.
307   //
308   if (TstInfo->Tsa != NULL) {
309     //
310     //  Ignored the optional Tsa field checking.
311     //
312   }
313 
314   Status = TRUE;
315 
316 _Exit:
317   X509_ALGOR_free (HashAlgo);
318   if (HashedMsg != NULL) {
319     FreePool (HashedMsg);
320   }
321 
322   return Status;
323 }
324 
325 /**
326   Verifies the validity of a TimeStamp Token as described in RFC 3161 ("Internet
327   X.509 Public Key Infrastructure Time-Stamp Protocol (TSP)").
328 
329   If TSToken is NULL, then return FALSE.
330   If TimestampedData is NULL, then return FALSE.
331 
332   @param[in]  TSToken          Pointer to the RFC3161 TimeStamp Token, which is generated
333                                by a TSA and located in the software publisher's SignerInfo
334                                structure.
335   @param[in]  TokenSize        Size of the TimeStamp Token in bytes.
336   @param[in]  TsaCert          Pointer to a trusted/root TSA certificate encoded in DER.
337   @param[in]  CertSize         Size of the trusted TSA certificate in bytes.
338   @param[in]  TimestampedData  Pointer to the data to be time-stamped.
339   @param[in]  DataSize         Size of timestamped data in bytes.
340   @param[out] SigningTime      Return the time of timestamp generation time if the timestamp
341                                signature is valid.
342 
343   @retval  TRUE   The specified timestamp token is valid.
344   @retval  FALSE  Invalid timestamp token.
345 
346 **/
347 BOOLEAN
348 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)349 TimestampTokenVerify (
350   IN  CONST UINT8  *TSToken,
351   IN  UINTN        TokenSize,
352   IN  CONST UINT8  *TsaCert,
353   IN  UINTN        CertSize,
354   IN  CONST UINT8  *TimestampedData,
355   IN  UINTN        DataSize,
356   OUT EFI_TIME     *SigningTime
357   )
358 {
359   BOOLEAN      Status;
360   CONST UINT8  *TokenTemp;
361   PKCS7        *Pkcs7;
362   X509         *Cert;
363   CONST UINT8  *CertTemp;
364   X509_STORE   *CertStore;
365   BIO          *OutBio;
366   UINT8        *TstData;
367   UINTN        TstSize;
368   CONST UINT8  *TstTemp;
369   TS_TST_INFO  *TstInfo;
370 
371   Status = FALSE;
372 
373   //
374   // Check input parameters
375   //
376   if ((TSToken == NULL) || (TsaCert == NULL) || (TimestampedData == NULL) ||
377       (TokenSize > INT_MAX) || (CertSize > INT_MAX) || (DataSize > INT_MAX)) {
378     return FALSE;
379   }
380 
381   //
382   // Initializations
383   //
384   if (SigningTime != NULL) {
385     SetMem (SigningTime, sizeof (EFI_TIME), 0);
386   }
387   Pkcs7     = NULL;
388   Cert      = NULL;
389   CertStore = NULL;
390   OutBio    = NULL;
391   TstData   = NULL;
392   TstInfo   = NULL;
393 
394   //
395   // TimeStamp Token should contain one valid DER-encoded ASN.1 PKCS#7 structure.
396   //
397   TokenTemp = TSToken;
398   Pkcs7     = d2i_PKCS7 (NULL, (const unsigned char **) &TokenTemp, (int) TokenSize);
399   if (Pkcs7 == NULL) {
400     goto _Exit;
401   }
402 
403   //
404   // The timestamp signature (TSA's response) will be one PKCS#7 signed data.
405   //
406   if (!PKCS7_type_is_signed (Pkcs7)) {
407     goto _Exit;
408   }
409 
410   //
411   // Read the trusted TSA certificate (DER-encoded), and Construct X509 Certificate.
412   //
413   CertTemp = TsaCert;
414   Cert = d2i_X509 (NULL, &CertTemp, (long) CertSize);
415   if (Cert == NULL) {
416     goto _Exit;
417   }
418 
419   //
420   // Setup X509 Store for trusted certificate.
421   //
422   CertStore = X509_STORE_new ();
423   if ((CertStore == NULL) || !(X509_STORE_add_cert (CertStore, Cert))) {
424     goto _Exit;
425   }
426 
427   //
428   // Allow partial certificate chains, terminated by a non-self-signed but
429   // still trusted intermediate certificate. Also disable time checks.
430   //
431   X509_STORE_set_flags (CertStore,
432                         X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_NO_CHECK_TIME);
433 
434   X509_STORE_set_purpose (CertStore, X509_PURPOSE_ANY);
435 
436   //
437   // Verifies the PKCS#7 signedData structure, and output the signed contents.
438   //
439   OutBio = BIO_new (BIO_s_mem ());
440   if (OutBio == NULL) {
441     goto _Exit;
442   }
443   if (!PKCS7_verify (Pkcs7, NULL, CertStore, NULL, OutBio, PKCS7_BINARY)) {
444     goto _Exit;
445   }
446 
447   //
448   // Read the signed contents detached in timestamp signature.
449   //
450   TstData = AllocateZeroPool (2048);
451   if (TstData == NULL) {
452     goto _Exit;
453   }
454   TstSize = BIO_read (OutBio, (void *) TstData, 2048);
455 
456   //
457   // Construct TS_TST_INFO structure from the signed contents.
458   //
459   TstTemp = TstData;
460   TstInfo = d2i_TS_TST_INFO (NULL, (const unsigned char **) &TstTemp,
461               (int)TstSize);
462   if (TstInfo == NULL) {
463     goto _Exit;
464   }
465 
466   //
467   // Check TS_TST_INFO structure.
468   //
469   Status = CheckTSTInfo (TstInfo, TimestampedData, DataSize);
470   if (!Status) {
471     goto _Exit;
472   }
473 
474   //
475   // Retrieve the signing time from TS_TST_INFO structure.
476   //
477   if (SigningTime != NULL) {
478     SetMem (SigningTime, sizeof (EFI_TIME), 0);
479     Status = ConvertAsn1TimeToEfiTime (TstInfo->GenTime, SigningTime);
480   }
481 
482 _Exit:
483   //
484   // Release Resources
485   //
486   PKCS7_free (Pkcs7);
487   X509_free (Cert);
488   X509_STORE_free (CertStore);
489   BIO_free (OutBio);
490   TS_TST_INFO_free (TstInfo);
491 
492   if (TstData != NULL) {
493     FreePool (TstData);
494   }
495 
496   return Status;
497 }
498 
499 /**
500   Verifies the validity of a RFC3161 Timestamp CounterSignature embedded in PE/COFF Authenticode
501   signature.
502 
503   If AuthData is NULL, then return FALSE.
504 
505   @param[in]  AuthData     Pointer to the Authenticode Signature retrieved from signed
506                            PE/COFF image to be verified.
507   @param[in]  DataSize     Size of the Authenticode Signature in bytes.
508   @param[in]  TsaCert      Pointer to a trusted/root TSA certificate encoded in DER, which
509                            is used for TSA certificate chain verification.
510   @param[in]  CertSize     Size of the trusted certificate in bytes.
511   @param[out] SigningTime  Return the time of timestamp generation time if the timestamp
512                            signature is valid.
513 
514   @retval  TRUE   The specified Authenticode includes a valid RFC3161 Timestamp CounterSignature.
515   @retval  FALSE  No valid RFC3161 Timestamp CounterSignature in the specified Authenticode data.
516 
517 **/
518 BOOLEAN
519 EFIAPI
ImageTimestampVerify(IN CONST UINT8 * AuthData,IN UINTN DataSize,IN CONST UINT8 * TsaCert,IN UINTN CertSize,OUT EFI_TIME * SigningTime)520 ImageTimestampVerify (
521   IN  CONST UINT8  *AuthData,
522   IN  UINTN        DataSize,
523   IN  CONST UINT8  *TsaCert,
524   IN  UINTN        CertSize,
525   OUT EFI_TIME     *SigningTime
526   )
527 {
528   BOOLEAN                      Status;
529   PKCS7                        *Pkcs7;
530   CONST UINT8                  *Temp;
531   STACK_OF(PKCS7_SIGNER_INFO)  *SignerInfos;
532   PKCS7_SIGNER_INFO            *SignInfo;
533   UINTN                        Index;
534   STACK_OF(X509_ATTRIBUTE)     *Sk;
535   X509_ATTRIBUTE               *Xa;
536   ASN1_OBJECT                  *XaObj;
537   ASN1_TYPE                    *Asn1Type;
538   ASN1_OCTET_STRING            *EncDigest;
539   UINT8                        *TSToken;
540   UINTN                        TokenSize;
541 
542   //
543   // Input Parameters Checking.
544   //
545   if ((AuthData == NULL) || (TsaCert == NULL)) {
546     return FALSE;
547   }
548 
549   if ((DataSize > INT_MAX) || (CertSize > INT_MAX)) {
550     return FALSE;
551   }
552 
553   //
554   // Register & Initialize necessary digest algorithms for PKCS#7 Handling.
555   //
556   if ((EVP_add_digest (EVP_md5 ()) == 0) || (EVP_add_digest (EVP_sha1 ()) == 0) ||
557       (EVP_add_digest (EVP_sha256 ()) == 0) || (EVP_add_digest_alias (SN_sha1WithRSAEncryption, SN_sha1WithRSA)) == 0) {
558     return FALSE;
559   }
560 
561   //
562   // Initialization.
563   //
564   Status    = FALSE;
565   Pkcs7     = NULL;
566   SignInfo  = NULL;
567 
568   //
569   // Decode ASN.1-encoded Authenticode data into PKCS7 structure.
570   //
571   Temp  = AuthData;
572   Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &Temp, (int) DataSize);
573   if (Pkcs7 == NULL) {
574     goto _Exit;
575   }
576 
577   //
578   // Check if there is one and only one signer.
579   //
580   SignerInfos = PKCS7_get_signer_info (Pkcs7);
581   if (!SignerInfos || (sk_PKCS7_SIGNER_INFO_num (SignerInfos) != 1)) {
582     goto _Exit;
583   }
584 
585   //
586   // Locate the TimeStamp CounterSignature.
587   //
588   SignInfo = sk_PKCS7_SIGNER_INFO_value (SignerInfos, 0);
589   if (SignInfo == NULL) {
590     goto _Exit;
591   }
592 
593   //
594   // Locate Message Digest which will be the data to be time-stamped.
595   //
596   EncDigest = SignInfo->enc_digest;
597   if (EncDigest == NULL) {
598     goto _Exit;
599   }
600 
601   //
602   // The RFC3161 timestamp counterSignature is contained in unauthenticatedAttributes field
603   // of SignerInfo.
604   //
605   Sk = SignInfo->unauth_attr;
606   if (Sk == NULL) {             // No timestamp counterSignature.
607     goto _Exit;
608   }
609 
610   Asn1Type = NULL;
611   for (Index = 0; Index < (UINTN) sk_X509_ATTRIBUTE_num (Sk); Index++) {
612     //
613     // Search valid RFC3161 timestamp counterSignature based on OBJID.
614     //
615     Xa = sk_X509_ATTRIBUTE_value (Sk, (int)Index);
616     if (Xa == NULL) {
617       continue;
618     }
619     XaObj = X509_ATTRIBUTE_get0_object(Xa);
620     if (XaObj == NULL) {
621       continue;
622     }
623     if ((OBJ_length(XaObj) != sizeof (mSpcRFC3161OidValue)) ||
624         (CompareMem (OBJ_get0_data(XaObj), mSpcRFC3161OidValue, sizeof (mSpcRFC3161OidValue)) != 0)) {
625       continue;
626     }
627     Asn1Type = X509_ATTRIBUTE_get0_type(Xa, 0);
628   }
629 
630   if (Asn1Type == NULL) {
631     Status = FALSE;
632     goto _Exit;
633   }
634   TSToken   = Asn1Type->value.octet_string->data;
635   TokenSize = Asn1Type->value.octet_string->length;
636 
637   //
638   // TimeStamp counterSignature (Token) verification.
639   //
640   Status = TimestampTokenVerify (
641              TSToken,
642              TokenSize,
643              TsaCert,
644              CertSize,
645              EncDigest->data,
646              EncDigest->length,
647              SigningTime
648              );
649 
650 _Exit:
651   //
652   // Release Resources
653   //
654   PKCS7_free (Pkcs7);
655 
656   return Status;
657 }
658