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