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