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