From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pg1-f174.google.com (mail-pg1-f174.google.com [209.85.215.174]) by mx.groups.io with SMTP id smtpd.web10.759.1651687495900958129 for ; Wed, 04 May 2022 11:04:55 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@gmail.com header.s=20210112 header.b=Lml111Nu; spf=pass (domain: gmail.com, ip: 209.85.215.174, mailfrom: kuqin12@gmail.com) Received: by mail-pg1-f174.google.com with SMTP id 6so1741783pgb.13 for ; Wed, 04 May 2022 11:04:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=CaPOiB3Z1JLJfZnf3WO/qneXclTOVQBHI9Yl0uQuzxU=; b=Lml111NumiX8191m+Dfde9L9jqSYZr9qgYSy3+rFi+EWl6GV2YxGLgtXC3ZWdNlcSC 1YNmRWPCM6jEVBbNpdWiE8X6s7SprJnSpoF3Nc+rfvRMxSpwXqHfS3oU/wA6wnQfFrCK bHXaDi0+icDpZGIwSX6v5BjpDYnZNABFiMQb63YgwOSGw0oIfwvQIc0uVugtfL7pa9ft ohckXV3YDaL+57wrt2YVpCeXN5NFJUb9D4KG9/YxFDX5AqqZ3zbJGEw8pr1mOdhuRM5y Y+wEQ0YcubUAJX3GLHuFzSUrL16A0N1kE3moUCgplSCPzmDADiBzyo4NZztimrL4AqFD ky/w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=CaPOiB3Z1JLJfZnf3WO/qneXclTOVQBHI9Yl0uQuzxU=; b=MoeLJuj9RPHyJ8XT1P6bqNDXR2Ddt/E0MUHyvFjCcYrKk8L+BVnlm5Me2QCE0zR3Ev YPjYG8BMxp3m7H3y+z5MvDHM11609KD/tKIw5UBZB+lSrGhM7qwe1rtBDuj29BLYY650 K/OUINRH2L80lKRSF441eUMQYGGwyJl8ljbPP+yMEEXHiLR7bjgLeztHed9hztShRGH+ +gniqZ0pRe5wcX+EQJ1YvVc98e958o/20vKSIsVwC3PpPbKltnSpC3z23DNacSYUdIXT u9JvHuyXKfczjCOwSDTlh6C1GDG3gFbOAA+Dj+Skyi3duyX8nZ3UCfb5rm0ci6hKdFkj +ZLg== X-Gm-Message-State: AOAM532d2fHGLUgTiX3YCHkKHhurD3uQdSbmBgXZrO3yHC1QIpFrlWUK rb3K9tb9C+IG4dUzJoZUd+yUClBxauV6+Q== X-Google-Smtp-Source: ABdhPJxXKs5kKcRVc4oawLnLDuus6no1UZIgd8dKgM3ZJjCXCHYVAEzdMZw8UGWRl7Cqrrv1CCJjyw== X-Received: by 2002:a63:8449:0:b0:3ab:5075:d40d with SMTP id k70-20020a638449000000b003ab5075d40dmr18762871pgd.12.1651687495184; Wed, 04 May 2022 11:04:55 -0700 (PDT) Return-Path: Received: from localhost.localdomain ([50.47.82.110]) by smtp.gmail.com with ESMTPSA id n5-20020aa79045000000b0050dc7628143sm8496347pfo.29.2022.05.04.11.04.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 04 May 2022 11:04:54 -0700 (PDT) From: "Kun Qin" To: devel@edk2.groups.io Cc: Jiewen Yao , Jian J Wang , Min Xu Subject: [PATCH v1 05/11] SecurityPkg: SecureBootVariableLib: Added newly supported interfaces Date: Wed, 4 May 2022 11:04:31 -0700 Message-Id: <20220504180438.1321-6-kuqin12@gmail.com> X-Mailer: git-send-email 2.35.1.windows.2 In-Reply-To: <20220504180438.1321-1-kuqin12@gmail.com> References: <20220504180438.1321-1-kuqin12@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: kuqin REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3911 This change updated the interfaces provided by SecureBootVariableLib. The new additions provided interfaces to enroll single authenticated variable from input, a helper function to query secure boot status, enroll all secure boot variables from UefiSecureBoot.h defined data structures, a as well as a routine that deletes all secure boot related variables. Cc: Jiewen Yao Cc: Jian J Wang Cc: Min Xu Signed-off-by: Kun Qin --- SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.c | 364 ++++++++++++++++++++ SecurityPkg/Include/Library/SecureBootVariableLib.h | 69 ++++ SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.inf | 2 + 3 files changed, 435 insertions(+) diff --git a/SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.c b/SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.c index f56f0322e943..8167e58ca84c 100644 --- a/SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.c +++ b/SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.c @@ -21,6 +21,7 @@ #include #include #include +#include // This time can be used when deleting variables, as it should be greater than any variable time. EFI_TIME mMaxTimestamp = { @@ -37,6 +38,25 @@ EFI_TIME mMaxTimestamp = { 0x00 }; +// +// MS Default Time-Based Payload Creation Date +// This is the date that is used when creating SecureBoot default variables. +// NOTE: This is a placeholder date that doesn't correspond to anything else. +// +EFI_TIME mDefaultPayloadTimestamp = { + 15, // Year (2015) + 8, // Month (Aug) + 28, // Day (28) + 0, // Hour + 0, // Minute + 0, // Second + 0, // Pad1 + 0, // Nanosecond + 0, // Timezone (Dummy value) + 0, // Daylight (Dummy value) + 0 // Pad2 +}; + /** Creates EFI Signature List structure. @param[in] Data A pointer to signature data. @@ -413,6 +433,44 @@ GetSetupMode ( return EFI_SUCCESS; } +/** + Helper function to quickly determine whether SecureBoot is enabled. + + @retval TRUE SecureBoot is verifiably enabled. + @retval FALSE SecureBoot is either disabled or an error prevented checking. + +**/ +BOOLEAN +EFIAPI +IsSecureBootEnabled ( + VOID + ) +{ + EFI_STATUS Status; + UINT8 *SecureBoot; + + SecureBoot = NULL; + + Status = GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID **)&SecureBoot, NULL); + // + // Skip verification if SecureBoot variable doesn't exist. + // + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Cannot check SecureBoot variable %r \n ", Status)); + return FALSE; + } + + // + // Skip verification if SecureBoot is disabled but not AuditMode + // + if (*SecureBoot == SECURE_BOOT_MODE_DISABLE) { + FreePool (SecureBoot); + return FALSE; + } else { + return TRUE; + } +} + /** Clears the content of the 'db' variable. @@ -531,3 +589,309 @@ DeletePlatformKey ( ); return Status; } + +/** + This function will delete the secure boot keys, thus + disabling secure boot. + + @return EFI_SUCCESS or underlying failure code. +**/ +EFI_STATUS +EFIAPI +DeleteSecureBootVariables ( + VOID + ) +{ + EFI_STATUS Status, TempStatus; + + DEBUG ((DEBUG_INFO, "%a - Attempting to delete the Secure Boot variables.\n", __FUNCTION__)); + + // + // Step 1: Notify that a PK update is coming shortly... + Status = DisablePKProtection (); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a - Failed to signal PK update start! %r\n", __FUNCTION__, Status)); + // Classify this as a PK deletion error. + Status = EFI_ABORTED; + } + + // + // Step 2: Attempt to delete the PK. + // Let's try to nuke the PK, why not... + if (!EFI_ERROR (Status)) { + Status = DeletePlatformKey (); + DEBUG ((DEBUG_INFO, "%a - PK Delete = %r\n", __FUNCTION__, Status)); + // If the PK is not found, then our work here is done. + if (Status == EFI_NOT_FOUND) { + Status = EFI_SUCCESS; + } + // If any other error occurred, let's inform the caller that the PK delete in particular failed. + else if (EFI_ERROR (Status)) { + Status = EFI_ABORTED; + } + } + + // + // Step 3: Attempt to delete remaining keys/databases... + // Now that the PK is deleted (assuming Status == EFI_SUCCESS) the system is in SETUP_MODE. + // Arguably we could leave these variables in place and let them be deleted by whoever wants to + // update all the SecureBoot variables. However, for cleanliness sake, let's try to + // get rid of them here. + if (!EFI_ERROR (Status)) { + // + // If any of THESE steps have an error, report the error but attempt to delete all keys. + // Using TempStatus will prevent an error from being trampled by an EFI_SUCCESS. + // Overwrite Status ONLY if TempStatus is an error. + // + // If the error is EFI_NOT_FOUND, we can safely ignore it since we were trying to delete + // the variables anyway. + // + TempStatus = DeleteKEK (); + DEBUG ((DEBUG_INFO, "%a - KEK Delete = %r\n", __FUNCTION__, TempStatus)); + if (EFI_ERROR (TempStatus) && (TempStatus != EFI_NOT_FOUND)) { + Status = EFI_ACCESS_DENIED; + } + + TempStatus = DeleteDb (); + DEBUG ((DEBUG_INFO, "%a - db Delete = %r\n", __FUNCTION__, TempStatus)); + if (EFI_ERROR (TempStatus) && (TempStatus != EFI_NOT_FOUND)) { + Status = EFI_ACCESS_DENIED; + } + + TempStatus = DeleteDbx (); + DEBUG ((DEBUG_INFO, "%a - dbx Delete = %r\n", __FUNCTION__, TempStatus)); + if (EFI_ERROR (TempStatus) && (TempStatus != EFI_NOT_FOUND)) { + Status = EFI_ACCESS_DENIED; + } + + TempStatus = DeleteDbt (); + DEBUG ((DEBUG_INFO, "%a - dbt Delete = %r\n", __FUNCTION__, TempStatus)); + if (EFI_ERROR (TempStatus) && (TempStatus != EFI_NOT_FOUND)) { + Status = EFI_ACCESS_DENIED; + } + } + + return Status; +}// DeleteSecureBootVariables() + +/** + A helper function to take in a variable payload, wrap it in the + proper authenticated variable structure, and install it in the + EFI variable space. + + @param[in] VariableName The name of the key/database. + @param[in] VendorGuid The namespace (ie. vendor GUID) of the variable + @param[in] DataSize Size parameter for target secure boot variable. + @param[in] Data Pointer to signature list formatted secure boot variable content. + + @retval EFI_SUCCESS The enrollment for authenticated variable was successful. + @retval EFI_OUT_OF_RESOURCES There are not enough memory resources to create time based payload. + @retval EFI_INVALID_PARAMETER The parameter is invalid. + @retval Others Unexpected error happens. +**/ +EFI_STATUS +EFIAPI +EnrollFromInput ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINTN DataSize, + IN VOID *Data + ) +{ + VOID *Payload; + UINTN PayloadSize; + EFI_STATUS Status; + + if ((VariableName == NULL) || (VendorGuid == 0)) { + DEBUG ((DEBUG_ERROR, "Input vendor variable invalid: %p and %p\n", VariableName, VendorGuid)); + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + if ((Data == NULL) || (DataSize == 0)) { + // You might as well just use DeleteVariable... + DEBUG ((DEBUG_ERROR, "Input argument invalid: %p: %x\n", Data, DataSize)); + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + // Bring in the noise... + PayloadSize = DataSize; + Payload = AllocateZeroPool (DataSize); + // Bring in the funk... + if (Payload == NULL) { + return EFI_OUT_OF_RESOURCES; + } else { + CopyMem (Payload, Data, DataSize); + } + + Status = CreateTimeBasedPayload (&PayloadSize, (UINT8 **)&Payload, &mDefaultPayloadTimestamp); + if (EFI_ERROR (Status) || (Payload == NULL)) { + DEBUG ((DEBUG_ERROR, "Fail to create time-based data payload: %r\n", Status)); + Payload = NULL; + Status = EFI_OUT_OF_RESOURCES; + goto Exit; + } + + // + // Allocate memory for auth variable + // + Status = gRT->SetVariable ( + VariableName, + VendorGuid, + (EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS | + EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS), + PayloadSize, + Payload + ); + + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "error: %a (\"%s\", %g): %r\n", + __FUNCTION__, + VariableName, + VendorGuid, + Status + )); + } + +Exit: + // + // Always Put Away Your Toys + // Payload will be reassigned by CreateTimeBasedPayload()... + if (Payload != NULL) { + FreePool (Payload); + Payload = NULL; + } + + return Status; +} + +/** + Similar to DeleteSecureBootVariables, this function is used to unilaterally + force the state of related SB variables (db, dbx, dbt, KEK, PK, etc.) to be + the built-in, hardcoded default vars. + + @param[in] SecureBootPayload Payload information for secure boot related keys. + + @retval EFI_SUCCESS SecureBoot keys are now set to defaults. + @retval EFI_ABORTED SecureBoot keys are not empty. Please delete keys first + or follow standard methods of altering keys (ie. use the signing system). + @retval EFI_SECURITY_VIOLATION Failed to create the PK. + @retval Others Something failed in one of the subfunctions. + +**/ +EFI_STATUS +EFIAPI +SetSecureBootVariablesToDefault ( + IN CONST SECURE_BOOT_PAYLOAD_INFO *SecureBootPayload + ) +{ + EFI_STATUS Status; + UINT8 *Data; + UINTN DataSize; + + DEBUG ((DEBUG_INFO, "%a() Entry\n", __FUNCTION__)); + + if (SecureBootPayload == NULL) { + DEBUG ((DEBUG_ERROR, "%a - Invalid SecureBoot payload is supplied!\n", __FUNCTION__)); + return EFI_INVALID_PARAMETER; + } + + // + // Right off the bat, if SecureBoot is currently enabled, bail. + if (IsSecureBootEnabled ()) { + DEBUG ((DEBUG_ERROR, "%a - Cannot set default keys while SecureBoot is enabled!\n", __FUNCTION__)); + return EFI_ABORTED; + } + + DEBUG ((DEBUG_INFO, "%a - Setting up key %s!\n", __FUNCTION__, SecureBootPayload->SecureBootKeyName)); + + // + // Start running down the list, creating variables in our wake. + // dbx is a good place to start. + Data = (UINT8 *)SecureBootPayload->DbxPtr; + DataSize = SecureBootPayload->DbxSize; + Status = EnrollFromInput ( + EFI_IMAGE_SECURITY_DATABASE1, + &gEfiImageSecurityDatabaseGuid, + DataSize, + Data + ); + + // If that went well, try the db (make sure to pick the right one!). + if (!EFI_ERROR (Status)) { + Data = (UINT8 *)SecureBootPayload->DbPtr; + DataSize = SecureBootPayload->DbSize; + Status = EnrollFromInput ( + EFI_IMAGE_SECURITY_DATABASE, + &gEfiImageSecurityDatabaseGuid, + DataSize, + Data + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a - Failed to enroll DB %r!\n", __FUNCTION__, Status)); + } + } else { + DEBUG ((DEBUG_ERROR, "%a - Failed to enroll DBX %r!\n", __FUNCTION__, Status)); + } + + // Keep it going. Keep it going. dbt if supplied... + if (!EFI_ERROR (Status) && (SecureBootPayload->DbtPtr != NULL)) { + Data = (UINT8 *)SecureBootPayload->DbtPtr; + DataSize = SecureBootPayload->DbtSize; + Status = EnrollFromInput ( + EFI_IMAGE_SECURITY_DATABASE2, + &gEfiImageSecurityDatabaseGuid, + DataSize, + Data + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a - Failed to enroll DBT %r!\n", __FUNCTION__, Status)); + } + } + + // Keep it going. Keep it going. KEK... + if (!EFI_ERROR (Status)) { + Data = (UINT8 *)SecureBootPayload->KekPtr; + DataSize = SecureBootPayload->KekSize; + Status = EnrollFromInput ( + EFI_KEY_EXCHANGE_KEY_NAME, + &gEfiGlobalVariableGuid, + DataSize, + Data + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a - Failed to enroll KEK %r!\n", __FUNCTION__, Status)); + } + } + + // + // Finally! The Big Daddy of them all. + // The PK! + // + if (!EFI_ERROR (Status)) { + // + // Finally, install the key. + Data = (UINT8 *)SecureBootPayload->PkPtr; + DataSize = SecureBootPayload->PkSize; + Status = EnrollFromInput ( + EFI_PLATFORM_KEY_NAME, + &gEfiGlobalVariableGuid, + DataSize, + Data + ); + + // + // Report PK creation errors. + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a - Failed to update the PK! - %r\n", __FUNCTION__, Status)); + Status = EFI_SECURITY_VIOLATION; + } + } + + return Status; +} diff --git a/SecurityPkg/Include/Library/SecureBootVariableLib.h b/SecurityPkg/Include/Library/SecureBootVariableLib.h index 24ff0df067fa..c486801c318b 100644 --- a/SecurityPkg/Include/Library/SecureBootVariableLib.h +++ b/SecurityPkg/Include/Library/SecureBootVariableLib.h @@ -43,6 +43,19 @@ GetSetupMode ( OUT UINT8 *SetupMode ); +/** + Helper function to quickly determine whether SecureBoot is enabled. + + @retval TRUE SecureBoot is verifiably enabled. + @retval FALSE SecureBoot is either disabled or an error prevented checking. + +**/ +BOOLEAN +EFIAPI +IsSecureBootEnabled ( + VOID + ); + /** Create a EFI Signature List with data supplied from input argument. The input certificates from KeyInfo parameter should be DER-encoded @@ -161,4 +174,60 @@ DeletePlatformKey ( VOID ); +/** + This function will delete the secure boot keys, thus + disabling secure boot. + + @return EFI_SUCCESS or underlying failure code. +**/ +EFI_STATUS +EFIAPI +DeleteSecureBootVariables ( + VOID + ); + +/** + A helper function to take in a variable payload, wrap it in the + proper authenticated variable structure, and install it in the + EFI variable space. + + @param[in] VariableName The name of the key/database. + @param[in] VendorGuid The namespace (ie. vendor GUID) of the variable + @param[in] DataSize Size parameter for target secure boot variable. + @param[in] Data Pointer to signature list formatted secure boot variable content. + + @retval EFI_SUCCESS The enrollment for authenticated variable was successful. + @retval EFI_OUT_OF_RESOURCES There are not enough memory resources to create time based payload. + @retval EFI_INVALID_PARAMETER The parameter is invalid. + @retval Others Unexpected error happens. +**/ +EFI_STATUS +EFIAPI +EnrollFromInput ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINTN DataSize, + IN VOID *Data + ); + +/** + Similar to DeleteSecureBootVariables, this function is used to unilaterally + force the state of related SB variables (db, dbx, dbt, KEK, PK, etc.) to be + the built-in, hardcoded default vars. + + @param[in] SecureBootPayload Payload information for secure boot related keys. + + @retval EFI_SUCCESS SecureBoot keys are now set to defaults. + @retval EFI_ABORTED SecureBoot keys are not empty. Please delete keys first + or follow standard methods of altering keys (ie. use the signing system). + @retval EFI_SECURITY_VIOLATION Failed to create the PK. + @retval Others Something failed in one of the subfunctions. + +**/ +EFI_STATUS +EFIAPI +SetSecureBootVariablesToDefault ( + IN CONST SECURE_BOOT_PAYLOAD_INFO *SecureBootPayload + ); + #endif diff --git a/SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.inf b/SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.inf index 3d4b77cfb073..ac8e4bf5cd6a 100644 --- a/SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.inf +++ b/SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.inf @@ -38,6 +38,8 @@ [LibraryClasses] BaseMemoryLib DebugLib MemoryAllocationLib + PlatformPKProtectionLib + UefiRuntimeServicesTableLib [Guids] ## CONSUMES ## Variable:L"SetupMode" -- 2.34.1.windows.1