EnrollDefaultKeys.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852
  1. /** @file
  2. Enroll default PK, KEK, db, dbx.
  3. Copyright (C) 2014-2019, Red Hat, Inc.
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include <Guid/AuthenticatedVariableFormat.h> // gEfiCustomModeEnableGuid
  7. #include <Guid/GlobalVariable.h> // EFI_SETUP_MODE_NAME
  8. #include <Guid/ImageAuthentication.h> // EFI_IMAGE_SECURITY_DATABASE
  9. #include <Guid/MicrosoftVendor.h> // gMicrosoftVendorGuid
  10. #include <Guid/OvmfPkKek1AppPrefix.h> // gOvmfPkKek1AppPrefixGuid
  11. #include <IndustryStandard/SmBios.h> // SMBIOS_HANDLE_PI_RESERVED
  12. #include <Library/BaseLib.h> // GUID_STRING_LENGTH
  13. #include <Library/BaseMemoryLib.h> // CopyGuid()
  14. #include <Library/DebugLib.h> // ASSERT()
  15. #include <Library/MemoryAllocationLib.h> // FreePool()
  16. #include <Library/PrintLib.h> // AsciiSPrint()
  17. #include <Library/ShellCEntryLib.h> // ShellAppMain()
  18. #include <Library/UefiBootServicesTableLib.h> // gBS
  19. #include <Library/UefiLib.h> // AsciiPrint()
  20. #include <Library/UefiRuntimeServicesTableLib.h> // gRT
  21. #include <Protocol/Smbios.h> // EFI_SMBIOS_PROTOCOL
  22. #include "EnrollDefaultKeys.h"
  23. /**
  24. Fetch the X509 certificate (to be used as Platform Key and first Key Exchange
  25. Key) from SMBIOS.
  26. @param[out] PkKek1 The X509 certificate in DER encoding from the
  27. hypervisor, to be enrolled as PK and first KEK
  28. entry. On success, the caller is responsible for
  29. releasing PkKek1 with FreePool().
  30. @param[out] SizeOfPkKek1 The size of PkKek1 in bytes.
  31. @retval EFI_SUCCESS PkKek1 and SizeOfPkKek1 have been set
  32. successfully.
  33. @retval EFI_NOT_FOUND An OEM String matching
  34. OVMF_PK_KEK1_APP_PREFIX_GUID has not been
  35. found.
  36. @retval EFI_PROTOCOL_ERROR In the OEM String matching
  37. OVMF_PK_KEK1_APP_PREFIX_GUID, the certificate
  38. is empty, or it has invalid base64 encoding.
  39. @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
  40. @return Error codes from gBS->LocateProtocol().
  41. **/
  42. STATIC
  43. EFI_STATUS
  44. GetPkKek1 (
  45. OUT UINT8 **PkKek1,
  46. OUT UINTN *SizeOfPkKek1
  47. )
  48. {
  49. CONST CHAR8 *Base64Cert;
  50. CHAR8 OvmfPkKek1AppPrefix[GUID_STRING_LENGTH + 1 + 1];
  51. EFI_STATUS Status;
  52. EFI_SMBIOS_PROTOCOL *Smbios;
  53. EFI_SMBIOS_HANDLE Handle;
  54. EFI_SMBIOS_TYPE Type;
  55. EFI_SMBIOS_TABLE_HEADER *Header;
  56. SMBIOS_TABLE_TYPE11 *OemStringsTable;
  57. UINTN Base64CertLen;
  58. UINTN DecodedCertSize;
  59. UINT8 *DecodedCert;
  60. Base64Cert = NULL;
  61. //
  62. // Format the application prefix, for OEM String matching.
  63. //
  64. AsciiSPrint (
  65. OvmfPkKek1AppPrefix,
  66. sizeof OvmfPkKek1AppPrefix,
  67. "%g:",
  68. &gOvmfPkKek1AppPrefixGuid
  69. );
  70. //
  71. // Scan all "OEM Strings" tables.
  72. //
  73. Status = gBS->LocateProtocol (
  74. &gEfiSmbiosProtocolGuid,
  75. NULL,
  76. (VOID **)&Smbios
  77. );
  78. if (EFI_ERROR (Status)) {
  79. AsciiPrint ("error: failed to locate EFI_SMBIOS_PROTOCOL: %r\n", Status);
  80. return Status;
  81. }
  82. Handle = SMBIOS_HANDLE_PI_RESERVED;
  83. Type = SMBIOS_TYPE_OEM_STRINGS;
  84. for (Status = Smbios->GetNext (Smbios, &Handle, &Type, &Header, NULL);
  85. !EFI_ERROR (Status);
  86. Status = Smbios->GetNext (Smbios, &Handle, &Type, &Header, NULL))
  87. {
  88. CONST CHAR8 *OemString;
  89. UINTN Idx;
  90. if (Header->Length < sizeof *OemStringsTable) {
  91. //
  92. // Malformed table header, skip to next.
  93. //
  94. continue;
  95. }
  96. OemStringsTable = (SMBIOS_TABLE_TYPE11 *)Header;
  97. //
  98. // Scan all strings in the unformatted area of the current "OEM Strings"
  99. // table.
  100. //
  101. OemString = (CONST CHAR8 *)(OemStringsTable + 1);
  102. for (Idx = 0; Idx < OemStringsTable->StringCount; ++Idx) {
  103. CHAR8 CandidatePrefix[sizeof OvmfPkKek1AppPrefix];
  104. //
  105. // NUL-terminate the candidate prefix for case-insensitive comparison.
  106. //
  107. AsciiStrnCpyS (
  108. CandidatePrefix,
  109. sizeof CandidatePrefix,
  110. OemString,
  111. GUID_STRING_LENGTH + 1
  112. );
  113. if (AsciiStriCmp (OvmfPkKek1AppPrefix, CandidatePrefix) == 0) {
  114. //
  115. // The current string matches the prefix.
  116. //
  117. Base64Cert = OemString + GUID_STRING_LENGTH + 1;
  118. break;
  119. }
  120. OemString += AsciiStrSize (OemString);
  121. }
  122. if (Idx < OemStringsTable->StringCount) {
  123. //
  124. // The current table has a matching string.
  125. //
  126. break;
  127. }
  128. }
  129. if (EFI_ERROR (Status)) {
  130. //
  131. // No table with a matching string has been found.
  132. //
  133. AsciiPrint (
  134. "error: OEM String with app prefix %g not found: %r\n",
  135. &gOvmfPkKek1AppPrefixGuid,
  136. Status
  137. );
  138. return EFI_NOT_FOUND;
  139. }
  140. ASSERT (Base64Cert != NULL);
  141. Base64CertLen = AsciiStrLen (Base64Cert);
  142. //
  143. // Verify the base64 encoding, and determine the decoded size.
  144. //
  145. DecodedCertSize = 0;
  146. Status = Base64Decode (Base64Cert, Base64CertLen, NULL, &DecodedCertSize);
  147. switch (Status) {
  148. case EFI_BUFFER_TOO_SMALL:
  149. ASSERT (DecodedCertSize > 0);
  150. break;
  151. case EFI_SUCCESS:
  152. AsciiPrint (
  153. "error: empty certificate after app prefix %g\n",
  154. &gOvmfPkKek1AppPrefixGuid
  155. );
  156. return EFI_PROTOCOL_ERROR;
  157. default:
  158. AsciiPrint (
  159. "error: invalid base64 string after app prefix %g\n",
  160. &gOvmfPkKek1AppPrefixGuid
  161. );
  162. return EFI_PROTOCOL_ERROR;
  163. }
  164. //
  165. // Allocate the output buffer.
  166. //
  167. DecodedCert = AllocatePool (DecodedCertSize);
  168. if (DecodedCert == NULL) {
  169. AsciiPrint ("error: failed to allocate memory\n");
  170. return EFI_OUT_OF_RESOURCES;
  171. }
  172. //
  173. // Decoding will succeed at this point.
  174. //
  175. Status = Base64Decode (
  176. Base64Cert,
  177. Base64CertLen,
  178. DecodedCert,
  179. &DecodedCertSize
  180. );
  181. ASSERT_EFI_ERROR (Status);
  182. *PkKek1 = DecodedCert;
  183. *SizeOfPkKek1 = DecodedCertSize;
  184. return EFI_SUCCESS;
  185. }
  186. /**
  187. Enroll a set of certificates in a global variable, overwriting it.
  188. The variable will be rewritten with NV+BS+RT+AT attributes.
  189. @param[in] VariableName The name of the variable to overwrite.
  190. @param[in] VendorGuid The namespace (ie. vendor GUID) of the variable to
  191. overwrite.
  192. @param[in] CertType The GUID determining the type of all the
  193. certificates in the set that is passed in. For
  194. example, gEfiCertX509Guid stands for DER-encoded
  195. X.509 certificates, while gEfiCertSha256Guid stands
  196. for SHA256 image hashes.
  197. @param[in] ... A list of
  198. IN CONST UINT8 *Cert,
  199. IN UINTN CertSize,
  200. IN CONST EFI_GUID *OwnerGuid
  201. triplets. If the first component of a triplet is
  202. NULL, then the other two components are not
  203. accessed, and processing is terminated. The list of
  204. certificates is enrolled in the variable specified,
  205. overwriting it. The OwnerGuid component identifies
  206. the agent installing the certificate.
  207. @retval EFI_INVALID_PARAMETER The triplet list is empty (ie. the first Cert
  208. value is NULL), or one of the CertSize values
  209. is 0, or one of the CertSize values would
  210. overflow the accumulated UINT32 data size.
  211. @retval EFI_OUT_OF_RESOURCES Out of memory while formatting variable
  212. payload.
  213. @retval EFI_SUCCESS Enrollment successful; the variable has been
  214. overwritten (or created).
  215. @return Error codes from gRT->GetTime() and
  216. gRT->SetVariable().
  217. **/
  218. STATIC
  219. EFI_STATUS
  220. EFIAPI
  221. EnrollListOfCerts (
  222. IN CHAR16 *VariableName,
  223. IN EFI_GUID *VendorGuid,
  224. IN EFI_GUID *CertType,
  225. ...
  226. )
  227. {
  228. UINTN DataSize;
  229. SINGLE_HEADER *SingleHeader;
  230. REPEATING_HEADER *RepeatingHeader;
  231. VA_LIST Marker;
  232. CONST UINT8 *Cert;
  233. EFI_STATUS Status;
  234. UINT8 *Data;
  235. UINT8 *Position;
  236. Status = EFI_SUCCESS;
  237. //
  238. // compute total size first, for UINT32 range check, and allocation
  239. //
  240. DataSize = sizeof *SingleHeader;
  241. VA_START (Marker, CertType);
  242. for (Cert = VA_ARG (Marker, CONST UINT8 *);
  243. Cert != NULL;
  244. Cert = VA_ARG (Marker, CONST UINT8 *))
  245. {
  246. UINTN CertSize;
  247. CertSize = VA_ARG (Marker, UINTN);
  248. (VOID)VA_ARG (Marker, CONST EFI_GUID *);
  249. if ((CertSize == 0) ||
  250. (CertSize > MAX_UINT32 - sizeof *RepeatingHeader) ||
  251. (DataSize > MAX_UINT32 - sizeof *RepeatingHeader - CertSize))
  252. {
  253. Status = EFI_INVALID_PARAMETER;
  254. break;
  255. }
  256. DataSize += sizeof *RepeatingHeader + CertSize;
  257. }
  258. VA_END (Marker);
  259. if (DataSize == sizeof *SingleHeader) {
  260. Status = EFI_INVALID_PARAMETER;
  261. }
  262. if (EFI_ERROR (Status)) {
  263. goto Out;
  264. }
  265. Data = AllocatePool (DataSize);
  266. if (Data == NULL) {
  267. Status = EFI_OUT_OF_RESOURCES;
  268. goto Out;
  269. }
  270. Position = Data;
  271. SingleHeader = (SINGLE_HEADER *)Position;
  272. Status = gRT->GetTime (&SingleHeader->TimeStamp, NULL);
  273. if (EFI_ERROR (Status)) {
  274. goto FreeData;
  275. }
  276. SingleHeader->TimeStamp.Pad1 = 0;
  277. SingleHeader->TimeStamp.Nanosecond = 0;
  278. SingleHeader->TimeStamp.TimeZone = 0;
  279. SingleHeader->TimeStamp.Daylight = 0;
  280. SingleHeader->TimeStamp.Pad2 = 0;
  281. #if 0
  282. SingleHeader->dwLength = DataSize - sizeof SingleHeader->TimeStamp;
  283. #else
  284. //
  285. // This looks like a bug in edk2. According to the UEFI specification,
  286. // dwLength is "The length of the entire certificate, including the length of
  287. // the header, in bytes". That shouldn't stop right after CertType -- it
  288. // should include everything below it.
  289. //
  290. SingleHeader->dwLength = sizeof *SingleHeader
  291. - sizeof SingleHeader->TimeStamp;
  292. #endif
  293. SingleHeader->wRevision = 0x0200;
  294. SingleHeader->wCertificateType = WIN_CERT_TYPE_EFI_GUID;
  295. CopyGuid (&SingleHeader->CertType, &gEfiCertPkcs7Guid);
  296. Position += sizeof *SingleHeader;
  297. VA_START (Marker, CertType);
  298. for (Cert = VA_ARG (Marker, CONST UINT8 *);
  299. Cert != NULL;
  300. Cert = VA_ARG (Marker, CONST UINT8 *))
  301. {
  302. UINTN CertSize;
  303. CONST EFI_GUID *OwnerGuid;
  304. CertSize = VA_ARG (Marker, UINTN);
  305. OwnerGuid = VA_ARG (Marker, CONST EFI_GUID *);
  306. RepeatingHeader = (REPEATING_HEADER *)Position;
  307. CopyGuid (&RepeatingHeader->SignatureType, CertType);
  308. RepeatingHeader->SignatureListSize =
  309. (UINT32)(sizeof *RepeatingHeader + CertSize);
  310. RepeatingHeader->SignatureHeaderSize = 0;
  311. RepeatingHeader->SignatureSize =
  312. (UINT32)(sizeof RepeatingHeader->SignatureOwner + CertSize);
  313. CopyGuid (&RepeatingHeader->SignatureOwner, OwnerGuid);
  314. Position += sizeof *RepeatingHeader;
  315. CopyMem (Position, Cert, CertSize);
  316. Position += CertSize;
  317. }
  318. VA_END (Marker);
  319. ASSERT (Data + DataSize == Position);
  320. Status = gRT->SetVariable (
  321. VariableName,
  322. VendorGuid,
  323. (EFI_VARIABLE_NON_VOLATILE |
  324. EFI_VARIABLE_BOOTSERVICE_ACCESS |
  325. EFI_VARIABLE_RUNTIME_ACCESS |
  326. EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS),
  327. DataSize,
  328. Data
  329. );
  330. FreeData:
  331. FreePool (Data);
  332. Out:
  333. if (EFI_ERROR (Status)) {
  334. AsciiPrint (
  335. "error: %a(\"%s\", %g): %r\n",
  336. __FUNCTION__,
  337. VariableName,
  338. VendorGuid,
  339. Status
  340. );
  341. }
  342. return Status;
  343. }
  344. /**
  345. Read a UEFI variable into a caller-allocated buffer, enforcing an exact size.
  346. @param[in] VariableName The name of the variable to read; passed to
  347. gRT->GetVariable().
  348. @param[in] VendorGuid The vendor (namespace) GUID of the variable to read;
  349. passed to gRT->GetVariable().
  350. @param[out] Data The caller-allocated buffer that is supposed to
  351. receive the variable's contents. On error, the
  352. contents of Data are indeterminate.
  353. @param[in] DataSize The size in bytes that the caller requires the UEFI
  354. variable to have. The caller is responsible for
  355. providing room for DataSize bytes in Data.
  356. @param[in] AllowMissing If FALSE, the variable is required to exist. If
  357. TRUE, the variable is permitted to be missing.
  358. @retval EFI_SUCCESS The UEFI variable exists, has the required size
  359. (DataSize), and has been read into Data.
  360. @retval EFI_SUCCESS The UEFI variable doesn't exist, and
  361. AllowMissing is TRUE. DataSize bytes in Data
  362. have been zeroed out.
  363. @retval EFI_NOT_FOUND The UEFI variable doesn't exist, and
  364. AllowMissing is FALSE.
  365. @retval EFI_BUFFER_TOO_SMALL The UEFI variable exists, but its size is
  366. greater than DataSize.
  367. @retval EFI_PROTOCOL_ERROR The UEFI variable exists, but its size is
  368. smaller than DataSize.
  369. @return Error codes propagated from gRT->GetVariable().
  370. **/
  371. STATIC
  372. EFI_STATUS
  373. GetExact (
  374. IN CHAR16 *VariableName,
  375. IN EFI_GUID *VendorGuid,
  376. OUT VOID *Data,
  377. IN UINTN DataSize,
  378. IN BOOLEAN AllowMissing
  379. )
  380. {
  381. UINTN Size;
  382. EFI_STATUS Status;
  383. Size = DataSize;
  384. Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &Size, Data);
  385. if (EFI_ERROR (Status)) {
  386. if ((Status == EFI_NOT_FOUND) && AllowMissing) {
  387. ZeroMem (Data, DataSize);
  388. return EFI_SUCCESS;
  389. }
  390. AsciiPrint (
  391. "error: GetVariable(\"%s\", %g): %r\n",
  392. VariableName,
  393. VendorGuid,
  394. Status
  395. );
  396. return Status;
  397. }
  398. if (Size != DataSize) {
  399. AsciiPrint (
  400. "error: GetVariable(\"%s\", %g): expected size 0x%Lx, "
  401. "got 0x%Lx\n",
  402. VariableName,
  403. VendorGuid,
  404. (UINT64)DataSize,
  405. (UINT64)Size
  406. );
  407. return EFI_PROTOCOL_ERROR;
  408. }
  409. return EFI_SUCCESS;
  410. }
  411. /**
  412. Populate a SETTINGS structure from the underlying UEFI variables.
  413. The following UEFI variables are standard variables:
  414. - L"SetupMode" (EFI_SETUP_MODE_NAME)
  415. - L"SecureBoot" (EFI_SECURE_BOOT_MODE_NAME)
  416. - L"VendorKeys" (EFI_VENDOR_KEYS_VARIABLE_NAME)
  417. The following UEFI variables are edk2 extensions:
  418. - L"SecureBootEnable" (EFI_SECURE_BOOT_ENABLE_NAME)
  419. - L"CustomMode" (EFI_CUSTOM_MODE_NAME)
  420. The L"SecureBootEnable" UEFI variable is permitted to be missing, in which
  421. case the corresponding field in the SETTINGS object will be zeroed out. The
  422. rest of the covered UEFI variables are required to exist; otherwise, the
  423. function will fail.
  424. @param[out] Settings The SETTINGS object to fill.
  425. @retval EFI_SUCCESS Settings has been populated.
  426. @return Error codes propagated from the GetExact() function. The
  427. contents of Settings are indeterminate.
  428. **/
  429. STATIC
  430. EFI_STATUS
  431. GetSettings (
  432. OUT SETTINGS *Settings
  433. )
  434. {
  435. EFI_STATUS Status;
  436. Status = GetExact (
  437. EFI_SETUP_MODE_NAME,
  438. &gEfiGlobalVariableGuid,
  439. &Settings->SetupMode,
  440. sizeof Settings->SetupMode,
  441. FALSE
  442. );
  443. if (EFI_ERROR (Status)) {
  444. return Status;
  445. }
  446. Status = GetExact (
  447. EFI_SECURE_BOOT_MODE_NAME,
  448. &gEfiGlobalVariableGuid,
  449. &Settings->SecureBoot,
  450. sizeof Settings->SecureBoot,
  451. FALSE
  452. );
  453. if (EFI_ERROR (Status)) {
  454. return Status;
  455. }
  456. Status = GetExact (
  457. EFI_SECURE_BOOT_ENABLE_NAME,
  458. &gEfiSecureBootEnableDisableGuid,
  459. &Settings->SecureBootEnable,
  460. sizeof Settings->SecureBootEnable,
  461. TRUE
  462. );
  463. if (EFI_ERROR (Status)) {
  464. return Status;
  465. }
  466. Status = GetExact (
  467. EFI_CUSTOM_MODE_NAME,
  468. &gEfiCustomModeEnableGuid,
  469. &Settings->CustomMode,
  470. sizeof Settings->CustomMode,
  471. FALSE
  472. );
  473. if (EFI_ERROR (Status)) {
  474. return Status;
  475. }
  476. Status = GetExact (
  477. EFI_VENDOR_KEYS_VARIABLE_NAME,
  478. &gEfiGlobalVariableGuid,
  479. &Settings->VendorKeys,
  480. sizeof Settings->VendorKeys,
  481. FALSE
  482. );
  483. return Status;
  484. }
  485. /**
  486. Print the contents of a SETTINGS structure to the UEFI console.
  487. @param[in] Settings The SETTINGS object to print the contents of.
  488. **/
  489. STATIC
  490. VOID
  491. PrintSettings (
  492. IN CONST SETTINGS *Settings
  493. )
  494. {
  495. AsciiPrint (
  496. "info: SetupMode=%d SecureBoot=%d SecureBootEnable=%d "
  497. "CustomMode=%d VendorKeys=%d\n",
  498. Settings->SetupMode,
  499. Settings->SecureBoot,
  500. Settings->SecureBootEnable,
  501. Settings->CustomMode,
  502. Settings->VendorKeys
  503. );
  504. }
  505. /**
  506. Entry point function of this shell application.
  507. **/
  508. INTN
  509. EFIAPI
  510. ShellAppMain (
  511. IN UINTN Argc,
  512. IN CHAR16 **Argv
  513. )
  514. {
  515. INTN RetVal;
  516. EFI_STATUS Status;
  517. SETTINGS Settings;
  518. UINT8 *PkKek1;
  519. UINTN SizeOfPkKek1;
  520. BOOLEAN NoDefault;
  521. if ((Argc == 2) && (StrCmp (Argv[1], L"--no-default") == 0)) {
  522. NoDefault = TRUE;
  523. } else {
  524. NoDefault = FALSE;
  525. }
  526. //
  527. // Prepare for failure.
  528. //
  529. RetVal = 1;
  530. //
  531. // If we're not in Setup Mode, we can't do anything.
  532. //
  533. Status = GetSettings (&Settings);
  534. if (EFI_ERROR (Status)) {
  535. return RetVal;
  536. }
  537. PrintSettings (&Settings);
  538. if (Settings.SetupMode != 1) {
  539. AsciiPrint ("error: already in User Mode\n");
  540. return RetVal;
  541. }
  542. //
  543. // Set PkKek1 and SizeOfPkKek1 to suppress incorrect compiler/analyzer
  544. // warnings.
  545. //
  546. PkKek1 = NULL;
  547. SizeOfPkKek1 = 0;
  548. //
  549. // Fetch the X509 certificate (to be used as Platform Key and first Key
  550. // Exchange Key) from SMBIOS.
  551. //
  552. Status = GetPkKek1 (&PkKek1, &SizeOfPkKek1);
  553. if (EFI_ERROR (Status)) {
  554. return RetVal;
  555. }
  556. //
  557. // Enter Custom Mode so we can enroll PK, KEK, db, and dbx without signature
  558. // checks on those variable writes.
  559. //
  560. if (Settings.CustomMode != CUSTOM_SECURE_BOOT_MODE) {
  561. Settings.CustomMode = CUSTOM_SECURE_BOOT_MODE;
  562. Status = gRT->SetVariable (
  563. EFI_CUSTOM_MODE_NAME,
  564. &gEfiCustomModeEnableGuid,
  565. (EFI_VARIABLE_NON_VOLATILE |
  566. EFI_VARIABLE_BOOTSERVICE_ACCESS),
  567. sizeof Settings.CustomMode,
  568. &Settings.CustomMode
  569. );
  570. if (EFI_ERROR (Status)) {
  571. AsciiPrint (
  572. "error: SetVariable(\"%s\", %g): %r\n",
  573. EFI_CUSTOM_MODE_NAME,
  574. &gEfiCustomModeEnableGuid,
  575. Status
  576. );
  577. goto FreePkKek1;
  578. }
  579. }
  580. //
  581. // Enroll db.
  582. //
  583. if (NoDefault) {
  584. Status = EnrollListOfCerts (
  585. EFI_IMAGE_SECURITY_DATABASE,
  586. &gEfiImageSecurityDatabaseGuid,
  587. &gEfiCertX509Guid,
  588. PkKek1,
  589. SizeOfPkKek1,
  590. &gEfiCallerIdGuid,
  591. NULL
  592. );
  593. } else {
  594. Status = EnrollListOfCerts (
  595. EFI_IMAGE_SECURITY_DATABASE,
  596. &gEfiImageSecurityDatabaseGuid,
  597. &gEfiCertX509Guid,
  598. mMicrosoftPca,
  599. mSizeOfMicrosoftPca,
  600. &gMicrosoftVendorGuid,
  601. mMicrosoftUefiCa,
  602. mSizeOfMicrosoftUefiCa,
  603. &gMicrosoftVendorGuid,
  604. NULL
  605. );
  606. }
  607. if (EFI_ERROR (Status)) {
  608. goto FreePkKek1;
  609. }
  610. //
  611. // Enroll dbx.
  612. //
  613. Status = EnrollListOfCerts (
  614. EFI_IMAGE_SECURITY_DATABASE1,
  615. &gEfiImageSecurityDatabaseGuid,
  616. &gEfiCertSha256Guid,
  617. mSha256OfDevNull,
  618. mSizeOfSha256OfDevNull,
  619. &gEfiCallerIdGuid,
  620. NULL
  621. );
  622. if (EFI_ERROR (Status)) {
  623. goto FreePkKek1;
  624. }
  625. //
  626. // Enroll KEK.
  627. //
  628. if (NoDefault) {
  629. Status = EnrollListOfCerts (
  630. EFI_KEY_EXCHANGE_KEY_NAME,
  631. &gEfiGlobalVariableGuid,
  632. &gEfiCertX509Guid,
  633. PkKek1,
  634. SizeOfPkKek1,
  635. &gEfiCallerIdGuid,
  636. NULL
  637. );
  638. } else {
  639. Status = EnrollListOfCerts (
  640. EFI_KEY_EXCHANGE_KEY_NAME,
  641. &gEfiGlobalVariableGuid,
  642. &gEfiCertX509Guid,
  643. PkKek1,
  644. SizeOfPkKek1,
  645. &gEfiCallerIdGuid,
  646. mMicrosoftKek,
  647. mSizeOfMicrosoftKek,
  648. &gMicrosoftVendorGuid,
  649. NULL
  650. );
  651. }
  652. if (EFI_ERROR (Status)) {
  653. goto FreePkKek1;
  654. }
  655. //
  656. // Enroll PK, leaving Setup Mode (entering User Mode) at once.
  657. //
  658. Status = EnrollListOfCerts (
  659. EFI_PLATFORM_KEY_NAME,
  660. &gEfiGlobalVariableGuid,
  661. &gEfiCertX509Guid,
  662. PkKek1,
  663. SizeOfPkKek1,
  664. &gEfiGlobalVariableGuid,
  665. NULL
  666. );
  667. if (EFI_ERROR (Status)) {
  668. goto FreePkKek1;
  669. }
  670. //
  671. // Leave Custom Mode, so that updates to PK, KEK, db, and dbx require valid
  672. // signatures.
  673. //
  674. Settings.CustomMode = STANDARD_SECURE_BOOT_MODE;
  675. Status = gRT->SetVariable (
  676. EFI_CUSTOM_MODE_NAME,
  677. &gEfiCustomModeEnableGuid,
  678. EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
  679. sizeof Settings.CustomMode,
  680. &Settings.CustomMode
  681. );
  682. if (EFI_ERROR (Status)) {
  683. AsciiPrint (
  684. "error: SetVariable(\"%s\", %g): %r\n",
  685. EFI_CUSTOM_MODE_NAME,
  686. &gEfiCustomModeEnableGuid,
  687. Status
  688. );
  689. goto FreePkKek1;
  690. }
  691. //
  692. // Final sanity check:
  693. //
  694. // [SetupMode]
  695. // (read-only, standardized by UEFI)
  696. // / \_
  697. // 0 1, default
  698. // / \_
  699. // PK enrolled no PK enrolled yet,
  700. // (this is called "User Mode") PK enrollment possible
  701. // |
  702. // |
  703. // [SecureBootEnable]
  704. // (read-write, edk2-specific, boot service only)
  705. // / \_
  706. // 0 1, default
  707. // / \_
  708. // [SecureBoot]=0 [SecureBoot]=1
  709. // (read-only, standardized by UEFI) (read-only, standardized by UEFI)
  710. // images are not verified images are verified, platform is
  711. // operating in Secure Boot mode
  712. // |
  713. // |
  714. // [CustomMode]
  715. // (read-write, edk2-specific, boot service only)
  716. // / \_
  717. // 0, default 1
  718. // / \_
  719. // PK, KEK, db, dbx PK, KEK, db, dbx
  720. // updates are verified updates are not verified
  721. //
  722. Status = GetSettings (&Settings);
  723. if (EFI_ERROR (Status)) {
  724. goto FreePkKek1;
  725. }
  726. PrintSettings (&Settings);
  727. if ((Settings.SetupMode != 0) || (Settings.SecureBoot != 1) ||
  728. (Settings.SecureBootEnable != 1) || (Settings.CustomMode != 0) ||
  729. (Settings.VendorKeys != 0))
  730. {
  731. AsciiPrint ("error: unexpected\n");
  732. goto FreePkKek1;
  733. }
  734. AsciiPrint ("info: success\n");
  735. RetVal = 0;
  736. FreePkKek1:
  737. FreePool (PkKek1);
  738. return RetVal;
  739. }