]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/VariableAuthenticated/RuntimeDxe/AuthService.c
Add security package to repository.
[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 Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "Variable.h"
17 #include "AuthService.h"
18
19 ///
20 /// Global database array for scratch
21 ///
22 UINT8 mPubKeyStore[MAX_KEYDB_SIZE];
23 UINT32 mPubKeyNumber;
24 UINT32 mPlatformMode;
25 EFI_GUID mSignatureSupport[SIGSUPPORT_NUM] = {EFI_CERT_RSA2048_SHA256_GUID, EFI_CERT_RSA2048_SHA1_GUID};
26 //
27 // Public Exponent of RSA Key.
28 //
29 CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };
30 //
31 // Hash context pointer
32 //
33 VOID *mHashCtx = NULL;
34
35
36 //
37 // Pointer to runtime buffer.
38 // For "Append" operation to an existing variable, a read/modify/write operation
39 // is supported by firmware internally. Reserve runtime buffer to cache previous
40 // variable data in runtime phase because memory allocation is forbidden in virtual mode.
41 //
42 VOID *mStorageArea = NULL;
43
44 /**
45 Update platform mode.
46
47 @param[in] Mode SETUP_MODE or USER_MODE.
48
49 @return EFI_INVALID_PARAMETER Invalid parameter.
50 @return EFI_SUCCESS Update platform mode successfully.
51
52 **/
53 EFI_STATUS
54 UpdatePlatformMode (
55 IN UINT32 Mode
56 );
57
58 /**
59 Initializes for authenticated varibale service.
60
61 @retval EFI_SUCCESS Function successfully executed.
62 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resources.
63
64 **/
65 EFI_STATUS
66 AutenticatedVariableServiceInitialize (
67 VOID
68 )
69 {
70 EFI_STATUS Status;
71 VARIABLE_POINTER_TRACK Variable;
72 UINT8 VarValue;
73 UINT32 VarAttr;
74 UINT8 *Data;
75 UINTN DataSize;
76 UINTN CtxSize;
77 //
78 // Initialize hash context.
79 //
80 CtxSize = Sha256GetContextSize ();
81 mHashCtx = AllocateRuntimePool (CtxSize);
82 if (mHashCtx == NULL) {
83 return EFI_OUT_OF_RESOURCES;
84 }
85
86 //
87 // Reserved runtime buffer for "Append" operation in virtual mode.
88 //
89 mStorageArea = AllocateRuntimePool (PcdGet32 (PcdMaxAppendVariableSize));
90 if (mStorageArea == NULL) {
91 return EFI_OUT_OF_RESOURCES;
92 }
93
94 //
95 // Check "AuthVarKeyDatabase" variable's existence.
96 // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
97 //
98 Status = FindVariable (
99 AUTHVAR_KEYDB_NAME,
100 &gEfiAuthenticatedVariableGuid,
101 &Variable,
102 &mVariableModuleGlobal->VariableGlobal
103 );
104
105 if (Variable.CurrPtr == NULL) {
106 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
107 VarValue = 0;
108 mPubKeyNumber = 0;
109 Status = UpdateVariable (
110 AUTHVAR_KEYDB_NAME,
111 &gEfiAuthenticatedVariableGuid,
112 &VarValue,
113 sizeof(UINT8),
114 VarAttr,
115 0,
116 0,
117 &Variable,
118 NULL
119 );
120 if (EFI_ERROR (Status)) {
121 return Status;
122 }
123 } else {
124 //
125 // Load database in global variable for cache.
126 //
127 DataSize = DataSizeOfVariable (Variable.CurrPtr);
128 Data = GetVariableDataPtr (Variable.CurrPtr);
129 ASSERT ((DataSize != 0) && (Data != NULL));
130 CopyMem (mPubKeyStore, (UINT8 *) Data, DataSize);
131 mPubKeyNumber = (UINT32) (DataSize / EFI_CERT_TYPE_RSA2048_SIZE);
132 }
133 //
134 // Check "SetupMode" variable's existence.
135 // If it doesn't exist, check PK database's existence to determine the value.
136 // Then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
137 //
138 Status = FindVariable (
139 EFI_SETUP_MODE_NAME,
140 &gEfiGlobalVariableGuid,
141 &Variable,
142 &mVariableModuleGlobal->VariableGlobal
143 );
144
145 if (Variable.CurrPtr == NULL) {
146 Status = FindVariable (
147 EFI_PLATFORM_KEY_NAME,
148 &gEfiGlobalVariableGuid,
149 &Variable,
150 &mVariableModuleGlobal->VariableGlobal
151 );
152 if (Variable.CurrPtr == NULL) {
153 mPlatformMode = SETUP_MODE;
154 } else {
155 mPlatformMode = USER_MODE;
156 }
157
158 VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
159 Status = UpdateVariable (
160 EFI_SETUP_MODE_NAME,
161 &gEfiGlobalVariableGuid,
162 &mPlatformMode,
163 sizeof(UINT8),
164 VarAttr,
165 0,
166 0,
167 &Variable,
168 NULL
169 );
170 if (EFI_ERROR (Status)) {
171 return Status;
172 }
173 } else {
174 mPlatformMode = *(GetVariableDataPtr (Variable.CurrPtr));
175 }
176 //
177 // Check "SignatureSupport" variable's existence.
178 // If it doesn't exist, then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
179 //
180 Status = FindVariable (
181 EFI_SIGNATURE_SUPPORT_NAME,
182 &gEfiGlobalVariableGuid,
183 &Variable,
184 &mVariableModuleGlobal->VariableGlobal
185 );
186
187 if (Variable.CurrPtr == NULL) {
188 VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
189 Status = UpdateVariable (
190 EFI_SIGNATURE_SUPPORT_NAME,
191 &gEfiGlobalVariableGuid,
192 mSignatureSupport,
193 SIGSUPPORT_NUM * sizeof(EFI_GUID),
194 VarAttr,
195 0,
196 0,
197 &Variable,
198 NULL
199 );
200 }
201
202 //
203 // Detect whether a secure platform-specific method to clear PK(Platform Key)
204 // is configured by platform owner. This method is provided for users force to clear PK
205 // in case incorrect enrollment mis-haps.
206 //
207 if (ForceClearPK ()) {
208 //
209 // 1. Check whether PK is existing, and clear PK if existing
210 //
211 FindVariable (
212 EFI_PLATFORM_KEY_NAME,
213 &gEfiGlobalVariableGuid,
214 &Variable,
215 &mVariableModuleGlobal->VariableGlobal
216 );
217 if (Variable.CurrPtr != NULL) {
218 VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
219 Status = UpdateVariable (
220 EFI_PLATFORM_KEY_NAME,
221 &gEfiGlobalVariableGuid,
222 NULL,
223 0,
224 VarAttr,
225 0,
226 0,
227 &Variable,
228 NULL
229 );
230 if (EFI_ERROR (Status)) {
231 return Status;
232 }
233 }
234
235 //
236 // 2. Update "SetupMode" variable to SETUP_MODE
237 //
238 UpdatePlatformMode (SETUP_MODE);
239 }
240 return Status;
241 }
242
243 /**
244 Add public key in store and return its index.
245
246 @param[in] PubKey Input pointer to Public Key data
247
248 @return Index of new added item
249
250 **/
251 UINT32
252 AddPubKeyInStore (
253 IN UINT8 *PubKey
254 )
255 {
256 EFI_STATUS Status;
257 BOOLEAN IsFound;
258 UINT32 Index;
259 VARIABLE_POINTER_TRACK Variable;
260 UINT8 *Ptr;
261
262 if (PubKey == NULL) {
263 return 0;
264 }
265
266 Status = FindVariable (
267 AUTHVAR_KEYDB_NAME,
268 &gEfiAuthenticatedVariableGuid,
269 &Variable,
270 &mVariableModuleGlobal->VariableGlobal
271 );
272 ASSERT_EFI_ERROR (Status);
273 //
274 // Check whether the public key entry does exist.
275 //
276 IsFound = FALSE;
277 for (Ptr = mPubKeyStore, Index = 1; Index <= mPubKeyNumber; Index++) {
278 if (CompareMem (Ptr, PubKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {
279 IsFound = TRUE;
280 break;
281 }
282 Ptr += EFI_CERT_TYPE_RSA2048_SIZE;
283 }
284
285 if (!IsFound) {
286 //
287 // Add public key in database.
288 //
289 if (mPubKeyNumber == MAX_KEY_NUM) {
290 //
291 // Notes: Database is full, need enhancement here, currently just return 0.
292 //
293 return 0;
294 }
295
296 CopyMem (mPubKeyStore + mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);
297 Index = ++mPubKeyNumber;
298 //
299 // Update public key database variable.
300 //
301 Status = UpdateVariable (
302 AUTHVAR_KEYDB_NAME,
303 &gEfiAuthenticatedVariableGuid,
304 mPubKeyStore,
305 mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE,
306 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS,
307 0,
308 0,
309 &Variable,
310 NULL
311 );
312 ASSERT_EFI_ERROR (Status);
313 }
314
315 return Index;
316 }
317
318 /**
319 Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256 type.
320 Follow the steps in UEFI2.2.
321
322 @param[in] Data Pointer to data with AuthInfo.
323 @param[in] DataSize Size of Data.
324 @param[in] PubKey Public key used for verification.
325
326 @return EFI_INVALID_PARAMETER Invalid parameter.
327 @retval EFI_SECURITY_VIOLATION If authentication failed.
328 @return EFI_SUCCESS Authentication successful.
329
330 **/
331 EFI_STATUS
332 VerifyCounterBasedPayload (
333 IN UINT8 *Data,
334 IN UINTN DataSize,
335 IN UINT8 *PubKey
336 )
337 {
338 BOOLEAN Status;
339 EFI_VARIABLE_AUTHENTICATION *CertData;
340 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;
341 UINT8 Digest[SHA256_DIGEST_SIZE];
342 VOID *Rsa;
343
344 Rsa = NULL;
345 CertData = NULL;
346 CertBlock = NULL;
347
348 if (Data == NULL || PubKey == NULL) {
349 return EFI_INVALID_PARAMETER;
350 }
351
352 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;
353 CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
354
355 //
356 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
357 // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256.
358 //
359 if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||
360 !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertRsa2048Sha256Guid)
361 ) {
362 //
363 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
364 //
365 return EFI_SECURITY_VIOLATION;
366 }
367 //
368 // Hash data payload with SHA256.
369 //
370 ZeroMem (Digest, SHA256_DIGEST_SIZE);
371 Status = Sha256Init (mHashCtx);
372 if (!Status) {
373 goto Done;
374 }
375 Status = Sha256Update (mHashCtx, Data + AUTHINFO_SIZE, (UINTN) (DataSize - AUTHINFO_SIZE));
376 if (!Status) {
377 goto Done;
378 }
379 //
380 // Hash Monotonic Count.
381 //
382 Status = Sha256Update (mHashCtx, &CertData->MonotonicCount, sizeof (UINT64));
383 if (!Status) {
384 goto Done;
385 }
386 Status = Sha256Final (mHashCtx, Digest);
387 if (!Status) {
388 goto Done;
389 }
390 //
391 // Generate & Initialize RSA Context.
392 //
393 Rsa = RsaNew ();
394 ASSERT (Rsa != NULL);
395 //
396 // Set RSA Key Components.
397 // NOTE: Only N and E are needed to be set as RSA public key for signature verification.
398 //
399 Status = RsaSetKey (Rsa, RsaKeyN, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);
400 if (!Status) {
401 goto Done;
402 }
403 Status = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));
404 if (!Status) {
405 goto Done;
406 }
407 //
408 // Verify the signature.
409 //
410 Status = RsaPkcs1Verify (
411 Rsa,
412 Digest,
413 SHA256_DIGEST_SIZE,
414 CertBlock->Signature,
415 EFI_CERT_TYPE_RSA2048_SHA256_SIZE
416 );
417
418 Done:
419 if (Rsa != NULL) {
420 RsaFree (Rsa);
421 }
422 if (Status) {
423 return EFI_SUCCESS;
424 } else {
425 return EFI_SECURITY_VIOLATION;
426 }
427 }
428
429
430 /**
431 Update platform mode.
432
433 @param[in] Mode SETUP_MODE or USER_MODE.
434
435 @return EFI_INVALID_PARAMETER Invalid parameter.
436 @return EFI_SUCCESS Update platform mode successfully.
437
438 **/
439 EFI_STATUS
440 UpdatePlatformMode (
441 IN UINT32 Mode
442 )
443 {
444 EFI_STATUS Status;
445 VARIABLE_POINTER_TRACK Variable;
446 UINT32 VarAttr;
447 UINT8 SecureBootMode;
448
449 Status = FindVariable (
450 EFI_SETUP_MODE_NAME,
451 &gEfiGlobalVariableGuid,
452 &Variable,
453 &mVariableModuleGlobal->VariableGlobal
454 );
455 if (EFI_ERROR (Status)) {
456 return Status;
457 }
458
459 mPlatformMode = Mode;
460 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
461 Status = UpdateVariable (
462 EFI_SETUP_MODE_NAME,
463 &gEfiGlobalVariableGuid,
464 &mPlatformMode,
465 sizeof(UINT8),
466 VarAttr,
467 0,
468 0,
469 &Variable,
470 NULL
471 );
472 if (EFI_ERROR (Status)) {
473 return Status;
474 }
475
476 //
477 // Check "SecureBoot" variable's existence.
478 // If it doesn't exist, firmware has no capability to perform driver signing verification,
479 // then set "SecureBoot" to 0.
480 //
481 Status = FindVariable (
482 EFI_SECURE_BOOT_MODE_NAME,
483 &gEfiGlobalVariableGuid,
484 &Variable,
485 &mVariableModuleGlobal->VariableGlobal
486 );
487 //
488 // If "SecureBoot" variable exists, then check "SetupMode" variable update.
489 // If "SetupMode" variable is USER_MODE, "SecureBoot" variable is set to 1.
490 // If "SetupMode" variable is SETUP_MODE, "SecureBoot" variable is set to 0.
491 //
492 if (Variable.CurrPtr == NULL) {
493 SecureBootMode = SECURE_BOOT_MODE_DISABLE;
494 } else {
495 if (mPlatformMode == USER_MODE) {
496 SecureBootMode = SECURE_BOOT_MODE_ENABLE;
497 } else if (mPlatformMode == SETUP_MODE) {
498 SecureBootMode = SECURE_BOOT_MODE_DISABLE;
499 } else {
500 return EFI_NOT_FOUND;
501 }
502 }
503
504 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
505 return UpdateVariable (
506 EFI_SECURE_BOOT_MODE_NAME,
507 &gEfiGlobalVariableGuid,
508 &SecureBootMode,
509 sizeof(UINT8),
510 VarAttr,
511 0,
512 0,
513 &Variable,
514 NULL
515 );
516 }
517
518 /**
519 Process variable with platform key for verification.
520
521 @param[in] VariableName Name of Variable to be found.
522 @param[in] VendorGuid Variable vendor GUID.
523 @param[in] Data Data pointer.
524 @param[in] DataSize Size of Data found. If size is less than the
525 data, this value contains the required size.
526 @param[in] Variable The variable information which is used to keep track of variable usage.
527 @param[in] Attributes Attribute value of the variable
528 @param[in] IsPk Indicate whether it is to process pk.
529
530 @return EFI_INVALID_PARAMETER Invalid parameter.
531 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation.
532 check carried out by the firmware.
533 @return EFI_SUCCESS Variable passed validation successfully.
534
535 **/
536 EFI_STATUS
537 ProcessVarWithPk (
538 IN CHAR16 *VariableName,
539 IN EFI_GUID *VendorGuid,
540 IN VOID *Data,
541 IN UINTN DataSize,
542 IN VARIABLE_POINTER_TRACK *Variable,
543 IN UINT32 Attributes OPTIONAL,
544 IN BOOLEAN IsPk
545 )
546 {
547 EFI_STATUS Status;
548 VARIABLE_POINTER_TRACK PkVariable;
549 EFI_SIGNATURE_LIST *OldPkList;
550 EFI_SIGNATURE_DATA *OldPkData;
551 EFI_VARIABLE_AUTHENTICATION *CertData;
552 BOOLEAN TimeBase;
553 BOOLEAN Del;
554
555 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
556 //
557 // PK and KEK should set EFI_VARIABLE_NON_VOLATILE attribute.
558 //
559 return EFI_INVALID_PARAMETER;
560 }
561
562 if (mPlatformMode == USER_MODE) {
563
564 if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
565 //
566 // EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute means time-based X509 Cert PK.
567 //
568 TimeBase = TRUE;
569 } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
570 //
571 // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute means counter-based RSA-2048 Cert PK.
572 //
573 TimeBase = FALSE;
574 } else {
575 return EFI_INVALID_PARAMETER;
576 }
577
578 if (TimeBase) {
579 //
580 // Verify against X509 Cert PK.
581 //
582 Del = FALSE;
583 Status = VerifyTimeBasedPayload (VariableName, VendorGuid, Data, DataSize, Variable, Attributes, TRUE, &Del);
584 if (!EFI_ERROR (Status)) {
585 //
586 // If delete PK in user mode, need change to setup mode.
587 //
588 if (Del && IsPk) {
589 Status = UpdatePlatformMode (SETUP_MODE);
590 }
591 }
592 return Status;
593 } else {
594 //
595 // Verify against RSA2048 Cert PK.
596 //
597 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;
598 if ((Variable->CurrPtr != NULL) && (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount)) {
599 //
600 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
601 //
602 return EFI_SECURITY_VIOLATION;
603 }
604 //
605 // Get platform key from variable.
606 //
607 Status = FindVariable (
608 EFI_PLATFORM_KEY_NAME,
609 &gEfiGlobalVariableGuid,
610 &PkVariable,
611 &mVariableModuleGlobal->VariableGlobal
612 );
613 ASSERT_EFI_ERROR (Status);
614
615 OldPkList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (PkVariable.CurrPtr);
616 OldPkData = (EFI_SIGNATURE_DATA *) ((UINT8 *) OldPkList + sizeof (EFI_SIGNATURE_LIST) + OldPkList->SignatureHeaderSize);
617 Status = VerifyCounterBasedPayload (Data, DataSize, OldPkData->SignatureData);
618 if (!EFI_ERROR (Status)) {
619 Status = UpdateVariable (
620 VariableName,
621 VendorGuid,
622 (UINT8*)Data + AUTHINFO_SIZE,
623 DataSize - AUTHINFO_SIZE,
624 Attributes,
625 0,
626 CertData->MonotonicCount,
627 Variable,
628 NULL
629 );
630
631 if (!EFI_ERROR (Status)) {
632 //
633 // If delete PK in user mode, need change to setup mode.
634 //
635 if ((DataSize == AUTHINFO_SIZE) && IsPk) {
636 Status = UpdatePlatformMode (SETUP_MODE);
637 }
638 }
639 }
640 }
641 } else {
642 Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, Variable, NULL);
643 //
644 // If enroll PK in setup mode, need change to user mode.
645 //
646 if ((DataSize != 0) && IsPk) {
647 Status = UpdatePlatformMode (USER_MODE);
648 }
649 }
650
651 return Status;
652 }
653
654 /**
655 Process variable with key exchange key for verification.
656
657 @param[in] VariableName Name of Variable to be found.
658 @param[in] VendorGuid Variable vendor GUID.
659 @param[in] Data Data pointer.
660 @param[in] DataSize Size of Data found. If size is less than the
661 data, this value contains the required size.
662 @param[in] Variable The variable information which is used to keep track of variable usage.
663 @param[in] Attributes Attribute value of the variable.
664
665 @return EFI_INVALID_PARAMETER Invalid parameter.
666 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation
667 check carried out by the firmware.
668 @return EFI_SUCCESS Variable pass validation successfully.
669
670 **/
671 EFI_STATUS
672 ProcessVarWithKek (
673 IN CHAR16 *VariableName,
674 IN EFI_GUID *VendorGuid,
675 IN VOID *Data,
676 IN UINTN DataSize,
677 IN VARIABLE_POINTER_TRACK *Variable,
678 IN UINT32 Attributes OPTIONAL
679 )
680 {
681 EFI_STATUS Status;
682 VARIABLE_POINTER_TRACK KekVariable;
683 EFI_SIGNATURE_LIST *KekList;
684 EFI_SIGNATURE_DATA *KekItem;
685 UINT32 KekCount;
686 EFI_VARIABLE_AUTHENTICATION *CertData;
687 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;
688 BOOLEAN IsFound;
689 UINT32 Index;
690 UINT32 KekDataSize;
691
692 if (mPlatformMode == USER_MODE) {
693 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {
694 //
695 // In user mode, should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute.
696 //
697 return EFI_INVALID_PARAMETER;
698 }
699
700 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;
701 CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
702 if ((Variable->CurrPtr != NULL) && (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount)) {
703 //
704 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
705 //
706 return EFI_SECURITY_VIOLATION;
707 }
708 //
709 // Get KEK database from variable.
710 //
711 Status = FindVariable (
712 EFI_KEY_EXCHANGE_KEY_NAME,
713 &gEfiGlobalVariableGuid,
714 &KekVariable,
715 &mVariableModuleGlobal->VariableGlobal
716 );
717 ASSERT_EFI_ERROR (Status);
718
719 KekDataSize = KekVariable.CurrPtr->DataSize;
720 KekList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (KekVariable.CurrPtr);
721
722 //
723 // Enumerate all Kek items in this list to verify the variable certificate data.
724 // If anyone is authenticated successfully, it means the variable is correct!
725 //
726 IsFound = FALSE;
727 while ((KekDataSize > 0) && (KekDataSize >= KekList->SignatureListSize)) {
728 if (CompareGuid (&KekList->SignatureType, &gEfiCertRsa2048Guid)) {
729 KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekList + sizeof (EFI_SIGNATURE_LIST) + KekList->SignatureHeaderSize);
730 KekCount = (KekList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - KekList->SignatureHeaderSize) / KekList->SignatureSize;
731 for (Index = 0; Index < KekCount; Index++) {
732 if (CompareMem (KekItem->SignatureData, CertBlock->PublicKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {
733 IsFound = TRUE;
734 break;
735 }
736 KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekItem + KekList->SignatureSize);
737 }
738 }
739 KekDataSize -= KekList->SignatureListSize;
740 KekList = (EFI_SIGNATURE_LIST *) ((UINT8 *) KekList + KekList->SignatureListSize);
741 }
742
743 if (!IsFound) {
744 return EFI_SECURITY_VIOLATION;
745 }
746
747 Status = VerifyCounterBasedPayload (Data, DataSize, CertBlock->PublicKey);
748 if (!EFI_ERROR (Status)) {
749 Status = UpdateVariable (
750 VariableName,
751 VendorGuid,
752 (UINT8*)Data + AUTHINFO_SIZE,
753 DataSize - AUTHINFO_SIZE,
754 Attributes,
755 0,
756 CertData->MonotonicCount,
757 Variable,
758 NULL
759 );
760 }
761 } else {
762 //
763 // If in setup mode, no authentication needed.
764 //
765 Status = UpdateVariable (
766 VariableName,
767 VendorGuid,
768 Data,
769 DataSize,
770 Attributes,
771 0,
772 0,
773 Variable,
774 NULL
775 );
776 }
777
778 return Status;
779 }
780
781 /**
782 Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
783
784 @param[in] VariableName Name of Variable to be found.
785 @param[in] VendorGuid Variable vendor GUID.
786
787 @param[in] Data Data pointer.
788 @param[in] DataSize Size of Data found. If size is less than the
789 data, this value contains the required size.
790 @param[in] Variable The variable information which is used to keep track of variable usage.
791 @param[in] Attributes Attribute value of the variable.
792
793 @return EFI_INVALID_PARAMETER Invalid parameter.
794 @return EFI_WRITE_PROTECTED Variable is write-protected and needs authentication with
795 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
796 @return EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
797 set, but the AuthInfo does NOT pass the validation
798 check carried out by the firmware.
799 @return EFI_SUCCESS Variable is not write-protected or pass validation successfully.
800
801 **/
802 EFI_STATUS
803 ProcessVariable (
804 IN CHAR16 *VariableName,
805 IN EFI_GUID *VendorGuid,
806 IN VOID *Data,
807 IN UINTN DataSize,
808 IN VARIABLE_POINTER_TRACK *Variable,
809 IN UINT32 Attributes
810 )
811 {
812 EFI_STATUS Status;
813 BOOLEAN IsDeletion;
814 BOOLEAN IsFirstTime;
815 UINT8 *PubKey;
816 EFI_VARIABLE_AUTHENTICATION *CertData;
817 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;
818 UINT32 KeyIndex;
819 UINT64 MonotonicCount;
820
821 KeyIndex = 0;
822 CertData = NULL;
823 CertBlock = NULL;
824 PubKey = NULL;
825 IsDeletion = FALSE;
826
827 //
828 // Process Time-based Authenticated variable.
829 //
830 if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
831 return VerifyTimeBasedPayload (VariableName, VendorGuid, Data, DataSize, Variable, Attributes, FALSE, NULL);
832 }
833
834 //
835 // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.
836 //
837 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
838 //
839 // Determine current operation type.
840 //
841 if (DataSize == AUTHINFO_SIZE) {
842 IsDeletion = TRUE;
843 }
844 //
845 // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
846 //
847 if (Variable->CurrPtr == NULL) {
848 IsFirstTime = TRUE;
849 } else if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {
850 IsFirstTime = TRUE;
851 } else {
852 KeyIndex = Variable->CurrPtr->PubKeyIndex;
853 IsFirstTime = FALSE;
854 }
855 } else if ((Variable->CurrPtr != NULL) &&
856 (Variable->CurrPtr->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0
857 ) {
858 //
859 // If the variable is already write-protected, it always needs authentication before update.
860 //
861 return EFI_WRITE_PROTECTED;
862 } else {
863 //
864 // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision.
865 // That means it is not authenticated variable, just update variable as usual.
866 //
867 Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, Variable, NULL);
868 return Status;
869 }
870
871 //
872 // Get PubKey and check Monotonic Count value corresponding to the variable.
873 //
874 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;
875 CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
876 PubKey = CertBlock->PublicKey;
877
878 //
879 // Update Monotonic Count value.
880 //
881 MonotonicCount = CertData->MonotonicCount;
882
883 if (!IsFirstTime) {
884 //
885 // Check input PubKey.
886 //
887 if (CompareMem (PubKey, mPubKeyStore + (KeyIndex - 1) * EFI_CERT_TYPE_RSA2048_SIZE, EFI_CERT_TYPE_RSA2048_SIZE) != 0) {
888 return EFI_SECURITY_VIOLATION;
889 }
890 //
891 // Compare the current monotonic count and ensure that it is greater than the last SetVariable
892 // operation with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute set.
893 //
894 if (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount) {
895 //
896 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
897 //
898 return EFI_SECURITY_VIOLATION;
899 }
900 }
901 //
902 // Verify the certificate in Data payload.
903 //
904 Status = VerifyCounterBasedPayload (Data, DataSize, PubKey);
905 if (EFI_ERROR (Status)) {
906 return Status;
907 }
908
909 //
910 // Now, the signature has been verified!
911 //
912 if (IsFirstTime && !IsDeletion) {
913 //
914 // Update public key database variable if need.
915 //
916 KeyIndex = AddPubKeyInStore (PubKey);
917 }
918
919 //
920 // Verification pass.
921 //
922 return UpdateVariable (VariableName, VendorGuid, (UINT8*)Data + AUTHINFO_SIZE, DataSize - AUTHINFO_SIZE, Attributes, KeyIndex, MonotonicCount, Variable, NULL);
923 }
924
925 /**
926 Compare two EFI_TIME data.
927
928
929 @param FirstTime A pointer to the first EFI_TIME data.
930 @param SecondTime A pointer to the second EFI_TIME data.
931
932 @retval TRUE The FirstTime is not later than the SecondTime.
933 @retval FALSE The FirstTime is later than the SecondTime.
934
935 **/
936 BOOLEAN
937 CompareTimeStamp (
938 IN EFI_TIME *FirstTime,
939 IN EFI_TIME *SecondTime
940 )
941 {
942 if (FirstTime->Year != SecondTime->Year) {
943 return (BOOLEAN) (FirstTime->Year < SecondTime->Year);
944 } else if (FirstTime->Month != SecondTime->Month) {
945 return (BOOLEAN) (FirstTime->Month < SecondTime->Month);
946 } else if (FirstTime->Day != SecondTime->Day) {
947 return (BOOLEAN) (FirstTime->Day < SecondTime->Day);
948 } else if (FirstTime->Hour != SecondTime->Hour) {
949 return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour);
950 } else if (FirstTime->Minute != SecondTime->Minute) {
951 return (BOOLEAN) (FirstTime->Minute < FirstTime->Minute);
952 }
953
954 return (BOOLEAN) (FirstTime->Second <= SecondTime->Second);
955 }
956
957 /**
958 Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
959
960 @param[in] VariableName Name of Variable to be found.
961 @param[in] VendorGuid Variable vendor GUID.
962 @param[in] Data Data pointer.
963 @param[in] DataSize Size of Data found. If size is less than the
964 data, this value contains the required size.
965 @param[in] Variable The variable information which is used to keep track of variable usage.
966 @param[in] Attributes Attribute value of the variable.
967 @param[in] Pk Verify against PK or KEK database.
968 @param[out] VarDel Delete the variable or not.
969
970 @retval EFI_INVALID_PARAMETER Invalid parameter.
971 @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation
972 check carried out by the firmware.
973 @retval EFI_OUT_OF_RESOURCES Failed to process variable due to lack
974 of resources.
975 @retval EFI_SUCCESS Variable pass validation successfully.
976
977 **/
978 EFI_STATUS
979 VerifyTimeBasedPayload (
980 IN CHAR16 *VariableName,
981 IN EFI_GUID *VendorGuid,
982 IN VOID *Data,
983 IN UINTN DataSize,
984 IN VARIABLE_POINTER_TRACK *Variable,
985 IN UINT32 Attributes,
986 IN BOOLEAN Pk,
987 OUT BOOLEAN *VarDel
988 )
989 {
990 UINT8 *RootCert;
991 UINT8 *SigData;
992 UINT8 *PayLoadPtr;
993 UINTN RootCertSize;
994 UINTN Index;
995 UINTN CertCount;
996 UINTN PayLoadSize;
997 UINT32 Attr;
998 UINT32 SigDataSize;
999 UINT32 KekDataSize;
1000 BOOLEAN Result;
1001 BOOLEAN VerifyStatus;
1002 EFI_STATUS Status;
1003 EFI_SIGNATURE_LIST *CertList;
1004 EFI_SIGNATURE_DATA *Cert;
1005 VARIABLE_POINTER_TRACK KekVariable;
1006 EFI_VARIABLE_AUTHENTICATION_2 *CertData;
1007 UINT8 *NewData;
1008 UINTN NewDataSize;
1009 VARIABLE_POINTER_TRACK PkVariable;
1010
1011
1012 Result = FALSE;
1013 VerifyStatus = FALSE;
1014 CertData = NULL;
1015 NewData = NULL;
1016 Attr = Attributes;
1017
1018 //
1019 // When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is
1020 // set, then the Data buffer shall begin with an instance of a complete (and serialized)
1021 // EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new
1022 // variable value and DataSize shall reflect the combined size of the descriptor and the new
1023 // variable value. The authentication descriptor is not part of the variable data and is not
1024 // returned by subsequent calls to GetVariable().
1025 //
1026 CertData = (EFI_VARIABLE_AUTHENTICATION_2 *) Data;
1027
1028 if ((Variable->CurrPtr != NULL) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {
1029 if (CompareTimeStamp (&CertData->TimeStamp, &Variable->CurrPtr->TimeStamp)) {
1030 //
1031 // TimeStamp check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
1032 //
1033 return EFI_SECURITY_VIOLATION;
1034 }
1035 }
1036
1037 //
1038 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
1039 // Cert type should be EFI_CERT_TYPE_PKCS7_GUID.
1040 //
1041 if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||
1042 !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertPkcs7Guid)
1043 ) {
1044 //
1045 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
1046 //
1047 return EFI_SECURITY_VIOLATION;
1048 }
1049
1050 //
1051 // Find out Pkcs7 SignedData which follows the EFI_VARIABLE_AUTHENTICATION_2 descriptor.
1052 // AuthInfo.Hdr.dwLength is the length of the entire certificate, including the length of the header.
1053 //
1054 SigData = (UINT8*) ((UINTN)Data + (UINTN)(((EFI_VARIABLE_AUTHENTICATION_2 *) 0)->AuthInfo.CertData));
1055 SigDataSize = CertData->AuthInfo.Hdr.dwLength - (UINT32)(UINTN)(((WIN_CERTIFICATE_UEFI_GUID *) 0)->CertData);
1056
1057 //
1058 // Find out the new data payload which follows Pkcs7 SignedData directly.
1059 //
1060 PayLoadPtr = (UINT8*) ((UINTN) SigData + (UINTN) SigDataSize);
1061 PayLoadSize = DataSize - (UINTN)(((EFI_VARIABLE_AUTHENTICATION_2 *) 0)->AuthInfo.CertData) - (UINTN) SigDataSize;
1062
1063
1064 //
1065 // Construct a buffer to fill with (VariableName, VendorGuid, Attributes, TimeStamp, Data).
1066 //
1067 NewDataSize = PayLoadSize + sizeof (EFI_TIME) + sizeof (UINT32) +
1068 sizeof (EFI_GUID) + StrSize (VariableName);
1069 NewData = (UINT8 *) AllocateZeroPool (NewDataSize);
1070
1071 if (NewData == NULL) {
1072 return EFI_OUT_OF_RESOURCES;
1073 }
1074
1075 CopyMem (NewData, VariableName, StrSize (VariableName));
1076
1077 CopyMem (NewData + StrSize (VariableName), VendorGuid, sizeof (EFI_GUID));
1078
1079 CopyMem (
1080 NewData + StrSize (VariableName) + sizeof (EFI_GUID),
1081 &Attr,
1082 sizeof (UINT32)
1083 );
1084
1085 CopyMem (
1086 NewData + StrSize (VariableName) + sizeof (EFI_GUID) + sizeof (UINT32),
1087 &CertData->TimeStamp,
1088 sizeof (EFI_TIME)
1089 );
1090
1091 CopyMem (NewData + (NewDataSize - PayLoadSize), PayLoadPtr, PayLoadSize);
1092
1093
1094 if (Pk) {
1095 //
1096 // Get platform key from variable.
1097 //
1098 Status = FindVariable (
1099 EFI_PLATFORM_KEY_NAME,
1100 &gEfiGlobalVariableGuid,
1101 &PkVariable,
1102 &mVariableModuleGlobal->VariableGlobal
1103 );
1104 if (EFI_ERROR (Status)) {
1105 return Status;
1106 }
1107
1108 CertList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (PkVariable.CurrPtr);
1109 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
1110 RootCert = Cert->SignatureData;
1111 RootCertSize = CertList->SignatureSize;
1112
1113
1114 //
1115 // Verify Pkcs7 SignedData via Pkcs7Verify library.
1116 //
1117 VerifyStatus = Pkcs7Verify (
1118 SigData,
1119 SigDataSize,
1120 RootCert,
1121 RootCertSize,
1122 NewData,
1123 NewDataSize
1124 );
1125
1126 } else {
1127
1128 //
1129 // Get KEK database from variable.
1130 //
1131 Status = FindVariable (
1132 EFI_KEY_EXCHANGE_KEY_NAME,
1133 &gEfiGlobalVariableGuid,
1134 &KekVariable,
1135 &mVariableModuleGlobal->VariableGlobal
1136 );
1137 if (EFI_ERROR (Status)) {
1138 return Status;
1139 }
1140
1141 //
1142 // Ready to verify Pkcs7 SignedData. Go through KEK Signature Database to find out X.509 CertList.
1143 //
1144 KekDataSize = KekVariable.CurrPtr->DataSize;
1145 CertList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (KekVariable.CurrPtr);
1146 while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {
1147 if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
1148 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
1149 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
1150 for (Index = 0; Index < CertCount; Index++) {
1151 //
1152 // Iterate each Signature Data Node within this CertList for a verify
1153 //
1154 RootCert = Cert->SignatureData;
1155 RootCertSize = CertList->SignatureSize;
1156
1157 //
1158 // Verify Pkcs7 SignedData via Pkcs7Verify library.
1159 //
1160 VerifyStatus = Pkcs7Verify (
1161 SigData,
1162 SigDataSize,
1163 RootCert,
1164 RootCertSize,
1165 NewData,
1166 NewDataSize
1167 );
1168 if (VerifyStatus) {
1169 goto Exit;
1170 }
1171 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
1172 }
1173 }
1174 KekDataSize -= CertList->SignatureListSize;
1175 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
1176 }
1177 }
1178
1179 Exit:
1180
1181 FreePool (NewData);
1182
1183 if (!VerifyStatus) {
1184 return EFI_SECURITY_VIOLATION;
1185 }
1186
1187 if ((PayLoadSize == 0) && (VarDel != NULL)) {
1188 *VarDel = TRUE;
1189 }
1190
1191 //
1192 // Final step: Update/Append Variable if it pass Pkcs7Verify
1193 //
1194 return UpdateVariable (
1195 VariableName,
1196 VendorGuid,
1197 PayLoadPtr,
1198 PayLoadSize,
1199 Attributes,
1200 0,
1201 0,
1202 Variable,
1203 &CertData->TimeStamp
1204 );
1205 }