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