| 1 | /** @file\r |
| 2 | Implement authentication services for the authenticated variables.\r |
| 3 | \r |
| 4 | Caution: This module requires additional review when modified.\r |
| 5 | This driver will have external input - variable data. It may be input in SMM mode.\r |
| 6 | This external input must be validated carefully to avoid security issue like\r |
| 7 | buffer overflow, integer overflow.\r |
| 8 | Variable attribute should also be checked to avoid authentication bypass.\r |
| 9 | The whole SMM authentication variable design relies on the integrity of flash part and SMM.\r |
| 10 | which is assumed to be protected by platform. All variable code and metadata in flash/SMM Memory\r |
| 11 | may not be modified without authorization. If platform fails to protect these resources,\r |
| 12 | the authentication service provided in this driver will be broken, and the behavior is undefined.\r |
| 13 | \r |
| 14 | ProcessVarWithPk(), ProcessVarWithKek() and ProcessVariable() are the function to do\r |
| 15 | variable authentication.\r |
| 16 | \r |
| 17 | VerifyTimeBasedPayloadAndUpdate() and VerifyCounterBasedPayload() are sub function to do verification.\r |
| 18 | They will do basic validation for authentication data structure, then call crypto library\r |
| 19 | to verify the signature.\r |
| 20 | \r |
| 21 | Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>\r |
| 22 | This program and the accompanying materials\r |
| 23 | are licensed and made available under the terms and conditions of the BSD License\r |
| 24 | which accompanies this distribution. The full text of the license may be found at\r |
| 25 | http://opensource.org/licenses/bsd-license.php\r |
| 26 | \r |
| 27 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r |
| 28 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r |
| 29 | \r |
| 30 | **/\r |
| 31 | \r |
| 32 | #include "AuthServiceInternal.h"\r |
| 33 | \r |
| 34 | //\r |
| 35 | // Public Exponent of RSA Key.\r |
| 36 | //\r |
| 37 | CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };\r |
| 38 | \r |
| 39 | CONST UINT8 mSha256OidValue[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 };\r |
| 40 | \r |
| 41 | //\r |
| 42 | // Requirement for different signature type which have been defined in UEFI spec.\r |
| 43 | // These data are used to perform SignatureList format check while setting PK/KEK variable.\r |
| 44 | //\r |
| 45 | EFI_SIGNATURE_ITEM mSupportSigItem[] = {\r |
| 46 | //{SigType, SigHeaderSize, SigDataSize }\r |
| 47 | {EFI_CERT_SHA256_GUID, 0, 32 },\r |
| 48 | {EFI_CERT_RSA2048_GUID, 0, 256 },\r |
| 49 | {EFI_CERT_RSA2048_SHA256_GUID, 0, 256 },\r |
| 50 | {EFI_CERT_SHA1_GUID, 0, 20 },\r |
| 51 | {EFI_CERT_RSA2048_SHA1_GUID, 0, 256 },\r |
| 52 | {EFI_CERT_X509_GUID, 0, ((UINT32) ~0)},\r |
| 53 | {EFI_CERT_SHA224_GUID, 0, 28 },\r |
| 54 | {EFI_CERT_SHA384_GUID, 0, 48 },\r |
| 55 | {EFI_CERT_SHA512_GUID, 0, 64 },\r |
| 56 | {EFI_CERT_X509_SHA256_GUID, 0, 48 },\r |
| 57 | {EFI_CERT_X509_SHA384_GUID, 0, 64 },\r |
| 58 | {EFI_CERT_X509_SHA512_GUID, 0, 80 }\r |
| 59 | };\r |
| 60 | \r |
| 61 | /**\r |
| 62 | Finds variable in storage blocks of volatile and non-volatile storage areas.\r |
| 63 | \r |
| 64 | This code finds variable in storage blocks of volatile and non-volatile storage areas.\r |
| 65 | If VariableName is an empty string, then we just return the first\r |
| 66 | qualified variable without comparing VariableName and VendorGuid.\r |
| 67 | \r |
| 68 | @param[in] VariableName Name of the variable to be found.\r |
| 69 | @param[in] VendorGuid Variable vendor GUID to be found.\r |
| 70 | @param[out] Data Pointer to data address.\r |
| 71 | @param[out] DataSize Pointer to data size.\r |
| 72 | \r |
| 73 | @retval EFI_INVALID_PARAMETER If VariableName is not an empty string,\r |
| 74 | while VendorGuid is NULL.\r |
| 75 | @retval EFI_SUCCESS Variable successfully found.\r |
| 76 | @retval EFI_NOT_FOUND Variable not found\r |
| 77 | \r |
| 78 | **/\r |
| 79 | EFI_STATUS\r |
| 80 | AuthServiceInternalFindVariable (\r |
| 81 | IN CHAR16 *VariableName,\r |
| 82 | IN EFI_GUID *VendorGuid,\r |
| 83 | OUT VOID **Data,\r |
| 84 | OUT UINTN *DataSize\r |
| 85 | )\r |
| 86 | {\r |
| 87 | EFI_STATUS Status;\r |
| 88 | AUTH_VARIABLE_INFO AuthVariableInfo;\r |
| 89 | \r |
| 90 | ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));\r |
| 91 | Status = mAuthVarLibContextIn->FindVariable (\r |
| 92 | VariableName,\r |
| 93 | VendorGuid,\r |
| 94 | &AuthVariableInfo\r |
| 95 | );\r |
| 96 | *Data = AuthVariableInfo.Data;\r |
| 97 | *DataSize = AuthVariableInfo.DataSize;\r |
| 98 | return Status;\r |
| 99 | }\r |
| 100 | \r |
| 101 | /**\r |
| 102 | Update the variable region with Variable information.\r |
| 103 | \r |
| 104 | @param[in] VariableName Name of variable.\r |
| 105 | @param[in] VendorGuid Guid of variable.\r |
| 106 | @param[in] Data Data pointer.\r |
| 107 | @param[in] DataSize Size of Data.\r |
| 108 | @param[in] Attributes Attribute value of the variable.\r |
| 109 | \r |
| 110 | @retval EFI_SUCCESS The update operation is success.\r |
| 111 | @retval EFI_INVALID_PARAMETER Invalid parameter.\r |
| 112 | @retval EFI_WRITE_PROTECTED Variable is write-protected.\r |
| 113 | @retval EFI_OUT_OF_RESOURCES There is not enough resource.\r |
| 114 | \r |
| 115 | **/\r |
| 116 | EFI_STATUS\r |
| 117 | AuthServiceInternalUpdateVariable (\r |
| 118 | IN CHAR16 *VariableName,\r |
| 119 | IN EFI_GUID *VendorGuid,\r |
| 120 | IN VOID *Data,\r |
| 121 | IN UINTN DataSize,\r |
| 122 | IN UINT32 Attributes\r |
| 123 | )\r |
| 124 | {\r |
| 125 | AUTH_VARIABLE_INFO AuthVariableInfo;\r |
| 126 | \r |
| 127 | ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));\r |
| 128 | AuthVariableInfo.VariableName = VariableName;\r |
| 129 | AuthVariableInfo.VendorGuid = VendorGuid;\r |
| 130 | AuthVariableInfo.Data = Data;\r |
| 131 | AuthVariableInfo.DataSize = DataSize;\r |
| 132 | AuthVariableInfo.Attributes = Attributes;\r |
| 133 | \r |
| 134 | return mAuthVarLibContextIn->UpdateVariable (\r |
| 135 | &AuthVariableInfo\r |
| 136 | );\r |
| 137 | }\r |
| 138 | \r |
| 139 | /**\r |
| 140 | Update the variable region with Variable information.\r |
| 141 | \r |
| 142 | @param[in] VariableName Name of variable.\r |
| 143 | @param[in] VendorGuid Guid of variable.\r |
| 144 | @param[in] Data Data pointer.\r |
| 145 | @param[in] DataSize Size of Data.\r |
| 146 | @param[in] Attributes Attribute value of the variable.\r |
| 147 | @param[in] KeyIndex Index of associated public key.\r |
| 148 | @param[in] MonotonicCount Value of associated monotonic count.\r |
| 149 | \r |
| 150 | @retval EFI_SUCCESS The update operation is success.\r |
| 151 | @retval EFI_INVALID_PARAMETER Invalid parameter.\r |
| 152 | @retval EFI_WRITE_PROTECTED Variable is write-protected.\r |
| 153 | @retval EFI_OUT_OF_RESOURCES There is not enough resource.\r |
| 154 | \r |
| 155 | **/\r |
| 156 | EFI_STATUS\r |
| 157 | AuthServiceInternalUpdateVariableWithMonotonicCount (\r |
| 158 | IN CHAR16 *VariableName,\r |
| 159 | IN EFI_GUID *VendorGuid,\r |
| 160 | IN VOID *Data,\r |
| 161 | IN UINTN DataSize,\r |
| 162 | IN UINT32 Attributes,\r |
| 163 | IN UINT32 KeyIndex,\r |
| 164 | IN UINT64 MonotonicCount\r |
| 165 | )\r |
| 166 | {\r |
| 167 | AUTH_VARIABLE_INFO AuthVariableInfo;\r |
| 168 | \r |
| 169 | ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));\r |
| 170 | AuthVariableInfo.VariableName = VariableName;\r |
| 171 | AuthVariableInfo.VendorGuid = VendorGuid;\r |
| 172 | AuthVariableInfo.Data = Data;\r |
| 173 | AuthVariableInfo.DataSize = DataSize;\r |
| 174 | AuthVariableInfo.Attributes = Attributes;\r |
| 175 | AuthVariableInfo.PubKeyIndex = KeyIndex;\r |
| 176 | AuthVariableInfo.MonotonicCount = MonotonicCount;\r |
| 177 | \r |
| 178 | return mAuthVarLibContextIn->UpdateVariable (\r |
| 179 | &AuthVariableInfo\r |
| 180 | );\r |
| 181 | }\r |
| 182 | \r |
| 183 | /**\r |
| 184 | Update the variable region with Variable information.\r |
| 185 | \r |
| 186 | @param[in] VariableName Name of variable.\r |
| 187 | @param[in] VendorGuid Guid of variable.\r |
| 188 | @param[in] Data Data pointer.\r |
| 189 | @param[in] DataSize Size of Data.\r |
| 190 | @param[in] Attributes Attribute value of the variable.\r |
| 191 | @param[in] TimeStamp Value of associated TimeStamp.\r |
| 192 | \r |
| 193 | @retval EFI_SUCCESS The update operation is success.\r |
| 194 | @retval EFI_INVALID_PARAMETER Invalid parameter.\r |
| 195 | @retval EFI_WRITE_PROTECTED Variable is write-protected.\r |
| 196 | @retval EFI_OUT_OF_RESOURCES There is not enough resource.\r |
| 197 | \r |
| 198 | **/\r |
| 199 | EFI_STATUS\r |
| 200 | AuthServiceInternalUpdateVariableWithTimeStamp (\r |
| 201 | IN CHAR16 *VariableName,\r |
| 202 | IN EFI_GUID *VendorGuid,\r |
| 203 | IN VOID *Data,\r |
| 204 | IN UINTN DataSize,\r |
| 205 | IN UINT32 Attributes,\r |
| 206 | IN EFI_TIME *TimeStamp\r |
| 207 | )\r |
| 208 | {\r |
| 209 | EFI_STATUS FindStatus;\r |
| 210 | VOID *OrgData;\r |
| 211 | UINTN OrgDataSize;\r |
| 212 | AUTH_VARIABLE_INFO AuthVariableInfo;\r |
| 213 | \r |
| 214 | FindStatus = AuthServiceInternalFindVariable (\r |
| 215 | VariableName,\r |
| 216 | VendorGuid,\r |
| 217 | &OrgData,\r |
| 218 | &OrgDataSize\r |
| 219 | );\r |
| 220 | \r |
| 221 | //\r |
| 222 | // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable\r |
| 223 | //\r |
| 224 | if (!EFI_ERROR (FindStatus) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0)) {\r |
| 225 | if ((CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&\r |
| 226 | ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) ||\r |
| 227 | (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0))) ||\r |
| 228 | (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0))) {\r |
| 229 | //\r |
| 230 | // For variables with formatted as EFI_SIGNATURE_LIST, the driver shall not perform an append of\r |
| 231 | // EFI_SIGNATURE_DATA values that are already part of the existing variable value.\r |
| 232 | //\r |
| 233 | FilterSignatureList (\r |
| 234 | OrgData,\r |
| 235 | OrgDataSize,\r |
| 236 | Data,\r |
| 237 | &DataSize\r |
| 238 | );\r |
| 239 | }\r |
| 240 | }\r |
| 241 | \r |
| 242 | ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));\r |
| 243 | AuthVariableInfo.VariableName = VariableName;\r |
| 244 | AuthVariableInfo.VendorGuid = VendorGuid;\r |
| 245 | AuthVariableInfo.Data = Data;\r |
| 246 | AuthVariableInfo.DataSize = DataSize;\r |
| 247 | AuthVariableInfo.Attributes = Attributes;\r |
| 248 | AuthVariableInfo.TimeStamp = TimeStamp;\r |
| 249 | return mAuthVarLibContextIn->UpdateVariable (\r |
| 250 | &AuthVariableInfo\r |
| 251 | );\r |
| 252 | }\r |
| 253 | \r |
| 254 | /**\r |
| 255 | Determine whether this operation needs a physical present user.\r |
| 256 | \r |
| 257 | @param[in] VariableName Name of the Variable.\r |
| 258 | @param[in] VendorGuid GUID of the Variable.\r |
| 259 | \r |
| 260 | @retval TRUE This variable is protected, only a physical present user could set this variable.\r |
| 261 | @retval FALSE This variable is not protected.\r |
| 262 | \r |
| 263 | **/\r |
| 264 | BOOLEAN\r |
| 265 | NeedPhysicallyPresent(\r |
| 266 | IN CHAR16 *VariableName,\r |
| 267 | IN EFI_GUID *VendorGuid\r |
| 268 | )\r |
| 269 | {\r |
| 270 | if ((CompareGuid (VendorGuid, &gEfiSecureBootEnableDisableGuid) && (StrCmp (VariableName, EFI_SECURE_BOOT_ENABLE_NAME) == 0))\r |
| 271 | || (CompareGuid (VendorGuid, &gEfiCustomModeEnableGuid) && (StrCmp (VariableName, EFI_CUSTOM_MODE_NAME) == 0))) {\r |
| 272 | return TRUE;\r |
| 273 | }\r |
| 274 | \r |
| 275 | return FALSE;\r |
| 276 | }\r |
| 277 | \r |
| 278 | /**\r |
| 279 | Determine whether the platform is operating in Custom Secure Boot mode.\r |
| 280 | \r |
| 281 | @retval TRUE The platform is operating in Custom mode.\r |
| 282 | @retval FALSE The platform is operating in Standard mode.\r |
| 283 | \r |
| 284 | **/\r |
| 285 | BOOLEAN\r |
| 286 | InCustomMode (\r |
| 287 | VOID\r |
| 288 | )\r |
| 289 | {\r |
| 290 | EFI_STATUS Status;\r |
| 291 | VOID *Data;\r |
| 292 | UINTN DataSize;\r |
| 293 | \r |
| 294 | Status = AuthServiceInternalFindVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, &Data, &DataSize);\r |
| 295 | if (!EFI_ERROR (Status) && (*(UINT8 *) Data == CUSTOM_SECURE_BOOT_MODE)) {\r |
| 296 | return TRUE;\r |
| 297 | }\r |
| 298 | \r |
| 299 | return FALSE;\r |
| 300 | }\r |
| 301 | \r |
| 302 | /**\r |
| 303 | Get available public key index.\r |
| 304 | \r |
| 305 | @param[in] PubKey Pointer to Public Key data.\r |
| 306 | \r |
| 307 | @return Public key index, 0 if no any public key index available.\r |
| 308 | \r |
| 309 | **/\r |
| 310 | UINT32\r |
| 311 | GetAvailableKeyIndex (\r |
| 312 | IN UINT8 *PubKey\r |
| 313 | )\r |
| 314 | {\r |
| 315 | EFI_STATUS Status;\r |
| 316 | UINT8 *Data;\r |
| 317 | UINTN DataSize;\r |
| 318 | UINT8 *Ptr;\r |
| 319 | UINT32 Index;\r |
| 320 | BOOLEAN IsFound;\r |
| 321 | EFI_GUID VendorGuid;\r |
| 322 | CHAR16 Name[1];\r |
| 323 | AUTH_VARIABLE_INFO AuthVariableInfo;\r |
| 324 | UINT32 KeyIndex;\r |
| 325 | \r |
| 326 | Status = AuthServiceInternalFindVariable (\r |
| 327 | AUTHVAR_KEYDB_NAME,\r |
| 328 | &gEfiAuthenticatedVariableGuid,\r |
| 329 | (VOID **) &Data,\r |
| 330 | &DataSize\r |
| 331 | );\r |
| 332 | if (EFI_ERROR (Status)) {\r |
| 333 | DEBUG ((EFI_D_ERROR, "Get public key database variable failure, Status = %r\n", Status));\r |
| 334 | return 0;\r |
| 335 | }\r |
| 336 | \r |
| 337 | if (mPubKeyNumber == mMaxKeyNumber) {\r |
| 338 | Name[0] = 0;\r |
| 339 | AuthVariableInfo.VariableName = Name;\r |
| 340 | ZeroMem (&VendorGuid, sizeof (VendorGuid));\r |
| 341 | AuthVariableInfo.VendorGuid = &VendorGuid;\r |
| 342 | mPubKeyNumber = 0;\r |
| 343 | //\r |
| 344 | // Collect valid key data.\r |
| 345 | //\r |
| 346 | do {\r |
| 347 | Status = mAuthVarLibContextIn->FindNextVariable (AuthVariableInfo.VariableName, AuthVariableInfo.VendorGuid, &AuthVariableInfo);\r |
| 348 | if (!EFI_ERROR (Status)) {\r |
| 349 | if (AuthVariableInfo.PubKeyIndex != 0) {\r |
| 350 | for (Ptr = Data; Ptr < (Data + DataSize); Ptr += sizeof (AUTHVAR_KEY_DB_DATA)) {\r |
| 351 | if (ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) Ptr)->KeyIndex)) == AuthVariableInfo.PubKeyIndex) {\r |
| 352 | //\r |
| 353 | // Check if the key data has been collected.\r |
| 354 | //\r |
| 355 | for (Index = 0; Index < mPubKeyNumber; Index++) {\r |
| 356 | if (ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyIndex)) == AuthVariableInfo.PubKeyIndex) {\r |
| 357 | break;\r |
| 358 | }\r |
| 359 | }\r |
| 360 | if (Index == mPubKeyNumber) {\r |
| 361 | //\r |
| 362 | // New key data.\r |
| 363 | //\r |
| 364 | CopyMem ((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + mPubKeyNumber, Ptr, sizeof (AUTHVAR_KEY_DB_DATA));\r |
| 365 | mPubKeyNumber++;\r |
| 366 | }\r |
| 367 | break;\r |
| 368 | }\r |
| 369 | }\r |
| 370 | }\r |
| 371 | }\r |
| 372 | } while (Status != EFI_NOT_FOUND);\r |
| 373 | \r |
| 374 | //\r |
| 375 | // No available space to add new public key.\r |
| 376 | //\r |
| 377 | if (mPubKeyNumber == mMaxKeyNumber) {\r |
| 378 | return 0;\r |
| 379 | }\r |
| 380 | }\r |
| 381 | \r |
| 382 | //\r |
| 383 | // Find available public key index.\r |
| 384 | //\r |
| 385 | for (KeyIndex = 1; KeyIndex <= mMaxKeyNumber; KeyIndex++) {\r |
| 386 | IsFound = FALSE;\r |
| 387 | for (Ptr = mPubKeyStore; Ptr < (mPubKeyStore + mPubKeyNumber * sizeof (AUTHVAR_KEY_DB_DATA)); Ptr += sizeof (AUTHVAR_KEY_DB_DATA)) {\r |
| 388 | if (ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) Ptr)->KeyIndex)) == KeyIndex) {\r |
| 389 | IsFound = TRUE;\r |
| 390 | break;\r |
| 391 | }\r |
| 392 | }\r |
| 393 | if (!IsFound) {\r |
| 394 | break;\r |
| 395 | }\r |
| 396 | }\r |
| 397 | \r |
| 398 | return KeyIndex;\r |
| 399 | }\r |
| 400 | \r |
| 401 | /**\r |
| 402 | Add public key in store and return its index.\r |
| 403 | \r |
| 404 | @param[in] PubKey Input pointer to Public Key data.\r |
| 405 | @param[in] VariableDataEntry The variable data entry.\r |
| 406 | \r |
| 407 | @return Index of new added public key.\r |
| 408 | \r |
| 409 | **/\r |
| 410 | UINT32\r |
| 411 | AddPubKeyInStore (\r |
| 412 | IN UINT8 *PubKey,\r |
| 413 | IN VARIABLE_ENTRY_CONSISTENCY *VariableDataEntry\r |
| 414 | )\r |
| 415 | {\r |
| 416 | EFI_STATUS Status;\r |
| 417 | UINT32 Index;\r |
| 418 | VARIABLE_ENTRY_CONSISTENCY PublicKeyEntry;\r |
| 419 | UINT32 Attributes;\r |
| 420 | UINT32 KeyIndex;\r |
| 421 | \r |
| 422 | if (PubKey == NULL) {\r |
| 423 | return 0;\r |
| 424 | }\r |
| 425 | \r |
| 426 | //\r |
| 427 | // Check whether the public key entry does exist.\r |
| 428 | //\r |
| 429 | for (Index = 0; Index < mPubKeyNumber; Index++) {\r |
| 430 | if (CompareMem (((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyData, PubKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {\r |
| 431 | return ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyIndex));\r |
| 432 | }\r |
| 433 | }\r |
| 434 | \r |
| 435 | KeyIndex = GetAvailableKeyIndex (PubKey);\r |
| 436 | if (KeyIndex == 0) {\r |
| 437 | return 0;\r |
| 438 | }\r |
| 439 | \r |
| 440 | //\r |
| 441 | // Check the variable space for both public key and variable data.\r |
| 442 | //\r |
| 443 | PublicKeyEntry.VariableSize = (mPubKeyNumber + 1) * sizeof (AUTHVAR_KEY_DB_DATA);\r |
| 444 | PublicKeyEntry.Guid = &gEfiAuthenticatedVariableGuid;\r |
| 445 | PublicKeyEntry.Name = AUTHVAR_KEYDB_NAME;\r |
| 446 | Attributes = VARIABLE_ATTRIBUTE_NV_BS_RT | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r |
| 447 | \r |
| 448 | if (!mAuthVarLibContextIn->CheckRemainingSpaceForConsistency (Attributes, &PublicKeyEntry, VariableDataEntry, NULL)) {\r |
| 449 | //\r |
| 450 | // No enough variable space.\r |
| 451 | //\r |
| 452 | return 0;\r |
| 453 | }\r |
| 454 | \r |
| 455 | WriteUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + mPubKeyNumber)->KeyIndex), KeyIndex);\r |
| 456 | CopyMem (((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + mPubKeyNumber)->KeyData, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);\r |
| 457 | mPubKeyNumber++;\r |
| 458 | \r |
| 459 | //\r |
| 460 | // Update public key database variable.\r |
| 461 | //\r |
| 462 | Status = AuthServiceInternalUpdateVariable (\r |
| 463 | AUTHVAR_KEYDB_NAME,\r |
| 464 | &gEfiAuthenticatedVariableGuid,\r |
| 465 | mPubKeyStore,\r |
| 466 | mPubKeyNumber * sizeof (AUTHVAR_KEY_DB_DATA),\r |
| 467 | Attributes\r |
| 468 | );\r |
| 469 | if (EFI_ERROR (Status)) {\r |
| 470 | DEBUG ((EFI_D_ERROR, "Update public key database variable failure, Status = %r\n", Status));\r |
| 471 | return 0;\r |
| 472 | }\r |
| 473 | \r |
| 474 | return KeyIndex;\r |
| 475 | }\r |
| 476 | \r |
| 477 | /**\r |
| 478 | Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256_GUID type.\r |
| 479 | Follow the steps in UEFI2.2.\r |
| 480 | \r |
| 481 | Caution: This function may receive untrusted input.\r |
| 482 | This function may be invoked in SMM mode, and datasize and data are external input.\r |
| 483 | This function will do basic validation, before parse the data.\r |
| 484 | This function will parse the authentication carefully to avoid security issues, like\r |
| 485 | buffer overflow, integer overflow.\r |
| 486 | \r |
| 487 | @param[in] Data Pointer to data with AuthInfo.\r |
| 488 | @param[in] DataSize Size of Data.\r |
| 489 | @param[in] PubKey Public key used for verification.\r |
| 490 | \r |
| 491 | @retval EFI_INVALID_PARAMETER Invalid parameter.\r |
| 492 | @retval EFI_SECURITY_VIOLATION If authentication failed.\r |
| 493 | @retval EFI_SUCCESS Authentication successful.\r |
| 494 | \r |
| 495 | **/\r |
| 496 | EFI_STATUS\r |
| 497 | VerifyCounterBasedPayload (\r |
| 498 | IN UINT8 *Data,\r |
| 499 | IN UINTN DataSize,\r |
| 500 | IN UINT8 *PubKey\r |
| 501 | )\r |
| 502 | {\r |
| 503 | BOOLEAN Status;\r |
| 504 | EFI_VARIABLE_AUTHENTICATION *CertData;\r |
| 505 | EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;\r |
| 506 | UINT8 Digest[SHA256_DIGEST_SIZE];\r |
| 507 | VOID *Rsa;\r |
| 508 | UINTN PayloadSize;\r |
| 509 | \r |
| 510 | PayloadSize = DataSize - AUTHINFO_SIZE;\r |
| 511 | Rsa = NULL;\r |
| 512 | CertData = NULL;\r |
| 513 | CertBlock = NULL;\r |
| 514 | \r |
| 515 | if (Data == NULL || PubKey == NULL) {\r |
| 516 | return EFI_INVALID_PARAMETER;\r |
| 517 | }\r |
| 518 | \r |
| 519 | CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;\r |
| 520 | CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);\r |
| 521 | \r |
| 522 | //\r |
| 523 | // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.\r |
| 524 | // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256_GUID.\r |
| 525 | //\r |
| 526 | if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||\r |
| 527 | !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertTypeRsa2048Sha256Guid)) {\r |
| 528 | //\r |
| 529 | // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.\r |
| 530 | //\r |
| 531 | return EFI_SECURITY_VIOLATION;\r |
| 532 | }\r |
| 533 | //\r |
| 534 | // Hash data payload with SHA256.\r |
| 535 | //\r |
| 536 | ZeroMem (Digest, SHA256_DIGEST_SIZE);\r |
| 537 | Status = Sha256Init (mHashCtx);\r |
| 538 | if (!Status) {\r |
| 539 | goto Done;\r |
| 540 | }\r |
| 541 | Status = Sha256Update (mHashCtx, Data + AUTHINFO_SIZE, PayloadSize);\r |
| 542 | if (!Status) {\r |
| 543 | goto Done;\r |
| 544 | }\r |
| 545 | //\r |
| 546 | // Hash Size.\r |
| 547 | //\r |
| 548 | Status = Sha256Update (mHashCtx, &PayloadSize, sizeof (UINTN));\r |
| 549 | if (!Status) {\r |
| 550 | goto Done;\r |
| 551 | }\r |
| 552 | //\r |
| 553 | // Hash Monotonic Count.\r |
| 554 | //\r |
| 555 | Status = Sha256Update (mHashCtx, &CertData->MonotonicCount, sizeof (UINT64));\r |
| 556 | if (!Status) {\r |
| 557 | goto Done;\r |
| 558 | }\r |
| 559 | Status = Sha256Final (mHashCtx, Digest);\r |
| 560 | if (!Status) {\r |
| 561 | goto Done;\r |
| 562 | }\r |
| 563 | //\r |
| 564 | // Generate & Initialize RSA Context.\r |
| 565 | //\r |
| 566 | Rsa = RsaNew ();\r |
| 567 | ASSERT (Rsa != NULL);\r |
| 568 | //\r |
| 569 | // Set RSA Key Components.\r |
| 570 | // NOTE: Only N and E are needed to be set as RSA public key for signature verification.\r |
| 571 | //\r |
| 572 | Status = RsaSetKey (Rsa, RsaKeyN, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);\r |
| 573 | if (!Status) {\r |
| 574 | goto Done;\r |
| 575 | }\r |
| 576 | Status = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));\r |
| 577 | if (!Status) {\r |
| 578 | goto Done;\r |
| 579 | }\r |
| 580 | //\r |
| 581 | // Verify the signature.\r |
| 582 | //\r |
| 583 | Status = RsaPkcs1Verify (\r |
| 584 | Rsa,\r |
| 585 | Digest,\r |
| 586 | SHA256_DIGEST_SIZE,\r |
| 587 | CertBlock->Signature,\r |
| 588 | EFI_CERT_TYPE_RSA2048_SHA256_SIZE\r |
| 589 | );\r |
| 590 | \r |
| 591 | Done:\r |
| 592 | if (Rsa != NULL) {\r |
| 593 | RsaFree (Rsa);\r |
| 594 | }\r |
| 595 | if (Status) {\r |
| 596 | return EFI_SUCCESS;\r |
| 597 | } else {\r |
| 598 | return EFI_SECURITY_VIOLATION;\r |
| 599 | }\r |
| 600 | }\r |
| 601 | \r |
| 602 | /**\r |
| 603 | Update platform mode.\r |
| 604 | \r |
| 605 | @param[in] Mode SETUP_MODE or USER_MODE.\r |
| 606 | \r |
| 607 | @return EFI_INVALID_PARAMETER Invalid parameter.\r |
| 608 | @return EFI_SUCCESS Update platform mode successfully.\r |
| 609 | \r |
| 610 | **/\r |
| 611 | EFI_STATUS\r |
| 612 | UpdatePlatformMode (\r |
| 613 | IN UINT32 Mode\r |
| 614 | )\r |
| 615 | {\r |
| 616 | EFI_STATUS Status;\r |
| 617 | VOID *Data;\r |
| 618 | UINTN DataSize;\r |
| 619 | UINT8 SecureBootMode;\r |
| 620 | UINT8 SecureBootEnable;\r |
| 621 | UINTN VariableDataSize;\r |
| 622 | \r |
| 623 | Status = AuthServiceInternalFindVariable (\r |
| 624 | EFI_SETUP_MODE_NAME,\r |
| 625 | &gEfiGlobalVariableGuid,\r |
| 626 | &Data,\r |
| 627 | &DataSize\r |
| 628 | );\r |
| 629 | if (EFI_ERROR (Status)) {\r |
| 630 | return Status;\r |
| 631 | }\r |
| 632 | \r |
| 633 | //\r |
| 634 | // Update the value of SetupMode variable by a simple mem copy, this could avoid possible\r |
| 635 | // variable storage reclaim at runtime.\r |
| 636 | //\r |
| 637 | mPlatformMode = (UINT8) Mode;\r |
| 638 | CopyMem (Data, &mPlatformMode, sizeof(UINT8));\r |
| 639 | \r |
| 640 | if (mAuthVarLibContextIn->AtRuntime ()) {\r |
| 641 | //\r |
| 642 | // SecureBoot Variable indicates whether the platform firmware is operating\r |
| 643 | // in Secure boot mode (1) or not (0), so we should not change SecureBoot\r |
| 644 | // Variable in runtime.\r |
| 645 | //\r |
| 646 | return Status;\r |
| 647 | }\r |
| 648 | \r |
| 649 | //\r |
| 650 | // Check "SecureBoot" variable's existence.\r |
| 651 | // If it doesn't exist, firmware has no capability to perform driver signing verification,\r |
| 652 | // then set "SecureBoot" to 0.\r |
| 653 | //\r |
| 654 | Status = AuthServiceInternalFindVariable (\r |
| 655 | EFI_SECURE_BOOT_MODE_NAME,\r |
| 656 | &gEfiGlobalVariableGuid,\r |
| 657 | &Data,\r |
| 658 | &DataSize\r |
| 659 | );\r |
| 660 | //\r |
| 661 | // If "SecureBoot" variable exists, then check "SetupMode" variable update.\r |
| 662 | // If "SetupMode" variable is USER_MODE, "SecureBoot" variable is set to 1.\r |
| 663 | // If "SetupMode" variable is SETUP_MODE, "SecureBoot" variable is set to 0.\r |
| 664 | //\r |
| 665 | if (EFI_ERROR (Status)) {\r |
| 666 | SecureBootMode = SECURE_BOOT_MODE_DISABLE;\r |
| 667 | } else {\r |
| 668 | if (mPlatformMode == USER_MODE) {\r |
| 669 | SecureBootMode = SECURE_BOOT_MODE_ENABLE;\r |
| 670 | } else if (mPlatformMode == SETUP_MODE) {\r |
| 671 | SecureBootMode = SECURE_BOOT_MODE_DISABLE;\r |
| 672 | } else {\r |
| 673 | return EFI_NOT_FOUND;\r |
| 674 | }\r |
| 675 | }\r |
| 676 | \r |
| 677 | Status = AuthServiceInternalUpdateVariable (\r |
| 678 | EFI_SECURE_BOOT_MODE_NAME,\r |
| 679 | &gEfiGlobalVariableGuid,\r |
| 680 | &SecureBootMode,\r |
| 681 | sizeof(UINT8),\r |
| 682 | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS\r |
| 683 | );\r |
| 684 | if (EFI_ERROR (Status)) {\r |
| 685 | return Status;\r |
| 686 | }\r |
| 687 | \r |
| 688 | //\r |
| 689 | // Check "SecureBootEnable" variable's existence. It can enable/disable secure boot feature.\r |
| 690 | //\r |
| 691 | Status = AuthServiceInternalFindVariable (\r |
| 692 | EFI_SECURE_BOOT_ENABLE_NAME,\r |
| 693 | &gEfiSecureBootEnableDisableGuid,\r |
| 694 | &Data,\r |
| 695 | &DataSize\r |
| 696 | );\r |
| 697 | \r |
| 698 | if (SecureBootMode == SECURE_BOOT_MODE_ENABLE) {\r |
| 699 | //\r |
| 700 | // Create the "SecureBootEnable" variable as secure boot is enabled.\r |
| 701 | //\r |
| 702 | SecureBootEnable = SECURE_BOOT_ENABLE;\r |
| 703 | VariableDataSize = sizeof (SecureBootEnable);\r |
| 704 | } else {\r |
| 705 | //\r |
| 706 | // Delete the "SecureBootEnable" variable if this variable exist as "SecureBoot"\r |
| 707 | // variable is not in secure boot state.\r |
| 708 | //\r |
| 709 | if (EFI_ERROR (Status)) {\r |
| 710 | return EFI_SUCCESS;\r |
| 711 | }\r |
| 712 | SecureBootEnable = SECURE_BOOT_DISABLE;\r |
| 713 | VariableDataSize = 0;\r |
| 714 | }\r |
| 715 | \r |
| 716 | Status = AuthServiceInternalUpdateVariable (\r |
| 717 | EFI_SECURE_BOOT_ENABLE_NAME,\r |
| 718 | &gEfiSecureBootEnableDisableGuid,\r |
| 719 | &SecureBootEnable,\r |
| 720 | VariableDataSize,\r |
| 721 | EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS\r |
| 722 | );\r |
| 723 | return Status;\r |
| 724 | }\r |
| 725 | \r |
| 726 | /**\r |
| 727 | Check input data form to make sure it is a valid EFI_SIGNATURE_LIST for PK/KEK/db/dbx/dbt variable.\r |
| 728 | \r |
| 729 | @param[in] VariableName Name of Variable to be check.\r |
| 730 | @param[in] VendorGuid Variable vendor GUID.\r |
| 731 | @param[in] Data Point to the variable data to be checked.\r |
| 732 | @param[in] DataSize Size of Data.\r |
| 733 | \r |
| 734 | @return EFI_INVALID_PARAMETER Invalid signature list format.\r |
| 735 | @return EFI_SUCCESS Passed signature list format check successfully.\r |
| 736 | \r |
| 737 | **/\r |
| 738 | EFI_STATUS\r |
| 739 | CheckSignatureListFormat(\r |
| 740 | IN CHAR16 *VariableName,\r |
| 741 | IN EFI_GUID *VendorGuid,\r |
| 742 | IN VOID *Data,\r |
| 743 | IN UINTN DataSize\r |
| 744 | )\r |
| 745 | {\r |
| 746 | EFI_SIGNATURE_LIST *SigList;\r |
| 747 | UINTN SigDataSize;\r |
| 748 | UINT32 Index;\r |
| 749 | UINT32 SigCount;\r |
| 750 | BOOLEAN IsPk;\r |
| 751 | VOID *RsaContext;\r |
| 752 | EFI_SIGNATURE_DATA *CertData;\r |
| 753 | UINTN CertLen;\r |
| 754 | \r |
| 755 | if (DataSize == 0) {\r |
| 756 | return EFI_SUCCESS;\r |
| 757 | }\r |
| 758 | \r |
| 759 | ASSERT (VariableName != NULL && VendorGuid != NULL && Data != NULL);\r |
| 760 | \r |
| 761 | if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0)){\r |
| 762 | IsPk = TRUE;\r |
| 763 | } else if ((CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0)) ||\r |
| 764 | (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&\r |
| 765 | ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) ||\r |
| 766 | (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0)))) {\r |
| 767 | IsPk = FALSE;\r |
| 768 | } else {\r |
| 769 | return EFI_SUCCESS;\r |
| 770 | }\r |
| 771 | \r |
| 772 | SigCount = 0;\r |
| 773 | SigList = (EFI_SIGNATURE_LIST *) Data;\r |
| 774 | SigDataSize = DataSize;\r |
| 775 | RsaContext = NULL;\r |
| 776 | \r |
| 777 | //\r |
| 778 | // Walk throuth the input signature list and check the data format.\r |
| 779 | // If any signature is incorrectly formed, the whole check will fail.\r |
| 780 | //\r |
| 781 | while ((SigDataSize > 0) && (SigDataSize >= SigList->SignatureListSize)) {\r |
| 782 | for (Index = 0; Index < (sizeof (mSupportSigItem) / sizeof (EFI_SIGNATURE_ITEM)); Index++ ) {\r |
| 783 | if (CompareGuid (&SigList->SignatureType, &mSupportSigItem[Index].SigType)) {\r |
| 784 | //\r |
| 785 | // The value of SignatureSize should always be 16 (size of SignatureOwner\r |
| 786 | // component) add the data length according to signature type.\r |
| 787 | //\r |
| 788 | if (mSupportSigItem[Index].SigDataSize != ((UINT32) ~0) &&\r |
| 789 | (SigList->SignatureSize - sizeof (EFI_GUID)) != mSupportSigItem[Index].SigDataSize) {\r |
| 790 | return EFI_INVALID_PARAMETER;\r |
| 791 | }\r |
| 792 | if (mSupportSigItem[Index].SigHeaderSize != ((UINT32) ~0) &&\r |
| 793 | SigList->SignatureHeaderSize != mSupportSigItem[Index].SigHeaderSize) {\r |
| 794 | return EFI_INVALID_PARAMETER;\r |
| 795 | }\r |
| 796 | break;\r |
| 797 | }\r |
| 798 | }\r |
| 799 | \r |
| 800 | if (Index == (sizeof (mSupportSigItem) / sizeof (EFI_SIGNATURE_ITEM))) {\r |
| 801 | //\r |
| 802 | // Undefined signature type.\r |
| 803 | //\r |
| 804 | return EFI_INVALID_PARAMETER;\r |
| 805 | }\r |
| 806 | \r |
| 807 | if (CompareGuid (&SigList->SignatureType, &gEfiCertX509Guid)) {\r |
| 808 | //\r |
| 809 | // Try to retrieve the RSA public key from the X.509 certificate.\r |
| 810 | // If this operation fails, it's not a valid certificate.\r |
| 811 | //\r |
| 812 | RsaContext = RsaNew ();\r |
| 813 | if (RsaContext == NULL) {\r |
| 814 | return EFI_INVALID_PARAMETER;\r |
| 815 | }\r |
| 816 | CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) + SigList->SignatureHeaderSize);\r |
| 817 | CertLen = SigList->SignatureSize - sizeof (EFI_GUID);\r |
| 818 | if (!RsaGetPublicKeyFromX509 (CertData->SignatureData, CertLen, &RsaContext)) {\r |
| 819 | RsaFree (RsaContext);\r |
| 820 | return EFI_INVALID_PARAMETER;\r |
| 821 | }\r |
| 822 | RsaFree (RsaContext);\r |
| 823 | }\r |
| 824 | \r |
| 825 | if ((SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) % SigList->SignatureSize != 0) {\r |
| 826 | return EFI_INVALID_PARAMETER;\r |
| 827 | }\r |
| 828 | SigCount += (SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) / SigList->SignatureSize;\r |
| 829 | \r |
| 830 | SigDataSize -= SigList->SignatureListSize;\r |
| 831 | SigList = (EFI_SIGNATURE_LIST *) ((UINT8 *) SigList + SigList->SignatureListSize);\r |
| 832 | }\r |
| 833 | \r |
| 834 | if (((UINTN) SigList - (UINTN) Data) != DataSize) {\r |
| 835 | return EFI_INVALID_PARAMETER;\r |
| 836 | }\r |
| 837 | \r |
| 838 | if (IsPk && SigCount > 1) {\r |
| 839 | return EFI_INVALID_PARAMETER;\r |
| 840 | }\r |
| 841 | \r |
| 842 | return EFI_SUCCESS;\r |
| 843 | }\r |
| 844 | \r |
| 845 | /**\r |
| 846 | Update "VendorKeys" variable to record the out of band secure boot key modification.\r |
| 847 | \r |
| 848 | @return EFI_SUCCESS Variable is updated successfully.\r |
| 849 | @return Others Failed to update variable.\r |
| 850 | \r |
| 851 | **/\r |
| 852 | EFI_STATUS\r |
| 853 | VendorKeyIsModified (\r |
| 854 | VOID\r |
| 855 | )\r |
| 856 | {\r |
| 857 | EFI_STATUS Status;\r |
| 858 | \r |
| 859 | if (mVendorKeyState == VENDOR_KEYS_MODIFIED) {\r |
| 860 | return EFI_SUCCESS;\r |
| 861 | }\r |
| 862 | mVendorKeyState = VENDOR_KEYS_MODIFIED;\r |
| 863 | \r |
| 864 | Status = AuthServiceInternalUpdateVariable (\r |
| 865 | EFI_VENDOR_KEYS_NV_VARIABLE_NAME,\r |
| 866 | &gEfiVendorKeysNvGuid,\r |
| 867 | &mVendorKeyState,\r |
| 868 | sizeof (UINT8),\r |
| 869 | EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS\r |
| 870 | );\r |
| 871 | if (EFI_ERROR (Status)) {\r |
| 872 | return Status;\r |
| 873 | }\r |
| 874 | \r |
| 875 | return AuthServiceInternalUpdateVariable (\r |
| 876 | EFI_VENDOR_KEYS_VARIABLE_NAME,\r |
| 877 | &gEfiGlobalVariableGuid,\r |
| 878 | &mVendorKeyState,\r |
| 879 | sizeof (UINT8),\r |
| 880 | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS\r |
| 881 | );\r |
| 882 | }\r |
| 883 | \r |
| 884 | /**\r |
| 885 | Process variable with platform key for verification.\r |
| 886 | \r |
| 887 | Caution: This function may receive untrusted input.\r |
| 888 | This function may be invoked in SMM mode, and datasize and data are external input.\r |
| 889 | This function will do basic validation, before parse the data.\r |
| 890 | This function will parse the authentication carefully to avoid security issues, like\r |
| 891 | buffer overflow, integer overflow.\r |
| 892 | This function will check attribute carefully to avoid authentication bypass.\r |
| 893 | \r |
| 894 | @param[in] VariableName Name of Variable to be found.\r |
| 895 | @param[in] VendorGuid Variable vendor GUID.\r |
| 896 | @param[in] Data Data pointer.\r |
| 897 | @param[in] DataSize Size of Data found. If size is less than the\r |
| 898 | data, this value contains the required size.\r |
| 899 | @param[in] Attributes Attribute value of the variable\r |
| 900 | @param[in] IsPk Indicate whether it is to process pk.\r |
| 901 | \r |
| 902 | @return EFI_INVALID_PARAMETER Invalid parameter.\r |
| 903 | @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation.\r |
| 904 | check carried out by the firmware.\r |
| 905 | @return EFI_SUCCESS Variable passed validation successfully.\r |
| 906 | \r |
| 907 | **/\r |
| 908 | EFI_STATUS\r |
| 909 | ProcessVarWithPk (\r |
| 910 | IN CHAR16 *VariableName,\r |
| 911 | IN EFI_GUID *VendorGuid,\r |
| 912 | IN VOID *Data,\r |
| 913 | IN UINTN DataSize,\r |
| 914 | IN UINT32 Attributes OPTIONAL,\r |
| 915 | IN BOOLEAN IsPk\r |
| 916 | )\r |
| 917 | {\r |
| 918 | EFI_STATUS Status;\r |
| 919 | BOOLEAN Del;\r |
| 920 | UINT8 *Payload;\r |
| 921 | UINTN PayloadSize;\r |
| 922 | \r |
| 923 | if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0 ||\r |
| 924 | (Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) {\r |
| 925 | //\r |
| 926 | // PK, KEK and db/dbx/dbt should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based\r |
| 927 | // authenticated variable.\r |
| 928 | //\r |
| 929 | return EFI_INVALID_PARAMETER;\r |
| 930 | }\r |
| 931 | \r |
| 932 | //\r |
| 933 | // Init state of Del. State may change due to secure check\r |
| 934 | //\r |
| 935 | Del = FALSE;\r |
| 936 | if ((InCustomMode() && UserPhysicalPresent()) || (mPlatformMode == SETUP_MODE && !IsPk)) {\r |
| 937 | Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);\r |
| 938 | PayloadSize = DataSize - AUTHINFO2_SIZE (Data);\r |
| 939 | if (PayloadSize == 0) {\r |
| 940 | Del = TRUE;\r |
| 941 | }\r |
| 942 | \r |
| 943 | Status = CheckSignatureListFormat(VariableName, VendorGuid, Payload, PayloadSize);\r |
| 944 | if (EFI_ERROR (Status)) {\r |
| 945 | return Status;\r |
| 946 | }\r |
| 947 | \r |
| 948 | Status = AuthServiceInternalUpdateVariableWithTimeStamp (\r |
| 949 | VariableName,\r |
| 950 | VendorGuid,\r |
| 951 | Payload,\r |
| 952 | PayloadSize,\r |
| 953 | Attributes,\r |
| 954 | &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp\r |
| 955 | );\r |
| 956 | if (EFI_ERROR(Status)) {\r |
| 957 | return Status;\r |
| 958 | }\r |
| 959 | \r |
| 960 | if ((mPlatformMode != SETUP_MODE) || IsPk) {\r |
| 961 | Status = VendorKeyIsModified ();\r |
| 962 | }\r |
| 963 | } else if (mPlatformMode == USER_MODE) {\r |
| 964 | //\r |
| 965 | // Verify against X509 Cert in PK database.\r |
| 966 | //\r |
| 967 | Status = VerifyTimeBasedPayloadAndUpdate (\r |
| 968 | VariableName,\r |
| 969 | VendorGuid,\r |
| 970 | Data,\r |
| 971 | DataSize,\r |
| 972 | Attributes,\r |
| 973 | AuthVarTypePk,\r |
| 974 | &Del\r |
| 975 | );\r |
| 976 | } else {\r |
| 977 | //\r |
| 978 | // Verify against the certificate in data payload.\r |
| 979 | //\r |
| 980 | Status = VerifyTimeBasedPayloadAndUpdate (\r |
| 981 | VariableName,\r |
| 982 | VendorGuid,\r |
| 983 | Data,\r |
| 984 | DataSize,\r |
| 985 | Attributes,\r |
| 986 | AuthVarTypePayload,\r |
| 987 | &Del\r |
| 988 | );\r |
| 989 | }\r |
| 990 | \r |
| 991 | if (!EFI_ERROR(Status) && IsPk) {\r |
| 992 | if (mPlatformMode == SETUP_MODE && !Del) {\r |
| 993 | //\r |
| 994 | // If enroll PK in setup mode, need change to user mode.\r |
| 995 | //\r |
| 996 | Status = UpdatePlatformMode (USER_MODE);\r |
| 997 | } else if (mPlatformMode == USER_MODE && Del){\r |
| 998 | //\r |
| 999 | // If delete PK in user mode, need change to setup mode.\r |
| 1000 | //\r |
| 1001 | Status = UpdatePlatformMode (SETUP_MODE);\r |
| 1002 | }\r |
| 1003 | }\r |
| 1004 | \r |
| 1005 | return Status;\r |
| 1006 | }\r |
| 1007 | \r |
| 1008 | /**\r |
| 1009 | Process variable with key exchange key for verification.\r |
| 1010 | \r |
| 1011 | Caution: This function may receive untrusted input.\r |
| 1012 | This function may be invoked in SMM mode, and datasize and data are external input.\r |
| 1013 | This function will do basic validation, before parse the data.\r |
| 1014 | This function will parse the authentication carefully to avoid security issues, like\r |
| 1015 | buffer overflow, integer overflow.\r |
| 1016 | This function will check attribute carefully to avoid authentication bypass.\r |
| 1017 | \r |
| 1018 | @param[in] VariableName Name of Variable to be found.\r |
| 1019 | @param[in] VendorGuid Variable vendor GUID.\r |
| 1020 | @param[in] Data Data pointer.\r |
| 1021 | @param[in] DataSize Size of Data found. If size is less than the\r |
| 1022 | data, this value contains the required size.\r |
| 1023 | @param[in] Attributes Attribute value of the variable.\r |
| 1024 | \r |
| 1025 | @return EFI_INVALID_PARAMETER Invalid parameter.\r |
| 1026 | @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation\r |
| 1027 | check carried out by the firmware.\r |
| 1028 | @return EFI_SUCCESS Variable pass validation successfully.\r |
| 1029 | \r |
| 1030 | **/\r |
| 1031 | EFI_STATUS\r |
| 1032 | ProcessVarWithKek (\r |
| 1033 | IN CHAR16 *VariableName,\r |
| 1034 | IN EFI_GUID *VendorGuid,\r |
| 1035 | IN VOID *Data,\r |
| 1036 | IN UINTN DataSize,\r |
| 1037 | IN UINT32 Attributes OPTIONAL\r |
| 1038 | )\r |
| 1039 | {\r |
| 1040 | EFI_STATUS Status;\r |
| 1041 | UINT8 *Payload;\r |
| 1042 | UINTN PayloadSize;\r |
| 1043 | \r |
| 1044 | if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0 ||\r |
| 1045 | (Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) {\r |
| 1046 | //\r |
| 1047 | // DB, DBX and DBT should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based\r |
| 1048 | // authenticated variable.\r |
| 1049 | //\r |
| 1050 | return EFI_INVALID_PARAMETER;\r |
| 1051 | }\r |
| 1052 | \r |
| 1053 | Status = EFI_SUCCESS;\r |
| 1054 | if (mPlatformMode == USER_MODE && !(InCustomMode() && UserPhysicalPresent())) {\r |
| 1055 | //\r |
| 1056 | // Time-based, verify against X509 Cert KEK.\r |
| 1057 | //\r |
| 1058 | return VerifyTimeBasedPayloadAndUpdate (\r |
| 1059 | VariableName,\r |
| 1060 | VendorGuid,\r |
| 1061 | Data,\r |
| 1062 | DataSize,\r |
| 1063 | Attributes,\r |
| 1064 | AuthVarTypeKek,\r |
| 1065 | NULL\r |
| 1066 | );\r |
| 1067 | } else {\r |
| 1068 | //\r |
| 1069 | // If in setup mode or custom secure boot mode, no authentication needed.\r |
| 1070 | //\r |
| 1071 | Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);\r |
| 1072 | PayloadSize = DataSize - AUTHINFO2_SIZE (Data);\r |
| 1073 | \r |
| 1074 | Status = CheckSignatureListFormat(VariableName, VendorGuid, Payload, PayloadSize);\r |
| 1075 | if (EFI_ERROR (Status)) {\r |
| 1076 | return Status;\r |
| 1077 | }\r |
| 1078 | \r |
| 1079 | Status = AuthServiceInternalUpdateVariableWithTimeStamp (\r |
| 1080 | VariableName,\r |
| 1081 | VendorGuid,\r |
| 1082 | Payload,\r |
| 1083 | PayloadSize,\r |
| 1084 | Attributes,\r |
| 1085 | &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp\r |
| 1086 | );\r |
| 1087 | if (EFI_ERROR (Status)) {\r |
| 1088 | return Status;\r |
| 1089 | }\r |
| 1090 | \r |
| 1091 | if (mPlatformMode != SETUP_MODE) {\r |
| 1092 | Status = VendorKeyIsModified ();\r |
| 1093 | }\r |
| 1094 | }\r |
| 1095 | \r |
| 1096 | return Status;\r |
| 1097 | }\r |
| 1098 | \r |
| 1099 | /**\r |
| 1100 | Check if it is to delete auth variable.\r |
| 1101 | \r |
| 1102 | @param[in] OrgAttributes Original attribute value of the variable.\r |
| 1103 | @param[in] Data Data pointer.\r |
| 1104 | @param[in] DataSize Size of Data.\r |
| 1105 | @param[in] Attributes Attribute value of the variable.\r |
| 1106 | \r |
| 1107 | @retval TRUE It is to delete auth variable.\r |
| 1108 | @retval FALSE It is not to delete auth variable.\r |
| 1109 | \r |
| 1110 | **/\r |
| 1111 | BOOLEAN\r |
| 1112 | IsDeleteAuthVariable (\r |
| 1113 | IN UINT32 OrgAttributes,\r |
| 1114 | IN VOID *Data,\r |
| 1115 | IN UINTN DataSize,\r |
| 1116 | IN UINT32 Attributes\r |
| 1117 | )\r |
| 1118 | {\r |
| 1119 | BOOLEAN Del;\r |
| 1120 | UINTN PayloadSize;\r |
| 1121 | \r |
| 1122 | Del = FALSE;\r |
| 1123 | \r |
| 1124 | //\r |
| 1125 | // To delete a variable created with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\r |
| 1126 | // or the EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute,\r |
| 1127 | // SetVariable must be used with attributes matching the existing variable\r |
| 1128 | // and the DataSize set to the size of the AuthInfo descriptor.\r |
| 1129 | //\r |
| 1130 | if ((Attributes == OrgAttributes) &&\r |
| 1131 | ((Attributes & (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) != 0)) {\r |
| 1132 | if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r |
| 1133 | PayloadSize = DataSize - AUTHINFO2_SIZE (Data);\r |
| 1134 | if (PayloadSize == 0) {\r |
| 1135 | Del = TRUE;\r |
| 1136 | }\r |
| 1137 | } else {\r |
| 1138 | PayloadSize = DataSize - AUTHINFO_SIZE;\r |
| 1139 | if (PayloadSize == 0) {\r |
| 1140 | Del = TRUE;\r |
| 1141 | }\r |
| 1142 | }\r |
| 1143 | }\r |
| 1144 | \r |
| 1145 | return Del;\r |
| 1146 | }\r |
| 1147 | \r |
| 1148 | /**\r |
| 1149 | Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set\r |
| 1150 | \r |
| 1151 | Caution: This function may receive untrusted input.\r |
| 1152 | This function may be invoked in SMM mode, and datasize and data are external input.\r |
| 1153 | This function will do basic validation, before parse the data.\r |
| 1154 | This function will parse the authentication carefully to avoid security issues, like\r |
| 1155 | buffer overflow, integer overflow.\r |
| 1156 | This function will check attribute carefully to avoid authentication bypass.\r |
| 1157 | \r |
| 1158 | @param[in] VariableName Name of the variable.\r |
| 1159 | @param[in] VendorGuid Variable vendor GUID.\r |
| 1160 | @param[in] Data Data pointer.\r |
| 1161 | @param[in] DataSize Size of Data.\r |
| 1162 | @param[in] Attributes Attribute value of the variable.\r |
| 1163 | \r |
| 1164 | @return EFI_INVALID_PARAMETER Invalid parameter.\r |
| 1165 | @return EFI_WRITE_PROTECTED Variable is write-protected and needs authentication with\r |
| 1166 | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r |
| 1167 | @return EFI_OUT_OF_RESOURCES The Database to save the public key is full.\r |
| 1168 | @return EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\r |
| 1169 | set, but the AuthInfo does NOT pass the validation\r |
| 1170 | check carried out by the firmware.\r |
| 1171 | @return EFI_SUCCESS Variable is not write-protected or pass validation successfully.\r |
| 1172 | \r |
| 1173 | **/\r |
| 1174 | EFI_STATUS\r |
| 1175 | ProcessVariable (\r |
| 1176 | IN CHAR16 *VariableName,\r |
| 1177 | IN EFI_GUID *VendorGuid,\r |
| 1178 | IN VOID *Data,\r |
| 1179 | IN UINTN DataSize,\r |
| 1180 | IN UINT32 Attributes\r |
| 1181 | )\r |
| 1182 | {\r |
| 1183 | EFI_STATUS Status;\r |
| 1184 | BOOLEAN IsDeletion;\r |
| 1185 | BOOLEAN IsFirstTime;\r |
| 1186 | UINT8 *PubKey;\r |
| 1187 | EFI_VARIABLE_AUTHENTICATION *CertData;\r |
| 1188 | EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;\r |
| 1189 | UINT32 KeyIndex;\r |
| 1190 | UINT64 MonotonicCount;\r |
| 1191 | VARIABLE_ENTRY_CONSISTENCY VariableDataEntry;\r |
| 1192 | UINT32 Index;\r |
| 1193 | AUTH_VARIABLE_INFO OrgVariableInfo;\r |
| 1194 | \r |
| 1195 | KeyIndex = 0;\r |
| 1196 | CertData = NULL;\r |
| 1197 | CertBlock = NULL;\r |
| 1198 | PubKey = NULL;\r |
| 1199 | IsDeletion = FALSE;\r |
| 1200 | Status = EFI_SUCCESS;\r |
| 1201 | \r |
| 1202 | ZeroMem (&OrgVariableInfo, sizeof (OrgVariableInfo));\r |
| 1203 | Status = mAuthVarLibContextIn->FindVariable (\r |
| 1204 | VariableName,\r |
| 1205 | VendorGuid,\r |
| 1206 | &OrgVariableInfo\r |
| 1207 | );\r |
| 1208 | \r |
| 1209 | if ((!EFI_ERROR (Status)) && IsDeleteAuthVariable (OrgVariableInfo.Attributes, Data, DataSize, Attributes) && UserPhysicalPresent()) {\r |
| 1210 | //\r |
| 1211 | // Allow the delete operation of common authenticated variable at user physical presence.\r |
| 1212 | //\r |
| 1213 | Status = AuthServiceInternalUpdateVariable (\r |
| 1214 | VariableName,\r |
| 1215 | VendorGuid,\r |
| 1216 | NULL,\r |
| 1217 | 0,\r |
| 1218 | 0\r |
| 1219 | );\r |
| 1220 | if (!EFI_ERROR (Status) && ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0)) {\r |
| 1221 | Status = DeleteCertsFromDb (VariableName, VendorGuid, Attributes);\r |
| 1222 | }\r |
| 1223 | \r |
| 1224 | return Status;\r |
| 1225 | }\r |
| 1226 | \r |
| 1227 | if (NeedPhysicallyPresent (VariableName, VendorGuid) && !UserPhysicalPresent()) {\r |
| 1228 | //\r |
| 1229 | // This variable is protected, only physical present user could modify its value.\r |
| 1230 | //\r |
| 1231 | return EFI_SECURITY_VIOLATION;\r |
| 1232 | }\r |
| 1233 | \r |
| 1234 | //\r |
| 1235 | // A time-based authenticated variable and a count-based authenticated variable\r |
| 1236 | // can't be updated by each other.\r |
| 1237 | //\r |
| 1238 | if (OrgVariableInfo.Data != NULL) {\r |
| 1239 | if (((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) &&\r |
| 1240 | ((OrgVariableInfo.Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0)) {\r |
| 1241 | return EFI_SECURITY_VIOLATION;\r |
| 1242 | }\r |
| 1243 | \r |
| 1244 | if (((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) &&\r |
| 1245 | ((OrgVariableInfo.Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0)) {\r |
| 1246 | return EFI_SECURITY_VIOLATION;\r |
| 1247 | }\r |
| 1248 | }\r |
| 1249 | \r |
| 1250 | //\r |
| 1251 | // Process Time-based Authenticated variable.\r |
| 1252 | //\r |
| 1253 | if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r |
| 1254 | return VerifyTimeBasedPayloadAndUpdate (\r |
| 1255 | VariableName,\r |
| 1256 | VendorGuid,\r |
| 1257 | Data,\r |
| 1258 | DataSize,\r |
| 1259 | Attributes,\r |
| 1260 | AuthVarTypePriv,\r |
| 1261 | NULL\r |
| 1262 | );\r |
| 1263 | }\r |
| 1264 | \r |
| 1265 | //\r |
| 1266 | // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.\r |
| 1267 | //\r |
| 1268 | if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r |
| 1269 | //\r |
| 1270 | // Determine current operation type.\r |
| 1271 | //\r |
| 1272 | if (DataSize == AUTHINFO_SIZE) {\r |
| 1273 | IsDeletion = TRUE;\r |
| 1274 | }\r |
| 1275 | //\r |
| 1276 | // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r |
| 1277 | //\r |
| 1278 | if (OrgVariableInfo.Data == NULL) {\r |
| 1279 | IsFirstTime = TRUE;\r |
| 1280 | } else if ((OrgVariableInfo.Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {\r |
| 1281 | IsFirstTime = TRUE;\r |
| 1282 | } else {\r |
| 1283 | KeyIndex = OrgVariableInfo.PubKeyIndex;\r |
| 1284 | IsFirstTime = FALSE;\r |
| 1285 | }\r |
| 1286 | } else if ((OrgVariableInfo.Data != NULL) &&\r |
| 1287 | ((OrgVariableInfo.Attributes & (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) != 0)\r |
| 1288 | ) {\r |
| 1289 | //\r |
| 1290 | // If the variable is already write-protected, it always needs authentication before update.\r |
| 1291 | //\r |
| 1292 | return EFI_WRITE_PROTECTED;\r |
| 1293 | } else {\r |
| 1294 | //\r |
| 1295 | // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision.\r |
| 1296 | // That means it is not authenticated variable, just update variable as usual.\r |
| 1297 | //\r |
| 1298 | Status = AuthServiceInternalUpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes);\r |
| 1299 | return Status;\r |
| 1300 | }\r |
| 1301 | \r |
| 1302 | //\r |
| 1303 | // Get PubKey and check Monotonic Count value corresponding to the variable.\r |
| 1304 | //\r |
| 1305 | CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;\r |
| 1306 | CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);\r |
| 1307 | PubKey = CertBlock->PublicKey;\r |
| 1308 | \r |
| 1309 | //\r |
| 1310 | // Update Monotonic Count value.\r |
| 1311 | //\r |
| 1312 | MonotonicCount = CertData->MonotonicCount;\r |
| 1313 | \r |
| 1314 | if (!IsFirstTime) {\r |
| 1315 | //\r |
| 1316 | // 2 cases need to check here\r |
| 1317 | // 1. Internal PubKey variable. PubKeyIndex is always 0\r |
| 1318 | // 2. Other counter-based AuthVariable. Check input PubKey.\r |
| 1319 | //\r |
| 1320 | if (KeyIndex == 0) {\r |
| 1321 | return EFI_SECURITY_VIOLATION;\r |
| 1322 | }\r |
| 1323 | for (Index = 0; Index < mPubKeyNumber; Index++) {\r |
| 1324 | if (ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyIndex)) == KeyIndex) {\r |
| 1325 | if (CompareMem (((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyData, PubKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {\r |
| 1326 | break;\r |
| 1327 | } else {\r |
| 1328 | return EFI_SECURITY_VIOLATION;\r |
| 1329 | }\r |
| 1330 | }\r |
| 1331 | }\r |
| 1332 | if (Index == mPubKeyNumber) {\r |
| 1333 | return EFI_SECURITY_VIOLATION;\r |
| 1334 | }\r |
| 1335 | \r |
| 1336 | //\r |
| 1337 | // Compare the current monotonic count and ensure that it is greater than the last SetVariable\r |
| 1338 | // operation with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute set.\r |
| 1339 | //\r |
| 1340 | if (MonotonicCount <= OrgVariableInfo.MonotonicCount) {\r |
| 1341 | //\r |
| 1342 | // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r |
| 1343 | //\r |
| 1344 | return EFI_SECURITY_VIOLATION;\r |
| 1345 | }\r |
| 1346 | }\r |
| 1347 | //\r |
| 1348 | // Verify the certificate in Data payload.\r |
| 1349 | //\r |
| 1350 | Status = VerifyCounterBasedPayload (Data, DataSize, PubKey);\r |
| 1351 | if (EFI_ERROR (Status)) {\r |
| 1352 | return Status;\r |
| 1353 | }\r |
| 1354 | \r |
| 1355 | //\r |
| 1356 | // Now, the signature has been verified!\r |
| 1357 | //\r |
| 1358 | if (IsFirstTime && !IsDeletion) {\r |
| 1359 | VariableDataEntry.VariableSize = DataSize - AUTHINFO_SIZE;\r |
| 1360 | VariableDataEntry.Guid = VendorGuid;\r |
| 1361 | VariableDataEntry.Name = VariableName;\r |
| 1362 | \r |
| 1363 | //\r |
| 1364 | // Update public key database variable if need.\r |
| 1365 | //\r |
| 1366 | KeyIndex = AddPubKeyInStore (PubKey, &VariableDataEntry);\r |
| 1367 | if (KeyIndex == 0) {\r |
| 1368 | return EFI_OUT_OF_RESOURCES;\r |
| 1369 | }\r |
| 1370 | }\r |
| 1371 | \r |
| 1372 | //\r |
| 1373 | // Verification pass.\r |
| 1374 | //\r |
| 1375 | return AuthServiceInternalUpdateVariableWithMonotonicCount (VariableName, VendorGuid, (UINT8*)Data + AUTHINFO_SIZE, DataSize - AUTHINFO_SIZE, Attributes, KeyIndex, MonotonicCount);\r |
| 1376 | }\r |
| 1377 | \r |
| 1378 | /**\r |
| 1379 | Filter out the duplicated EFI_SIGNATURE_DATA from the new data by comparing to the original data.\r |
| 1380 | \r |
| 1381 | @param[in] Data Pointer to original EFI_SIGNATURE_LIST.\r |
| 1382 | @param[in] DataSize Size of Data buffer.\r |
| 1383 | @param[in, out] NewData Pointer to new EFI_SIGNATURE_LIST.\r |
| 1384 | @param[in, out] NewDataSize Size of NewData buffer.\r |
| 1385 | \r |
| 1386 | **/\r |
| 1387 | EFI_STATUS\r |
| 1388 | FilterSignatureList (\r |
| 1389 | IN VOID *Data,\r |
| 1390 | IN UINTN DataSize,\r |
| 1391 | IN OUT VOID *NewData,\r |
| 1392 | IN OUT UINTN *NewDataSize\r |
| 1393 | )\r |
| 1394 | {\r |
| 1395 | EFI_SIGNATURE_LIST *CertList;\r |
| 1396 | EFI_SIGNATURE_DATA *Cert;\r |
| 1397 | UINTN CertCount;\r |
| 1398 | EFI_SIGNATURE_LIST *NewCertList;\r |
| 1399 | EFI_SIGNATURE_DATA *NewCert;\r |
| 1400 | UINTN NewCertCount;\r |
| 1401 | UINTN Index;\r |
| 1402 | UINTN Index2;\r |
| 1403 | UINTN Size;\r |
| 1404 | UINT8 *Tail;\r |
| 1405 | UINTN CopiedCount;\r |
| 1406 | UINTN SignatureListSize;\r |
| 1407 | BOOLEAN IsNewCert;\r |
| 1408 | UINT8 *TempData;\r |
| 1409 | UINTN TempDataSize;\r |
| 1410 | EFI_STATUS Status;\r |
| 1411 | \r |
| 1412 | if (*NewDataSize == 0) {\r |
| 1413 | return EFI_SUCCESS;\r |
| 1414 | }\r |
| 1415 | \r |
| 1416 | TempDataSize = *NewDataSize;\r |
| 1417 | Status = mAuthVarLibContextIn->GetScratchBuffer (&TempDataSize, (VOID **) &TempData);\r |
| 1418 | if (EFI_ERROR (Status)) {\r |
| 1419 | return EFI_OUT_OF_RESOURCES;\r |
| 1420 | }\r |
| 1421 | \r |
| 1422 | Tail = TempData;\r |
| 1423 | \r |
| 1424 | NewCertList = (EFI_SIGNATURE_LIST *) NewData;\r |
| 1425 | while ((*NewDataSize > 0) && (*NewDataSize >= NewCertList->SignatureListSize)) {\r |
| 1426 | NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCertList + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);\r |
| 1427 | NewCertCount = (NewCertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - NewCertList->SignatureHeaderSize) / NewCertList->SignatureSize;\r |
| 1428 | \r |
| 1429 | CopiedCount = 0;\r |
| 1430 | for (Index = 0; Index < NewCertCount; Index++) {\r |
| 1431 | IsNewCert = TRUE;\r |
| 1432 | \r |
| 1433 | Size = DataSize;\r |
| 1434 | CertList = (EFI_SIGNATURE_LIST *) Data;\r |
| 1435 | while ((Size > 0) && (Size >= CertList->SignatureListSize)) {\r |
| 1436 | if (CompareGuid (&CertList->SignatureType, &NewCertList->SignatureType) &&\r |
| 1437 | (CertList->SignatureSize == NewCertList->SignatureSize)) {\r |
| 1438 | Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r |
| 1439 | CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r |
| 1440 | for (Index2 = 0; Index2 < CertCount; Index2++) {\r |
| 1441 | //\r |
| 1442 | // Iterate each Signature Data in this Signature List.\r |
| 1443 | //\r |
| 1444 | if (CompareMem (NewCert, Cert, CertList->SignatureSize) == 0) {\r |
| 1445 | IsNewCert = FALSE;\r |
| 1446 | break;\r |
| 1447 | }\r |
| 1448 | Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r |
| 1449 | }\r |
| 1450 | }\r |
| 1451 | \r |
| 1452 | if (!IsNewCert) {\r |
| 1453 | break;\r |
| 1454 | }\r |
| 1455 | Size -= CertList->SignatureListSize;\r |
| 1456 | CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r |
| 1457 | }\r |
| 1458 | \r |
| 1459 | if (IsNewCert) {\r |
| 1460 | //\r |
| 1461 | // New EFI_SIGNATURE_DATA, keep it.\r |
| 1462 | //\r |
| 1463 | if (CopiedCount == 0) {\r |
| 1464 | //\r |
| 1465 | // Copy EFI_SIGNATURE_LIST header for only once.\r |
| 1466 | //\r |
| 1467 | CopyMem (Tail, NewCertList, sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);\r |
| 1468 | Tail = Tail + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize;\r |
| 1469 | }\r |
| 1470 | \r |
| 1471 | CopyMem (Tail, NewCert, NewCertList->SignatureSize);\r |
| 1472 | Tail += NewCertList->SignatureSize;\r |
| 1473 | CopiedCount++;\r |
| 1474 | }\r |
| 1475 | \r |
| 1476 | NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCert + NewCertList->SignatureSize);\r |
| 1477 | }\r |
| 1478 | \r |
| 1479 | //\r |
| 1480 | // Update SignatureListSize in the kept EFI_SIGNATURE_LIST.\r |
| 1481 | //\r |
| 1482 | if (CopiedCount != 0) {\r |
| 1483 | SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize + (CopiedCount * NewCertList->SignatureSize);\r |
| 1484 | CertList = (EFI_SIGNATURE_LIST *) (Tail - SignatureListSize);\r |
| 1485 | CertList->SignatureListSize = (UINT32) SignatureListSize;\r |
| 1486 | }\r |
| 1487 | \r |
| 1488 | *NewDataSize -= NewCertList->SignatureListSize;\r |
| 1489 | NewCertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) NewCertList + NewCertList->SignatureListSize);\r |
| 1490 | }\r |
| 1491 | \r |
| 1492 | TempDataSize = (Tail - (UINT8 *) TempData);\r |
| 1493 | \r |
| 1494 | CopyMem (NewData, TempData, TempDataSize);\r |
| 1495 | *NewDataSize = TempDataSize;\r |
| 1496 | \r |
| 1497 | return EFI_SUCCESS;\r |
| 1498 | }\r |
| 1499 | \r |
| 1500 | /**\r |
| 1501 | Compare two EFI_TIME data.\r |
| 1502 | \r |
| 1503 | \r |
| 1504 | @param FirstTime A pointer to the first EFI_TIME data.\r |
| 1505 | @param SecondTime A pointer to the second EFI_TIME data.\r |
| 1506 | \r |
| 1507 | @retval TRUE The FirstTime is not later than the SecondTime.\r |
| 1508 | @retval FALSE The FirstTime is later than the SecondTime.\r |
| 1509 | \r |
| 1510 | **/\r |
| 1511 | BOOLEAN\r |
| 1512 | AuthServiceInternalCompareTimeStamp (\r |
| 1513 | IN EFI_TIME *FirstTime,\r |
| 1514 | IN EFI_TIME *SecondTime\r |
| 1515 | )\r |
| 1516 | {\r |
| 1517 | if (FirstTime->Year != SecondTime->Year) {\r |
| 1518 | return (BOOLEAN) (FirstTime->Year < SecondTime->Year);\r |
| 1519 | } else if (FirstTime->Month != SecondTime->Month) {\r |
| 1520 | return (BOOLEAN) (FirstTime->Month < SecondTime->Month);\r |
| 1521 | } else if (FirstTime->Day != SecondTime->Day) {\r |
| 1522 | return (BOOLEAN) (FirstTime->Day < SecondTime->Day);\r |
| 1523 | } else if (FirstTime->Hour != SecondTime->Hour) {\r |
| 1524 | return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour);\r |
| 1525 | } else if (FirstTime->Minute != SecondTime->Minute) {\r |
| 1526 | return (BOOLEAN) (FirstTime->Minute < SecondTime->Minute);\r |
| 1527 | }\r |
| 1528 | \r |
| 1529 | return (BOOLEAN) (FirstTime->Second <= SecondTime->Second);\r |
| 1530 | }\r |
| 1531 | \r |
| 1532 | /**\r |
| 1533 | Calculate SHA256 digest of SignerCert CommonName + ToplevelCert tbsCertificate\r |
| 1534 | SignerCert and ToplevelCert are inside the signer certificate chain.\r |
| 1535 | \r |
| 1536 | @param[in] SignerCert A pointer to SignerCert data.\r |
| 1537 | @param[in] SignerCertSize Length of SignerCert data.\r |
| 1538 | @param[in] TopLevelCert A pointer to TopLevelCert data.\r |
| 1539 | @param[in] TopLevelCertSize Length of TopLevelCert data.\r |
| 1540 | @param[out] Sha256Digest Sha256 digest calculated.\r |
| 1541 | \r |
| 1542 | @return EFI_ABORTED Digest process failed.\r |
| 1543 | @return EFI_SUCCESS SHA256 Digest is succesfully calculated.\r |
| 1544 | \r |
| 1545 | **/\r |
| 1546 | EFI_STATUS\r |
| 1547 | CalculatePrivAuthVarSignChainSHA256Digest(\r |
| 1548 | IN UINT8 *SignerCert,\r |
| 1549 | IN UINTN SignerCertSize,\r |
| 1550 | IN UINT8 *TopLevelCert,\r |
| 1551 | IN UINTN TopLevelCertSize,\r |
| 1552 | OUT UINT8 *Sha256Digest\r |
| 1553 | )\r |
| 1554 | {\r |
| 1555 | UINT8 *TbsCert;\r |
| 1556 | UINTN TbsCertSize;\r |
| 1557 | UINT8 CertCommonName[128];\r |
| 1558 | UINTN CertCommonNameSize;\r |
| 1559 | BOOLEAN CryptoStatus;\r |
| 1560 | EFI_STATUS Status;\r |
| 1561 | \r |
| 1562 | CertCommonNameSize = sizeof(CertCommonName);\r |
| 1563 | \r |
| 1564 | //\r |
| 1565 | // Get SignerCert CommonName\r |
| 1566 | //\r |
| 1567 | Status = X509GetCommonName(SignerCert, SignerCertSize, CertCommonName, &CertCommonNameSize);\r |
| 1568 | if (EFI_ERROR(Status)) {\r |
| 1569 | DEBUG((DEBUG_INFO, "%a Get SignerCert CommonName failed with status %x\n", __FUNCTION__, Status));\r |
| 1570 | return EFI_ABORTED;\r |
| 1571 | }\r |
| 1572 | \r |
| 1573 | //\r |
| 1574 | // Get TopLevelCert tbsCertificate\r |
| 1575 | //\r |
| 1576 | if (!X509GetTBSCert(TopLevelCert, TopLevelCertSize, &TbsCert, &TbsCertSize)) {\r |
| 1577 | DEBUG((DEBUG_INFO, "%a Get Top-level Cert tbsCertificate failed!\n", __FUNCTION__));\r |
| 1578 | return EFI_ABORTED;\r |
| 1579 | }\r |
| 1580 | \r |
| 1581 | //\r |
| 1582 | // Digest SignerCert CN + TopLevelCert tbsCertificate\r |
| 1583 | //\r |
| 1584 | ZeroMem (Sha256Digest, SHA256_DIGEST_SIZE);\r |
| 1585 | CryptoStatus = Sha256Init (mHashCtx);\r |
| 1586 | if (!CryptoStatus) {\r |
| 1587 | return EFI_ABORTED;\r |
| 1588 | }\r |
| 1589 | \r |
| 1590 | //\r |
| 1591 | // '\0' is forced in CertCommonName. No overflow issue\r |
| 1592 | //\r |
| 1593 | CryptoStatus = Sha256Update (mHashCtx, CertCommonName, AsciiStrLen((CHAR8 *)CertCommonName));\r |
| 1594 | if (!CryptoStatus) {\r |
| 1595 | return EFI_ABORTED;\r |
| 1596 | }\r |
| 1597 | \r |
| 1598 | CryptoStatus = Sha256Update (mHashCtx, TbsCert, TbsCertSize);\r |
| 1599 | if (!CryptoStatus) {\r |
| 1600 | return EFI_ABORTED;\r |
| 1601 | }\r |
| 1602 | \r |
| 1603 | CryptoStatus = Sha256Final (mHashCtx, Sha256Digest);\r |
| 1604 | if (!CryptoStatus) {\r |
| 1605 | return EFI_ABORTED;\r |
| 1606 | }\r |
| 1607 | \r |
| 1608 | return EFI_SUCCESS;\r |
| 1609 | }\r |
| 1610 | \r |
| 1611 | /**\r |
| 1612 | Find matching signer's certificates for common authenticated variable\r |
| 1613 | by corresponding VariableName and VendorGuid from "certdb" or "certdbv".\r |
| 1614 | \r |
| 1615 | The data format of "certdb" or "certdbv":\r |
| 1616 | //\r |
| 1617 | // UINT32 CertDbListSize;\r |
| 1618 | // /// AUTH_CERT_DB_DATA Certs1[];\r |
| 1619 | // /// AUTH_CERT_DB_DATA Certs2[];\r |
| 1620 | // /// ...\r |
| 1621 | // /// AUTH_CERT_DB_DATA Certsn[];\r |
| 1622 | //\r |
| 1623 | \r |
| 1624 | @param[in] VariableName Name of authenticated Variable.\r |
| 1625 | @param[in] VendorGuid Vendor GUID of authenticated Variable.\r |
| 1626 | @param[in] Data Pointer to variable "certdb" or "certdbv".\r |
| 1627 | @param[in] DataSize Size of variable "certdb" or "certdbv".\r |
| 1628 | @param[out] CertOffset Offset of matching CertData, from starting of Data.\r |
| 1629 | @param[out] CertDataSize Length of CertData in bytes.\r |
| 1630 | @param[out] CertNodeOffset Offset of matching AUTH_CERT_DB_DATA , from\r |
| 1631 | starting of Data.\r |
| 1632 | @param[out] CertNodeSize Length of AUTH_CERT_DB_DATA in bytes.\r |
| 1633 | \r |
| 1634 | @retval EFI_INVALID_PARAMETER Any input parameter is invalid.\r |
| 1635 | @retval EFI_NOT_FOUND Fail to find matching certs.\r |
| 1636 | @retval EFI_SUCCESS Find matching certs and output parameters.\r |
| 1637 | \r |
| 1638 | **/\r |
| 1639 | EFI_STATUS\r |
| 1640 | FindCertsFromDb (\r |
| 1641 | IN CHAR16 *VariableName,\r |
| 1642 | IN EFI_GUID *VendorGuid,\r |
| 1643 | IN UINT8 *Data,\r |
| 1644 | IN UINTN DataSize,\r |
| 1645 | OUT UINT32 *CertOffset, OPTIONAL\r |
| 1646 | OUT UINT32 *CertDataSize, OPTIONAL\r |
| 1647 | OUT UINT32 *CertNodeOffset,OPTIONAL\r |
| 1648 | OUT UINT32 *CertNodeSize OPTIONAL\r |
| 1649 | )\r |
| 1650 | {\r |
| 1651 | UINT32 Offset;\r |
| 1652 | AUTH_CERT_DB_DATA *Ptr;\r |
| 1653 | UINT32 CertSize;\r |
| 1654 | UINT32 NameSize;\r |
| 1655 | UINT32 NodeSize;\r |
| 1656 | UINT32 CertDbListSize;\r |
| 1657 | \r |
| 1658 | if ((VariableName == NULL) || (VendorGuid == NULL) || (Data == NULL)) {\r |
| 1659 | return EFI_INVALID_PARAMETER;\r |
| 1660 | }\r |
| 1661 | \r |
| 1662 | //\r |
| 1663 | // Check whether DataSize matches recorded CertDbListSize.\r |
| 1664 | //\r |
| 1665 | if (DataSize < sizeof (UINT32)) {\r |
| 1666 | return EFI_INVALID_PARAMETER;\r |
| 1667 | }\r |
| 1668 | \r |
| 1669 | CertDbListSize = ReadUnaligned32 ((UINT32 *) Data);\r |
| 1670 | \r |
| 1671 | if (CertDbListSize != (UINT32) DataSize) {\r |
| 1672 | return EFI_INVALID_PARAMETER;\r |
| 1673 | }\r |
| 1674 | \r |
| 1675 | Offset = sizeof (UINT32);\r |
| 1676 | \r |
| 1677 | //\r |
| 1678 | // Get corresponding certificates by VendorGuid and VariableName.\r |
| 1679 | //\r |
| 1680 | while (Offset < (UINT32) DataSize) {\r |
| 1681 | Ptr = (AUTH_CERT_DB_DATA *) (Data + Offset);\r |
| 1682 | //\r |
| 1683 | // Check whether VendorGuid matches.\r |
| 1684 | //\r |
| 1685 | if (CompareGuid (&Ptr->VendorGuid, VendorGuid)) {\r |
| 1686 | NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);\r |
| 1687 | NameSize = ReadUnaligned32 (&Ptr->NameSize);\r |
| 1688 | CertSize = ReadUnaligned32 (&Ptr->CertDataSize);\r |
| 1689 | \r |
| 1690 | if (NodeSize != sizeof (EFI_GUID) + sizeof (UINT32) * 3 + CertSize +\r |
| 1691 | sizeof (CHAR16) * NameSize) {\r |
| 1692 | return EFI_INVALID_PARAMETER;\r |
| 1693 | }\r |
| 1694 | \r |
| 1695 | Offset = Offset + sizeof (EFI_GUID) + sizeof (UINT32) * 3;\r |
| 1696 | //\r |
| 1697 | // Check whether VariableName matches.\r |
| 1698 | //\r |
| 1699 | if ((NameSize == StrLen (VariableName)) &&\r |
| 1700 | (CompareMem (Data + Offset, VariableName, NameSize * sizeof (CHAR16)) == 0)) {\r |
| 1701 | Offset = Offset + NameSize * sizeof (CHAR16);\r |
| 1702 | \r |
| 1703 | if (CertOffset != NULL) {\r |
| 1704 | *CertOffset = Offset;\r |
| 1705 | }\r |
| 1706 | \r |
| 1707 | if (CertDataSize != NULL) {\r |
| 1708 | *CertDataSize = CertSize;\r |
| 1709 | }\r |
| 1710 | \r |
| 1711 | if (CertNodeOffset != NULL) {\r |
| 1712 | *CertNodeOffset = (UINT32) ((UINT8 *) Ptr - Data);\r |
| 1713 | }\r |
| 1714 | \r |
| 1715 | if (CertNodeSize != NULL) {\r |
| 1716 | *CertNodeSize = NodeSize;\r |
| 1717 | }\r |
| 1718 | \r |
| 1719 | return EFI_SUCCESS;\r |
| 1720 | } else {\r |
| 1721 | Offset = Offset + NameSize * sizeof (CHAR16) + CertSize;\r |
| 1722 | }\r |
| 1723 | } else {\r |
| 1724 | NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);\r |
| 1725 | Offset = Offset + NodeSize;\r |
| 1726 | }\r |
| 1727 | }\r |
| 1728 | \r |
| 1729 | return EFI_NOT_FOUND;\r |
| 1730 | }\r |
| 1731 | \r |
| 1732 | /**\r |
| 1733 | Retrieve signer's certificates for common authenticated variable\r |
| 1734 | by corresponding VariableName and VendorGuid from "certdb"\r |
| 1735 | or "certdbv" according to authenticated variable attributes.\r |
| 1736 | \r |
| 1737 | @param[in] VariableName Name of authenticated Variable.\r |
| 1738 | @param[in] VendorGuid Vendor GUID of authenticated Variable.\r |
| 1739 | @param[in] Attributes Attributes of authenticated variable.\r |
| 1740 | @param[out] CertData Pointer to signer's certificates.\r |
| 1741 | @param[out] CertDataSize Length of CertData in bytes.\r |
| 1742 | \r |
| 1743 | @retval EFI_INVALID_PARAMETER Any input parameter is invalid.\r |
| 1744 | @retval EFI_NOT_FOUND Fail to find "certdb"/"certdbv" or matching certs.\r |
| 1745 | @retval EFI_SUCCESS Get signer's certificates successfully.\r |
| 1746 | \r |
| 1747 | **/\r |
| 1748 | EFI_STATUS\r |
| 1749 | GetCertsFromDb (\r |
| 1750 | IN CHAR16 *VariableName,\r |
| 1751 | IN EFI_GUID *VendorGuid,\r |
| 1752 | IN UINT32 Attributes,\r |
| 1753 | OUT UINT8 **CertData,\r |
| 1754 | OUT UINT32 *CertDataSize\r |
| 1755 | )\r |
| 1756 | {\r |
| 1757 | EFI_STATUS Status;\r |
| 1758 | UINT8 *Data;\r |
| 1759 | UINTN DataSize;\r |
| 1760 | UINT32 CertOffset;\r |
| 1761 | CHAR16 *DbName;\r |
| 1762 | \r |
| 1763 | if ((VariableName == NULL) || (VendorGuid == NULL) || (CertData == NULL) || (CertDataSize == NULL)) {\r |
| 1764 | return EFI_INVALID_PARAMETER;\r |
| 1765 | }\r |
| 1766 | \r |
| 1767 | \r |
| 1768 | if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r |
| 1769 | //\r |
| 1770 | // Get variable "certdb".\r |
| 1771 | //\r |
| 1772 | DbName = EFI_CERT_DB_NAME;\r |
| 1773 | } else {\r |
| 1774 | //\r |
| 1775 | // Get variable "certdbv".\r |
| 1776 | //\r |
| 1777 | DbName = EFI_CERT_DB_VOLATILE_NAME;\r |
| 1778 | }\r |
| 1779 | \r |
| 1780 | //\r |
| 1781 | // Get variable "certdb" or "certdbv".\r |
| 1782 | //\r |
| 1783 | Status = AuthServiceInternalFindVariable (\r |
| 1784 | DbName,\r |
| 1785 | &gEfiCertDbGuid,\r |
| 1786 | (VOID **) &Data,\r |
| 1787 | &DataSize\r |
| 1788 | );\r |
| 1789 | if (EFI_ERROR (Status)) {\r |
| 1790 | return Status;\r |
| 1791 | }\r |
| 1792 | \r |
| 1793 | if ((DataSize == 0) || (Data == NULL)) {\r |
| 1794 | ASSERT (FALSE);\r |
| 1795 | return EFI_NOT_FOUND;\r |
| 1796 | }\r |
| 1797 | \r |
| 1798 | Status = FindCertsFromDb (\r |
| 1799 | VariableName,\r |
| 1800 | VendorGuid,\r |
| 1801 | Data,\r |
| 1802 | DataSize,\r |
| 1803 | &CertOffset,\r |
| 1804 | CertDataSize,\r |
| 1805 | NULL,\r |
| 1806 | NULL\r |
| 1807 | );\r |
| 1808 | \r |
| 1809 | if (EFI_ERROR (Status)) {\r |
| 1810 | return Status;\r |
| 1811 | }\r |
| 1812 | \r |
| 1813 | *CertData = Data + CertOffset;\r |
| 1814 | return EFI_SUCCESS;\r |
| 1815 | }\r |
| 1816 | \r |
| 1817 | /**\r |
| 1818 | Delete matching signer's certificates when deleting common authenticated\r |
| 1819 | variable by corresponding VariableName and VendorGuid from "certdb" or \r |
| 1820 | "certdbv" according to authenticated variable attributes.\r |
| 1821 | \r |
| 1822 | @param[in] VariableName Name of authenticated Variable.\r |
| 1823 | @param[in] VendorGuid Vendor GUID of authenticated Variable.\r |
| 1824 | @param[in] Attributes Attributes of authenticated variable.\r |
| 1825 | \r |
| 1826 | @retval EFI_INVALID_PARAMETER Any input parameter is invalid.\r |
| 1827 | @retval EFI_NOT_FOUND Fail to find "certdb"/"certdbv" or matching certs.\r |
| 1828 | @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.\r |
| 1829 | @retval EFI_SUCCESS The operation is completed successfully.\r |
| 1830 | \r |
| 1831 | **/\r |
| 1832 | EFI_STATUS\r |
| 1833 | DeleteCertsFromDb (\r |
| 1834 | IN CHAR16 *VariableName,\r |
| 1835 | IN EFI_GUID *VendorGuid,\r |
| 1836 | IN UINT32 Attributes\r |
| 1837 | )\r |
| 1838 | {\r |
| 1839 | EFI_STATUS Status;\r |
| 1840 | UINT8 *Data;\r |
| 1841 | UINTN DataSize;\r |
| 1842 | UINT32 VarAttr;\r |
| 1843 | UINT32 CertNodeOffset;\r |
| 1844 | UINT32 CertNodeSize;\r |
| 1845 | UINT8 *NewCertDb;\r |
| 1846 | UINT32 NewCertDbSize;\r |
| 1847 | CHAR16 *DbName;\r |
| 1848 | \r |
| 1849 | if ((VariableName == NULL) || (VendorGuid == NULL)) {\r |
| 1850 | return EFI_INVALID_PARAMETER;\r |
| 1851 | }\r |
| 1852 | \r |
| 1853 | if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r |
| 1854 | //\r |
| 1855 | // Get variable "certdb".\r |
| 1856 | //\r |
| 1857 | DbName = EFI_CERT_DB_NAME;\r |
| 1858 | VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r |
| 1859 | } else {\r |
| 1860 | //\r |
| 1861 | // Get variable "certdbv".\r |
| 1862 | //\r |
| 1863 | DbName = EFI_CERT_DB_VOLATILE_NAME;\r |
| 1864 | VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r |
| 1865 | }\r |
| 1866 | \r |
| 1867 | Status = AuthServiceInternalFindVariable (\r |
| 1868 | DbName,\r |
| 1869 | &gEfiCertDbGuid,\r |
| 1870 | (VOID **) &Data,\r |
| 1871 | &DataSize\r |
| 1872 | );\r |
| 1873 | \r |
| 1874 | if (EFI_ERROR (Status)) {\r |
| 1875 | return Status;\r |
| 1876 | }\r |
| 1877 | \r |
| 1878 | if ((DataSize == 0) || (Data == NULL)) {\r |
| 1879 | ASSERT (FALSE);\r |
| 1880 | return EFI_NOT_FOUND;\r |
| 1881 | }\r |
| 1882 | \r |
| 1883 | if (DataSize == sizeof (UINT32)) {\r |
| 1884 | //\r |
| 1885 | // There is no certs in "certdb" or "certdbv".\r |
| 1886 | //\r |
| 1887 | return EFI_SUCCESS;\r |
| 1888 | }\r |
| 1889 | \r |
| 1890 | //\r |
| 1891 | // Get corresponding cert node from "certdb" or "certdbv".\r |
| 1892 | //\r |
| 1893 | Status = FindCertsFromDb (\r |
| 1894 | VariableName,\r |
| 1895 | VendorGuid,\r |
| 1896 | Data,\r |
| 1897 | DataSize,\r |
| 1898 | NULL,\r |
| 1899 | NULL,\r |
| 1900 | &CertNodeOffset,\r |
| 1901 | &CertNodeSize\r |
| 1902 | );\r |
| 1903 | \r |
| 1904 | if (EFI_ERROR (Status)) {\r |
| 1905 | return Status;\r |
| 1906 | }\r |
| 1907 | \r |
| 1908 | if (DataSize < (CertNodeOffset + CertNodeSize)) {\r |
| 1909 | return EFI_NOT_FOUND;\r |
| 1910 | }\r |
| 1911 | \r |
| 1912 | //\r |
| 1913 | // Construct new data content of variable "certdb" or "certdbv".\r |
| 1914 | //\r |
| 1915 | NewCertDbSize = (UINT32) DataSize - CertNodeSize;\r |
| 1916 | NewCertDb = (UINT8*) mCertDbStore;\r |
| 1917 | \r |
| 1918 | //\r |
| 1919 | // Copy the DB entries before deleting node.\r |
| 1920 | //\r |
| 1921 | CopyMem (NewCertDb, Data, CertNodeOffset);\r |
| 1922 | //\r |
| 1923 | // Update CertDbListSize.\r |
| 1924 | //\r |
| 1925 | CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32));\r |
| 1926 | //\r |
| 1927 | // Copy the DB entries after deleting node.\r |
| 1928 | //\r |
| 1929 | if (DataSize > (CertNodeOffset + CertNodeSize)) {\r |
| 1930 | CopyMem (\r |
| 1931 | NewCertDb + CertNodeOffset,\r |
| 1932 | Data + CertNodeOffset + CertNodeSize,\r |
| 1933 | DataSize - CertNodeOffset - CertNodeSize\r |
| 1934 | );\r |
| 1935 | }\r |
| 1936 | \r |
| 1937 | //\r |
| 1938 | // Set "certdb" or "certdbv".\r |
| 1939 | //\r |
| 1940 | Status = AuthServiceInternalUpdateVariable (\r |
| 1941 | DbName,\r |
| 1942 | &gEfiCertDbGuid,\r |
| 1943 | NewCertDb,\r |
| 1944 | NewCertDbSize,\r |
| 1945 | VarAttr\r |
| 1946 | );\r |
| 1947 | \r |
| 1948 | return Status;\r |
| 1949 | }\r |
| 1950 | \r |
| 1951 | /**\r |
| 1952 | Insert signer's certificates for common authenticated variable with VariableName\r |
| 1953 | and VendorGuid in AUTH_CERT_DB_DATA to "certdb" or "certdbv" according to\r |
| 1954 | time based authenticated variable attributes. CertData is the SHA256 digest of\r |
| 1955 | SignerCert CommonName + TopLevelCert tbsCertificate.\r |
| 1956 | \r |
| 1957 | @param[in] VariableName Name of authenticated Variable.\r |
| 1958 | @param[in] VendorGuid Vendor GUID of authenticated Variable.\r |
| 1959 | @param[in] Attributes Attributes of authenticated variable.\r |
| 1960 | @param[in] SignerCert Signer certificate data.\r |
| 1961 | @param[in] SignerCertSize Length of signer certificate.\r |
| 1962 | @param[in] TopLevelCert Top-level certificate data.\r |
| 1963 | @param[in] TopLevelCertSize Length of top-level certificate.\r |
| 1964 | \r |
| 1965 | @retval EFI_INVALID_PARAMETER Any input parameter is invalid.\r |
| 1966 | @retval EFI_ACCESS_DENIED An AUTH_CERT_DB_DATA entry with same VariableName\r |
| 1967 | and VendorGuid already exists.\r |
| 1968 | @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.\r |
| 1969 | @retval EFI_SUCCESS Insert an AUTH_CERT_DB_DATA entry to "certdb" or "certdbv"\r |
| 1970 | \r |
| 1971 | **/\r |
| 1972 | EFI_STATUS\r |
| 1973 | InsertCertsToDb (\r |
| 1974 | IN CHAR16 *VariableName,\r |
| 1975 | IN EFI_GUID *VendorGuid,\r |
| 1976 | IN UINT32 Attributes,\r |
| 1977 | IN UINT8 *SignerCert,\r |
| 1978 | IN UINTN SignerCertSize,\r |
| 1979 | IN UINT8 *TopLevelCert,\r |
| 1980 | IN UINTN TopLevelCertSize\r |
| 1981 | )\r |
| 1982 | {\r |
| 1983 | EFI_STATUS Status;\r |
| 1984 | UINT8 *Data;\r |
| 1985 | UINTN DataSize;\r |
| 1986 | UINT32 VarAttr;\r |
| 1987 | UINT8 *NewCertDb;\r |
| 1988 | UINT32 NewCertDbSize;\r |
| 1989 | UINT32 CertNodeSize;\r |
| 1990 | UINT32 NameSize;\r |
| 1991 | UINT32 CertDataSize;\r |
| 1992 | AUTH_CERT_DB_DATA *Ptr;\r |
| 1993 | CHAR16 *DbName;\r |
| 1994 | UINT8 Sha256Digest[SHA256_DIGEST_SIZE];\r |
| 1995 | \r |
| 1996 | if ((VariableName == NULL) || (VendorGuid == NULL) || (SignerCert == NULL) ||(TopLevelCert == NULL)) {\r |
| 1997 | return EFI_INVALID_PARAMETER;\r |
| 1998 | }\r |
| 1999 | \r |
| 2000 | if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r |
| 2001 | //\r |
| 2002 | // Get variable "certdb".\r |
| 2003 | //\r |
| 2004 | DbName = EFI_CERT_DB_NAME;\r |
| 2005 | VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r |
| 2006 | } else {\r |
| 2007 | //\r |
| 2008 | // Get variable "certdbv".\r |
| 2009 | //\r |
| 2010 | DbName = EFI_CERT_DB_VOLATILE_NAME;\r |
| 2011 | VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r |
| 2012 | }\r |
| 2013 | \r |
| 2014 | //\r |
| 2015 | // Get variable "certdb" or "certdbv".\r |
| 2016 | //\r |
| 2017 | Status = AuthServiceInternalFindVariable (\r |
| 2018 | DbName,\r |
| 2019 | &gEfiCertDbGuid,\r |
| 2020 | (VOID **) &Data,\r |
| 2021 | &DataSize\r |
| 2022 | );\r |
| 2023 | if (EFI_ERROR (Status)) {\r |
| 2024 | return Status;\r |
| 2025 | }\r |
| 2026 | \r |
| 2027 | if ((DataSize == 0) || (Data == NULL)) {\r |
| 2028 | ASSERT (FALSE);\r |
| 2029 | return EFI_NOT_FOUND;\r |
| 2030 | }\r |
| 2031 | \r |
| 2032 | //\r |
| 2033 | // Find whether matching cert node already exists in "certdb" or "certdbv".\r |
| 2034 | // If yes return error.\r |
| 2035 | //\r |
| 2036 | Status = FindCertsFromDb (\r |
| 2037 | VariableName,\r |
| 2038 | VendorGuid,\r |
| 2039 | Data,\r |
| 2040 | DataSize,\r |
| 2041 | NULL,\r |
| 2042 | NULL,\r |
| 2043 | NULL,\r |
| 2044 | NULL\r |
| 2045 | );\r |
| 2046 | \r |
| 2047 | if (!EFI_ERROR (Status)) {\r |
| 2048 | ASSERT (FALSE);\r |
| 2049 | return EFI_ACCESS_DENIED;\r |
| 2050 | }\r |
| 2051 | \r |
| 2052 | //\r |
| 2053 | // Construct new data content of variable "certdb" or "certdbv".\r |
| 2054 | //\r |
| 2055 | NameSize = (UINT32) StrLen (VariableName);\r |
| 2056 | CertDataSize = sizeof(Sha256Digest);\r |
| 2057 | CertNodeSize = sizeof (AUTH_CERT_DB_DATA) + (UINT32) CertDataSize + NameSize * sizeof (CHAR16);\r |
| 2058 | NewCertDbSize = (UINT32) DataSize + CertNodeSize;\r |
| 2059 | if (NewCertDbSize > mMaxCertDbSize) {\r |
| 2060 | return EFI_OUT_OF_RESOURCES;\r |
| 2061 | }\r |
| 2062 | \r |
| 2063 | Status = CalculatePrivAuthVarSignChainSHA256Digest(\r |
| 2064 | SignerCert,\r |
| 2065 | SignerCertSize,\r |
| 2066 | TopLevelCert,\r |
| 2067 | TopLevelCertSize,\r |
| 2068 | Sha256Digest\r |
| 2069 | );\r |
| 2070 | if (EFI_ERROR (Status)) {\r |
| 2071 | return Status;\r |
| 2072 | }\r |
| 2073 | \r |
| 2074 | NewCertDb = (UINT8*) mCertDbStore;\r |
| 2075 | \r |
| 2076 | //\r |
| 2077 | // Copy the DB entries before inserting node.\r |
| 2078 | //\r |
| 2079 | CopyMem (NewCertDb, Data, DataSize);\r |
| 2080 | //\r |
| 2081 | // Update CertDbListSize.\r |
| 2082 | //\r |
| 2083 | CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32));\r |
| 2084 | //\r |
| 2085 | // Construct new cert node.\r |
| 2086 | //\r |
| 2087 | Ptr = (AUTH_CERT_DB_DATA *) (NewCertDb + DataSize);\r |
| 2088 | CopyGuid (&Ptr->VendorGuid, VendorGuid);\r |
| 2089 | CopyMem (&Ptr->CertNodeSize, &CertNodeSize, sizeof (UINT32));\r |
| 2090 | CopyMem (&Ptr->NameSize, &NameSize, sizeof (UINT32));\r |
| 2091 | CopyMem (&Ptr->CertDataSize, &CertDataSize, sizeof (UINT32));\r |
| 2092 | \r |
| 2093 | CopyMem (\r |
| 2094 | (UINT8 *) Ptr + sizeof (AUTH_CERT_DB_DATA),\r |
| 2095 | VariableName,\r |
| 2096 | NameSize * sizeof (CHAR16)\r |
| 2097 | );\r |
| 2098 | \r |
| 2099 | CopyMem (\r |
| 2100 | (UINT8 *) Ptr + sizeof (AUTH_CERT_DB_DATA) + NameSize * sizeof (CHAR16),\r |
| 2101 | Sha256Digest,\r |
| 2102 | CertDataSize\r |
| 2103 | );\r |
| 2104 | \r |
| 2105 | //\r |
| 2106 | // Set "certdb" or "certdbv".\r |
| 2107 | //\r |
| 2108 | Status = AuthServiceInternalUpdateVariable (\r |
| 2109 | DbName,\r |
| 2110 | &gEfiCertDbGuid,\r |
| 2111 | NewCertDb,\r |
| 2112 | NewCertDbSize,\r |
| 2113 | VarAttr\r |
| 2114 | );\r |
| 2115 | \r |
| 2116 | return Status;\r |
| 2117 | }\r |
| 2118 | \r |
| 2119 | /**\r |
| 2120 | Clean up signer's certificates for common authenticated variable\r |
| 2121 | by corresponding VariableName and VendorGuid from "certdb".\r |
| 2122 | System may break down during Timebased Variable update & certdb update,\r |
| 2123 | make them inconsistent, this function is called in AuthVariable Init\r |
| 2124 | to ensure consistency.\r |
| 2125 | \r |
| 2126 | @retval EFI_NOT_FOUND Fail to find variable "certdb".\r |
| 2127 | @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.\r |
| 2128 | @retval EFI_SUCCESS The operation is completed successfully.\r |
| 2129 | \r |
| 2130 | **/\r |
| 2131 | EFI_STATUS\r |
| 2132 | CleanCertsFromDb (\r |
| 2133 | VOID\r |
| 2134 | )\r |
| 2135 | {\r |
| 2136 | UINT32 Offset;\r |
| 2137 | AUTH_CERT_DB_DATA *Ptr;\r |
| 2138 | UINT32 NameSize;\r |
| 2139 | UINT32 NodeSize;\r |
| 2140 | CHAR16 *VariableName;\r |
| 2141 | EFI_STATUS Status;\r |
| 2142 | BOOLEAN CertCleaned;\r |
| 2143 | UINT8 *Data;\r |
| 2144 | UINTN DataSize;\r |
| 2145 | EFI_GUID AuthVarGuid;\r |
| 2146 | AUTH_VARIABLE_INFO AuthVariableInfo;\r |
| 2147 | \r |
| 2148 | Status = EFI_SUCCESS;\r |
| 2149 | \r |
| 2150 | //\r |
| 2151 | // Get corresponding certificates by VendorGuid and VariableName.\r |
| 2152 | //\r |
| 2153 | do {\r |
| 2154 | CertCleaned = FALSE;\r |
| 2155 | \r |
| 2156 | //\r |
| 2157 | // Get latest variable "certdb"\r |
| 2158 | //\r |
| 2159 | Status = AuthServiceInternalFindVariable (\r |
| 2160 | EFI_CERT_DB_NAME,\r |
| 2161 | &gEfiCertDbGuid,\r |
| 2162 | (VOID **) &Data,\r |
| 2163 | &DataSize\r |
| 2164 | );\r |
| 2165 | if (EFI_ERROR (Status)) {\r |
| 2166 | return Status;\r |
| 2167 | }\r |
| 2168 | \r |
| 2169 | if ((DataSize == 0) || (Data == NULL)) {\r |
| 2170 | ASSERT (FALSE);\r |
| 2171 | return EFI_NOT_FOUND;\r |
| 2172 | }\r |
| 2173 | \r |
| 2174 | Offset = sizeof (UINT32);\r |
| 2175 | \r |
| 2176 | while (Offset < (UINT32) DataSize) {\r |
| 2177 | Ptr = (AUTH_CERT_DB_DATA *) (Data + Offset);\r |
| 2178 | NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);\r |
| 2179 | NameSize = ReadUnaligned32 (&Ptr->NameSize);\r |
| 2180 | \r |
| 2181 | //\r |
| 2182 | // Get VarName tailed with '\0'\r |
| 2183 | //\r |
| 2184 | VariableName = AllocateZeroPool((NameSize + 1) * sizeof(CHAR16));\r |
| 2185 | if (VariableName == NULL) {\r |
| 2186 | return EFI_OUT_OF_RESOURCES;\r |
| 2187 | }\r |
| 2188 | CopyMem (VariableName, (UINT8 *) Ptr + sizeof (AUTH_CERT_DB_DATA), NameSize * sizeof(CHAR16));\r |
| 2189 | //\r |
| 2190 | // Keep VarGuid aligned\r |
| 2191 | //\r |
| 2192 | CopyMem (&AuthVarGuid, &Ptr->VendorGuid, sizeof(EFI_GUID));\r |
| 2193 | \r |
| 2194 | //\r |
| 2195 | // Find corresponding time auth variable\r |
| 2196 | //\r |
| 2197 | ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));\r |
| 2198 | Status = mAuthVarLibContextIn->FindVariable (\r |
| 2199 | VariableName,\r |
| 2200 | &AuthVarGuid,\r |
| 2201 | &AuthVariableInfo\r |
| 2202 | );\r |
| 2203 | \r |
| 2204 | if (EFI_ERROR(Status) || (AuthVariableInfo.Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) {\r |
| 2205 | Status = DeleteCertsFromDb(\r |
| 2206 | VariableName,\r |
| 2207 | &AuthVarGuid,\r |
| 2208 | AuthVariableInfo.Attributes\r |
| 2209 | );\r |
| 2210 | CertCleaned = TRUE;\r |
| 2211 | DEBUG((EFI_D_INFO, "Recovery!! Cert for Auth Variable %s Guid %g is removed for consistency\n", VariableName, &AuthVarGuid));\r |
| 2212 | FreePool(VariableName);\r |
| 2213 | break;\r |
| 2214 | }\r |
| 2215 | \r |
| 2216 | FreePool(VariableName);\r |
| 2217 | Offset = Offset + NodeSize;\r |
| 2218 | }\r |
| 2219 | } while (CertCleaned);\r |
| 2220 | \r |
| 2221 | return Status;\r |
| 2222 | }\r |
| 2223 | \r |
| 2224 | /**\r |
| 2225 | Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set\r |
| 2226 | \r |
| 2227 | Caution: This function may receive untrusted input.\r |
| 2228 | This function may be invoked in SMM mode, and datasize and data are external input.\r |
| 2229 | This function will do basic validation, before parse the data.\r |
| 2230 | This function will parse the authentication carefully to avoid security issues, like\r |
| 2231 | buffer overflow, integer overflow.\r |
| 2232 | \r |
| 2233 | @param[in] VariableName Name of Variable to be found.\r |
| 2234 | @param[in] VendorGuid Variable vendor GUID.\r |
| 2235 | @param[in] Data Data pointer.\r |
| 2236 | @param[in] DataSize Size of Data found. If size is less than the\r |
| 2237 | data, this value contains the required size.\r |
| 2238 | @param[in] Attributes Attribute value of the variable.\r |
| 2239 | @param[in] AuthVarType Verify against PK, KEK database, private database or certificate in data payload.\r |
| 2240 | @param[in] OrgTimeStamp Pointer to original time stamp,\r |
| 2241 | original variable is not found if NULL.\r |
| 2242 | @param[out] VarPayloadPtr Pointer to variable payload address.\r |
| 2243 | @param[out] VarPayloadSize Pointer to variable payload size.\r |
| 2244 | \r |
| 2245 | @retval EFI_INVALID_PARAMETER Invalid parameter.\r |
| 2246 | @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation\r |
| 2247 | check carried out by the firmware.\r |
| 2248 | @retval EFI_OUT_OF_RESOURCES Failed to process variable due to lack\r |
| 2249 | of resources.\r |
| 2250 | @retval EFI_SUCCESS Variable pass validation successfully.\r |
| 2251 | \r |
| 2252 | **/\r |
| 2253 | EFI_STATUS\r |
| 2254 | VerifyTimeBasedPayload (\r |
| 2255 | IN CHAR16 *VariableName,\r |
| 2256 | IN EFI_GUID *VendorGuid,\r |
| 2257 | IN VOID *Data,\r |
| 2258 | IN UINTN DataSize,\r |
| 2259 | IN UINT32 Attributes,\r |
| 2260 | IN AUTHVAR_TYPE AuthVarType,\r |
| 2261 | IN EFI_TIME *OrgTimeStamp,\r |
| 2262 | OUT UINT8 **VarPayloadPtr,\r |
| 2263 | OUT UINTN *VarPayloadSize\r |
| 2264 | )\r |
| 2265 | {\r |
| 2266 | EFI_VARIABLE_AUTHENTICATION_2 *CertData;\r |
| 2267 | UINT8 *SigData;\r |
| 2268 | UINT32 SigDataSize;\r |
| 2269 | UINT8 *PayloadPtr;\r |
| 2270 | UINTN PayloadSize;\r |
| 2271 | UINT32 Attr;\r |
| 2272 | BOOLEAN VerifyStatus;\r |
| 2273 | EFI_STATUS Status;\r |
| 2274 | EFI_SIGNATURE_LIST *CertList;\r |
| 2275 | EFI_SIGNATURE_DATA *Cert;\r |
| 2276 | UINTN Index;\r |
| 2277 | UINTN CertCount;\r |
| 2278 | UINT32 KekDataSize;\r |
| 2279 | UINT8 *NewData;\r |
| 2280 | UINTN NewDataSize;\r |
| 2281 | UINT8 *Buffer;\r |
| 2282 | UINTN Length;\r |
| 2283 | UINT8 *TopLevelCert;\r |
| 2284 | UINTN TopLevelCertSize;\r |
| 2285 | UINT8 *TrustedCert;\r |
| 2286 | UINTN TrustedCertSize;\r |
| 2287 | UINT8 *SignerCerts;\r |
| 2288 | UINTN CertStackSize;\r |
| 2289 | UINT8 *CertsInCertDb;\r |
| 2290 | UINT32 CertsSizeinDb;\r |
| 2291 | UINT8 Sha256Digest[SHA256_DIGEST_SIZE];\r |
| 2292 | \r |
| 2293 | //\r |
| 2294 | // 1. TopLevelCert is the top-level issuer certificate in signature Signer Cert Chain\r |
| 2295 | // 2. TrustedCert is the certificate which firmware trusts. It could be saved in protected\r |
| 2296 | // storage or PK payload on PK init\r |
| 2297 | //\r |
| 2298 | VerifyStatus = FALSE;\r |
| 2299 | CertData = NULL;\r |
| 2300 | NewData = NULL;\r |
| 2301 | Attr = Attributes;\r |
| 2302 | SignerCerts = NULL;\r |
| 2303 | TopLevelCert = NULL;\r |
| 2304 | CertsInCertDb = NULL;\r |
| 2305 | \r |
| 2306 | //\r |
| 2307 | // When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is\r |
| 2308 | // set, then the Data buffer shall begin with an instance of a complete (and serialized)\r |
| 2309 | // EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new\r |
| 2310 | // variable value and DataSize shall reflect the combined size of the descriptor and the new\r |
| 2311 | // variable value. The authentication descriptor is not part of the variable data and is not\r |
| 2312 | // returned by subsequent calls to GetVariable().\r |
| 2313 | //\r |
| 2314 | CertData = (EFI_VARIABLE_AUTHENTICATION_2 *) Data;\r |
| 2315 | \r |
| 2316 | //\r |
| 2317 | // Verify that Pad1, Nanosecond, TimeZone, Daylight and Pad2 components of the\r |
| 2318 | // TimeStamp value are set to zero.\r |
| 2319 | //\r |
| 2320 | if ((CertData->TimeStamp.Pad1 != 0) ||\r |
| 2321 | (CertData->TimeStamp.Nanosecond != 0) ||\r |
| 2322 | (CertData->TimeStamp.TimeZone != 0) ||\r |
| 2323 | (CertData->TimeStamp.Daylight != 0) ||\r |
| 2324 | (CertData->TimeStamp.Pad2 != 0)) {\r |
| 2325 | return EFI_SECURITY_VIOLATION;\r |
| 2326 | }\r |
| 2327 | \r |
| 2328 | if ((OrgTimeStamp != NULL) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {\r |
| 2329 | if (AuthServiceInternalCompareTimeStamp (&CertData->TimeStamp, OrgTimeStamp)) {\r |
| 2330 | //\r |
| 2331 | // TimeStamp check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r |
| 2332 | //\r |
| 2333 | return EFI_SECURITY_VIOLATION;\r |
| 2334 | }\r |
| 2335 | }\r |
| 2336 | \r |
| 2337 | //\r |
| 2338 | // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.\r |
| 2339 | // Cert type should be EFI_CERT_TYPE_PKCS7_GUID.\r |
| 2340 | //\r |
| 2341 | if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||\r |
| 2342 | !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertPkcs7Guid)) {\r |
| 2343 | //\r |
| 2344 | // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.\r |
| 2345 | //\r |
| 2346 | return EFI_SECURITY_VIOLATION;\r |
| 2347 | }\r |
| 2348 | \r |
| 2349 | //\r |
| 2350 | // Find out Pkcs7 SignedData which follows the EFI_VARIABLE_AUTHENTICATION_2 descriptor.\r |
| 2351 | // AuthInfo.Hdr.dwLength is the length of the entire certificate, including the length of the header.\r |
| 2352 | //\r |
| 2353 | SigData = CertData->AuthInfo.CertData;\r |
| 2354 | SigDataSize = CertData->AuthInfo.Hdr.dwLength - (UINT32) (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData));\r |
| 2355 | \r |
| 2356 | //\r |
| 2357 | // SignedData.digestAlgorithms shall contain the digest algorithm used when preparing the\r |
| 2358 | // signature. Only a digest algorithm of SHA-256 is accepted.\r |
| 2359 | //\r |
| 2360 | // According to PKCS#7 Definition:\r |
| 2361 | // SignedData ::= SEQUENCE {\r |
| 2362 | // version Version,\r |
| 2363 | // digestAlgorithms DigestAlgorithmIdentifiers,\r |
| 2364 | // contentInfo ContentInfo,\r |
| 2365 | // .... }\r |
| 2366 | // The DigestAlgorithmIdentifiers can be used to determine the hash algorithm \r |
| 2367 | // in VARIABLE_AUTHENTICATION_2 descriptor.\r |
| 2368 | // This field has the fixed offset (+13) and be calculated based on two bytes of length encoding.\r |
| 2369 | //\r |
| 2370 | if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r |
| 2371 | if (SigDataSize >= (13 + sizeof (mSha256OidValue))) {\r |
| 2372 | if (((*(SigData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE) || \r |
| 2373 | (CompareMem (SigData + 13, &mSha256OidValue, sizeof (mSha256OidValue)) != 0)) {\r |
| 2374 | return EFI_SECURITY_VIOLATION;\r |
| 2375 | }\r |
| 2376 | }\r |
| 2377 | }\r |
| 2378 | \r |
| 2379 | //\r |
| 2380 | // Find out the new data payload which follows Pkcs7 SignedData directly.\r |
| 2381 | //\r |
| 2382 | PayloadPtr = SigData + SigDataSize;\r |
| 2383 | PayloadSize = DataSize - OFFSET_OF_AUTHINFO2_CERT_DATA - (UINTN) SigDataSize;\r |
| 2384 | \r |
| 2385 | //\r |
| 2386 | // Construct a serialization buffer of the values of the VariableName, VendorGuid and Attributes\r |
| 2387 | // parameters of the SetVariable() call and the TimeStamp component of the\r |
| 2388 | // EFI_VARIABLE_AUTHENTICATION_2 descriptor followed by the variable's new value\r |
| 2389 | // i.e. (VariableName, VendorGuid, Attributes, TimeStamp, Data)\r |
| 2390 | //\r |
| 2391 | NewDataSize = PayloadSize + sizeof (EFI_TIME) + sizeof (UINT32) +\r |
| 2392 | sizeof (EFI_GUID) + StrSize (VariableName) - sizeof (CHAR16);\r |
| 2393 | \r |
| 2394 | //\r |
| 2395 | // Here is to reuse scratch data area(at the end of volatile variable store)\r |
| 2396 | // to reduce SMRAM consumption for SMM variable driver.\r |
| 2397 | // The scratch buffer is enough to hold the serialized data and safe to use,\r |
| 2398 | // because it is only used at here to do verification temporarily first\r |
| 2399 | // and then used in UpdateVariable() for a time based auth variable set.\r |
| 2400 | //\r |
| 2401 | Status = mAuthVarLibContextIn->GetScratchBuffer (&NewDataSize, (VOID **) &NewData);\r |
| 2402 | if (EFI_ERROR (Status)) {\r |
| 2403 | return EFI_OUT_OF_RESOURCES;\r |
| 2404 | }\r |
| 2405 | \r |
| 2406 | Buffer = NewData;\r |
| 2407 | Length = StrLen (VariableName) * sizeof (CHAR16);\r |
| 2408 | CopyMem (Buffer, VariableName, Length);\r |
| 2409 | Buffer += Length;\r |
| 2410 | \r |
| 2411 | Length = sizeof (EFI_GUID);\r |
| 2412 | CopyMem (Buffer, VendorGuid, Length);\r |
| 2413 | Buffer += Length;\r |
| 2414 | \r |
| 2415 | Length = sizeof (UINT32);\r |
| 2416 | CopyMem (Buffer, &Attr, Length);\r |
| 2417 | Buffer += Length;\r |
| 2418 | \r |
| 2419 | Length = sizeof (EFI_TIME);\r |
| 2420 | CopyMem (Buffer, &CertData->TimeStamp, Length);\r |
| 2421 | Buffer += Length;\r |
| 2422 | \r |
| 2423 | CopyMem (Buffer, PayloadPtr, PayloadSize);\r |
| 2424 | \r |
| 2425 | if (AuthVarType == AuthVarTypePk) {\r |
| 2426 | //\r |
| 2427 | // Verify that the signature has been made with the current Platform Key (no chaining for PK).\r |
| 2428 | // First, get signer's certificates from SignedData.\r |
| 2429 | //\r |
| 2430 | VerifyStatus = Pkcs7GetSigners (\r |
| 2431 | SigData,\r |
| 2432 | SigDataSize,\r |
| 2433 | &SignerCerts,\r |
| 2434 | &CertStackSize,\r |
| 2435 | &TopLevelCert,\r |
| 2436 | &TopLevelCertSize\r |
| 2437 | );\r |
| 2438 | if (!VerifyStatus) {\r |
| 2439 | goto Exit;\r |
| 2440 | }\r |
| 2441 | \r |
| 2442 | //\r |
| 2443 | // Second, get the current platform key from variable. Check whether it's identical with signer's certificates\r |
| 2444 | // in SignedData. If not, return error immediately.\r |
| 2445 | //\r |
| 2446 | Status = AuthServiceInternalFindVariable (\r |
| 2447 | EFI_PLATFORM_KEY_NAME,\r |
| 2448 | &gEfiGlobalVariableGuid,\r |
| 2449 | &Data,\r |
| 2450 | &DataSize\r |
| 2451 | );\r |
| 2452 | if (EFI_ERROR (Status)) {\r |
| 2453 | VerifyStatus = FALSE;\r |
| 2454 | goto Exit;\r |
| 2455 | }\r |
| 2456 | CertList = (EFI_SIGNATURE_LIST *) Data;\r |
| 2457 | Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r |
| 2458 | if ((TopLevelCertSize != (CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1))) ||\r |
| 2459 | (CompareMem (Cert->SignatureData, TopLevelCert, TopLevelCertSize) != 0)) {\r |
| 2460 | VerifyStatus = FALSE;\r |
| 2461 | goto Exit;\r |
| 2462 | }\r |
| 2463 | \r |
| 2464 | //\r |
| 2465 | // Verify Pkcs7 SignedData via Pkcs7Verify library.\r |
| 2466 | //\r |
| 2467 | VerifyStatus = Pkcs7Verify (\r |
| 2468 | SigData,\r |
| 2469 | SigDataSize,\r |
| 2470 | TopLevelCert,\r |
| 2471 | TopLevelCertSize,\r |
| 2472 | NewData,\r |
| 2473 | NewDataSize\r |
| 2474 | );\r |
| 2475 | \r |
| 2476 | } else if (AuthVarType == AuthVarTypeKek) {\r |
| 2477 | \r |
| 2478 | //\r |
| 2479 | // Get KEK database from variable.\r |
| 2480 | //\r |
| 2481 | Status = AuthServiceInternalFindVariable (\r |
| 2482 | EFI_KEY_EXCHANGE_KEY_NAME,\r |
| 2483 | &gEfiGlobalVariableGuid,\r |
| 2484 | &Data,\r |
| 2485 | &DataSize\r |
| 2486 | );\r |
| 2487 | if (EFI_ERROR (Status)) {\r |
| 2488 | return Status;\r |
| 2489 | }\r |
| 2490 | \r |
| 2491 | //\r |
| 2492 | // Ready to verify Pkcs7 SignedData. Go through KEK Signature Database to find out X.509 CertList.\r |
| 2493 | //\r |
| 2494 | KekDataSize = (UINT32) DataSize;\r |
| 2495 | CertList = (EFI_SIGNATURE_LIST *) Data;\r |
| 2496 | while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {\r |
| 2497 | if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {\r |
| 2498 | Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r |
| 2499 | CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r |
| 2500 | for (Index = 0; Index < CertCount; Index++) {\r |
| 2501 | //\r |
| 2502 | // Iterate each Signature Data Node within this CertList for a verify\r |
| 2503 | //\r |
| 2504 | TrustedCert = Cert->SignatureData;\r |
| 2505 | TrustedCertSize = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);\r |
| 2506 | \r |
| 2507 | //\r |
| 2508 | // Verify Pkcs7 SignedData via Pkcs7Verify library.\r |
| 2509 | //\r |
| 2510 | VerifyStatus = Pkcs7Verify (\r |
| 2511 | SigData,\r |
| 2512 | SigDataSize,\r |
| 2513 | TrustedCert,\r |
| 2514 | TrustedCertSize,\r |
| 2515 | NewData,\r |
| 2516 | NewDataSize\r |
| 2517 | );\r |
| 2518 | if (VerifyStatus) {\r |
| 2519 | goto Exit;\r |
| 2520 | }\r |
| 2521 | Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r |
| 2522 | }\r |
| 2523 | }\r |
| 2524 | KekDataSize -= CertList->SignatureListSize;\r |
| 2525 | CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r |
| 2526 | }\r |
| 2527 | } else if (AuthVarType == AuthVarTypePriv) {\r |
| 2528 | \r |
| 2529 | //\r |
| 2530 | // Process common authenticated variable except PK/KEK/DB/DBX/DBT.\r |
| 2531 | // Get signer's certificates from SignedData.\r |
| 2532 | //\r |
| 2533 | VerifyStatus = Pkcs7GetSigners (\r |
| 2534 | SigData,\r |
| 2535 | SigDataSize,\r |
| 2536 | &SignerCerts,\r |
| 2537 | &CertStackSize,\r |
| 2538 | &TopLevelCert,\r |
| 2539 | &TopLevelCertSize\r |
| 2540 | );\r |
| 2541 | if (!VerifyStatus) {\r |
| 2542 | goto Exit;\r |
| 2543 | }\r |
| 2544 | \r |
| 2545 | //\r |
| 2546 | // Get previously stored signer's certificates from certdb or certdbv for existing\r |
| 2547 | // variable. Check whether they are identical with signer's certificates\r |
| 2548 | // in SignedData. If not, return error immediately.\r |
| 2549 | //\r |
| 2550 | if (OrgTimeStamp != NULL) {\r |
| 2551 | VerifyStatus = FALSE;\r |
| 2552 | \r |
| 2553 | Status = GetCertsFromDb (VariableName, VendorGuid, Attributes, &CertsInCertDb, &CertsSizeinDb);\r |
| 2554 | if (EFI_ERROR (Status)) {\r |
| 2555 | goto Exit;\r |
| 2556 | }\r |
| 2557 | \r |
| 2558 | if (CertsSizeinDb == SHA256_DIGEST_SIZE) {\r |
| 2559 | //\r |
| 2560 | // Check hash of signer cert CommonName + Top-level issuer tbsCertificate against data in CertDb\r |
| 2561 | //\r |
| 2562 | Status = CalculatePrivAuthVarSignChainSHA256Digest(\r |
| 2563 | SignerCerts + sizeof(UINT8) + sizeof(UINT32),\r |
| 2564 | ReadUnaligned32 ((UINT32 *)(SignerCerts + sizeof(UINT8))),\r |
| 2565 | TopLevelCert,\r |
| 2566 | TopLevelCertSize,\r |
| 2567 | Sha256Digest\r |
| 2568 | );\r |
| 2569 | if (EFI_ERROR(Status) || CompareMem (Sha256Digest, CertsInCertDb, CertsSizeinDb) != 0){\r |
| 2570 | goto Exit;\r |
| 2571 | }\r |
| 2572 | } else {\r |
| 2573 | //\r |
| 2574 | // Keep backward compatible with previous solution which saves whole signer certs stack in CertDb\r |
| 2575 | //\r |
| 2576 | if ((CertStackSize != CertsSizeinDb) ||\r |
| 2577 | (CompareMem (SignerCerts, CertsInCertDb, CertsSizeinDb) != 0)) {\r |
| 2578 | goto Exit;\r |
| 2579 | }\r |
| 2580 | }\r |
| 2581 | }\r |
| 2582 | \r |
| 2583 | VerifyStatus = Pkcs7Verify (\r |
| 2584 | SigData,\r |
| 2585 | SigDataSize,\r |
| 2586 | TopLevelCert,\r |
| 2587 | TopLevelCertSize,\r |
| 2588 | NewData,\r |
| 2589 | NewDataSize\r |
| 2590 | );\r |
| 2591 | if (!VerifyStatus) {\r |
| 2592 | goto Exit;\r |
| 2593 | }\r |
| 2594 | \r |
| 2595 | if ((OrgTimeStamp == NULL) && (PayloadSize != 0)) {\r |
| 2596 | //\r |
| 2597 | // When adding a new common authenticated variable, always save Hash of cn of signer cert + tbsCertificate of Top-level issuer\r |
| 2598 | //\r |
| 2599 | Status = InsertCertsToDb (\r |
| 2600 | VariableName,\r |
| 2601 | VendorGuid,\r |
| 2602 | Attributes,\r |
| 2603 | SignerCerts + sizeof(UINT8) + sizeof(UINT32),\r |
| 2604 | ReadUnaligned32 ((UINT32 *)(SignerCerts + sizeof(UINT8))),\r |
| 2605 | TopLevelCert,\r |
| 2606 | TopLevelCertSize\r |
| 2607 | );\r |
| 2608 | if (EFI_ERROR (Status)) {\r |
| 2609 | VerifyStatus = FALSE;\r |
| 2610 | goto Exit;\r |
| 2611 | }\r |
| 2612 | }\r |
| 2613 | } else if (AuthVarType == AuthVarTypePayload) {\r |
| 2614 | CertList = (EFI_SIGNATURE_LIST *) PayloadPtr;\r |
| 2615 | Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r |
| 2616 | TrustedCert = Cert->SignatureData;\r |
| 2617 | TrustedCertSize = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);\r |
| 2618 | //\r |
| 2619 | // Verify Pkcs7 SignedData via Pkcs7Verify library.\r |
| 2620 | //\r |
| 2621 | VerifyStatus = Pkcs7Verify (\r |
| 2622 | SigData,\r |
| 2623 | SigDataSize,\r |
| 2624 | TrustedCert,\r |
| 2625 | TrustedCertSize,\r |
| 2626 | NewData,\r |
| 2627 | NewDataSize\r |
| 2628 | );\r |
| 2629 | } else {\r |
| 2630 | return EFI_SECURITY_VIOLATION;\r |
| 2631 | }\r |
| 2632 | \r |
| 2633 | Exit:\r |
| 2634 | \r |
| 2635 | if (AuthVarType == AuthVarTypePk || AuthVarType == AuthVarTypePriv) {\r |
| 2636 | Pkcs7FreeSigners (TopLevelCert);\r |
| 2637 | Pkcs7FreeSigners (SignerCerts);\r |
| 2638 | }\r |
| 2639 | \r |
| 2640 | if (!VerifyStatus) {\r |
| 2641 | return EFI_SECURITY_VIOLATION;\r |
| 2642 | }\r |
| 2643 | \r |
| 2644 | Status = CheckSignatureListFormat(VariableName, VendorGuid, PayloadPtr, PayloadSize);\r |
| 2645 | if (EFI_ERROR (Status)) {\r |
| 2646 | return Status;\r |
| 2647 | }\r |
| 2648 | \r |
| 2649 | *VarPayloadPtr = PayloadPtr;\r |
| 2650 | *VarPayloadSize = PayloadSize;\r |
| 2651 | \r |
| 2652 | return EFI_SUCCESS;\r |
| 2653 | }\r |
| 2654 | \r |
| 2655 | /**\r |
| 2656 | Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set\r |
| 2657 | \r |
| 2658 | Caution: This function may receive untrusted input.\r |
| 2659 | This function may be invoked in SMM mode, and datasize and data are external input.\r |
| 2660 | This function will do basic validation, before parse the data.\r |
| 2661 | This function will parse the authentication carefully to avoid security issues, like\r |
| 2662 | buffer overflow, integer overflow.\r |
| 2663 | \r |
| 2664 | @param[in] VariableName Name of Variable to be found.\r |
| 2665 | @param[in] VendorGuid Variable vendor GUID.\r |
| 2666 | @param[in] Data Data pointer.\r |
| 2667 | @param[in] DataSize Size of Data found. If size is less than the\r |
| 2668 | data, this value contains the required size.\r |
| 2669 | @param[in] Attributes Attribute value of the variable.\r |
| 2670 | @param[in] AuthVarType Verify against PK, KEK database, private database or certificate in data payload.\r |
| 2671 | @param[out] VarDel Delete the variable or not.\r |
| 2672 | \r |
| 2673 | @retval EFI_INVALID_PARAMETER Invalid parameter.\r |
| 2674 | @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation\r |
| 2675 | check carried out by the firmware.\r |
| 2676 | @retval EFI_OUT_OF_RESOURCES Failed to process variable due to lack\r |
| 2677 | of resources.\r |
| 2678 | @retval EFI_SUCCESS Variable pass validation successfully.\r |
| 2679 | \r |
| 2680 | **/\r |
| 2681 | EFI_STATUS\r |
| 2682 | VerifyTimeBasedPayloadAndUpdate (\r |
| 2683 | IN CHAR16 *VariableName,\r |
| 2684 | IN EFI_GUID *VendorGuid,\r |
| 2685 | IN VOID *Data,\r |
| 2686 | IN UINTN DataSize,\r |
| 2687 | IN UINT32 Attributes,\r |
| 2688 | IN AUTHVAR_TYPE AuthVarType,\r |
| 2689 | OUT BOOLEAN *VarDel\r |
| 2690 | )\r |
| 2691 | {\r |
| 2692 | EFI_STATUS Status;\r |
| 2693 | EFI_STATUS FindStatus;\r |
| 2694 | UINT8 *PayloadPtr;\r |
| 2695 | UINTN PayloadSize;\r |
| 2696 | EFI_VARIABLE_AUTHENTICATION_2 *CertData;\r |
| 2697 | AUTH_VARIABLE_INFO OrgVariableInfo;\r |
| 2698 | BOOLEAN IsDel;\r |
| 2699 | \r |
| 2700 | ZeroMem (&OrgVariableInfo, sizeof (OrgVariableInfo));\r |
| 2701 | FindStatus = mAuthVarLibContextIn->FindVariable (\r |
| 2702 | VariableName,\r |
| 2703 | VendorGuid,\r |
| 2704 | &OrgVariableInfo\r |
| 2705 | );\r |
| 2706 | \r |
| 2707 | Status = VerifyTimeBasedPayload (\r |
| 2708 | VariableName,\r |
| 2709 | VendorGuid,\r |
| 2710 | Data,\r |
| 2711 | DataSize,\r |
| 2712 | Attributes,\r |
| 2713 | AuthVarType,\r |
| 2714 | (!EFI_ERROR (FindStatus)) ? OrgVariableInfo.TimeStamp : NULL,\r |
| 2715 | &PayloadPtr,\r |
| 2716 | &PayloadSize\r |
| 2717 | );\r |
| 2718 | if (EFI_ERROR (Status)) {\r |
| 2719 | return Status;\r |
| 2720 | }\r |
| 2721 | \r |
| 2722 | if (!EFI_ERROR(FindStatus)\r |
| 2723 | && (PayloadSize == 0)\r |
| 2724 | && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {\r |
| 2725 | IsDel = TRUE;\r |
| 2726 | } else {\r |
| 2727 | IsDel = FALSE;\r |
| 2728 | }\r |
| 2729 | \r |
| 2730 | CertData = (EFI_VARIABLE_AUTHENTICATION_2 *) Data;\r |
| 2731 | \r |
| 2732 | //\r |
| 2733 | // Final step: Update/Append Variable if it pass Pkcs7Verify\r |
| 2734 | //\r |
| 2735 | Status = AuthServiceInternalUpdateVariableWithTimeStamp (\r |
| 2736 | VariableName,\r |
| 2737 | VendorGuid,\r |
| 2738 | PayloadPtr,\r |
| 2739 | PayloadSize,\r |
| 2740 | Attributes,\r |
| 2741 | &CertData->TimeStamp\r |
| 2742 | );\r |
| 2743 | \r |
| 2744 | //\r |
| 2745 | // Delete signer's certificates when delete the common authenticated variable.\r |
| 2746 | //\r |
| 2747 | if (IsDel && AuthVarType == AuthVarTypePriv && !EFI_ERROR(Status) ) {\r |
| 2748 | Status = DeleteCertsFromDb (VariableName, VendorGuid, Attributes);\r |
| 2749 | }\r |
| 2750 | \r |
| 2751 | if (VarDel != NULL) {\r |
| 2752 | if (IsDel && !EFI_ERROR(Status)) {\r |
| 2753 | *VarDel = TRUE;\r |
| 2754 | } else {\r |
| 2755 | *VarDel = FALSE;\r |
| 2756 | }\r |
| 2757 | }\r |
| 2758 | \r |
| 2759 | return Status;\r |
| 2760 | }\r |