]> git.proxmox.com Git - mirror_edk2.git/blame - CryptoPkg/Library/BaseCryptLib/Pk/CryptTs.c
CryptoPkg: Add some comments for API usage clarification.
[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
1463ce18 8Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>\r
2ac68e8b
QL
9This program and the accompanying materials\r
10are licensed and made available under the terms and conditions of the BSD License\r
11which accompanies this distribution. The full text of the license may be found at\r
12http://opensource.org/licenses/bsd-license.php\r
13\r
14THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
15WITHOUT 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
30UINT8 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
44typedef 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
52DECLARE_ASN1_FUNCTIONS (TS_MESSAGE_IMPRINT)\r
53ASN1_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
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
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
77DECLARE_ASN1_FUNCTIONS (TS_ACCURACY)\r
78ASN1_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
83IMPLEMENT_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
107typedef 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
123DECLARE_ASN1_FUNCTIONS (TS_TST_INFO)\r
124ASN1_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
136IMPLEMENT_ASN1_FUNCTIONS (TS_TST_INFO)\r
137\r
138\r
139/**\r
140 Verification callback function to override any existing callbacks in OpenSSL\r
141 for intermediate TSA certificate supports.\r
142\r
143 @param[in] Status Original status before calling this callback.\r
144 @param[in] Context X509 store context.\r
145\r
146 @retval 1 Current X509 certificate is verified successfully.\r
147 @retval 0 Verification failed.\r
148\r
149**/\r
150int\r
151TSVerifyCallback (\r
152 IN int Status,\r
153 IN X509_STORE_CTX *Context\r
154 )\r
155{\r
156 X509_OBJECT *Obj;\r
157 INTN Error;\r
158 INTN Index;\r
159 INTN Count;\r
160\r
161 Obj = NULL;\r
162 Error = (INTN) X509_STORE_CTX_get_error (Context);\r
163\r
164 //\r
165 // X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT and X509_V_ERR_UNABLE_TO_GET_ISSUER_\r
166 // CERT_LOCALLY mean a X509 certificate is not self signed and its issuer\r
167 // can not be found in X509_verify_cert of X509_vfy.c.\r
168 // In order to support intermediate certificate node, we override the\r
169 // errors if the certification is obtained from X509 store, i.e. it is\r
170 // a trusted ceritifcate node that is enrolled by user.\r
171 // Besides,X509_V_ERR_CERT_UNTRUSTED and X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE\r
172 // are also ignored to enable such feature.\r
173 //\r
174 if ((Error == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT) ||\r
175 (Error == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)) {\r
176 Obj = (X509_OBJECT *) malloc (sizeof (X509_OBJECT));\r
177 if (Obj == NULL) {\r
178 return 0;\r
179 }\r
180\r
181 Obj->type = X509_LU_X509;\r
182 Obj->data.x509 = Context->current_cert;\r
183\r
184 CRYPTO_w_lock (CRYPTO_LOCK_X509_STORE);\r
185\r
186 if (X509_OBJECT_retrieve_match (Context->ctx->objs, Obj)) {\r
187 Status = 1;\r
188 } else {\r
189 //\r
190 // If any certificate in the chain is enrolled as trusted certificate,\r
191 // pass the certificate verification.\r
192 //\r
193 if (Error == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY) {\r
194 Count = (INTN) sk_X509_num (Context->chain);\r
195 for (Index = 0; Index < Count; Index++) {\r
196 Obj->data.x509 = sk_X509_value (Context->chain, (int) Index);\r
197 if (X509_OBJECT_retrieve_match (Context->ctx->objs, Obj)) {\r
198 Status = 1;\r
199 break;\r
200 }\r
201 }\r
202 }\r
203 }\r
204\r
205 CRYPTO_w_unlock (CRYPTO_LOCK_X509_STORE);\r
206 }\r
207\r
208 if ((Error == X509_V_ERR_CERT_UNTRUSTED) ||\r
209 (Error == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE)) {\r
210 Status = 1;\r
211 }\r
212\r
213 if (Obj != NULL) {\r
214 OPENSSL_free (Obj);\r
215 }\r
216\r
217 return Status;\r
218}\r
219\r
220/**\r
221 Convert ASN.1 GeneralizedTime to EFI Time.\r
222\r
223 @param[in] Asn1Time Pointer to the ASN.1 GeneralizedTime to be converted.\r
224 @param[out] SigningTime Return the corresponding EFI Time.\r
225\r
226 @retval TRUE The time convertion succeeds.\r
227 @retval FALSE Invalid parameters.\r
228\r
229**/\r
230BOOLEAN\r
231EFIAPI\r
232ConvertAsn1TimeToEfiTime (\r
233 IN ASN1_TIME *Asn1Time,\r
234 OUT EFI_TIME *EfiTime\r
235 )\r
236{\r
237 CONST CHAR8 *Str;\r
238 UINTN Index;\r
239\r
240 if ((Asn1Time == NULL) || (EfiTime == NULL)) {\r
241 return FALSE;\r
242 }\r
243\r
244 Str = (CONST CHAR8*)Asn1Time->data;\r
245 SetMem (EfiTime, 0, sizeof (EFI_TIME));\r
246\r
247 Index = 0;\r
248 if (Asn1Time->type == V_ASN1_UTCTIME) { /* two digit year */\r
249 EfiTime->Year = (Str[Index++] - '0') * 10;\r
250 EfiTime->Year += (Str[Index++] - '0');\r
251 if (EfiTime->Year < 70) {\r
252 EfiTime->Year += 100;\r
253 }\r
254 } else if (Asn1Time->type == V_ASN1_GENERALIZEDTIME) { /* four digit year */\r
255 EfiTime->Year = (Str[Index++] - '0') * 1000;\r
256 EfiTime->Year += (Str[Index++] - '0') * 100;\r
257 EfiTime->Year += (Str[Index++] - '0') * 10;\r
258 EfiTime->Year += (Str[Index++] - '0');\r
259 if ((EfiTime->Year < 1900) || (EfiTime->Year > 9999)) {\r
260 return FALSE;\r
261 }\r
262 }\r
263\r
264 EfiTime->Month = (Str[Index++] - '0') * 10;\r
265 EfiTime->Month += (Str[Index++] - '0');\r
266 if ((EfiTime->Month < 1) || (EfiTime->Month > 12)) {\r
267 return FALSE;\r
268 }\r
269\r
270 EfiTime->Day = (Str[Index++] - '0') * 10;\r
271 EfiTime->Day += (Str[Index++] - '0');\r
272 if ((EfiTime->Day < 1) || (EfiTime->Day > 31)) {\r
273 return FALSE;\r
274 }\r
275\r
276 EfiTime->Hour = (Str[Index++] - '0') * 10;\r
277 EfiTime->Hour += (Str[Index++] - '0');\r
278 if (EfiTime->Hour > 23) {\r
279 return FALSE;\r
280 }\r
281\r
282 EfiTime->Minute = (Str[Index++] - '0') * 10;\r
283 EfiTime->Minute += (Str[Index++] - '0');\r
284 if (EfiTime->Minute > 59) {\r
285 return FALSE;\r
286 }\r
287\r
288 EfiTime->Second = (Str[Index++] - '0') * 10;\r
289 EfiTime->Second += (Str[Index++] - '0');\r
290 if (EfiTime->Second > 59) {\r
291 return FALSE;\r
292 }\r
293\r
294 /* Note: we did not adjust the time based on time zone information */\r
295\r
296 return TRUE;\r
297}\r
298\r
299/**\r
300\r
301 Check the validity of TimeStamp Token Information.\r
302\r
303 @param[in] TstInfo Pointer to the TS_TST_INFO structure.\r
304 @param[in] TimestampedData Pointer to the data to be time-stamped.\r
305 @param[in] DataSize Size of timestamped data in bytes.\r
306\r
307 @retval TRUE The TimeStamp Token Information is valid.\r
308 @retval FALSE Invalid TimeStamp Token Information.\r
309\r
310**/\r
311BOOLEAN\r
312EFIAPI\r
313CheckTSTInfo (\r
314 IN CONST TS_TST_INFO *TstInfo,\r
315 IN CONST UINT8 *TimestampedData,\r
316 IN UINTN DataSize\r
317 )\r
318{\r
319 BOOLEAN Status;\r
320 TS_MESSAGE_IMPRINT *Imprint;\r
321 X509_ALGOR *HashAlgo;\r
322 CONST EVP_MD *Md;\r
323 EVP_MD_CTX MdCtx;\r
324 UINTN MdSize;\r
325 UINT8 *HashedMsg;\r
326\r
327 //\r
328 // Initialization\r
329 //\r
330 Status = FALSE;\r
331 HashAlgo = NULL;\r
332 HashedMsg = NULL;\r
333\r
334 //\r
335 // -- Check version number of Timestamp:\r
336 // The version field (currently v1) describes the version of the time-stamp token.\r
337 // Conforming time-stamping servers MUST be able to provide version 1 time-stamp tokens.\r
338 //\r
339 if ((ASN1_INTEGER_get (TstInfo->Version)) != 1) {\r
340 return FALSE;\r
341 }\r
342\r
343 //\r
344 // -- Check Policies\r
345 // The policy field MUST indicate the TSA's policy under which the response was produced.\r
346 //\r
347 if (TstInfo->Policy == NULL) {\r
348 /// NOTE: Need to check if the requested and returned policies.\r
349 /// We have no information about the Requested TSA Policy.\r
350 return FALSE;\r
351 }\r
352\r
353 //\r
354 // -- Compute & Check Message Imprint\r
355 //\r
356 Imprint = TstInfo->MessageImprint;\r
357 HashAlgo = X509_ALGOR_dup (Imprint->HashAlgorithm);\r
358\r
359 Md = EVP_get_digestbyobj (HashAlgo->algorithm);\r
360 if (Md == NULL) {\r
361 goto _Exit;\r
362 }\r
363\r
364 MdSize = EVP_MD_size (Md);\r
365 HashedMsg = AllocateZeroPool (MdSize);\r
366 if (HashedMsg == NULL) {\r
367 goto _Exit;\r
368 }\r
369 EVP_DigestInit (&MdCtx, Md);\r
370 EVP_DigestUpdate (&MdCtx, TimestampedData, DataSize);\r
371 EVP_DigestFinal (&MdCtx, HashedMsg, NULL);\r
372 if ((MdSize == (UINTN)ASN1_STRING_length (Imprint->HashedMessage)) &&\r
373 (CompareMem (HashedMsg, ASN1_STRING_data (Imprint->HashedMessage), MdSize) != 0)) {\r
374 goto _Exit;\r
375 }\r
376\r
377 //\r
378 // -- Check Nonces\r
379 //\r
380 if (TstInfo->Nonce != NULL) {\r
381 //\r
382 // Nonces is optional, No error if no nonce is returned;\r
383 //\r
384 }\r
385\r
386 //\r
387 // -- Check if the TSA name and signer certificate is matched.\r
388 //\r
389 if (TstInfo->Tsa != NULL) {\r
390 //\r
391 // Ignored the optional Tsa field checking.\r
392 //\r
393 }\r
394\r
395 Status = TRUE;\r
396\r
397_Exit:\r
398 X509_ALGOR_free (HashAlgo);\r
399 if (HashedMsg != NULL) {\r
400 FreePool (HashedMsg);\r
401 }\r
402\r
403 return Status;\r
404}\r
405\r
406/**\r
407 Verifies the validility of a TimeStamp Token as described in RFC 3161 ("Internet\r
408 X.509 Public Key Infrastructure Time-Stamp Protocol (TSP)").\r
409\r
410 If TSToken is NULL, then return FALSE.\r
411 If TimestampedData is NULL, then return FALSE.\r
412\r
413 @param[in] TSToken Pointer to the RFC3161 TimeStamp Token, which is generated\r
414 by a TSA and located in the software publisher's SignerInfo\r
415 structure.\r
416 @param[in] TokenSize Size of the TimeStamp Token in bytes.\r
417 @param[in] TsaCert Pointer to a trusted/root TSA certificate encoded in DER.\r
418 @param[in] CertSize Size of the trusted TSA certificate in bytes.\r
419 @param[in] TimestampedData Pointer to the data to be time-stamped.\r
420 @param[in] DataSize Size of timestamped data in bytes.\r
421 @param[out] SigningTime Return the time of timestamp generation time if the timestamp\r
422 signature is valid.\r
423\r
424 @retval TRUE The specified timestamp token is valid.\r
425 @retval FALSE Invalid timestamp token.\r
426\r
427**/\r
428BOOLEAN\r
429EFIAPI\r
430TimestampTokenVerify (\r
431 IN CONST UINT8 *TSToken,\r
432 IN UINTN TokenSize,\r
433 IN CONST UINT8 *TsaCert,\r
434 IN UINTN CertSize,\r
435 IN CONST UINT8 *TimestampedData,\r
436 IN UINTN DataSize,\r
437 OUT EFI_TIME *SigningTime\r
438 )\r
439{\r
440 BOOLEAN Status;\r
441 CONST UINT8 *TokenTemp;\r
442 PKCS7 *Pkcs7;\r
443 X509 *Cert;\r
1463ce18 444 CONST UINT8 *CertTemp;\r
2ac68e8b
QL
445 X509_STORE *CertStore;\r
446 BIO *OutBio;\r
447 UINT8 *TstData;\r
448 UINTN TstSize;\r
1463ce18 449 CONST UINT8 *TstTemp;\r
2ac68e8b
QL
450 TS_TST_INFO *TstInfo;\r
451\r
452 Status = FALSE;\r
453\r
454 //\r
455 // Check input parameters\r
456 //\r
457 if ((TSToken == NULL) || (TsaCert == NULL) || (TimestampedData == NULL) ||\r
458 (TokenSize > INT_MAX) || (CertSize > INT_MAX) || (DataSize > INT_MAX)) {\r
459 return FALSE;\r
460 }\r
461\r
462 //\r
463 // Initializations\r
464 //\r
465 if (SigningTime != NULL) {\r
466 SetMem (SigningTime, sizeof (EFI_TIME), 0);\r
467 }\r
468 Pkcs7 = NULL;\r
469 Cert = NULL;\r
470 CertStore = NULL;\r
471 OutBio = NULL;\r
472 TstData = NULL;\r
473 TstInfo = NULL;\r
474\r
475 //\r
476 // TimeStamp Token should contain one valid DER-encoded ASN.1 PKCS#7 structure.\r
477 //\r
478 TokenTemp = TSToken;\r
479 Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &TokenTemp, (int) TokenSize);\r
480 if (Pkcs7 == NULL) {\r
481 goto _Exit;\r
482 }\r
483\r
484 //\r
485 // The timestamp signature (TSA's response) will be one PKCS#7 signed data.\r
486 //\r
487 if (!PKCS7_type_is_signed (Pkcs7)) {\r
488 goto _Exit;\r
489 }\r
490\r
491 //\r
492 // Read the trusted TSA certificate (DER-encoded), and Construct X509 Certificate.\r
493 //\r
1463ce18
QL
494 CertTemp = TsaCert;\r
495 Cert = d2i_X509 (NULL, &CertTemp, (long) CertSize);\r
2ac68e8b
QL
496 if (Cert == NULL) {\r
497 goto _Exit;\r
498 }\r
499\r
500 //\r
501 // Setup X509 Store for trusted certificate.\r
502 //\r
503 CertStore = X509_STORE_new ();\r
504 if ((CertStore == NULL) || !(X509_STORE_add_cert (CertStore, Cert))) {\r
505 goto _Exit;\r
506 }\r
507\r
508 //\r
509 // Register customized X509 verification callback function to support\r
510 // trusted intermediate TSA certificate anchor.\r
511 //\r
512 CertStore->verify_cb = TSVerifyCallback;\r
513\r
514 X509_STORE_set_purpose (CertStore, X509_PURPOSE_ANY);\r
515\r
516 //\r
517 // Verifies the PKCS#7 signedData structure, and output the signed contents.\r
518 //\r
519 OutBio = BIO_new (BIO_s_mem ());\r
520 if (OutBio == NULL) {\r
521 goto _Exit;\r
522 }\r
523 if (!PKCS7_verify (Pkcs7, NULL, CertStore, NULL, OutBio, PKCS7_BINARY)) {\r
524 goto _Exit;\r
525 }\r
526\r
527 //\r
528 // Read the signed contents detached in timestamp signature.\r
529 //\r
530 TstData = AllocateZeroPool (2048);\r
531 if (TstData == NULL) {\r
532 goto _Exit;\r
533 }\r
534 TstSize = BIO_read (OutBio, (void *) TstData, 2048);\r
535\r
536 //\r
537 // Construct TS_TST_INFO structure from the signed contents.\r
538 //\r
539 TstTemp = TstData;\r
017c285e
LE
540 TstInfo = d2i_TS_TST_INFO (NULL, (const unsigned char **) &TstTemp,\r
541 (int)TstSize);\r
2ac68e8b
QL
542 if (TstInfo == NULL) {\r
543 goto _Exit;\r
544 }\r
545\r
546 //\r
547 // Check TS_TST_INFO structure.\r
548 //\r
549 Status = CheckTSTInfo (TstInfo, TimestampedData, DataSize);\r
550 if (!Status) {\r
551 goto _Exit;\r
552 }\r
553\r
554 //\r
555 // Retrieve the signing time from TS_TST_INFO structure.\r
556 //\r
557 if (SigningTime != NULL) {\r
558 SetMem (SigningTime, sizeof (EFI_TIME), 0);\r
559 Status = ConvertAsn1TimeToEfiTime (TstInfo->GenTime, SigningTime);\r
560 }\r
561\r
562_Exit:\r
563 //\r
564 // Release Resources\r
565 //\r
566 PKCS7_free (Pkcs7);\r
567 X509_free (Cert);\r
568 X509_STORE_free (CertStore);\r
569 BIO_free (OutBio);\r
570 TS_TST_INFO_free (TstInfo);\r
571\r
572 if (TstData != NULL) {\r
573 FreePool (TstData);\r
574 }\r
575\r
576 return Status;\r
577}\r
578\r
579/**\r
580 Verifies the validility of a RFC3161 Timestamp CounterSignature embedded in PE/COFF Authenticode\r
581 signature.\r
582\r
583 If AuthData is NULL, then return FALSE.\r
584\r
585 @param[in] AuthData Pointer to the Authenticode Signature retrieved from signed\r
586 PE/COFF image to be verified.\r
587 @param[in] DataSize Size of the Authenticode Signature in bytes.\r
588 @param[in] TsaCert Pointer to a trusted/root TSA certificate encoded in DER, which\r
589 is used for TSA certificate chain verification.\r
590 @param[in] CertSize Size of the trusted certificate in bytes.\r
591 @param[out] SigningTime Return the time of timestamp generation time if the timestamp\r
592 signature is valid.\r
593\r
594 @retval TRUE The specified Authenticode includes a valid RFC3161 Timestamp CounterSignature.\r
595 @retval FALSE No valid RFC3161 Timestamp CounterSignature in the specified Authenticode data.\r
596\r
597**/\r
598BOOLEAN\r
599EFIAPI\r
600ImageTimestampVerify (\r
601 IN CONST UINT8 *AuthData,\r
602 IN UINTN DataSize,\r
603 IN CONST UINT8 *TsaCert,\r
604 IN UINTN CertSize,\r
605 OUT EFI_TIME *SigningTime\r
606 )\r
607{\r
608 BOOLEAN Status;\r
609 PKCS7 *Pkcs7;\r
1463ce18 610 CONST UINT8 *Temp;\r
2ac68e8b
QL
611 STACK_OF(PKCS7_SIGNER_INFO) *SignerInfos;\r
612 PKCS7_SIGNER_INFO *SignInfo;\r
613 UINTN Index;\r
614 STACK_OF(X509_ATTRIBUTE) *Sk;\r
615 X509_ATTRIBUTE *Xa;\r
616 ASN1_TYPE *Asn1Type;\r
617 ASN1_OCTET_STRING *EncDigest;\r
618 UINT8 *TSToken;\r
619 UINTN TokenSize;\r
620\r
621 //\r
622 // Input Parameters Checking.\r
623 //\r
624 if ((AuthData == NULL) || (TsaCert == NULL)) {\r
625 return FALSE;\r
626 }\r
627\r
628 if ((DataSize > INT_MAX) || (CertSize > INT_MAX)) {\r
629 return FALSE;\r
630 }\r
631\r
632 //\r
633 // Register & Initialize necessary digest algorithms for PKCS#7 Handling.\r
634 //\r
635 if ((EVP_add_digest (EVP_md5 ()) == 0) || (EVP_add_digest (EVP_sha1 ()) == 0) ||\r
636 (EVP_add_digest (EVP_sha256 ()) == 0) || (EVP_add_digest_alias (SN_sha1WithRSAEncryption, SN_sha1WithRSA)) == 0) {\r
637 return FALSE;\r
638 }\r
639\r
640 //\r
641 // Initialization.\r
642 //\r
643 Status = FALSE;\r
644 Pkcs7 = NULL;\r
645 SignInfo = NULL;\r
646\r
647 //\r
648 // Decode ASN.1-encoded Authenticode data into PKCS7 structure.\r
649 //\r
1463ce18
QL
650 Temp = AuthData;\r
651 Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &Temp, (int) DataSize);\r
2ac68e8b
QL
652 if (Pkcs7 == NULL) {\r
653 goto _Exit;\r
654 }\r
655\r
656 //\r
657 // Check if there is one and only one signer.\r
658 //\r
659 SignerInfos = PKCS7_get_signer_info (Pkcs7);\r
660 if (!SignerInfos || (sk_PKCS7_SIGNER_INFO_num (SignerInfos) != 1)) {\r
661 goto _Exit;\r
662 }\r
663\r
664 //\r
665 // Locate the TimeStamp CounterSignature.\r
666 //\r
667 SignInfo = sk_PKCS7_SIGNER_INFO_value (SignerInfos, 0);\r
668 if (SignInfo == NULL) {\r
669 goto _Exit;\r
670 }\r
671\r
672 //\r
673 // Locate Message Digest which will be the data to be time-stamped.\r
674 //\r
675 EncDigest = SignInfo->enc_digest;\r
676 if (EncDigest == NULL) {\r
677 goto _Exit;\r
678 }\r
679\r
680 //\r
681 // The RFC3161 timestamp counterSignature is contained in unauthenticatedAttributes field\r
682 // of SignerInfo.\r
683 //\r
684 Sk = SignInfo->unauth_attr;\r
685 if (Sk == NULL) { // No timestamp counterSignature.\r
686 goto _Exit;\r
687 }\r
688\r
689 Asn1Type = NULL;\r
690 for (Index = 0; Index < (UINTN) sk_X509_ATTRIBUTE_num (Sk); Index++) {\r
691 //\r
692 // Search valid RFC3161 timestamp counterSignature based on OBJID.\r
693 //\r
694 Xa = sk_X509_ATTRIBUTE_value (Sk, (int)Index);\r
695 if ((Xa->object->length != sizeof (mSpcRFC3161OidValue)) ||\r
696 (CompareMem (Xa->object->data, mSpcRFC3161OidValue, sizeof (mSpcRFC3161OidValue)) != 0)) {\r
697 continue;\r
698 }\r
699 Asn1Type = sk_ASN1_TYPE_value (Xa->value.set, 0);\r
700 }\r
701\r
702 if (Asn1Type == NULL) {\r
703 Status = FALSE;\r
704 goto _Exit;\r
705 }\r
706 TSToken = Asn1Type->value.octet_string->data;\r
707 TokenSize = Asn1Type->value.octet_string->length;\r
708\r
709 //\r
710 // TimeStamp counterSignature (Token) verification.\r
711 //\r
712 Status = TimestampTokenVerify (\r
713 TSToken,\r
714 TokenSize,\r
715 TsaCert,\r
716 CertSize,\r
717 EncDigest->data,\r
718 EncDigest->length,\r
719 SigningTime\r
720 );\r
721\r
722_Exit:\r
723 //\r
724 // Release Resources\r
725 //\r
726 PKCS7_free (Pkcs7);\r
727\r
728 return Status;\r
729}\r