]> git.proxmox.com Git - mirror_edk2.git/blob - CryptoPkg/Library/BaseCryptLib/Pk/CryptTs.c
CryptoPkg: Fix various typos
[mirror_edk2.git] / CryptoPkg / Library / BaseCryptLib / Pk / CryptTs.c
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 - 2017, 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 conversion 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
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 MdCtx = NULL;
253
254 //
255 // -- Check version number of Timestamp:
256 // The version field (currently v1) describes the version of the time-stamp token.
257 // Conforming time-stamping servers MUST be able to provide version 1 time-stamp tokens.
258 //
259 if ((ASN1_INTEGER_get (TstInfo->Version)) != 1) {
260 return FALSE;
261 }
262
263 //
264 // -- Check Policies
265 // The policy field MUST indicate the TSA's policy under which the response was produced.
266 //
267 if (TstInfo->Policy == NULL) {
268 /// NOTE: Need to check if the requested and returned policies.
269 /// We have no information about the Requested TSA Policy.
270 return FALSE;
271 }
272
273 //
274 // -- Compute & Check Message Imprint
275 //
276 Imprint = TstInfo->MessageImprint;
277 HashAlgo = X509_ALGOR_dup (Imprint->HashAlgorithm);
278
279 Md = EVP_get_digestbyobj (HashAlgo->algorithm);
280 if (Md == NULL) {
281 goto _Exit;
282 }
283
284 MdSize = EVP_MD_size (Md);
285 HashedMsg = AllocateZeroPool (MdSize);
286 if (HashedMsg == NULL) {
287 goto _Exit;
288 }
289 MdCtx = EVP_MD_CTX_new ();
290 if (MdCtx == NULL) {
291 goto _Exit;
292 }
293 if ((EVP_DigestInit_ex (MdCtx, Md, NULL) != 1) ||
294 (EVP_DigestUpdate (MdCtx, TimestampedData, DataSize) != 1) ||
295 (EVP_DigestFinal (MdCtx, HashedMsg, NULL) != 1)) {
296 goto _Exit;
297 }
298 if ((MdSize == (UINTN)ASN1_STRING_length (Imprint->HashedMessage)) &&
299 (CompareMem (HashedMsg, ASN1_STRING_get0_data (Imprint->HashedMessage), MdSize) != 0)) {
300 goto _Exit;
301 }
302
303 //
304 // -- Check Nonces
305 //
306 if (TstInfo->Nonce != NULL) {
307 //
308 // Nonces is optional, No error if no nonce is returned;
309 //
310 }
311
312 //
313 // -- Check if the TSA name and signer certificate is matched.
314 //
315 if (TstInfo->Tsa != NULL) {
316 //
317 // Ignored the optional Tsa field checking.
318 //
319 }
320
321 Status = TRUE;
322
323 _Exit:
324 X509_ALGOR_free (HashAlgo);
325 EVP_MD_CTX_free (MdCtx);
326 if (HashedMsg != NULL) {
327 FreePool (HashedMsg);
328 }
329
330 return Status;
331 }
332
333 /**
334 Verifies the validity of a TimeStamp Token as described in RFC 3161 ("Internet
335 X.509 Public Key Infrastructure Time-Stamp Protocol (TSP)").
336
337 If TSToken is NULL, then return FALSE.
338 If TimestampedData is NULL, then return FALSE.
339
340 @param[in] TSToken Pointer to the RFC3161 TimeStamp Token, which is generated
341 by a TSA and located in the software publisher's SignerInfo
342 structure.
343 @param[in] TokenSize Size of the TimeStamp Token in bytes.
344 @param[in] TsaCert Pointer to a trusted/root TSA certificate encoded in DER.
345 @param[in] CertSize Size of the trusted TSA certificate in bytes.
346 @param[in] TimestampedData Pointer to the data to be time-stamped.
347 @param[in] DataSize Size of timestamped data in bytes.
348 @param[out] SigningTime Return the time of timestamp generation time if the timestamp
349 signature is valid.
350
351 @retval TRUE The specified timestamp token is valid.
352 @retval FALSE Invalid timestamp token.
353
354 **/
355 BOOLEAN
356 EFIAPI
357 TimestampTokenVerify (
358 IN CONST UINT8 *TSToken,
359 IN UINTN TokenSize,
360 IN CONST UINT8 *TsaCert,
361 IN UINTN CertSize,
362 IN CONST UINT8 *TimestampedData,
363 IN UINTN DataSize,
364 OUT EFI_TIME *SigningTime
365 )
366 {
367 BOOLEAN Status;
368 CONST UINT8 *TokenTemp;
369 PKCS7 *Pkcs7;
370 X509 *Cert;
371 CONST UINT8 *CertTemp;
372 X509_STORE *CertStore;
373 BIO *OutBio;
374 UINT8 *TstData;
375 UINTN TstSize;
376 CONST UINT8 *TstTemp;
377 TS_TST_INFO *TstInfo;
378
379 Status = FALSE;
380
381 //
382 // Check input parameters
383 //
384 if ((TSToken == NULL) || (TsaCert == NULL) || (TimestampedData == NULL) ||
385 (TokenSize > INT_MAX) || (CertSize > INT_MAX) || (DataSize > INT_MAX)) {
386 return FALSE;
387 }
388
389 //
390 // Initializations
391 //
392 if (SigningTime != NULL) {
393 SetMem (SigningTime, sizeof (EFI_TIME), 0);
394 }
395 Pkcs7 = NULL;
396 Cert = NULL;
397 CertStore = NULL;
398 OutBio = NULL;
399 TstData = NULL;
400 TstInfo = NULL;
401
402 //
403 // TimeStamp Token should contain one valid DER-encoded ASN.1 PKCS#7 structure.
404 //
405 TokenTemp = TSToken;
406 Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &TokenTemp, (int) TokenSize);
407 if (Pkcs7 == NULL) {
408 goto _Exit;
409 }
410
411 //
412 // The timestamp signature (TSA's response) will be one PKCS#7 signed data.
413 //
414 if (!PKCS7_type_is_signed (Pkcs7)) {
415 goto _Exit;
416 }
417
418 //
419 // Read the trusted TSA certificate (DER-encoded), and Construct X509 Certificate.
420 //
421 CertTemp = TsaCert;
422 Cert = d2i_X509 (NULL, &CertTemp, (long) CertSize);
423 if (Cert == NULL) {
424 goto _Exit;
425 }
426
427 //
428 // Setup X509 Store for trusted certificate.
429 //
430 CertStore = X509_STORE_new ();
431 if ((CertStore == NULL) || !(X509_STORE_add_cert (CertStore, Cert))) {
432 goto _Exit;
433 }
434
435 //
436 // Allow partial certificate chains, terminated by a non-self-signed but
437 // still trusted intermediate certificate. Also disable time checks.
438 //
439 X509_STORE_set_flags (CertStore,
440 X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_NO_CHECK_TIME);
441
442 X509_STORE_set_purpose (CertStore, X509_PURPOSE_ANY);
443
444 //
445 // Verifies the PKCS#7 signedData structure, and output the signed contents.
446 //
447 OutBio = BIO_new (BIO_s_mem ());
448 if (OutBio == NULL) {
449 goto _Exit;
450 }
451 if (!PKCS7_verify (Pkcs7, NULL, CertStore, NULL, OutBio, PKCS7_BINARY)) {
452 goto _Exit;
453 }
454
455 //
456 // Read the signed contents detached in timestamp signature.
457 //
458 TstData = AllocateZeroPool (2048);
459 if (TstData == NULL) {
460 goto _Exit;
461 }
462 TstSize = BIO_read (OutBio, (void *) TstData, 2048);
463
464 //
465 // Construct TS_TST_INFO structure from the signed contents.
466 //
467 TstTemp = TstData;
468 TstInfo = d2i_TS_TST_INFO (NULL, (const unsigned char **) &TstTemp,
469 (int)TstSize);
470 if (TstInfo == NULL) {
471 goto _Exit;
472 }
473
474 //
475 // Check TS_TST_INFO structure.
476 //
477 Status = CheckTSTInfo (TstInfo, TimestampedData, DataSize);
478 if (!Status) {
479 goto _Exit;
480 }
481
482 //
483 // Retrieve the signing time from TS_TST_INFO structure.
484 //
485 if (SigningTime != NULL) {
486 SetMem (SigningTime, sizeof (EFI_TIME), 0);
487 Status = ConvertAsn1TimeToEfiTime (TstInfo->GenTime, SigningTime);
488 }
489
490 _Exit:
491 //
492 // Release Resources
493 //
494 PKCS7_free (Pkcs7);
495 X509_free (Cert);
496 X509_STORE_free (CertStore);
497 BIO_free (OutBio);
498 TS_TST_INFO_free (TstInfo);
499
500 if (TstData != NULL) {
501 FreePool (TstData);
502 }
503
504 return Status;
505 }
506
507 /**
508 Verifies the validity of a RFC3161 Timestamp CounterSignature embedded in PE/COFF Authenticode
509 signature.
510
511 If AuthData is NULL, then return FALSE.
512
513 @param[in] AuthData Pointer to the Authenticode Signature retrieved from signed
514 PE/COFF image to be verified.
515 @param[in] DataSize Size of the Authenticode Signature in bytes.
516 @param[in] TsaCert Pointer to a trusted/root TSA certificate encoded in DER, which
517 is used for TSA certificate chain verification.
518 @param[in] CertSize Size of the trusted certificate in bytes.
519 @param[out] SigningTime Return the time of timestamp generation time if the timestamp
520 signature is valid.
521
522 @retval TRUE The specified Authenticode includes a valid RFC3161 Timestamp CounterSignature.
523 @retval FALSE No valid RFC3161 Timestamp CounterSignature in the specified Authenticode data.
524
525 **/
526 BOOLEAN
527 EFIAPI
528 ImageTimestampVerify (
529 IN CONST UINT8 *AuthData,
530 IN UINTN DataSize,
531 IN CONST UINT8 *TsaCert,
532 IN UINTN CertSize,
533 OUT EFI_TIME *SigningTime
534 )
535 {
536 BOOLEAN Status;
537 PKCS7 *Pkcs7;
538 CONST UINT8 *Temp;
539 STACK_OF(PKCS7_SIGNER_INFO) *SignerInfos;
540 PKCS7_SIGNER_INFO *SignInfo;
541 UINTN Index;
542 STACK_OF(X509_ATTRIBUTE) *Sk;
543 X509_ATTRIBUTE *Xa;
544 ASN1_OBJECT *XaObj;
545 ASN1_TYPE *Asn1Type;
546 ASN1_OCTET_STRING *EncDigest;
547 UINT8 *TSToken;
548 UINTN TokenSize;
549
550 //
551 // Input Parameters Checking.
552 //
553 if ((AuthData == NULL) || (TsaCert == NULL)) {
554 return FALSE;
555 }
556
557 if ((DataSize > INT_MAX) || (CertSize > INT_MAX)) {
558 return FALSE;
559 }
560
561 //
562 // Register & Initialize necessary digest algorithms for PKCS#7 Handling.
563 //
564 if ((EVP_add_digest (EVP_md5 ()) == 0) || (EVP_add_digest (EVP_sha1 ()) == 0) ||
565 (EVP_add_digest (EVP_sha256 ()) == 0) || (EVP_add_digest_alias (SN_sha1WithRSAEncryption, SN_sha1WithRSA)) == 0) {
566 return FALSE;
567 }
568
569 //
570 // Initialization.
571 //
572 Status = FALSE;
573 Pkcs7 = NULL;
574 SignInfo = NULL;
575
576 //
577 // Decode ASN.1-encoded Authenticode data into PKCS7 structure.
578 //
579 Temp = AuthData;
580 Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &Temp, (int) DataSize);
581 if (Pkcs7 == NULL) {
582 goto _Exit;
583 }
584
585 //
586 // Check if there is one and only one signer.
587 //
588 SignerInfos = PKCS7_get_signer_info (Pkcs7);
589 if (!SignerInfos || (sk_PKCS7_SIGNER_INFO_num (SignerInfos) != 1)) {
590 goto _Exit;
591 }
592
593 //
594 // Locate the TimeStamp CounterSignature.
595 //
596 SignInfo = sk_PKCS7_SIGNER_INFO_value (SignerInfos, 0);
597 if (SignInfo == NULL) {
598 goto _Exit;
599 }
600
601 //
602 // Locate Message Digest which will be the data to be time-stamped.
603 //
604 EncDigest = SignInfo->enc_digest;
605 if (EncDigest == NULL) {
606 goto _Exit;
607 }
608
609 //
610 // The RFC3161 timestamp counterSignature is contained in unauthenticatedAttributes field
611 // of SignerInfo.
612 //
613 Sk = SignInfo->unauth_attr;
614 if (Sk == NULL) { // No timestamp counterSignature.
615 goto _Exit;
616 }
617
618 Asn1Type = NULL;
619 for (Index = 0; Index < (UINTN) sk_X509_ATTRIBUTE_num (Sk); Index++) {
620 //
621 // Search valid RFC3161 timestamp counterSignature based on OBJID.
622 //
623 Xa = sk_X509_ATTRIBUTE_value (Sk, (int)Index);
624 if (Xa == NULL) {
625 continue;
626 }
627 XaObj = X509_ATTRIBUTE_get0_object(Xa);
628 if (XaObj == NULL) {
629 continue;
630 }
631 if ((OBJ_length(XaObj) != sizeof (mSpcRFC3161OidValue)) ||
632 (CompareMem (OBJ_get0_data(XaObj), mSpcRFC3161OidValue, sizeof (mSpcRFC3161OidValue)) != 0)) {
633 continue;
634 }
635 Asn1Type = X509_ATTRIBUTE_get0_type(Xa, 0);
636 }
637
638 if (Asn1Type == NULL) {
639 Status = FALSE;
640 goto _Exit;
641 }
642 TSToken = Asn1Type->value.octet_string->data;
643 TokenSize = Asn1Type->value.octet_string->length;
644
645 //
646 // TimeStamp counterSignature (Token) verification.
647 //
648 Status = TimestampTokenVerify (
649 TSToken,
650 TokenSize,
651 TsaCert,
652 CertSize,
653 EncDigest->data,
654 EncDigest->length,
655 SigningTime
656 );
657
658 _Exit:
659 //
660 // Release Resources
661 //
662 PKCS7_free (Pkcs7);
663
664 return Status;
665 }