SecurityPkg: Fix assert when setting key from eMMC/SD/USB
[mirror_edk2.git] / SecurityPkg / VariableAuthenticated / SecureBootConfigDxe / SecureBootConfigFileExplorer.c
1 /** @file
2 Internal file explorer functions for SecureBoot configuration module.
3
4 Copyright (c) 2012 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "SecureBootConfigImpl.h"
16
17 VOID *mStartOpCodeHandle = NULL;
18 VOID *mEndOpCodeHandle = NULL;
19 EFI_IFR_GUID_LABEL *mStartLabel = NULL;
20 EFI_IFR_GUID_LABEL *mEndLabel = NULL;
21
22 /**
23 Refresh the global UpdateData structure.
24
25 **/
26 VOID
27 RefreshUpdateData (
28 VOID
29 )
30 {
31 //
32 // Free current updated date
33 //
34 if (mStartOpCodeHandle != NULL) {
35 HiiFreeOpCodeHandle (mStartOpCodeHandle);
36 }
37
38 //
39 // Create new OpCode Handle
40 //
41 mStartOpCodeHandle = HiiAllocateOpCodeHandle ();
42
43 //
44 // Create Hii Extend Label OpCode as the start opcode
45 //
46 mStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
47 mStartOpCodeHandle,
48 &gEfiIfrTianoGuid,
49 NULL,
50 sizeof (EFI_IFR_GUID_LABEL)
51 );
52 mStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
53 }
54
55 /**
56 Clean up the dynamic opcode at label and form specified by both LabelId.
57
58 @param[in] LabelId It is both the Form ID and Label ID for opcode deletion.
59 @param[in] PrivateData Module private data.
60
61 **/
62 VOID
63 CleanUpPage (
64 IN UINT16 LabelId,
65 IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData
66 )
67 {
68 RefreshUpdateData ();
69
70 //
71 // Remove all op-codes from dynamic page
72 //
73 mStartLabel->Number = LabelId;
74 HiiUpdateForm (
75 PrivateData->HiiHandle,
76 &gSecureBootConfigFormSetGuid,
77 LabelId,
78 mStartOpCodeHandle, // Label LabelId
79 mEndOpCodeHandle // LABEL_END
80 );
81 }
82
83 /**
84 This function will open a file or directory referenced by DevicePath.
85
86 This function opens a file with the open mode according to the file path. The
87 Attributes is valid only for EFI_FILE_MODE_CREATE.
88
89 @param[in, out] FilePath On input, the device path to the file.
90 On output, the remaining device path.
91 @param[out] FileHandle Pointer to the file handle.
92 @param[in] OpenMode The mode to open the file with.
93 @param[in] Attributes The file's file attributes.
94
95 @retval EFI_SUCCESS The information was set.
96 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
97 @retval EFI_UNSUPPORTED Could not open the file path.
98 @retval EFI_NOT_FOUND The specified file could not be found on the
99 device or the file system could not be found on
100 the device.
101 @retval EFI_NO_MEDIA The device has no medium.
102 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
103 medium is no longer supported.
104 @retval EFI_DEVICE_ERROR The device reported an error.
105 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
106 @retval EFI_WRITE_PROTECTED The file or medium is write protected.
107 @retval EFI_ACCESS_DENIED The file was opened read only.
108 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
109 file.
110 @retval EFI_VOLUME_FULL The volume is full.
111 **/
112 EFI_STATUS
113 EFIAPI
114 OpenFileByDevicePath(
115 IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath,
116 OUT EFI_FILE_HANDLE *FileHandle,
117 IN UINT64 OpenMode,
118 IN UINT64 Attributes
119 )
120 {
121 EFI_STATUS Status;
122 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *EfiSimpleFileSystemProtocol;
123 EFI_FILE_PROTOCOL *Handle1;
124 EFI_FILE_PROTOCOL *Handle2;
125 EFI_HANDLE DeviceHandle;
126 CHAR16 *PathName;
127 UINTN PathLength;
128
129 if ((FilePath == NULL || FileHandle == NULL)) {
130 return EFI_INVALID_PARAMETER;
131 }
132
133 Status = gBS->LocateDevicePath (
134 &gEfiSimpleFileSystemProtocolGuid,
135 FilePath,
136 &DeviceHandle
137 );
138 if (EFI_ERROR (Status)) {
139 return Status;
140 }
141
142 Status = gBS->OpenProtocol(
143 DeviceHandle,
144 &gEfiSimpleFileSystemProtocolGuid,
145 (VOID**)&EfiSimpleFileSystemProtocol,
146 gImageHandle,
147 NULL,
148 EFI_OPEN_PROTOCOL_GET_PROTOCOL
149 );
150 if (EFI_ERROR (Status)) {
151 return Status;
152 }
153
154 Status = EfiSimpleFileSystemProtocol->OpenVolume(EfiSimpleFileSystemProtocol, &Handle1);
155 if (EFI_ERROR (Status)) {
156 FileHandle = NULL;
157 return Status;
158 }
159
160 //
161 // go down directories one node at a time.
162 //
163 while (!IsDevicePathEnd (*FilePath)) {
164 //
165 // For file system access each node should be a file path component
166 //
167 if (DevicePathType (*FilePath) != MEDIA_DEVICE_PATH ||
168 DevicePathSubType (*FilePath) != MEDIA_FILEPATH_DP
169 ) {
170 FileHandle = NULL;
171 return (EFI_INVALID_PARAMETER);
172 }
173 //
174 // Open this file path node
175 //
176 Handle2 = Handle1;
177 Handle1 = NULL;
178 PathLength = DevicePathNodeLength (*FilePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL);
179 PathName = AllocateCopyPool (PathLength, ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName);
180 if (PathName == NULL) {
181 return EFI_OUT_OF_RESOURCES;
182 }
183
184 //
185 // Try to test opening an existing file
186 //
187 Status = Handle2->Open (
188 Handle2,
189 &Handle1,
190 PathName,
191 OpenMode &~EFI_FILE_MODE_CREATE,
192 0
193 );
194
195 //
196 // see if the error was that it needs to be created
197 //
198 if ((EFI_ERROR (Status)) && (OpenMode != (OpenMode &~EFI_FILE_MODE_CREATE))) {
199 Status = Handle2->Open (
200 Handle2,
201 &Handle1,
202 PathName,
203 OpenMode,
204 Attributes
205 );
206 }
207 //
208 // Close the last node
209 //
210 Handle2->Close (Handle2);
211
212 FreePool (PathName);
213
214 if (EFI_ERROR(Status)) {
215 return (Status);
216 }
217
218 //
219 // Get the next node
220 //
221 *FilePath = NextDevicePathNode (*FilePath);
222 }
223
224 //
225 // This is a weak spot since if the undefined SHELL_FILE_HANDLE format changes this must change also!
226 //
227 *FileHandle = (VOID*)Handle1;
228 return EFI_SUCCESS;
229 }
230
231
232 /**
233 Extract filename from device path. The returned buffer is allocated using AllocateCopyPool.
234 The caller is responsible for freeing the allocated buffer using FreePool(). If return NULL
235 means not enough memory resource.
236
237 @param DevicePath Device path.
238
239 @retval NULL Not enough memory resourece for AllocateCopyPool.
240 @retval Other A new allocated string that represents the file name.
241
242 **/
243 CHAR16 *
244 ExtractFileNameFromDevicePath (
245 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
246 )
247 {
248 CHAR16 *String;
249 CHAR16 *MatchString;
250 CHAR16 *LastMatch;
251 CHAR16 *FileName;
252 UINTN Length;
253
254 ASSERT(DevicePath != NULL);
255
256 String = DevicePathToStr(DevicePath);
257 MatchString = String;
258 LastMatch = String;
259 FileName = NULL;
260
261 while(MatchString != NULL){
262 LastMatch = MatchString + 1;
263 MatchString = StrStr(LastMatch,L"\\");
264 }
265
266 Length = StrLen(LastMatch);
267 FileName = AllocateCopyPool ((Length + 1) * sizeof(CHAR16), LastMatch);
268 if (FileName != NULL) {
269 *(FileName + Length) = 0;
270 }
271
272 FreePool(String);
273
274 return FileName;
275 }
276
277
278 /**
279 Update the form base on the selected file.
280
281 @param FilePath Point to the file path.
282 @param FormId The form need to display.
283
284 @retval TRUE Exit caller function.
285 @retval FALSE Not exit caller function.
286
287 **/
288 BOOLEAN
289 UpdatePage(
290 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
291 IN EFI_FORM_ID FormId
292 )
293 {
294 CHAR16 *FileName;
295 EFI_STRING_ID StringToken;
296
297 FileName = NULL;
298
299 if (FilePath != NULL) {
300 FileName = ExtractFileNameFromDevicePath(FilePath);
301 }
302 if (FileName == NULL) {
303 //
304 // FileName = NULL has two case:
305 // 1. FilePath == NULL, not select file.
306 // 2. FilePath != NULL, but ExtractFileNameFromDevicePath return NULL not enough memory resource.
307 // In these two case, no need to update the form, and exit the caller function.
308 //
309 return TRUE;
310 }
311 StringToken = HiiSetString (gSecureBootPrivateData->HiiHandle, 0, FileName, NULL);
312
313 gSecureBootPrivateData->FileContext->FileName = FileName;
314
315 OpenFileByDevicePath(
316 &FilePath,
317 &gSecureBootPrivateData->FileContext->FHandle,
318 EFI_FILE_MODE_READ,
319 0
320 );
321 //
322 // Create Subtitle op-code for the display string of the option.
323 //
324 RefreshUpdateData ();
325 mStartLabel->Number = FormId;
326
327 HiiCreateSubTitleOpCode (
328 mStartOpCodeHandle,
329 StringToken,
330 0,
331 0,
332 0
333 );
334
335 HiiUpdateForm (
336 gSecureBootPrivateData->HiiHandle,
337 &gSecureBootConfigFormSetGuid,
338 FormId,
339 mStartOpCodeHandle, // Label FormId
340 mEndOpCodeHandle // LABEL_END
341 );
342
343 return TRUE;
344 }
345
346 /**
347 Update the PK form base on the input file path info.
348
349 @param FilePath Point to the file path.
350
351 @retval TRUE Exit caller function.
352 @retval FALSE Not exit caller function.
353 **/
354 BOOLEAN
355 EFIAPI
356 UpdatePKFromFile (
357 IN EFI_DEVICE_PATH_PROTOCOL *FilePath
358 )
359 {
360 return UpdatePage(FilePath, FORMID_ENROLL_PK_FORM);
361
362 }
363
364 /**
365 Update the KEK form base on the input file path info.
366
367 @param FilePath Point to the file path.
368
369 @retval TRUE Exit caller function.
370 @retval FALSE Not exit caller function.
371 **/
372 BOOLEAN
373 EFIAPI
374 UpdateKEKFromFile (
375 IN EFI_DEVICE_PATH_PROTOCOL *FilePath
376 )
377 {
378 return UpdatePage(FilePath, FORMID_ENROLL_KEK_FORM);
379 }
380
381 /**
382 Update the DB form base on the input file path info.
383
384 @param FilePath Point to the file path.
385
386 @retval TRUE Exit caller function.
387 @retval FALSE Not exit caller function.
388 **/
389 BOOLEAN
390 EFIAPI
391 UpdateDBFromFile (
392 IN EFI_DEVICE_PATH_PROTOCOL *FilePath
393 )
394 {
395 return UpdatePage(FilePath, SECUREBOOT_ENROLL_SIGNATURE_TO_DB);
396 }
397
398 /**
399 Update the DBX form base on the input file path info.
400
401 @param FilePath Point to the file path.
402
403 @retval TRUE Exit caller function.
404 @retval FALSE Not exit caller function.
405 **/
406 BOOLEAN
407 EFIAPI
408 UpdateDBXFromFile (
409 IN EFI_DEVICE_PATH_PROTOCOL *FilePath
410 )
411 {
412 return UpdatePage(FilePath, SECUREBOOT_ENROLL_SIGNATURE_TO_DBX);
413 }
414
415 /**
416 Update the DBT form base on the input file path info.
417
418 @param FilePath Point to the file path.
419
420 @retval TRUE Exit caller function.
421 @retval FALSE Not exit caller function.
422 **/
423 BOOLEAN
424 EFIAPI
425 UpdateDBTFromFile (
426 IN EFI_DEVICE_PATH_PROTOCOL *FilePath
427 )
428 {
429 return UpdatePage(FilePath, SECUREBOOT_ENROLL_SIGNATURE_TO_DBT);
430 }
431