]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/VariableAuthenticated/RuntimeDxe/AuthService.c
1. Correct the counter-based hash algorithm according to UEFI spec.
[mirror_edk2.git] / SecurityPkg / VariableAuthenticated / RuntimeDxe / AuthService.c
1 /** @file
2 Implement authentication services for the authenticated variable
3 service in UEFI2.2.
4
5 Caution: This module requires additional review when modified.
6 This driver will have external input - variable data. It may be input in SMM mode.
7 This external input must be validated carefully to avoid security issue like
8 buffer overflow, integer overflow.
9 Variable attribute should also be checked to avoid authentication bypass.
10
11 ProcessVarWithPk(), ProcessVarWithKek() and ProcessVariable() are the function to do
12 variable authentication.
13
14 VerifyTimeBasedPayload() and VerifyCounterBasedPayload() are sub function to do verification.
15 They will do basic validation for authentication data structure, then call crypto library
16 to verify the signature.
17
18 Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>
19 This program and the accompanying materials
20 are licensed and made available under the terms and conditions of the BSD License
21 which accompanies this distribution. The full text of the license may be found at
22 http://opensource.org/licenses/bsd-license.php
23
24 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
25 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
26
27 **/
28
29 #include "Variable.h"
30 #include "AuthService.h"
31
32 ///
33 /// Global database array for scratch
34 ///
35 UINT8 mPubKeyStore[MAX_KEYDB_SIZE];
36 UINT32 mPubKeyNumber;
37 UINT8 mCertDbStore[MAX_CERTDB_SIZE];
38 UINT32 mPlatformMode;
39 EFI_GUID mSignatureSupport[] = {EFI_CERT_SHA1_GUID, EFI_CERT_SHA256_GUID, EFI_CERT_RSA2048_GUID, EFI_CERT_X509_GUID};
40 //
41 // Public Exponent of RSA Key.
42 //
43 CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };
44 //
45 // Hash context pointer
46 //
47 VOID *mHashCtx = NULL;
48
49 //
50 // Pointer to runtime buffer.
51 // For "Append" operation to an existing variable, a read/modify/write operation
52 // is supported by firmware internally. Reserve runtime buffer to cache previous
53 // variable data in runtime phase because memory allocation is forbidden in virtual mode.
54 //
55 VOID *mStorageArea = NULL;
56
57 //
58 // The serialization of the values of the VariableName, VendorGuid and Attributes
59 // parameters of the SetVariable() call and the TimeStamp component of the
60 // EFI_VARIABLE_AUTHENTICATION_2 descriptor followed by the variable's new value
61 // i.e. (VariableName, VendorGuid, Attributes, TimeStamp, Data)
62 //
63 UINT8 *mSerializationRuntimeBuffer = NULL;
64
65 //
66 // Requirement for different signature type which have been defined in UEFI spec.
67 // These data are used to peform SignatureList format check while setting PK/KEK variable.
68 //
69 EFI_SIGNATURE_ITEM mSupportSigItem[] = {
70 //{SigType, SigHeaderSize, SigDataSize }
71 {EFI_CERT_SHA256_GUID, 0, 32 },
72 {EFI_CERT_RSA2048_GUID, 0, 256 },
73 {EFI_CERT_RSA2048_SHA256_GUID, 0, 256 },
74 {EFI_CERT_SHA1_GUID, 0, 20 },
75 {EFI_CERT_RSA2048_SHA1_GUID, 0, 256 },
76 {EFI_CERT_X509_GUID, 0, ((UINT32) ~0)},
77 {EFI_CERT_SHA224_GUID, 0, 28 },
78 {EFI_CERT_SHA384_GUID, 0, 48 },
79 {EFI_CERT_SHA512_GUID, 0, 64 }
80 };
81
82 /**
83 Determine whether this operation needs a physical present user.
84
85 @param[in] VariableName Name of the Variable.
86 @param[in] VendorGuid GUID of the Variable.
87
88 @retval TRUE This variable is protected, only a physical present user could set this variable.
89 @retval FALSE This variable is not protected.
90
91 **/
92 BOOLEAN
93 NeedPhysicallyPresent(
94 IN CHAR16 *VariableName,
95 IN EFI_GUID *VendorGuid
96 )
97 {
98 if ((CompareGuid (VendorGuid, &gEfiSecureBootEnableDisableGuid) && (StrCmp (VariableName, EFI_SECURE_BOOT_ENABLE_NAME) == 0))
99 || (CompareGuid (VendorGuid, &gEfiCustomModeEnableGuid) && (StrCmp (VariableName, EFI_CUSTOM_MODE_NAME) == 0))) {
100 return TRUE;
101 }
102
103 return FALSE;
104 }
105
106 /**
107 Determine whether the platform is operating in Custom Secure Boot mode.
108
109 @retval TRUE The platform is operating in Custom mode.
110 @retval FALSE The platform is operating in Standard mode.
111
112 **/
113 BOOLEAN
114 InCustomMode (
115 VOID
116 )
117 {
118 VARIABLE_POINTER_TRACK Variable;
119
120 FindVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
121 if (Variable.CurrPtr != NULL && *(GetVariableDataPtr (Variable.CurrPtr)) == CUSTOM_SECURE_BOOT_MODE) {
122 return TRUE;
123 }
124
125 return FALSE;
126 }
127
128
129 /**
130 Internal function to delete a Variable given its name and GUID, no authentication
131 required.
132
133 @param[in] VariableName Name of the Variable.
134 @param[in] VendorGuid GUID of the Variable.
135
136 @retval EFI_SUCCESS Variable deleted successfully.
137 @retval Others The driver failded to start the device.
138
139 **/
140 EFI_STATUS
141 DeleteVariable (
142 IN CHAR16 *VariableName,
143 IN EFI_GUID *VendorGuid
144 )
145 {
146 EFI_STATUS Status;
147 VARIABLE_POINTER_TRACK Variable;
148
149 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
150 if (EFI_ERROR (Status)) {
151 return EFI_SUCCESS;
152 }
153
154 ASSERT (Variable.CurrPtr != NULL);
155 return UpdateVariable (VariableName, VendorGuid, NULL, 0, 0, 0, 0, &Variable, NULL);
156 }
157
158 /**
159 Initializes for authenticated varibale service.
160
161 @retval EFI_SUCCESS Function successfully executed.
162 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resources.
163
164 **/
165 EFI_STATUS
166 AutenticatedVariableServiceInitialize (
167 VOID
168 )
169 {
170 EFI_STATUS Status;
171 VARIABLE_POINTER_TRACK Variable;
172 VARIABLE_POINTER_TRACK PkVariable;
173 UINT8 VarValue;
174 UINT32 VarAttr;
175 UINT8 *Data;
176 UINTN DataSize;
177 UINTN CtxSize;
178 UINT8 SecureBootMode;
179 UINT8 SecureBootEnable;
180 UINT8 CustomMode;
181 UINT32 ListSize;
182
183 //
184 // Initialize hash context.
185 //
186 CtxSize = Sha256GetContextSize ();
187 mHashCtx = AllocateRuntimePool (CtxSize);
188 if (mHashCtx == NULL) {
189 return EFI_OUT_OF_RESOURCES;
190 }
191
192 //
193 // Reserved runtime buffer for "Append" operation in virtual mode.
194 //
195 mStorageArea = AllocateRuntimePool (PcdGet32 (PcdMaxVariableSize));
196 if (mStorageArea == NULL) {
197 return EFI_OUT_OF_RESOURCES;
198 }
199
200 //
201 // Prepare runtime buffer for serialized data of time-based authenticated
202 // Variable, i.e. (VariableName, VendorGuid, Attributes, TimeStamp, Data).
203 //
204 mSerializationRuntimeBuffer = AllocateRuntimePool (PcdGet32 (PcdMaxVariableSize) + sizeof (EFI_GUID) + sizeof (UINT32) + sizeof (EFI_TIME));
205 if (mSerializationRuntimeBuffer == NULL) {
206 return EFI_OUT_OF_RESOURCES;
207 }
208
209 //
210 // Check "AuthVarKeyDatabase" variable's existence.
211 // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
212 //
213 Status = FindVariable (
214 AUTHVAR_KEYDB_NAME,
215 &gEfiAuthenticatedVariableGuid,
216 &Variable,
217 &mVariableModuleGlobal->VariableGlobal,
218 FALSE
219 );
220
221 if (Variable.CurrPtr == NULL) {
222 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
223 VarValue = 0;
224 mPubKeyNumber = 0;
225 Status = UpdateVariable (
226 AUTHVAR_KEYDB_NAME,
227 &gEfiAuthenticatedVariableGuid,
228 &VarValue,
229 sizeof(UINT8),
230 VarAttr,
231 0,
232 0,
233 &Variable,
234 NULL
235 );
236 if (EFI_ERROR (Status)) {
237 return Status;
238 }
239 } else {
240 //
241 // Load database in global variable for cache.
242 //
243 DataSize = DataSizeOfVariable (Variable.CurrPtr);
244 Data = GetVariableDataPtr (Variable.CurrPtr);
245 ASSERT ((DataSize != 0) && (Data != NULL));
246 CopyMem (mPubKeyStore, (UINT8 *) Data, DataSize);
247 mPubKeyNumber = (UINT32) (DataSize / EFI_CERT_TYPE_RSA2048_SIZE);
248 }
249
250 FindVariable (EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid, &PkVariable, &mVariableModuleGlobal->VariableGlobal, FALSE);
251 if (PkVariable.CurrPtr == NULL) {
252 DEBUG ((EFI_D_INFO, "Variable %s does not exist.\n", EFI_PLATFORM_KEY_NAME));
253 } else {
254 DEBUG ((EFI_D_INFO, "Variable %s exists.\n", EFI_PLATFORM_KEY_NAME));
255 }
256
257 //
258 // Create "SetupMode" varable with BS+RT attribute set.
259 //
260 FindVariable (EFI_SETUP_MODE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
261 if (PkVariable.CurrPtr == NULL) {
262 mPlatformMode = SETUP_MODE;
263 } else {
264 mPlatformMode = USER_MODE;
265 }
266 Status = UpdateVariable (
267 EFI_SETUP_MODE_NAME,
268 &gEfiGlobalVariableGuid,
269 &mPlatformMode,
270 sizeof(UINT8),
271 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
272 0,
273 0,
274 &Variable,
275 NULL
276 );
277 if (EFI_ERROR (Status)) {
278 return Status;
279 }
280
281 //
282 // Create "SignatureSupport" varable with BS+RT attribute set.
283 //
284 FindVariable (EFI_SIGNATURE_SUPPORT_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
285 Status = UpdateVariable (
286 EFI_SIGNATURE_SUPPORT_NAME,
287 &gEfiGlobalVariableGuid,
288 mSignatureSupport,
289 sizeof(mSignatureSupport),
290 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
291 0,
292 0,
293 &Variable,
294 NULL
295 );
296 if (EFI_ERROR (Status)) {
297 return Status;
298 }
299
300 //
301 // If "SecureBootEnable" variable exists, then update "SecureBoot" variable.
302 // If "SecureBootEnable" variable is SECURE_BOOT_ENABLE and in USER_MODE, Set "SecureBoot" variable to SECURE_BOOT_MODE_ENABLE.
303 // If "SecureBootEnable" variable is SECURE_BOOT_DISABLE, Set "SecureBoot" variable to SECURE_BOOT_MODE_DISABLE.
304 //
305 SecureBootEnable = SECURE_BOOT_DISABLE;
306 FindVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
307 if (Variable.CurrPtr != NULL) {
308 SecureBootEnable = *(GetVariableDataPtr (Variable.CurrPtr));
309 } else if (mPlatformMode == USER_MODE) {
310 //
311 // "SecureBootEnable" not exist, initialize it in USER_MODE.
312 //
313 SecureBootEnable = SECURE_BOOT_ENABLE;
314 Status = UpdateVariable (
315 EFI_SECURE_BOOT_ENABLE_NAME,
316 &gEfiSecureBootEnableDisableGuid,
317 &SecureBootEnable,
318 sizeof (UINT8),
319 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
320 0,
321 0,
322 &Variable,
323 NULL
324 );
325 if (EFI_ERROR (Status)) {
326 return Status;
327 }
328 }
329
330 //
331 // Create "SecureBoot" varable with BS+RT attribute set.
332 //
333 if (SecureBootEnable == SECURE_BOOT_ENABLE && mPlatformMode == USER_MODE) {
334 SecureBootMode = SECURE_BOOT_MODE_ENABLE;
335 } else {
336 SecureBootMode = SECURE_BOOT_MODE_DISABLE;
337 }
338 FindVariable (EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
339 Status = UpdateVariable (
340 EFI_SECURE_BOOT_MODE_NAME,
341 &gEfiGlobalVariableGuid,
342 &SecureBootMode,
343 sizeof (UINT8),
344 EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
345 0,
346 0,
347 &Variable,
348 NULL
349 );
350 if (EFI_ERROR (Status)) {
351 return Status;
352 }
353
354 DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SETUP_MODE_NAME, mPlatformMode));
355 DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_MODE_NAME, SecureBootMode));
356 DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_ENABLE_NAME, SecureBootEnable));
357
358 //
359 // Check "CustomMode" variable's existence.
360 //
361 FindVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
362 if (Variable.CurrPtr != NULL) {
363 CustomMode = *(GetVariableDataPtr (Variable.CurrPtr));
364 } else {
365 //
366 // "CustomMode" not exist, initialize it in STANDARD_SECURE_BOOT_MODE.
367 //
368 CustomMode = STANDARD_SECURE_BOOT_MODE;
369 Status = UpdateVariable (
370 EFI_CUSTOM_MODE_NAME,
371 &gEfiCustomModeEnableGuid,
372 &CustomMode,
373 sizeof (UINT8),
374 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
375 0,
376 0,
377 &Variable,
378 NULL
379 );
380 if (EFI_ERROR (Status)) {
381 return Status;
382 }
383 }
384
385 DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_CUSTOM_MODE_NAME, CustomMode));
386
387 //
388 // Check "certdb" variable's existence.
389 // If it doesn't exist, then create a new one with
390 // EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set.
391 //
392 Status = FindVariable (
393 EFI_CERT_DB_NAME,
394 &gEfiCertDbGuid,
395 &Variable,
396 &mVariableModuleGlobal->VariableGlobal,
397 FALSE
398 );
399
400 if (Variable.CurrPtr == NULL) {
401 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
402 ListSize = sizeof (UINT32);
403 Status = UpdateVariable (
404 EFI_CERT_DB_NAME,
405 &gEfiCertDbGuid,
406 &ListSize,
407 sizeof (UINT32),
408 VarAttr,
409 0,
410 0,
411 &Variable,
412 NULL
413 );
414 if (EFI_ERROR (Status)) {
415 return Status;
416 }
417 }
418
419 return Status;
420 }
421
422 /**
423 Add public key in store and return its index.
424
425 @param[in] PubKey Input pointer to Public Key data
426
427 @return Index of new added item
428
429 **/
430 UINT32
431 AddPubKeyInStore (
432 IN UINT8 *PubKey
433 )
434 {
435 EFI_STATUS Status;
436 BOOLEAN IsFound;
437 UINT32 Index;
438 VARIABLE_POINTER_TRACK Variable;
439 UINT8 *Ptr;
440
441 if (PubKey == NULL) {
442 return 0;
443 }
444
445 Status = FindVariable (
446 AUTHVAR_KEYDB_NAME,
447 &gEfiAuthenticatedVariableGuid,
448 &Variable,
449 &mVariableModuleGlobal->VariableGlobal,
450 FALSE
451 );
452 ASSERT_EFI_ERROR (Status);
453 //
454 // Check whether the public key entry does exist.
455 //
456 IsFound = FALSE;
457 for (Ptr = mPubKeyStore, Index = 1; Index <= mPubKeyNumber; Index++) {
458 if (CompareMem (Ptr, PubKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {
459 IsFound = TRUE;
460 break;
461 }
462 Ptr += EFI_CERT_TYPE_RSA2048_SIZE;
463 }
464
465 if (!IsFound) {
466 //
467 // Add public key in database.
468 //
469 if (mPubKeyNumber == MAX_KEY_NUM) {
470 //
471 // Notes: Database is full, need enhancement here, currently just return 0.
472 //
473 return 0;
474 }
475
476 CopyMem (mPubKeyStore + mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);
477 Index = ++mPubKeyNumber;
478 //
479 // Update public key database variable.
480 //
481 Status = UpdateVariable (
482 AUTHVAR_KEYDB_NAME,
483 &gEfiAuthenticatedVariableGuid,
484 mPubKeyStore,
485 mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE,
486 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS,
487 0,
488 0,
489 &Variable,
490 NULL
491 );
492 ASSERT_EFI_ERROR (Status);
493 }
494
495 return Index;
496 }
497
498 /**
499 Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256_GUID type.
500 Follow the steps in UEFI2.2.
501
502 Caution: This function may receive untrusted input.
503 This function may be invoked in SMM mode, and datasize and data are external input.
504 This function will do basic validation, before parse the data.
505 This function will parse the authentication carefully to avoid security issues, like
506 buffer overflow, integer overflow.
507
508 @param[in] Data Pointer to data with AuthInfo.
509 @param[in] DataSize Size of Data.
510 @param[in] PubKey Public key used for verification.
511
512 @retval EFI_INVALID_PARAMETER Invalid parameter.
513 @retval EFI_SECURITY_VIOLATION If authentication failed.
514 @retval EFI_SUCCESS Authentication successful.
515
516 **/
517 EFI_STATUS
518 VerifyCounterBasedPayload (
519 IN UINT8 *Data,
520 IN UINTN DataSize,
521 IN UINT8 *PubKey
522 )
523 {
524 BOOLEAN Status;
525 EFI_VARIABLE_AUTHENTICATION *CertData;
526 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;
527 UINT8 Digest[SHA256_DIGEST_SIZE];
528 VOID *Rsa;
529 UINTN PayloadSize;
530
531 PayloadSize = DataSize - AUTHINFO_SIZE;
532 Rsa = NULL;
533 CertData = NULL;
534 CertBlock = NULL;
535
536 if (Data == NULL || PubKey == NULL) {
537 return EFI_INVALID_PARAMETER;
538 }
539
540 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;
541 CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
542
543 //
544 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
545 // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256_GUID.
546 //
547 if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||
548 !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertTypeRsa2048Sha256Guid)
549 ) {
550 //
551 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
552 //
553 return EFI_SECURITY_VIOLATION;
554 }
555 //
556 // Hash data payload with SHA256.
557 //
558 ZeroMem (Digest, SHA256_DIGEST_SIZE);
559 Status = Sha256Init (mHashCtx);
560 if (!Status) {
561 goto Done;
562 }
563 Status = Sha256Update (mHashCtx, Data + AUTHINFO_SIZE, PayloadSize);
564 if (!Status) {
565 goto Done;
566 }
567 //
568 // Hash Size.
569 //
570 Status = Sha256Update (mHashCtx, &PayloadSize, sizeof (UINTN));
571 if (!Status) {
572 goto Done;
573 }
574 //
575 // Hash Monotonic Count.
576 //
577 Status = Sha256Update (mHashCtx, &CertData->MonotonicCount, sizeof (UINT64));
578 if (!Status) {
579 goto Done;
580 }
581 Status = Sha256Final (mHashCtx, Digest);
582 if (!Status) {
583 goto Done;
584 }
585 //
586 // Generate & Initialize RSA Context.
587 //
588 Rsa = RsaNew ();
589 ASSERT (Rsa != NULL);
590 //
591 // Set RSA Key Components.
592 // NOTE: Only N and E are needed to be set as RSA public key for signature verification.
593 //
594 Status = RsaSetKey (Rsa, RsaKeyN, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);
595 if (!Status) {
596 goto Done;
597 }
598 Status = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));
599 if (!Status) {
600 goto Done;
601 }
602 //
603 // Verify the signature.
604 //
605 Status = RsaPkcs1Verify (
606 Rsa,
607 Digest,
608 SHA256_DIGEST_SIZE,
609 CertBlock->Signature,
610 EFI_CERT_TYPE_RSA2048_SHA256_SIZE
611 );
612
613 Done:
614 if (Rsa != NULL) {
615 RsaFree (Rsa);
616 }
617 if (Status) {
618 return EFI_SUCCESS;
619 } else {
620 return EFI_SECURITY_VIOLATION;
621 }
622 }
623
624 /**
625 Update platform mode.
626
627 @param[in] Mode SETUP_MODE or USER_MODE.
628
629 @return EFI_INVALID_PARAMETER Invalid parameter.
630 @return EFI_SUCCESS Update platform mode successfully.
631
632 **/
633 EFI_STATUS
634 UpdatePlatformMode (
635 IN UINT32 Mode
636 )
637 {
638 EFI_STATUS Status;
639 VARIABLE_POINTER_TRACK Variable;
640 UINT32 VarAttr;
641 UINT8 SecureBootMode;
642 UINT8 SecureBootEnable;
643 UINTN VariableDataSize;
644
645 Status = FindVariable (
646 EFI_SETUP_MODE_NAME,
647 &gEfiGlobalVariableGuid,
648 &Variable,
649 &mVariableModuleGlobal->VariableGlobal,
650 FALSE
651 );
652 if (EFI_ERROR (Status)) {
653 return Status;
654 }
655
656 //
657 // Update the value of SetupMode variable by a simple mem copy, this could avoid possible
658 // variable storage reclaim at runtime.
659 //
660 mPlatformMode = (UINT8) Mode;
661 CopyMem (GetVariableDataPtr (Variable.CurrPtr), &mPlatformMode, sizeof(UINT8));
662
663 if (AtRuntime ()) {
664 //
665 // SecureBoot Variable indicates whether the platform firmware is operating
666 // in Secure boot mode (1) or not (0), so we should not change SecureBoot
667 // Variable in runtime.
668 //
669 return Status;
670 }
671
672 //
673 // Check "SecureBoot" variable's existence.
674 // If it doesn't exist, firmware has no capability to perform driver signing verification,
675 // then set "SecureBoot" to 0.
676 //
677 Status = FindVariable (
678 EFI_SECURE_BOOT_MODE_NAME,
679 &gEfiGlobalVariableGuid,
680 &Variable,
681 &mVariableModuleGlobal->VariableGlobal,
682 FALSE
683 );
684 //
685 // If "SecureBoot" variable exists, then check "SetupMode" variable update.
686 // If "SetupMode" variable is USER_MODE, "SecureBoot" variable is set to 1.
687 // If "SetupMode" variable is SETUP_MODE, "SecureBoot" variable is set to 0.
688 //
689 if (Variable.CurrPtr == NULL) {
690 SecureBootMode = SECURE_BOOT_MODE_DISABLE;
691 } else {
692 if (mPlatformMode == USER_MODE) {
693 SecureBootMode = SECURE_BOOT_MODE_ENABLE;
694 } else if (mPlatformMode == SETUP_MODE) {
695 SecureBootMode = SECURE_BOOT_MODE_DISABLE;
696 } else {
697 return EFI_NOT_FOUND;
698 }
699 }
700
701 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
702 Status = UpdateVariable (
703 EFI_SECURE_BOOT_MODE_NAME,
704 &gEfiGlobalVariableGuid,
705 &SecureBootMode,
706 sizeof(UINT8),
707 VarAttr,
708 0,
709 0,
710 &Variable,
711 NULL
712 );
713 if (EFI_ERROR (Status)) {
714 return Status;
715 }
716
717 //
718 // Check "SecureBootEnable" variable's existence. It can enable/disable secure boot feature.
719 //
720 Status = FindVariable (
721 EFI_SECURE_BOOT_ENABLE_NAME,
722 &gEfiSecureBootEnableDisableGuid,
723 &Variable,
724 &mVariableModuleGlobal->VariableGlobal,
725 FALSE
726 );
727
728 if (SecureBootMode == SECURE_BOOT_MODE_ENABLE) {
729 //
730 // Create the "SecureBootEnable" variable as secure boot is enabled.
731 //
732 SecureBootEnable = SECURE_BOOT_ENABLE;
733 VariableDataSize = sizeof (SecureBootEnable);
734 } else {
735 //
736 // Delete the "SecureBootEnable" variable if this variable exist as "SecureBoot"
737 // variable is not in secure boot state.
738 //
739 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
740 return EFI_SUCCESS;
741 }
742 SecureBootEnable = SECURE_BOOT_DISABLE;
743 VariableDataSize = 0;
744 }
745
746 Status = UpdateVariable (
747 EFI_SECURE_BOOT_ENABLE_NAME,
748 &gEfiSecureBootEnableDisableGuid,
749 &SecureBootEnable,
750 VariableDataSize,
751 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
752 0,
753 0,
754 &Variable,
755 NULL
756 );
757 return Status;
758 }
759
760 /**
761 Check input data form to make sure it is a valid EFI_SIGNATURE_LIST for PK/KEK/db/dbx variable.
762
763 @param[in] VariableName Name of Variable to be check.
764 @param[in] VendorGuid Variable vendor GUID.
765 @param[in] Data Point to the variable data to be checked.
766 @param[in] DataSize Size of Data.
767
768 @return EFI_INVALID_PARAMETER Invalid signature list format.
769 @return EFI_SUCCESS Passed signature list format check successfully.
770
771 **/
772 EFI_STATUS
773 CheckSignatureListFormat(
774 IN CHAR16 *VariableName,
775 IN EFI_GUID *VendorGuid,
776 IN VOID *Data,
777 IN UINTN DataSize
778 )
779 {
780 EFI_SIGNATURE_LIST *SigList;
781 UINTN SigDataSize;
782 UINT32 Index;
783 UINT32 SigCount;
784 BOOLEAN IsPk;
785 VOID *RsaContext;
786 EFI_SIGNATURE_DATA *CertData;
787 UINTN CertLen;
788
789 if (DataSize == 0) {
790 return EFI_SUCCESS;
791 }
792
793 ASSERT (VariableName != NULL && VendorGuid != NULL && Data != NULL);
794
795 if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0)){
796 IsPk = TRUE;
797 } else if ((CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0) ||
798 (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&
799 (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0 || StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0))){
800 IsPk = FALSE;
801 } else {
802 return EFI_SUCCESS;
803 }
804
805 SigCount = 0;
806 SigList = (EFI_SIGNATURE_LIST *) Data;
807 SigDataSize = DataSize;
808 RsaContext = NULL;
809
810 //
811 // Walk throuth the input signature list and check the data format.
812 // If any signature is incorrectly formed, the whole check will fail.
813 //
814 while ((SigDataSize > 0) && (SigDataSize >= SigList->SignatureListSize)) {
815 for (Index = 0; Index < (sizeof (mSupportSigItem) / sizeof (EFI_SIGNATURE_ITEM)); Index++ ) {
816 if (CompareGuid (&SigList->SignatureType, &mSupportSigItem[Index].SigType)) {
817 //
818 // The value of SignatureSize should always be 16 (size of SignatureOwner
819 // component) add the data length according to signature type.
820 //
821 if (mSupportSigItem[Index].SigDataSize != ((UINT32) ~0) &&
822 (SigList->SignatureSize - sizeof (EFI_GUID)) != mSupportSigItem[Index].SigDataSize) {
823 return EFI_INVALID_PARAMETER;
824 }
825 if (mSupportSigItem[Index].SigHeaderSize != ((UINTN) ~0) &&
826 SigList->SignatureHeaderSize != mSupportSigItem[Index].SigHeaderSize) {
827 return EFI_INVALID_PARAMETER;
828 }
829 break;
830 }
831 }
832
833 if (Index == (sizeof (mSupportSigItem) / sizeof (EFI_SIGNATURE_ITEM))) {
834 //
835 // Undefined signature type.
836 //
837 return EFI_INVALID_PARAMETER;
838 }
839
840 if (CompareGuid (&SigList->SignatureType, &gEfiCertX509Guid)) {
841 //
842 // Try to retrieve the RSA public key from the X.509 certificate.
843 // If this operation fails, it's not a valid certificate.
844 //
845 RsaContext = RsaNew ();
846 if (RsaContext == NULL) {
847 return EFI_INVALID_PARAMETER;
848 }
849 CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) + SigList->SignatureHeaderSize);
850 CertLen = SigList->SignatureSize - sizeof (EFI_GUID);
851 if (!RsaGetPublicKeyFromX509 (CertData->SignatureData, CertLen, &RsaContext)) {
852 RsaFree (RsaContext);
853 return EFI_INVALID_PARAMETER;
854 }
855 RsaFree (RsaContext);
856 }
857
858 if ((SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) % SigList->SignatureSize != 0) {
859 return EFI_INVALID_PARAMETER;
860 }
861 SigCount += (SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) / SigList->SignatureSize;
862
863 SigDataSize -= SigList->SignatureListSize;
864 SigList = (EFI_SIGNATURE_LIST *) ((UINT8 *) SigList + SigList->SignatureListSize);
865 }
866
867 if (((UINTN) SigList - (UINTN) Data) != DataSize) {
868 return EFI_INVALID_PARAMETER;
869 }
870
871 if (IsPk && SigCount > 1) {
872 return EFI_INVALID_PARAMETER;
873 }
874
875 return EFI_SUCCESS;
876 }
877
878 /**
879 Process variable with platform key for verification.
880
881 Caution: This function may receive untrusted input.
882 This function may be invoked in SMM mode, and datasize and data are external input.
883 This function will do basic validation, before parse the data.
884 This function will parse the authentication carefully to avoid security issues, like
885 buffer overflow, integer overflow.
886 This function will check attribute carefully to avoid authentication bypass.
887
888 @param[in] VariableName Name of Variable to be found.
889 @param[in] VendorGuid Variable vendor GUID.
890 @param[in] Data Data pointer.
891 @param[in] DataSize Size of Data found. If size is less than the
892 data, this value contains the required size.
893 @param[in] Variable The variable information which is used to keep track of variable usage.
894 @param[in] Attributes Attribute value of the variable
895 @param[in] IsPk Indicate whether it is to process pk.
896
897 @return EFI_INVALID_PARAMETER Invalid parameter.
898 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation.
899 check carried out by the firmware.
900 @return EFI_SUCCESS Variable passed validation successfully.
901
902 **/
903 EFI_STATUS
904 ProcessVarWithPk (
905 IN CHAR16 *VariableName,
906 IN EFI_GUID *VendorGuid,
907 IN VOID *Data,
908 IN UINTN DataSize,
909 IN VARIABLE_POINTER_TRACK *Variable,
910 IN UINT32 Attributes OPTIONAL,
911 IN BOOLEAN IsPk
912 )
913 {
914 EFI_STATUS Status;
915 BOOLEAN Del;
916 UINT8 *Payload;
917 UINTN PayloadSize;
918
919 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0 ||
920 (Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) {
921 //
922 // PK, KEK and db/dbx should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based
923 // authenticated variable.
924 //
925 return EFI_INVALID_PARAMETER;
926 }
927
928 Del = FALSE;
929 if ((InCustomMode() && UserPhysicalPresent()) || (mPlatformMode == SETUP_MODE && !IsPk)) {
930 Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);
931 PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
932 if (PayloadSize == 0) {
933 Del = TRUE;
934 }
935
936 Status = CheckSignatureListFormat(VariableName, VendorGuid, Payload, PayloadSize);
937 if (EFI_ERROR (Status)) {
938 return Status;
939 }
940
941 Status = UpdateVariable (
942 VariableName,
943 VendorGuid,
944 Payload,
945 PayloadSize,
946 Attributes,
947 0,
948 0,
949 Variable,
950 &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp
951 );
952 } else if (mPlatformMode == USER_MODE) {
953 //
954 // Verify against X509 Cert in PK database.
955 //
956 Status = VerifyTimeBasedPayload (
957 VariableName,
958 VendorGuid,
959 Data,
960 DataSize,
961 Variable,
962 Attributes,
963 AuthVarTypePk,
964 &Del
965 );
966 } else {
967 //
968 // Verify against the certificate in data payload.
969 //
970 Status = VerifyTimeBasedPayload (
971 VariableName,
972 VendorGuid,
973 Data,
974 DataSize,
975 Variable,
976 Attributes,
977 AuthVarTypePayload,
978 &Del
979 );
980 }
981
982 if (!EFI_ERROR(Status) && IsPk) {
983 if (mPlatformMode == SETUP_MODE && !Del) {
984 //
985 // If enroll PK in setup mode, need change to user mode.
986 //
987 Status = UpdatePlatformMode (USER_MODE);
988 } else if (mPlatformMode == USER_MODE && Del){
989 //
990 // If delete PK in user mode, need change to setup mode.
991 //
992 Status = UpdatePlatformMode (SETUP_MODE);
993 }
994 }
995
996 return Status;
997 }
998
999 /**
1000 Process variable with key exchange key for verification.
1001
1002 Caution: This function may receive untrusted input.
1003 This function may be invoked in SMM mode, and datasize and data are external input.
1004 This function will do basic validation, before parse the data.
1005 This function will parse the authentication carefully to avoid security issues, like
1006 buffer overflow, integer overflow.
1007 This function will check attribute carefully to avoid authentication bypass.
1008
1009 @param[in] VariableName Name of Variable to be found.
1010 @param[in] VendorGuid Variable vendor GUID.
1011 @param[in] Data Data pointer.
1012 @param[in] DataSize Size of Data found. If size is less than the
1013 data, this value contains the required size.
1014 @param[in] Variable The variable information which is used to keep track of variable usage.
1015 @param[in] Attributes Attribute value of the variable.
1016
1017 @return EFI_INVALID_PARAMETER Invalid parameter.
1018 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation
1019 check carried out by the firmware.
1020 @return EFI_SUCCESS Variable pass validation successfully.
1021
1022 **/
1023 EFI_STATUS
1024 ProcessVarWithKek (
1025 IN CHAR16 *VariableName,
1026 IN EFI_GUID *VendorGuid,
1027 IN VOID *Data,
1028 IN UINTN DataSize,
1029 IN VARIABLE_POINTER_TRACK *Variable,
1030 IN UINT32 Attributes OPTIONAL
1031 )
1032 {
1033 EFI_STATUS Status;
1034 UINT8 *Payload;
1035 UINTN PayloadSize;
1036
1037 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0 ||
1038 (Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) {
1039 //
1040 // DB and DBX should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based
1041 // authenticated variable.
1042 //
1043 return EFI_INVALID_PARAMETER;
1044 }
1045
1046 Status = EFI_SUCCESS;
1047 if (mPlatformMode == USER_MODE && !(InCustomMode() && UserPhysicalPresent())) {
1048 //
1049 // Time-based, verify against X509 Cert KEK.
1050 //
1051 return VerifyTimeBasedPayload (
1052 VariableName,
1053 VendorGuid,
1054 Data,
1055 DataSize,
1056 Variable,
1057 Attributes,
1058 AuthVarTypeKek,
1059 NULL
1060 );
1061 } else {
1062 //
1063 // If in setup mode or custom secure boot mode, no authentication needed.
1064 //
1065 Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);
1066 PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
1067
1068 Status = CheckSignatureListFormat(VariableName, VendorGuid, Payload, PayloadSize);
1069 if (EFI_ERROR (Status)) {
1070 return Status;
1071 }
1072
1073 Status = UpdateVariable (
1074 VariableName,
1075 VendorGuid,
1076 Payload,
1077 PayloadSize,
1078 Attributes,
1079 0,
1080 0,
1081 Variable,
1082 &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp
1083 );
1084 }
1085
1086 return Status;
1087 }
1088
1089 /**
1090 Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
1091
1092 Caution: This function may receive untrusted input.
1093 This function may be invoked in SMM mode, and datasize and data are external input.
1094 This function will do basic validation, before parse the data.
1095 This function will parse the authentication carefully to avoid security issues, like
1096 buffer overflow, integer overflow.
1097 This function will check attribute carefully to avoid authentication bypass.
1098
1099 @param[in] VariableName Name of Variable to be found.
1100 @param[in] VendorGuid Variable vendor GUID.
1101
1102 @param[in] Data Data pointer.
1103 @param[in] DataSize Size of Data found. If size is less than the
1104 data, this value contains the required size.
1105 @param[in] Variable The variable information which is used to keep track of variable usage.
1106 @param[in] Attributes Attribute value of the variable.
1107
1108 @return EFI_INVALID_PARAMETER Invalid parameter.
1109 @return EFI_WRITE_PROTECTED Variable is write-protected and needs authentication with
1110 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
1111 @return EFI_OUT_OF_RESOURCES The Database to save the public key is full.
1112 @return EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
1113 set, but the AuthInfo does NOT pass the validation
1114 check carried out by the firmware.
1115 @return EFI_SUCCESS Variable is not write-protected or pass validation successfully.
1116
1117 **/
1118 EFI_STATUS
1119 ProcessVariable (
1120 IN CHAR16 *VariableName,
1121 IN EFI_GUID *VendorGuid,
1122 IN VOID *Data,
1123 IN UINTN DataSize,
1124 IN VARIABLE_POINTER_TRACK *Variable,
1125 IN UINT32 Attributes
1126 )
1127 {
1128 EFI_STATUS Status;
1129 BOOLEAN IsDeletion;
1130 BOOLEAN IsFirstTime;
1131 UINT8 *PubKey;
1132 EFI_VARIABLE_AUTHENTICATION *CertData;
1133 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;
1134 UINT32 KeyIndex;
1135 UINT64 MonotonicCount;
1136
1137 KeyIndex = 0;
1138 CertData = NULL;
1139 CertBlock = NULL;
1140 PubKey = NULL;
1141 IsDeletion = FALSE;
1142
1143 if (NeedPhysicallyPresent(VariableName, VendorGuid) && !UserPhysicalPresent()) {
1144 //
1145 // This variable is protected, only physical present user could modify its value.
1146 //
1147 return EFI_SECURITY_VIOLATION;
1148 }
1149
1150 //
1151 // A time-based authenticated variable and a count-based authenticated variable
1152 // can't be updated by each other.
1153 //
1154 if (Variable->CurrPtr != NULL) {
1155 if (((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) &&
1156 ((Variable->CurrPtr->Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0)) {
1157 return EFI_SECURITY_VIOLATION;
1158 }
1159
1160 if (((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) &&
1161 ((Variable->CurrPtr->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0)) {
1162 return EFI_SECURITY_VIOLATION;
1163 }
1164 }
1165
1166 //
1167 // Process Time-based Authenticated variable.
1168 //
1169 if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
1170 return VerifyTimeBasedPayload (
1171 VariableName,
1172 VendorGuid,
1173 Data,
1174 DataSize,
1175 Variable,
1176 Attributes,
1177 AuthVarTypePriv,
1178 NULL
1179 );
1180 }
1181
1182 //
1183 // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.
1184 //
1185 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
1186 //
1187 // Determine current operation type.
1188 //
1189 if (DataSize == AUTHINFO_SIZE) {
1190 IsDeletion = TRUE;
1191 }
1192 //
1193 // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
1194 //
1195 if (Variable->CurrPtr == NULL) {
1196 IsFirstTime = TRUE;
1197 } else if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {
1198 IsFirstTime = TRUE;
1199 } else {
1200 KeyIndex = Variable->CurrPtr->PubKeyIndex;
1201 IsFirstTime = FALSE;
1202 }
1203 } else if ((Variable->CurrPtr != NULL) &&
1204 ((Variable->CurrPtr->Attributes & (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) != 0)
1205 ) {
1206 //
1207 // If the variable is already write-protected, it always needs authentication before update.
1208 //
1209 return EFI_WRITE_PROTECTED;
1210 } else {
1211 //
1212 // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision.
1213 // That means it is not authenticated variable, just update variable as usual.
1214 //
1215 Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, Variable, NULL);
1216 return Status;
1217 }
1218
1219 //
1220 // Get PubKey and check Monotonic Count value corresponding to the variable.
1221 //
1222 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;
1223 CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
1224 PubKey = CertBlock->PublicKey;
1225
1226 //
1227 // Update Monotonic Count value.
1228 //
1229 MonotonicCount = CertData->MonotonicCount;
1230
1231 if (!IsFirstTime) {
1232 //
1233 // Check input PubKey.
1234 //
1235 if (CompareMem (PubKey, mPubKeyStore + (KeyIndex - 1) * EFI_CERT_TYPE_RSA2048_SIZE, EFI_CERT_TYPE_RSA2048_SIZE) != 0) {
1236 return EFI_SECURITY_VIOLATION;
1237 }
1238 //
1239 // Compare the current monotonic count and ensure that it is greater than the last SetVariable
1240 // operation with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute set.
1241 //
1242 if (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount) {
1243 //
1244 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
1245 //
1246 return EFI_SECURITY_VIOLATION;
1247 }
1248 }
1249 //
1250 // Verify the certificate in Data payload.
1251 //
1252 Status = VerifyCounterBasedPayload (Data, DataSize, PubKey);
1253 if (EFI_ERROR (Status)) {
1254 return Status;
1255 }
1256
1257 //
1258 // Now, the signature has been verified!
1259 //
1260 if (IsFirstTime && !IsDeletion) {
1261 //
1262 // Update public key database variable if need.
1263 //
1264 KeyIndex = AddPubKeyInStore (PubKey);
1265 if (KeyIndex == 0) {
1266 return EFI_OUT_OF_RESOURCES;
1267 }
1268 }
1269
1270 //
1271 // Verification pass.
1272 //
1273 return UpdateVariable (VariableName, VendorGuid, (UINT8*)Data + AUTHINFO_SIZE, DataSize - AUTHINFO_SIZE, Attributes, KeyIndex, MonotonicCount, Variable, NULL);
1274 }
1275
1276 /**
1277 Merge two buffers which formatted as EFI_SIGNATURE_LIST. Only the new EFI_SIGNATURE_DATA
1278 will be appended to the original EFI_SIGNATURE_LIST, duplicate EFI_SIGNATURE_DATA
1279 will be ignored.
1280
1281 @param[in, out] Data Pointer to original EFI_SIGNATURE_LIST.
1282 @param[in] DataSize Size of Data buffer.
1283 @param[in] NewData Pointer to new EFI_SIGNATURE_LIST to be appended.
1284 @param[in] NewDataSize Size of NewData buffer.
1285
1286 @return Size of the merged buffer.
1287
1288 **/
1289 UINTN
1290 AppendSignatureList (
1291 IN OUT VOID *Data,
1292 IN UINTN DataSize,
1293 IN VOID *NewData,
1294 IN UINTN NewDataSize
1295 )
1296 {
1297 EFI_SIGNATURE_LIST *CertList;
1298 EFI_SIGNATURE_DATA *Cert;
1299 UINTN CertCount;
1300 EFI_SIGNATURE_LIST *NewCertList;
1301 EFI_SIGNATURE_DATA *NewCert;
1302 UINTN NewCertCount;
1303 UINTN Index;
1304 UINTN Index2;
1305 UINTN Size;
1306 UINT8 *Tail;
1307 UINTN CopiedCount;
1308 UINTN SignatureListSize;
1309 BOOLEAN IsNewCert;
1310
1311 Tail = (UINT8 *) Data + DataSize;
1312
1313 NewCertList = (EFI_SIGNATURE_LIST *) NewData;
1314 while ((NewDataSize > 0) && (NewDataSize >= NewCertList->SignatureListSize)) {
1315 NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCertList + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);
1316 NewCertCount = (NewCertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - NewCertList->SignatureHeaderSize) / NewCertList->SignatureSize;
1317
1318 CopiedCount = 0;
1319 for (Index = 0; Index < NewCertCount; Index++) {
1320 IsNewCert = TRUE;
1321
1322 Size = DataSize;
1323 CertList = (EFI_SIGNATURE_LIST *) Data;
1324 while ((Size > 0) && (Size >= CertList->SignatureListSize)) {
1325 if (CompareGuid (&CertList->SignatureType, &NewCertList->SignatureType) &&
1326 (CertList->SignatureSize == NewCertList->SignatureSize)) {
1327 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
1328 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
1329 for (Index2 = 0; Index2 < CertCount; Index2++) {
1330 //
1331 // Iterate each Signature Data in this Signature List.
1332 //
1333 if (CompareMem (NewCert, Cert, CertList->SignatureSize) == 0) {
1334 IsNewCert = FALSE;
1335 break;
1336 }
1337 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
1338 }
1339 }
1340
1341 if (!IsNewCert) {
1342 break;
1343 }
1344 Size -= CertList->SignatureListSize;
1345 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
1346 }
1347
1348 if (IsNewCert) {
1349 //
1350 // New EFI_SIGNATURE_DATA, append it.
1351 //
1352 if (CopiedCount == 0) {
1353 //
1354 // Copy EFI_SIGNATURE_LIST header for only once.
1355 //
1356 CopyMem (Tail, NewCertList, sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);
1357 Tail = Tail + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize;
1358 }
1359
1360 CopyMem (Tail, NewCert, NewCertList->SignatureSize);
1361 Tail += NewCertList->SignatureSize;
1362 CopiedCount++;
1363 }
1364
1365 NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCert + NewCertList->SignatureSize);
1366 }
1367
1368 //
1369 // Update SignatureListSize in newly appended EFI_SIGNATURE_LIST.
1370 //
1371 if (CopiedCount != 0) {
1372 SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize + (CopiedCount * NewCertList->SignatureSize);
1373 CertList = (EFI_SIGNATURE_LIST *) (Tail - SignatureListSize);
1374 CertList->SignatureListSize = (UINT32) SignatureListSize;
1375 }
1376
1377 NewDataSize -= NewCertList->SignatureListSize;
1378 NewCertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) NewCertList + NewCertList->SignatureListSize);
1379 }
1380
1381 return (Tail - (UINT8 *) Data);
1382 }
1383
1384 /**
1385 Compare two EFI_TIME data.
1386
1387
1388 @param FirstTime A pointer to the first EFI_TIME data.
1389 @param SecondTime A pointer to the second EFI_TIME data.
1390
1391 @retval TRUE The FirstTime is not later than the SecondTime.
1392 @retval FALSE The FirstTime is later than the SecondTime.
1393
1394 **/
1395 BOOLEAN
1396 CompareTimeStamp (
1397 IN EFI_TIME *FirstTime,
1398 IN EFI_TIME *SecondTime
1399 )
1400 {
1401 if (FirstTime->Year != SecondTime->Year) {
1402 return (BOOLEAN) (FirstTime->Year < SecondTime->Year);
1403 } else if (FirstTime->Month != SecondTime->Month) {
1404 return (BOOLEAN) (FirstTime->Month < SecondTime->Month);
1405 } else if (FirstTime->Day != SecondTime->Day) {
1406 return (BOOLEAN) (FirstTime->Day < SecondTime->Day);
1407 } else if (FirstTime->Hour != SecondTime->Hour) {
1408 return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour);
1409 } else if (FirstTime->Minute != SecondTime->Minute) {
1410 return (BOOLEAN) (FirstTime->Minute < SecondTime->Minute);
1411 }
1412
1413 return (BOOLEAN) (FirstTime->Second <= SecondTime->Second);
1414 }
1415
1416 /**
1417 Find matching signer's certificates for common authenticated variable
1418 by corresponding VariableName and VendorGuid from "certdb".
1419
1420 The data format of "certdb":
1421 //
1422 // UINT32 CertDbListSize;
1423 // /// AUTH_CERT_DB_DATA Certs1[];
1424 // /// AUTH_CERT_DB_DATA Certs2[];
1425 // /// ...
1426 // /// AUTH_CERT_DB_DATA Certsn[];
1427 //
1428
1429 @param[in] VariableName Name of authenticated Variable.
1430 @param[in] VendorGuid Vendor GUID of authenticated Variable.
1431 @param[in] Data Pointer to variable "certdb".
1432 @param[in] DataSize Size of variable "certdb".
1433 @param[out] CertOffset Offset of matching CertData, from starting of Data.
1434 @param[out] CertDataSize Length of CertData in bytes.
1435 @param[out] CertNodeOffset Offset of matching AUTH_CERT_DB_DATA , from
1436 starting of Data.
1437 @param[out] CertNodeSize Length of AUTH_CERT_DB_DATA in bytes.
1438
1439 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
1440 @retval EFI_NOT_FOUND Fail to find matching certs.
1441 @retval EFI_SUCCESS Find matching certs and output parameters.
1442
1443 **/
1444 EFI_STATUS
1445 FindCertsFromDb (
1446 IN CHAR16 *VariableName,
1447 IN EFI_GUID *VendorGuid,
1448 IN UINT8 *Data,
1449 IN UINTN DataSize,
1450 OUT UINT32 *CertOffset, OPTIONAL
1451 OUT UINT32 *CertDataSize, OPTIONAL
1452 OUT UINT32 *CertNodeOffset,OPTIONAL
1453 OUT UINT32 *CertNodeSize OPTIONAL
1454 )
1455 {
1456 UINT32 Offset;
1457 AUTH_CERT_DB_DATA *Ptr;
1458 UINT32 CertSize;
1459 UINT32 NameSize;
1460 UINT32 NodeSize;
1461 UINT32 CertDbListSize;
1462
1463 if ((VariableName == NULL) || (VendorGuid == NULL) || (Data == NULL)) {
1464 return EFI_INVALID_PARAMETER;
1465 }
1466
1467 //
1468 // Check whether DataSize matches recorded CertDbListSize.
1469 //
1470 if (DataSize < sizeof (UINT32)) {
1471 return EFI_INVALID_PARAMETER;
1472 }
1473
1474 CertDbListSize = ReadUnaligned32 ((UINT32 *) Data);
1475
1476 if (CertDbListSize != (UINT32) DataSize) {
1477 return EFI_INVALID_PARAMETER;
1478 }
1479
1480 Offset = sizeof (UINT32);
1481
1482 //
1483 // Get corresponding certificates by VendorGuid and VariableName.
1484 //
1485 while (Offset < (UINT32) DataSize) {
1486 Ptr = (AUTH_CERT_DB_DATA *) (Data + Offset);
1487 //
1488 // Check whether VendorGuid matches.
1489 //
1490 if (CompareGuid (&Ptr->VendorGuid, VendorGuid)) {
1491 NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);
1492 NameSize = ReadUnaligned32 (&Ptr->NameSize);
1493 CertSize = ReadUnaligned32 (&Ptr->CertDataSize);
1494
1495 if (NodeSize != sizeof (EFI_GUID) + sizeof (UINT32) * 3 + CertSize +
1496 sizeof (CHAR16) * NameSize) {
1497 return EFI_INVALID_PARAMETER;
1498 }
1499
1500 Offset = Offset + sizeof (EFI_GUID) + sizeof (UINT32) * 3;
1501 //
1502 // Check whether VariableName matches.
1503 //
1504 if ((NameSize == StrLen (VariableName)) &&
1505 (CompareMem (Data + Offset, VariableName, NameSize * sizeof (CHAR16)) == 0)) {
1506 Offset = Offset + NameSize * sizeof (CHAR16);
1507
1508 if (CertOffset != NULL) {
1509 *CertOffset = Offset;
1510 }
1511
1512 if (CertDataSize != NULL) {
1513 *CertDataSize = CertSize;
1514 }
1515
1516 if (CertNodeOffset != NULL) {
1517 *CertNodeOffset = (UINT32) ((UINT8 *) Ptr - Data);
1518 }
1519
1520 if (CertNodeSize != NULL) {
1521 *CertNodeSize = NodeSize;
1522 }
1523
1524 return EFI_SUCCESS;
1525 } else {
1526 Offset = Offset + NameSize * sizeof (CHAR16) + CertSize;
1527 }
1528 } else {
1529 NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);
1530 Offset = Offset + NodeSize;
1531 }
1532 }
1533
1534 return EFI_NOT_FOUND;
1535 }
1536
1537 /**
1538 Retrieve signer's certificates for common authenticated variable
1539 by corresponding VariableName and VendorGuid from "certdb".
1540
1541 @param[in] VariableName Name of authenticated Variable.
1542 @param[in] VendorGuid Vendor GUID of authenticated Variable.
1543 @param[out] CertData Pointer to signer's certificates.
1544 @param[out] CertDataSize Length of CertData in bytes.
1545
1546 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
1547 @retval EFI_NOT_FOUND Fail to find "certdb" or matching certs.
1548 @retval EFI_SUCCESS Get signer's certificates successfully.
1549
1550 **/
1551 EFI_STATUS
1552 GetCertsFromDb (
1553 IN CHAR16 *VariableName,
1554 IN EFI_GUID *VendorGuid,
1555 OUT UINT8 **CertData,
1556 OUT UINT32 *CertDataSize
1557 )
1558 {
1559 VARIABLE_POINTER_TRACK CertDbVariable;
1560 EFI_STATUS Status;
1561 UINT8 *Data;
1562 UINTN DataSize;
1563 UINT32 CertOffset;
1564
1565 if ((VariableName == NULL) || (VendorGuid == NULL) || (CertData == NULL) || (CertDataSize == NULL)) {
1566 return EFI_INVALID_PARAMETER;
1567 }
1568
1569 //
1570 // Get variable "certdb".
1571 //
1572 Status = FindVariable (
1573 EFI_CERT_DB_NAME,
1574 &gEfiCertDbGuid,
1575 &CertDbVariable,
1576 &mVariableModuleGlobal->VariableGlobal,
1577 FALSE
1578 );
1579 if (EFI_ERROR (Status)) {
1580 return Status;
1581 }
1582
1583 DataSize = DataSizeOfVariable (CertDbVariable.CurrPtr);
1584 Data = GetVariableDataPtr (CertDbVariable.CurrPtr);
1585 if ((DataSize == 0) || (Data == NULL)) {
1586 ASSERT (FALSE);
1587 return EFI_NOT_FOUND;
1588 }
1589
1590 Status = FindCertsFromDb (
1591 VariableName,
1592 VendorGuid,
1593 Data,
1594 DataSize,
1595 &CertOffset,
1596 CertDataSize,
1597 NULL,
1598 NULL
1599 );
1600
1601 if (EFI_ERROR (Status)) {
1602 return Status;
1603 }
1604
1605 *CertData = Data + CertOffset;
1606 return EFI_SUCCESS;
1607 }
1608
1609 /**
1610 Delete matching signer's certificates when deleting common authenticated
1611 variable by corresponding VariableName and VendorGuid from "certdb".
1612
1613 @param[in] VariableName Name of authenticated Variable.
1614 @param[in] VendorGuid Vendor GUID of authenticated Variable.
1615
1616 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
1617 @retval EFI_NOT_FOUND Fail to find "certdb" or matching certs.
1618 @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.
1619 @retval EFI_SUCCESS The operation is completed successfully.
1620
1621 **/
1622 EFI_STATUS
1623 DeleteCertsFromDb (
1624 IN CHAR16 *VariableName,
1625 IN EFI_GUID *VendorGuid
1626 )
1627 {
1628 VARIABLE_POINTER_TRACK CertDbVariable;
1629 EFI_STATUS Status;
1630 UINT8 *Data;
1631 UINTN DataSize;
1632 UINT32 VarAttr;
1633 UINT32 CertNodeOffset;
1634 UINT32 CertNodeSize;
1635 UINT8 *NewCertDb;
1636 UINT32 NewCertDbSize;
1637
1638 if ((VariableName == NULL) || (VendorGuid == NULL)) {
1639 return EFI_INVALID_PARAMETER;
1640 }
1641
1642 //
1643 // Get variable "certdb".
1644 //
1645 Status = FindVariable (
1646 EFI_CERT_DB_NAME,
1647 &gEfiCertDbGuid,
1648 &CertDbVariable,
1649 &mVariableModuleGlobal->VariableGlobal,
1650 FALSE
1651 );
1652 if (EFI_ERROR (Status)) {
1653 return Status;
1654 }
1655
1656 DataSize = DataSizeOfVariable (CertDbVariable.CurrPtr);
1657 Data = GetVariableDataPtr (CertDbVariable.CurrPtr);
1658 if ((DataSize == 0) || (Data == NULL)) {
1659 ASSERT (FALSE);
1660 return EFI_NOT_FOUND;
1661 }
1662
1663 if (DataSize == sizeof (UINT32)) {
1664 //
1665 // There is no certs in certdb.
1666 //
1667 return EFI_SUCCESS;
1668 }
1669
1670 //
1671 // Get corresponding cert node from certdb.
1672 //
1673 Status = FindCertsFromDb (
1674 VariableName,
1675 VendorGuid,
1676 Data,
1677 DataSize,
1678 NULL,
1679 NULL,
1680 &CertNodeOffset,
1681 &CertNodeSize
1682 );
1683
1684 if (EFI_ERROR (Status)) {
1685 return Status;
1686 }
1687
1688 if (DataSize < (CertNodeOffset + CertNodeSize)) {
1689 return EFI_NOT_FOUND;
1690 }
1691
1692 //
1693 // Construct new data content of variable "certdb".
1694 //
1695 NewCertDbSize = (UINT32) DataSize - CertNodeSize;
1696 NewCertDb = (UINT8*) mCertDbStore;
1697
1698 //
1699 // Copy the DB entries before deleting node.
1700 //
1701 CopyMem (NewCertDb, Data, CertNodeOffset);
1702 //
1703 // Update CertDbListSize.
1704 //
1705 CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32));
1706 //
1707 // Copy the DB entries after deleting node.
1708 //
1709 if (DataSize > (CertNodeOffset + CertNodeSize)) {
1710 CopyMem (
1711 NewCertDb + CertNodeOffset,
1712 Data + CertNodeOffset + CertNodeSize,
1713 DataSize - CertNodeOffset - CertNodeSize
1714 );
1715 }
1716
1717 //
1718 // Set "certdb".
1719 //
1720 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
1721 Status = UpdateVariable (
1722 EFI_CERT_DB_NAME,
1723 &gEfiCertDbGuid,
1724 NewCertDb,
1725 NewCertDbSize,
1726 VarAttr,
1727 0,
1728 0,
1729 &CertDbVariable,
1730 NULL
1731 );
1732
1733 return Status;
1734 }
1735
1736 /**
1737 Insert signer's certificates for common authenticated variable with VariableName
1738 and VendorGuid in AUTH_CERT_DB_DATA to "certdb".
1739
1740 @param[in] VariableName Name of authenticated Variable.
1741 @param[in] VendorGuid Vendor GUID of authenticated Variable.
1742 @param[in] CertData Pointer to signer's certificates.
1743 @param[in] CertDataSize Length of CertData in bytes.
1744
1745 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
1746 @retval EFI_ACCESS_DENIED An AUTH_CERT_DB_DATA entry with same VariableName
1747 and VendorGuid already exists.
1748 @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.
1749 @retval EFI_SUCCESS Insert an AUTH_CERT_DB_DATA entry to "certdb"
1750
1751 **/
1752 EFI_STATUS
1753 InsertCertsToDb (
1754 IN CHAR16 *VariableName,
1755 IN EFI_GUID *VendorGuid,
1756 IN UINT8 *CertData,
1757 IN UINTN CertDataSize
1758 )
1759 {
1760 VARIABLE_POINTER_TRACK CertDbVariable;
1761 EFI_STATUS Status;
1762 UINT8 *Data;
1763 UINTN DataSize;
1764 UINT32 VarAttr;
1765 UINT8 *NewCertDb;
1766 UINT32 NewCertDbSize;
1767 UINT32 CertNodeSize;
1768 UINT32 NameSize;
1769 AUTH_CERT_DB_DATA *Ptr;
1770
1771 if ((VariableName == NULL) || (VendorGuid == NULL) || (CertData == NULL)) {
1772 return EFI_INVALID_PARAMETER;
1773 }
1774
1775 //
1776 // Get variable "certdb".
1777 //
1778 Status = FindVariable (
1779 EFI_CERT_DB_NAME,
1780 &gEfiCertDbGuid,
1781 &CertDbVariable,
1782 &mVariableModuleGlobal->VariableGlobal,
1783 FALSE
1784 );
1785 if (EFI_ERROR (Status)) {
1786 return Status;
1787 }
1788
1789 DataSize = DataSizeOfVariable (CertDbVariable.CurrPtr);
1790 Data = GetVariableDataPtr (CertDbVariable.CurrPtr);
1791 if ((DataSize == 0) || (Data == NULL)) {
1792 ASSERT (FALSE);
1793 return EFI_NOT_FOUND;
1794 }
1795
1796 //
1797 // Find whether matching cert node already exists in "certdb".
1798 // If yes return error.
1799 //
1800 Status = FindCertsFromDb (
1801 VariableName,
1802 VendorGuid,
1803 Data,
1804 DataSize,
1805 NULL,
1806 NULL,
1807 NULL,
1808 NULL
1809 );
1810
1811 if (!EFI_ERROR (Status)) {
1812 ASSERT (FALSE);
1813 return EFI_ACCESS_DENIED;
1814 }
1815
1816 //
1817 // Construct new data content of variable "certdb".
1818 //
1819 NameSize = (UINT32) StrLen (VariableName);
1820 CertNodeSize = sizeof (AUTH_CERT_DB_DATA) + (UINT32) CertDataSize + NameSize * sizeof (CHAR16);
1821 NewCertDbSize = (UINT32) DataSize + CertNodeSize;
1822 if (NewCertDbSize > MAX_CERTDB_SIZE) {
1823 return EFI_OUT_OF_RESOURCES;
1824 }
1825 NewCertDb = (UINT8*) mCertDbStore;
1826
1827 //
1828 // Copy the DB entries before deleting node.
1829 //
1830 CopyMem (NewCertDb, Data, DataSize);
1831 //
1832 // Update CertDbListSize.
1833 //
1834 CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32));
1835 //
1836 // Construct new cert node.
1837 //
1838 Ptr = (AUTH_CERT_DB_DATA *) (NewCertDb + DataSize);
1839 CopyGuid (&Ptr->VendorGuid, VendorGuid);
1840 CopyMem (&Ptr->CertNodeSize, &CertNodeSize, sizeof (UINT32));
1841 CopyMem (&Ptr->NameSize, &NameSize, sizeof (UINT32));
1842 CopyMem (&Ptr->CertDataSize, &CertDataSize, sizeof (UINT32));
1843
1844 CopyMem (
1845 (UINT8 *) Ptr + sizeof (AUTH_CERT_DB_DATA),
1846 VariableName,
1847 NameSize * sizeof (CHAR16)
1848 );
1849
1850 CopyMem (
1851 (UINT8 *) Ptr + sizeof (AUTH_CERT_DB_DATA) + NameSize * sizeof (CHAR16),
1852 CertData,
1853 CertDataSize
1854 );
1855
1856 //
1857 // Set "certdb".
1858 //
1859 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
1860 Status = UpdateVariable (
1861 EFI_CERT_DB_NAME,
1862 &gEfiCertDbGuid,
1863 NewCertDb,
1864 NewCertDbSize,
1865 VarAttr,
1866 0,
1867 0,
1868 &CertDbVariable,
1869 NULL
1870 );
1871
1872 return Status;
1873 }
1874
1875 /**
1876 Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
1877
1878 Caution: This function may receive untrusted input.
1879 This function may be invoked in SMM mode, and datasize and data are external input.
1880 This function will do basic validation, before parse the data.
1881 This function will parse the authentication carefully to avoid security issues, like
1882 buffer overflow, integer overflow.
1883
1884 @param[in] VariableName Name of Variable to be found.
1885 @param[in] VendorGuid Variable vendor GUID.
1886 @param[in] Data Data pointer.
1887 @param[in] DataSize Size of Data found. If size is less than the
1888 data, this value contains the required size.
1889 @param[in] Variable The variable information which is used to keep track of variable usage.
1890 @param[in] Attributes Attribute value of the variable.
1891 @param[in] AuthVarType Verify against PK, KEK database, private database or certificate in data payload.
1892 @param[out] VarDel Delete the variable or not.
1893
1894 @retval EFI_INVALID_PARAMETER Invalid parameter.
1895 @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation
1896 check carried out by the firmware.
1897 @retval EFI_OUT_OF_RESOURCES Failed to process variable due to lack
1898 of resources.
1899 @retval EFI_SUCCESS Variable pass validation successfully.
1900
1901 **/
1902 EFI_STATUS
1903 VerifyTimeBasedPayload (
1904 IN CHAR16 *VariableName,
1905 IN EFI_GUID *VendorGuid,
1906 IN VOID *Data,
1907 IN UINTN DataSize,
1908 IN VARIABLE_POINTER_TRACK *Variable,
1909 IN UINT32 Attributes,
1910 IN AUTHVAR_TYPE AuthVarType,
1911 OUT BOOLEAN *VarDel
1912 )
1913 {
1914 UINT8 *RootCert;
1915 UINT8 *SigData;
1916 UINT8 *PayloadPtr;
1917 UINTN RootCertSize;
1918 UINTN Index;
1919 UINTN CertCount;
1920 UINTN PayloadSize;
1921 UINT32 Attr;
1922 UINT32 SigDataSize;
1923 UINT32 KekDataSize;
1924 BOOLEAN VerifyStatus;
1925 EFI_STATUS Status;
1926 EFI_SIGNATURE_LIST *CertList;
1927 EFI_SIGNATURE_DATA *Cert;
1928 VARIABLE_POINTER_TRACK KekVariable;
1929 EFI_VARIABLE_AUTHENTICATION_2 *CertData;
1930 UINT8 *NewData;
1931 UINTN NewDataSize;
1932 VARIABLE_POINTER_TRACK PkVariable;
1933 UINT8 *Buffer;
1934 UINTN Length;
1935 UINT8 *SignerCerts;
1936 UINT8 *WrapSigData;
1937 UINTN CertStackSize;
1938 UINT8 *CertsInCertDb;
1939 UINT32 CertsSizeinDb;
1940
1941 VerifyStatus = FALSE;
1942 CertData = NULL;
1943 NewData = NULL;
1944 Attr = Attributes;
1945 WrapSigData = NULL;
1946 SignerCerts = NULL;
1947 RootCert = NULL;
1948
1949 //
1950 // When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is
1951 // set, then the Data buffer shall begin with an instance of a complete (and serialized)
1952 // EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new
1953 // variable value and DataSize shall reflect the combined size of the descriptor and the new
1954 // variable value. The authentication descriptor is not part of the variable data and is not
1955 // returned by subsequent calls to GetVariable().
1956 //
1957 CertData = (EFI_VARIABLE_AUTHENTICATION_2 *) Data;
1958
1959 //
1960 // Verify that Pad1, Nanosecond, TimeZone, Daylight and Pad2 components of the
1961 // TimeStamp value are set to zero.
1962 //
1963 if ((CertData->TimeStamp.Pad1 != 0) ||
1964 (CertData->TimeStamp.Nanosecond != 0) ||
1965 (CertData->TimeStamp.TimeZone != 0) ||
1966 (CertData->TimeStamp.Daylight != 0) ||
1967 (CertData->TimeStamp.Pad2 != 0)) {
1968 return EFI_SECURITY_VIOLATION;
1969 }
1970
1971 if ((Variable->CurrPtr != NULL) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {
1972 if (CompareTimeStamp (&CertData->TimeStamp, &Variable->CurrPtr->TimeStamp)) {
1973 //
1974 // TimeStamp check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
1975 //
1976 return EFI_SECURITY_VIOLATION;
1977 }
1978 }
1979
1980 //
1981 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
1982 // Cert type should be EFI_CERT_TYPE_PKCS7_GUID.
1983 //
1984 if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||
1985 !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertPkcs7Guid)) {
1986 //
1987 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
1988 //
1989 return EFI_SECURITY_VIOLATION;
1990 }
1991
1992 //
1993 // Find out Pkcs7 SignedData which follows the EFI_VARIABLE_AUTHENTICATION_2 descriptor.
1994 // AuthInfo.Hdr.dwLength is the length of the entire certificate, including the length of the header.
1995 //
1996 SigData = CertData->AuthInfo.CertData;
1997 SigDataSize = CertData->AuthInfo.Hdr.dwLength - (UINT32) (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData));
1998
1999 //
2000 // Find out the new data payload which follows Pkcs7 SignedData directly.
2001 //
2002 PayloadPtr = SigData + SigDataSize;
2003 PayloadSize = DataSize - OFFSET_OF_AUTHINFO2_CERT_DATA - (UINTN) SigDataSize;
2004
2005 //
2006 // Construct a buffer to fill with (VariableName, VendorGuid, Attributes, TimeStamp, Data).
2007 //
2008 NewDataSize = PayloadSize + sizeof (EFI_TIME) + sizeof (UINT32) +
2009 sizeof (EFI_GUID) + StrSize (VariableName) - sizeof (CHAR16);
2010 NewData = mSerializationRuntimeBuffer;
2011
2012 Buffer = NewData;
2013 Length = StrLen (VariableName) * sizeof (CHAR16);
2014 CopyMem (Buffer, VariableName, Length);
2015 Buffer += Length;
2016
2017 Length = sizeof (EFI_GUID);
2018 CopyMem (Buffer, VendorGuid, Length);
2019 Buffer += Length;
2020
2021 Length = sizeof (UINT32);
2022 CopyMem (Buffer, &Attr, Length);
2023 Buffer += Length;
2024
2025 Length = sizeof (EFI_TIME);
2026 CopyMem (Buffer, &CertData->TimeStamp, Length);
2027 Buffer += Length;
2028
2029 CopyMem (Buffer, PayloadPtr, PayloadSize);
2030
2031 if (AuthVarType == AuthVarTypePk) {
2032 //
2033 // Get platform key from variable.
2034 //
2035 Status = FindVariable (
2036 EFI_PLATFORM_KEY_NAME,
2037 &gEfiGlobalVariableGuid,
2038 &PkVariable,
2039 &mVariableModuleGlobal->VariableGlobal,
2040 FALSE
2041 );
2042 if (EFI_ERROR (Status)) {
2043 return Status;
2044 }
2045
2046 CertList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (PkVariable.CurrPtr);
2047 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
2048 RootCert = Cert->SignatureData;
2049 RootCertSize = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);
2050
2051
2052 //
2053 // Verify Pkcs7 SignedData via Pkcs7Verify library.
2054 //
2055 VerifyStatus = Pkcs7Verify (
2056 SigData,
2057 SigDataSize,
2058 RootCert,
2059 RootCertSize,
2060 NewData,
2061 NewDataSize
2062 );
2063
2064 } else if (AuthVarType == AuthVarTypeKek) {
2065
2066 //
2067 // Get KEK database from variable.
2068 //
2069 Status = FindVariable (
2070 EFI_KEY_EXCHANGE_KEY_NAME,
2071 &gEfiGlobalVariableGuid,
2072 &KekVariable,
2073 &mVariableModuleGlobal->VariableGlobal,
2074 FALSE
2075 );
2076 if (EFI_ERROR (Status)) {
2077 return Status;
2078 }
2079
2080 //
2081 // Ready to verify Pkcs7 SignedData. Go through KEK Signature Database to find out X.509 CertList.
2082 //
2083 KekDataSize = KekVariable.CurrPtr->DataSize;
2084 CertList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (KekVariable.CurrPtr);
2085 while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {
2086 if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
2087 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
2088 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
2089 for (Index = 0; Index < CertCount; Index++) {
2090 //
2091 // Iterate each Signature Data Node within this CertList for a verify
2092 //
2093 RootCert = Cert->SignatureData;
2094 RootCertSize = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);
2095
2096 //
2097 // Verify Pkcs7 SignedData via Pkcs7Verify library.
2098 //
2099 VerifyStatus = Pkcs7Verify (
2100 SigData,
2101 SigDataSize,
2102 RootCert,
2103 RootCertSize,
2104 NewData,
2105 NewDataSize
2106 );
2107 if (VerifyStatus) {
2108 goto Exit;
2109 }
2110 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
2111 }
2112 }
2113 KekDataSize -= CertList->SignatureListSize;
2114 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
2115 }
2116 } else if (AuthVarType == AuthVarTypePriv) {
2117
2118 //
2119 // Process common authenticated variable except PK/KEK/DB/DBX.
2120 // Get signer's certificates from SignedData.
2121 //
2122 VerifyStatus = Pkcs7GetSigners (
2123 SigData,
2124 SigDataSize,
2125 &SignerCerts,
2126 &CertStackSize,
2127 &RootCert,
2128 &RootCertSize
2129 );
2130 if (!VerifyStatus) {
2131 goto Exit;
2132 }
2133
2134 //
2135 // Get previously stored signer's certificates from certdb for existing
2136 // variable. Check whether they are identical with signer's certificates
2137 // in SignedData. If not, return error immediately.
2138 //
2139 if ((Variable->CurrPtr != NULL)) {
2140 VerifyStatus = FALSE;
2141
2142 Status = GetCertsFromDb (VariableName, VendorGuid, &CertsInCertDb, &CertsSizeinDb);
2143 if (EFI_ERROR (Status)) {
2144 goto Exit;
2145 }
2146
2147 if ((CertStackSize != CertsSizeinDb) ||
2148 (CompareMem (SignerCerts, CertsInCertDb, CertsSizeinDb) != 0)) {
2149 goto Exit;
2150 }
2151 }
2152
2153 VerifyStatus = Pkcs7Verify (
2154 SigData,
2155 SigDataSize,
2156 RootCert,
2157 RootCertSize,
2158 NewData,
2159 NewDataSize
2160 );
2161 if (!VerifyStatus) {
2162 goto Exit;
2163 }
2164
2165 //
2166 // Delete signer's certificates when delete the common authenticated variable.
2167 //
2168 if ((PayloadSize == 0) && (Variable->CurrPtr != NULL) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {
2169 Status = DeleteCertsFromDb (VariableName, VendorGuid);
2170 if (EFI_ERROR (Status)) {
2171 VerifyStatus = FALSE;
2172 goto Exit;
2173 }
2174 } else if (Variable->CurrPtr == NULL && PayloadSize != 0) {
2175 //
2176 // Insert signer's certificates when adding a new common authenticated variable.
2177 //
2178 Status = InsertCertsToDb (VariableName, VendorGuid, SignerCerts, CertStackSize);
2179 if (EFI_ERROR (Status)) {
2180 VerifyStatus = FALSE;
2181 goto Exit;
2182 }
2183 }
2184 } else if (AuthVarType == AuthVarTypePayload) {
2185 CertList = (EFI_SIGNATURE_LIST *) PayloadPtr;
2186 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
2187 RootCert = Cert->SignatureData;
2188 RootCertSize = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);
2189
2190 // Verify Pkcs7 SignedData via Pkcs7Verify library.
2191 //
2192 VerifyStatus = Pkcs7Verify (
2193 SigData,
2194 SigDataSize,
2195 RootCert,
2196 RootCertSize,
2197 NewData,
2198 NewDataSize
2199 );
2200 } else {
2201 return EFI_SECURITY_VIOLATION;
2202 }
2203
2204 Exit:
2205
2206 if (AuthVarType == AuthVarTypePriv) {
2207 Pkcs7FreeSigners (RootCert);
2208 Pkcs7FreeSigners (SignerCerts);
2209 }
2210
2211 if (!VerifyStatus) {
2212 return EFI_SECURITY_VIOLATION;
2213 }
2214
2215 Status = CheckSignatureListFormat(VariableName, VendorGuid, PayloadPtr, PayloadSize);
2216 if (EFI_ERROR (Status)) {
2217 return Status;
2218 }
2219
2220 if ((PayloadSize == 0) && (VarDel != NULL)) {
2221 *VarDel = TRUE;
2222 }
2223
2224 //
2225 // Final step: Update/Append Variable if it pass Pkcs7Verify
2226 //
2227 return UpdateVariable (
2228 VariableName,
2229 VendorGuid,
2230 PayloadPtr,
2231 PayloadSize,
2232 Attributes,
2233 0,
2234 0,
2235 Variable,
2236 &CertData->TimeStamp
2237 );
2238 }
2239