1 /** @file
2   Implement authentication services for the authenticated variables.
3 
4   Caution: This module requires additional review when modified.
5   This driver will have external input - variable data. It may be input in SMM mode.
6   This external input must be validated carefully to avoid security issue like
7   buffer overflow, integer overflow.
8   Variable attribute should also be checked to avoid authentication bypass.
9      The whole SMM authentication variable design relies on the integrity of flash part and SMM.
10   which is assumed to be protected by platform.  All variable code and metadata in flash/SMM Memory
11   may not be modified without authorization. If platform fails to protect these resources,
12   the authentication service provided in this driver will be broken, and the behavior is undefined.
13 
14 Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
15 This program and the accompanying materials
16 are licensed and made available under the terms and conditions of the BSD License
17 which accompanies this distribution.  The full text of the license may be found at
18 http://opensource.org/licenses/bsd-license.php
19 
20 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
21 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
22 
23 **/
24 
25 #include "AuthServiceInternal.h"
26 
27 ///
28 /// Global database array for scratch
29 ///
30 UINT8    *mPubKeyStore;
31 UINT32   mPubKeyNumber;
32 UINT32   mMaxKeyNumber;
33 UINT32   mMaxKeyDbSize;
34 UINT8    *mCertDbStore;
35 UINT32   mMaxCertDbSize;
36 UINT8    mVendorKeyState;
37 
38 EFI_GUID mSignatureSupport[] = {EFI_CERT_SHA1_GUID, EFI_CERT_SHA256_GUID, EFI_CERT_RSA2048_GUID, EFI_CERT_X509_GUID};
39 
40 //
41 // Hash context pointer
42 //
43 VOID  *mHashCtx = NULL;
44 
45 VARIABLE_ENTRY_PROPERTY mAuthVarEntry[] = {
46   {
47     &gEfiSecureBootEnableDisableGuid,
48     EFI_SECURE_BOOT_ENABLE_NAME,
49     {
50       VAR_CHECK_VARIABLE_PROPERTY_REVISION,
51       0,
52       VARIABLE_ATTRIBUTE_NV_BS,
53       sizeof (UINT8),
54       sizeof (UINT8)
55     }
56   },
57   {
58     &gEfiCustomModeEnableGuid,
59     EFI_CUSTOM_MODE_NAME,
60     {
61       VAR_CHECK_VARIABLE_PROPERTY_REVISION,
62       0,
63       VARIABLE_ATTRIBUTE_NV_BS,
64       sizeof (UINT8),
65       sizeof (UINT8)
66     }
67   },
68   {
69     &gEfiVendorKeysNvGuid,
70     EFI_VENDOR_KEYS_NV_VARIABLE_NAME,
71     {
72       VAR_CHECK_VARIABLE_PROPERTY_REVISION,
73       VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
74       VARIABLE_ATTRIBUTE_NV_BS_RT_AT,
75       sizeof (UINT8),
76       sizeof (UINT8)
77     }
78   },
79   {
80     &gEfiAuthenticatedVariableGuid,
81     AUTHVAR_KEYDB_NAME,
82     {
83       VAR_CHECK_VARIABLE_PROPERTY_REVISION,
84       VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
85       VARIABLE_ATTRIBUTE_NV_BS_RT_AW,
86       sizeof (UINT8),
87       MAX_UINTN
88     }
89   },
90   {
91     &gEfiCertDbGuid,
92     EFI_CERT_DB_NAME,
93     {
94       VAR_CHECK_VARIABLE_PROPERTY_REVISION,
95       VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
96       VARIABLE_ATTRIBUTE_NV_BS_RT_AT,
97       sizeof (UINT32),
98       MAX_UINTN
99     }
100   },
101   {
102     &gEdkiiSecureBootModeGuid,
103     L"SecureBootMode",
104     {
105       VAR_CHECK_VARIABLE_PROPERTY_REVISION,
106       VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
107       VARIABLE_ATTRIBUTE_NV_BS_RT,
108       sizeof (UINT8),
109       sizeof (UINT8)
110     }
111   }
112 };
113 
114 VOID **mAuthVarAddressPointer[10];
115 
116 AUTH_VAR_LIB_CONTEXT_IN *mAuthVarLibContextIn = NULL;
117 
118 /**
119   Initialization for authenticated varibale services.
120   If this initialization returns error status, other APIs will not work
121   and expect to be not called then.
122 
123   @param[in]  AuthVarLibContextIn   Pointer to input auth variable lib context.
124   @param[out] AuthVarLibContextOut  Pointer to output auth variable lib context.
125 
126   @retval EFI_SUCCESS               Function successfully executed.
127   @retval EFI_INVALID_PARAMETER     If AuthVarLibContextIn == NULL or AuthVarLibContextOut == NULL.
128   @retval EFI_OUT_OF_RESOURCES      Fail to allocate enough resource.
129   @retval EFI_UNSUPPORTED           Unsupported to process authenticated variable.
130 
131 **/
132 EFI_STATUS
133 EFIAPI
AuthVariableLibInitialize(IN AUTH_VAR_LIB_CONTEXT_IN * AuthVarLibContextIn,OUT AUTH_VAR_LIB_CONTEXT_OUT * AuthVarLibContextOut)134 AuthVariableLibInitialize (
135   IN  AUTH_VAR_LIB_CONTEXT_IN   *AuthVarLibContextIn,
136   OUT AUTH_VAR_LIB_CONTEXT_OUT  *AuthVarLibContextOut
137   )
138 {
139   EFI_STATUS            Status;
140   UINT8                 VarValue;
141   UINT32                VarAttr;
142   UINT8                 *Data;
143   UINTN                 DataSize;
144   UINTN                 CtxSize;
145   UINT8                 CustomMode;
146   UINT32                ListSize;
147 
148   if ((AuthVarLibContextIn == NULL) || (AuthVarLibContextOut == NULL)) {
149     return EFI_INVALID_PARAMETER;
150   }
151 
152   mAuthVarLibContextIn = AuthVarLibContextIn;
153 
154   //
155   // Initialize hash context.
156   //
157   CtxSize   = Sha256GetContextSize ();
158   mHashCtx  = AllocateRuntimePool (CtxSize);
159   if (mHashCtx == NULL) {
160     return EFI_OUT_OF_RESOURCES;
161   }
162 
163   //
164   // Reserve runtime buffer for public key database. The size excludes variable header and name size.
165   //
166   mMaxKeyDbSize = (UINT32) (mAuthVarLibContextIn->MaxAuthVariableSize - sizeof (AUTHVAR_KEYDB_NAME));
167   mMaxKeyNumber = mMaxKeyDbSize / sizeof (AUTHVAR_KEY_DB_DATA);
168   mPubKeyStore  = AllocateRuntimePool (mMaxKeyDbSize);
169   if (mPubKeyStore == NULL) {
170     return EFI_OUT_OF_RESOURCES;
171   }
172 
173   //
174   // Reserve runtime buffer for certificate database. The size excludes variable header and name size.
175   //
176   mMaxCertDbSize = (UINT32) (mAuthVarLibContextIn->MaxAuthVariableSize - sizeof (EFI_CERT_DB_NAME));
177   mCertDbStore   = AllocateRuntimePool (mMaxCertDbSize);
178   if (mCertDbStore == NULL) {
179     return EFI_OUT_OF_RESOURCES;
180   }
181 
182   //
183   // Check "AuthVarKeyDatabase" variable's existence.
184   // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
185   //
186   Status = AuthServiceInternalFindVariable (
187              AUTHVAR_KEYDB_NAME,
188              &gEfiAuthenticatedVariableGuid,
189              (VOID **) &Data,
190              &DataSize
191              );
192   if (EFI_ERROR (Status)) {
193     VarAttr       = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
194     VarValue      = 0;
195     mPubKeyNumber = 0;
196     Status        = AuthServiceInternalUpdateVariable (
197                       AUTHVAR_KEYDB_NAME,
198                       &gEfiAuthenticatedVariableGuid,
199                       &VarValue,
200                       sizeof(UINT8),
201                       VarAttr
202                       );
203     if (EFI_ERROR (Status)) {
204       return Status;
205     }
206   } else {
207     //
208     // Load database in global variable for cache.
209     //
210     ASSERT ((DataSize != 0) && (Data != NULL));
211     //
212     // "AuthVarKeyDatabase" is an internal variable. Its DataSize is always ensured not to exceed mPubKeyStore buffer size(See definition before)
213     //  Therefore, there is no memory overflow in underlying CopyMem.
214     //
215     CopyMem (mPubKeyStore, (UINT8 *) Data, DataSize);
216     mPubKeyNumber = (UINT32) (DataSize / sizeof (AUTHVAR_KEY_DB_DATA));
217   }
218 
219   //
220   // Init Secure Boot variables
221   //
222   Status = InitSecureBootVariables ();
223 
224 
225   //
226   // Create "SignatureSupport" variable with BS+RT attribute set.
227   //
228   Status  = AuthServiceInternalUpdateVariable (
229               EFI_SIGNATURE_SUPPORT_NAME,
230               &gEfiGlobalVariableGuid,
231               mSignatureSupport,
232               sizeof(mSignatureSupport),
233               EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS
234               );
235   if (EFI_ERROR (Status)) {
236     return Status;
237   }
238 
239   //
240   // Initialize "CustomMode" in STANDARD_SECURE_BOOT_MODE state.
241   //
242   CustomMode = STANDARD_SECURE_BOOT_MODE;
243   Status = AuthServiceInternalUpdateVariable (
244              EFI_CUSTOM_MODE_NAME,
245              &gEfiCustomModeEnableGuid,
246              &CustomMode,
247              sizeof (UINT8),
248              EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
249              );
250   if (EFI_ERROR (Status)) {
251     return Status;
252   }
253 
254   DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_CUSTOM_MODE_NAME, CustomMode));
255 
256   //
257   // Check "certdb" variable's existence.
258   // If it doesn't exist, then create a new one with
259   // EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set.
260   //
261   Status = AuthServiceInternalFindVariable (
262              EFI_CERT_DB_NAME,
263              &gEfiCertDbGuid,
264              (VOID **) &Data,
265              &DataSize
266              );
267   if (EFI_ERROR (Status)) {
268     VarAttr  = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
269     ListSize = sizeof (UINT32);
270     Status   = AuthServiceInternalUpdateVariable (
271                  EFI_CERT_DB_NAME,
272                  &gEfiCertDbGuid,
273                  &ListSize,
274                  sizeof (UINT32),
275                  VarAttr
276                  );
277     if (EFI_ERROR (Status)) {
278       return Status;
279     }
280   } else {
281     //
282     // Clean up Certs to make certDB & Time based auth variable consistent
283     //
284     Status = CleanCertsFromDb();
285     if (EFI_ERROR (Status)) {
286       DEBUG ((EFI_D_ERROR, "Clean up CertDB fail! Status %x\n", Status));
287       return Status;
288     }
289   }
290 
291   //
292   // Check "VendorKeysNv" variable's existence and create "VendorKeys" variable accordingly.
293   //
294   Status = AuthServiceInternalFindVariable (EFI_VENDOR_KEYS_NV_VARIABLE_NAME, &gEfiVendorKeysNvGuid, (VOID **) &Data, &DataSize);
295   if (!EFI_ERROR (Status)) {
296     mVendorKeyState = *(UINT8 *)Data;
297   } else {
298     //
299     // "VendorKeysNv" not exist, initialize it in VENDOR_KEYS_VALID state.
300     //
301     mVendorKeyState = VENDOR_KEYS_VALID;
302     Status = AuthServiceInternalUpdateVariable (
303                EFI_VENDOR_KEYS_NV_VARIABLE_NAME,
304                &gEfiVendorKeysNvGuid,
305                &mVendorKeyState,
306                sizeof (UINT8),
307                EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
308                );
309     if (EFI_ERROR (Status)) {
310       return Status;
311     }
312   }
313 
314   //
315   // Create "VendorKeys" variable with BS+RT attribute set.
316   //
317   Status = AuthServiceInternalUpdateVariable (
318              EFI_VENDOR_KEYS_VARIABLE_NAME,
319              &gEfiGlobalVariableGuid,
320              &mVendorKeyState,
321              sizeof (UINT8),
322              EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS
323              );
324   if (EFI_ERROR (Status)) {
325     return Status;
326   }
327 
328   DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_VENDOR_KEYS_VARIABLE_NAME, mVendorKeyState));
329 
330   AuthVarLibContextOut->StructVersion = AUTH_VAR_LIB_CONTEXT_OUT_STRUCT_VERSION;
331   AuthVarLibContextOut->StructSize = sizeof (AUTH_VAR_LIB_CONTEXT_OUT);
332   AuthVarLibContextOut->AuthVarEntry = mAuthVarEntry;
333   AuthVarLibContextOut->AuthVarEntryCount = sizeof (mAuthVarEntry) / sizeof (mAuthVarEntry[0]);
334   mAuthVarAddressPointer[0] = (VOID **) &mPubKeyStore;
335   mAuthVarAddressPointer[1] = (VOID **) &mCertDbStore;
336   mAuthVarAddressPointer[2] = (VOID **) &mHashCtx;
337   mAuthVarAddressPointer[3] = (VOID **) &mAuthVarLibContextIn;
338   mAuthVarAddressPointer[4] = (VOID **) &(mAuthVarLibContextIn->FindVariable),
339   mAuthVarAddressPointer[5] = (VOID **) &(mAuthVarLibContextIn->FindNextVariable),
340   mAuthVarAddressPointer[6] = (VOID **) &(mAuthVarLibContextIn->UpdateVariable),
341   mAuthVarAddressPointer[7] = (VOID **) &(mAuthVarLibContextIn->GetScratchBuffer),
342   mAuthVarAddressPointer[8] = (VOID **) &(mAuthVarLibContextIn->CheckRemainingSpaceForConsistency),
343   mAuthVarAddressPointer[9] = (VOID **) &(mAuthVarLibContextIn->AtRuntime),
344   AuthVarLibContextOut->AddressPointer = mAuthVarAddressPointer;
345   AuthVarLibContextOut->AddressPointerCount = sizeof (mAuthVarAddressPointer) / sizeof (mAuthVarAddressPointer[0]);
346 
347   return Status;
348 }
349 
350 /**
351   Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set.
352 
353   @param[in] VariableName           Name of the variable.
354   @param[in] VendorGuid             Variable vendor GUID.
355   @param[in] Data                   Data pointer.
356   @param[in] DataSize               Size of Data.
357   @param[in] Attributes             Attribute value of the variable.
358 
359   @retval EFI_SUCCESS               The firmware has successfully stored the variable and its data as
360                                     defined by the Attributes.
361   @retval EFI_INVALID_PARAMETER     Invalid parameter.
362   @retval EFI_WRITE_PROTECTED       Variable is write-protected.
363   @retval EFI_OUT_OF_RESOURCES      There is not enough resource.
364   @retval EFI_SECURITY_VIOLATION    The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
365                                     or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS
366                                     set, but the AuthInfo does NOT pass the validation
367                                     check carried out by the firmware.
368   @retval EFI_UNSUPPORTED           Unsupported to process authenticated variable.
369 
370 **/
371 EFI_STATUS
372 EFIAPI
AuthVariableLibProcessVariable(IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid,IN VOID * Data,IN UINTN DataSize,IN UINT32 Attributes)373 AuthVariableLibProcessVariable (
374   IN CHAR16         *VariableName,
375   IN EFI_GUID       *VendorGuid,
376   IN VOID           *Data,
377   IN UINTN          DataSize,
378   IN UINT32         Attributes
379   )
380 {
381   EFI_STATUS        Status;
382 
383   //
384   // Process PK, KEK, Sigdb, AuditMode, DeployedMode separately.
385   //
386   if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0)){
387     Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, Attributes, TRUE);
388   } else if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0)) {
389     Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, Attributes, FALSE);
390   } else if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)
391           && (StrCmp (VariableName, EFI_AUDIT_MODE_NAME) == 0 || StrCmp (VariableName, EFI_DEPLOYED_MODE_NAME) == 0)) {
392     Status = ProcessSecureBootModeVar(VariableName, VendorGuid, Data, DataSize, Attributes);
393   } else if (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&
394              ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE)  == 0) ||
395               (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) ||
396               (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0)
397              )) {
398     Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, Attributes, FALSE);
399     if (EFI_ERROR (Status)) {
400       Status = ProcessVarWithKek (VariableName, VendorGuid, Data, DataSize, Attributes);
401     }
402   } else {
403     Status = ProcessVariable (VariableName, VendorGuid, Data, DataSize, Attributes);
404   }
405 
406   return Status;
407 }
408