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