TianoCore EDK2 master
Loading...
Searching...
No Matches
CryptTs.c
Go to the documentation of this file.
1
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//
24GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 mSpcRFC3161OidValue[] = {
25 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x03, 0x03, 0x01
26};
27
38typedef struct {
39 X509_ALGOR *HashAlgorithm;
40 ASN1_OCTET_STRING *HashedMessage;
42
43//
44// ASN.1 Functions for TS_MESSAGE_IMPRINT
45//
47DECLARE_ASN1_FUNCTIONS (
49 )
50ASN1_SEQUENCE (TS_MESSAGE_IMPRINT) =
51{
52 ASN1_SIMPLE (TS_MESSAGE_IMPRINT, HashAlgorithm, X509_ALGOR),
53 ASN1_SIMPLE (TS_MESSAGE_IMPRINT, HashedMessage, ASN1_OCTET_STRING)
54}
55
56ASN1_SEQUENCE_END (TS_MESSAGE_IMPRINT)
57IMPLEMENT_ASN1_FUNCTIONS (TS_MESSAGE_IMPRINT)
58
59
68typedef struct {
69 ASN1_INTEGER *Seconds;
70 ASN1_INTEGER *Millis;
71 ASN1_INTEGER *Micros;
73
74//
75// ASN.1 Functions for TS_ACCURACY
76//
78DECLARE_ASN1_FUNCTIONS (
80 )
81ASN1_SEQUENCE (TS_ACCURACY) =
82{
83 ASN1_OPT (TS_ACCURACY, Seconds, ASN1_INTEGER),
84 ASN1_IMP_OPT (TS_ACCURACY, Millis, ASN1_INTEGER, 0),
85 ASN1_IMP_OPT (TS_ACCURACY, Micros, ASN1_INTEGER, 1)
86}
87
88ASN1_SEQUENCE_END (TS_ACCURACY)
89IMPLEMENT_ASN1_FUNCTIONS (TS_ACCURACY)
90
91
113typedef struct {
114 ASN1_INTEGER *Version;
115 ASN1_OBJECT *Policy;
116 TS_MESSAGE_IMPRINT *MessageImprint;
117 ASN1_INTEGER *SerialNumber;
118 ASN1_GENERALIZEDTIME *GenTime;
119 TS_ACCURACY *Accuracy;
120 ASN1_BOOLEAN Ordering;
121 ASN1_INTEGER *Nonce;
122 GENERAL_NAME *Tsa;
123 STACK_OF (X509_EXTENSION) *Extensions;
125
126//
127// ASN.1 Functions for TS_TST_INFO
128//
130DECLARE_ASN1_FUNCTIONS (
132 )
133ASN1_SEQUENCE (TS_TST_INFO) =
134{
135 ASN1_SIMPLE (TS_TST_INFO, Version, ASN1_INTEGER),
136 ASN1_SIMPLE (TS_TST_INFO, Policy, ASN1_OBJECT),
137 ASN1_SIMPLE (TS_TST_INFO, MessageImprint, TS_MESSAGE_IMPRINT),
138 ASN1_SIMPLE (TS_TST_INFO, SerialNumber, ASN1_INTEGER),
139 ASN1_SIMPLE (TS_TST_INFO, GenTime, ASN1_GENERALIZEDTIME),
140 ASN1_OPT (TS_TST_INFO, Accuracy, TS_ACCURACY),
141 ASN1_OPT (TS_TST_INFO, Ordering, ASN1_FBOOLEAN),
142 ASN1_OPT (TS_TST_INFO, Nonce, ASN1_INTEGER),
143 ASN1_EXP_OPT (TS_TST_INFO, Tsa, GENERAL_NAME, 0),
144 ASN1_IMP_SEQUENCE_OF_OPT (TS_TST_INFO, Extensions, X509_EXTENSION, 1)
145}
146
147ASN1_SEQUENCE_END (TS_TST_INFO)
148IMPLEMENT_ASN1_FUNCTIONS (TS_TST_INFO)
149
150
160STATIC
161BOOLEAN
163 IN ASN1_TIME *Asn1Time,
164 OUT EFI_TIME *EfiTime
165 )
166{
167 CONST CHAR8 *Str;
168 UINTN Index;
169
170 if ((Asn1Time == NULL) || (EfiTime == NULL)) {
171 return FALSE;
172 }
173
174 Str = (CONST CHAR8 *)Asn1Time->data;
175 SetMem (EfiTime, sizeof (EFI_TIME), 0);
176
177 Index = 0;
178 if (Asn1Time->type == V_ASN1_UTCTIME) {
179 /* two digit year */
180 EfiTime->Year = (Str[Index++] - '0') * 10;
181 EfiTime->Year += (Str[Index++] - '0');
182 if (EfiTime->Year < 70) {
183 EfiTime->Year += 100;
184 }
185 } else if (Asn1Time->type == V_ASN1_GENERALIZEDTIME) {
186 /* four digit year */
187 EfiTime->Year = (Str[Index++] - '0') * 1000;
188 EfiTime->Year += (Str[Index++] - '0') * 100;
189 EfiTime->Year += (Str[Index++] - '0') * 10;
190 EfiTime->Year += (Str[Index++] - '0');
191 if ((EfiTime->Year < 1900) || (EfiTime->Year > 9999)) {
192 return FALSE;
193 }
194 }
195
196 EfiTime->Month = (Str[Index++] - '0') * 10;
197 EfiTime->Month += (Str[Index++] - '0');
198 if ((EfiTime->Month < 1) || (EfiTime->Month > 12)) {
199 return FALSE;
200 }
201
202 EfiTime->Day = (Str[Index++] - '0') * 10;
203 EfiTime->Day += (Str[Index++] - '0');
204 if ((EfiTime->Day < 1) || (EfiTime->Day > 31)) {
205 return FALSE;
206 }
207
208 EfiTime->Hour = (Str[Index++] - '0') * 10;
209 EfiTime->Hour += (Str[Index++] - '0');
210 if (EfiTime->Hour > 23) {
211 return FALSE;
212 }
213
214 EfiTime->Minute = (Str[Index++] - '0') * 10;
215 EfiTime->Minute += (Str[Index++] - '0');
216 if (EfiTime->Minute > 59) {
217 return FALSE;
218 }
219
220 EfiTime->Second = (Str[Index++] - '0') * 10;
221 EfiTime->Second += (Str[Index++] - '0');
222 if (EfiTime->Second > 59) {
223 return FALSE;
224 }
225
226 /* Note: we did not adjust the time based on time zone information */
227
228 return TRUE;
229}
230
243STATIC
244BOOLEAN
246 IN CONST TS_TST_INFO *TstInfo,
247 IN CONST UINT8 *TimestampedData,
248 IN UINTN DataSize
249 )
250{
251 BOOLEAN Status;
252 TS_MESSAGE_IMPRINT *Imprint;
253 X509_ALGOR *HashAlgo;
254 CONST EVP_MD *Md;
255 EVP_MD_CTX *MdCtx;
256 UINTN MdSize;
257 UINT8 *HashedMsg;
258
259 //
260 // Initialization
261 //
262 Status = FALSE;
263 HashAlgo = NULL;
264 HashedMsg = NULL;
265 MdCtx = NULL;
266
267 //
268 // -- Check version number of Timestamp:
269 // The version field (currently v1) describes the version of the time-stamp token.
270 // Conforming time-stamping servers MUST be able to provide version 1 time-stamp tokens.
271 //
272 if ((ASN1_INTEGER_get (TstInfo->Version)) != 1) {
273 return FALSE;
274 }
275
276 //
277 // -- Check Policies
278 // The policy field MUST indicate the TSA's policy under which the response was produced.
279 //
280 if (TstInfo->Policy == NULL) {
283 return FALSE;
284 }
285
286 //
287 // -- Compute & Check Message Imprint
288 //
289 Imprint = TstInfo->MessageImprint;
290 HashAlgo = X509_ALGOR_dup (Imprint->HashAlgorithm);
291
292 Md = EVP_get_digestbyobj (HashAlgo->algorithm);
293 if (Md == NULL) {
294 goto _Exit;
295 }
296
297 MdSize = EVP_MD_size (Md);
298 HashedMsg = AllocateZeroPool (MdSize);
299 if (HashedMsg == NULL) {
300 goto _Exit;
301 }
302
303 MdCtx = EVP_MD_CTX_new ();
304 if (MdCtx == NULL) {
305 goto _Exit;
306 }
307
308 if ((EVP_DigestInit_ex (MdCtx, Md, NULL) != 1) ||
309 (EVP_DigestUpdate (MdCtx, TimestampedData, DataSize) != 1) ||
310 (EVP_DigestFinal (MdCtx, HashedMsg, NULL) != 1))
311 {
312 goto _Exit;
313 }
314
315 if ((MdSize == (UINTN)ASN1_STRING_length (Imprint->HashedMessage)) &&
316 (CompareMem (HashedMsg, ASN1_STRING_get0_data (Imprint->HashedMessage), MdSize) != 0))
317 {
318 goto _Exit;
319 }
320
321 //
322 // -- Check Nonces
323 //
324 if (TstInfo->Nonce != NULL) {
325 //
326 // Nonces is optional, No error if no nonce is returned;
327 //
328 }
329
330 //
331 // -- Check if the TSA name and signer certificate is matched.
332 //
333 if (TstInfo->Tsa != NULL) {
334 //
335 // Ignored the optional Tsa field checking.
336 //
337 }
338
339 Status = TRUE;
340
341_Exit:
342 X509_ALGOR_free (HashAlgo);
343 EVP_MD_CTX_free (MdCtx);
344 if (HashedMsg != NULL) {
345 FreePool (HashedMsg);
346 }
347
348 return Status;
349}
350
373STATIC
374BOOLEAN
376 IN CONST UINT8 *TSToken,
377 IN UINTN TokenSize,
378 IN CONST UINT8 *TsaCert,
379 IN UINTN CertSize,
380 IN CONST UINT8 *TimestampedData,
381 IN UINTN DataSize,
382 OUT EFI_TIME *SigningTime
383 )
384{
385 BOOLEAN Status;
386 CONST UINT8 *TokenTemp;
387 PKCS7 *Pkcs7;
388 X509 *Cert;
389 CONST UINT8 *CertTemp;
390 X509_STORE *CertStore;
391 BIO *OutBio;
392 UINT8 *TstData;
393 UINTN TstSize;
394 CONST UINT8 *TstTemp;
395 TS_TST_INFO *TstInfo;
396
397 Status = FALSE;
398
399 //
400 // Check input parameters
401 //
402 if ((TSToken == NULL) || (TsaCert == NULL) || (TimestampedData == NULL) ||
403 (TokenSize > INT_MAX) || (CertSize > INT_MAX) || (DataSize > INT_MAX))
404 {
405 return FALSE;
406 }
407
408 //
409 // Initializations
410 //
411 if (SigningTime != NULL) {
412 SetMem (SigningTime, sizeof (EFI_TIME), 0);
413 }
414
415 Pkcs7 = NULL;
416 Cert = NULL;
417 CertStore = NULL;
418 OutBio = NULL;
419 TstData = NULL;
420 TstInfo = NULL;
421
422 //
423 // TimeStamp Token should contain one valid DER-encoded ASN.1 PKCS#7 structure.
424 //
425 TokenTemp = TSToken;
426 Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **)&TokenTemp, (int)TokenSize);
427 if (Pkcs7 == NULL) {
428 goto _Exit;
429 }
430
431 //
432 // The timestamp signature (TSA's response) will be one PKCS#7 signed data.
433 //
434 if (!PKCS7_type_is_signed (Pkcs7)) {
435 goto _Exit;
436 }
437
438 //
439 // Read the trusted TSA certificate (DER-encoded), and Construct X509 Certificate.
440 //
441 CertTemp = TsaCert;
442 Cert = d2i_X509 (NULL, &CertTemp, (long)CertSize);
443 if (Cert == NULL) {
444 goto _Exit;
445 }
446
447 //
448 // Setup X509 Store for trusted certificate.
449 //
450 CertStore = X509_STORE_new ();
451 if ((CertStore == NULL) || !(X509_STORE_add_cert (CertStore, Cert))) {
452 goto _Exit;
453 }
454
455 //
456 // Allow partial certificate chains, terminated by a non-self-signed but
457 // still trusted intermediate certificate. Also disable time checks.
458 //
459 X509_STORE_set_flags (
460 CertStore,
461 X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_NO_CHECK_TIME
462 );
463
464 X509_STORE_set_purpose (CertStore, X509_PURPOSE_ANY);
465
466 //
467 // Verifies the PKCS#7 signedData structure, and output the signed contents.
468 //
469 OutBio = BIO_new (BIO_s_mem ());
470 if (OutBio == NULL) {
471 goto _Exit;
472 }
473
474 if (!PKCS7_verify (Pkcs7, NULL, CertStore, NULL, OutBio, PKCS7_BINARY)) {
475 goto _Exit;
476 }
477
478 //
479 // Read the signed contents detached in timestamp signature.
480 //
481 TstData = AllocateZeroPool (2048);
482 if (TstData == NULL) {
483 goto _Exit;
484 }
485
486 TstSize = BIO_read (OutBio, (void *)TstData, 2048);
487
488 //
489 // Construct TS_TST_INFO structure from the signed contents.
490 //
491 TstTemp = TstData;
492 TstInfo = d2i_TS_TST_INFO (
493 NULL,
494 (const unsigned char **)&TstTemp,
495 (int)TstSize
496 );
497 if (TstInfo == NULL) {
498 goto _Exit;
499 }
500
501 //
502 // Check TS_TST_INFO structure.
503 //
504 Status = CheckTSTInfo (TstInfo, TimestampedData, DataSize);
505 if (!Status) {
506 goto _Exit;
507 }
508
509 //
510 // Retrieve the signing time from TS_TST_INFO structure.
511 //
512 if (SigningTime != NULL) {
513 SetMem (SigningTime, sizeof (EFI_TIME), 0);
514 Status = ConvertAsn1TimeToEfiTime (TstInfo->GenTime, SigningTime);
515 }
516
517_Exit:
518 //
519 // Release Resources
520 //
521 PKCS7_free (Pkcs7);
522 X509_free (Cert);
523 X509_STORE_free (CertStore);
524 BIO_free (OutBio);
525 TS_TST_INFO_free (TstInfo);
526
527 if (TstData != NULL) {
528 FreePool (TstData);
529 }
530
531 return Status;
532}
533
553BOOLEAN
554EFIAPI
556 IN CONST UINT8 *AuthData,
557 IN UINTN DataSize,
558 IN CONST UINT8 *TsaCert,
559 IN UINTN CertSize,
560 OUT EFI_TIME *SigningTime
561 )
562{
563 BOOLEAN Status;
564 PKCS7 *Pkcs7;
565 CONST UINT8 *Temp;
566
567 STACK_OF (PKCS7_SIGNER_INFO) *SignerInfos;
568 PKCS7_SIGNER_INFO *SignInfo;
569 UINTN Index;
570
571 STACK_OF (X509_ATTRIBUTE) *Sk;
572 X509_ATTRIBUTE *Xa;
573 ASN1_OBJECT *XaObj;
574 ASN1_TYPE *Asn1Type;
575 ASN1_OCTET_STRING *EncDigest;
576 UINT8 *TSToken;
577 UINTN TokenSize;
578
579 //
580 // Input Parameters Checking.
581 //
582 if ((AuthData == NULL) || (TsaCert == NULL)) {
583 return FALSE;
584 }
585
586 if ((DataSize > INT_MAX) || (CertSize > INT_MAX)) {
587 return FALSE;
588 }
589
590 //
591 // Register & Initialize necessary digest algorithms for PKCS#7 Handling.
592 //
593 if ((EVP_add_digest (EVP_md5 ()) == 0) || (EVP_add_digest (EVP_sha1 ()) == 0) ||
594 (EVP_add_digest (EVP_sha256 ()) == 0) || (EVP_add_digest (EVP_sha384 ()) == 0) ||
595 (EVP_add_digest (EVP_sha512 ()) == 0) || ((EVP_add_digest_alias (SN_sha1WithRSAEncryption, SN_sha1WithRSA)) == 0))
596 {
597 return FALSE;
598 }
599
600 //
601 // Initialization.
602 //
603 Status = FALSE;
604 Pkcs7 = NULL;
605 SignInfo = NULL;
606
607 //
608 // Decode ASN.1-encoded Authenticode data into PKCS7 structure.
609 //
610 Temp = AuthData;
611 Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **)&Temp, (int)DataSize);
612 if (Pkcs7 == NULL) {
613 goto _Exit;
614 }
615
616 //
617 // Check if there is one and only one signer.
618 //
619 SignerInfos = PKCS7_get_signer_info (Pkcs7);
620 if (!SignerInfos || (sk_PKCS7_SIGNER_INFO_num (SignerInfos) != 1)) {
621 goto _Exit;
622 }
623
624 //
625 // Locate the TimeStamp CounterSignature.
626 //
627 SignInfo = sk_PKCS7_SIGNER_INFO_value (SignerInfos, 0);
628 if (SignInfo == NULL) {
629 goto _Exit;
630 }
631
632 //
633 // Locate Message Digest which will be the data to be time-stamped.
634 //
635 EncDigest = SignInfo->enc_digest;
636 if (EncDigest == NULL) {
637 goto _Exit;
638 }
639
640 //
641 // The RFC3161 timestamp counterSignature is contained in unauthenticatedAttributes field
642 // of SignerInfo.
643 //
644 Sk = SignInfo->unauth_attr;
645 if (Sk == NULL) {
646 // No timestamp counterSignature.
647 goto _Exit;
648 }
649
650 Asn1Type = NULL;
651 for (Index = 0; Index < (UINTN)sk_X509_ATTRIBUTE_num (Sk); Index++) {
652 //
653 // Search valid RFC3161 timestamp counterSignature based on OBJID.
654 //
655 Xa = sk_X509_ATTRIBUTE_value (Sk, (int)Index);
656 if (Xa == NULL) {
657 continue;
658 }
659
660 XaObj = X509_ATTRIBUTE_get0_object (Xa);
661 if (XaObj == NULL) {
662 continue;
663 }
664
665 if ((OBJ_length (XaObj) != sizeof (mSpcRFC3161OidValue)) ||
666 (CompareMem (OBJ_get0_data (XaObj), mSpcRFC3161OidValue, sizeof (mSpcRFC3161OidValue)) != 0))
667 {
668 continue;
669 }
670
671 Asn1Type = X509_ATTRIBUTE_get0_type (Xa, 0);
672 }
673
674 if (Asn1Type == NULL) {
675 Status = FALSE;
676 goto _Exit;
677 }
678
679 TSToken = Asn1Type->value.octet_string->data;
680 TokenSize = Asn1Type->value.octet_string->length;
681
682 //
683 // TimeStamp counterSignature (Token) verification.
684 //
685 Status = TimestampTokenVerify (
686 TSToken,
687 TokenSize,
688 TsaCert,
689 CertSize,
690 EncDigest->data,
691 EncDigest->length,
692 SigningTime
693 );
694
695_Exit:
696 //
697 // Release Resources
698 //
699 PKCS7_free (Pkcs7);
700
701 return Status;
702}
UINT64 UINTN
INTN EFIAPI CompareMem(IN CONST VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI SetMem(OUT VOID *Buffer, IN UINTN Length, IN UINT8 Value)
Definition: SetMemWrapper.c:38
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#define STATIC
Definition: Base.h:264
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define GLOBAL_REMOVE_IF_UNREFERENCED
Definition: Base.h:48
STATIC BOOLEAN CheckTSTInfo(IN CONST TS_TST_INFO *TstInfo, IN CONST UINT8 *TimestampedData, IN UINTN DataSize)
Definition: CryptTs.c:245
STATIC BOOLEAN ConvertAsn1TimeToEfiTime(IN ASN1_TIME *Asn1Time, OUT EFI_TIME *EfiTime)
Definition: CryptTs.c:162
BOOLEAN EFIAPI ImageTimestampVerify(IN CONST UINT8 *AuthData, IN UINTN DataSize, IN CONST UINT8 *TsaCert, IN UINTN CertSize, OUT EFI_TIME *SigningTime)
Definition: CryptTs.c:555
STATIC BOOLEAN TimestampTokenVerify(IN CONST UINT8 *TSToken, IN UINTN TokenSize, IN CONST UINT8 *TsaCert, IN UINTN CertSize, IN CONST UINT8 *TimestampedData, IN UINTN DataSize, OUT EFI_TIME *SigningTime)
Definition: CryptTs.c:375