EDKII之安全启动详细介绍

2024-08-22 17:12

本文主要是介绍EDKII之安全启动详细介绍,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 安全启动简介
    • 安全启动流程介绍
    • 签名过程
    • BIOS实现
    • 小结

安全启动简介

安全启动(Secure Boot)是一种计算机系统的安全功能,旨在确保系统启动过程中只能加载经过数字签名的受信任的操作系统和启动加载程序。通过使用安全启动,系统可以防止恶意软件在启动过程中植入并运行,提高系统的安全性。

安全启动的工作原理通常包括以下几个步骤:

  1. 启动固件验证:在计算机启动时,启动固件(如UEFI固件)会验证操作系统引导加载程序的数字签名,确保其来自受信任的发布者。
  2. 操作系统验证:启动加载程序会验证操作系统内核和驱动程序的数字签名,以确保它们没有被篡改。
  3. 启动链验证:整个启动链中的每个组件都会被验证,包括引导加载程序、内核、驱动程序等。
  4. 安全启动状态:如果所有组件的数字签名验证通过,系统将进入安全启动状态,允许操作系统正常加载和运行。

通过安全启动,系统可以有效防止恶意软件在启动过程中进行植入和篡改,提高系统的整体安全性。安全启动通常与UEFI固件结合使用,是现代计算机系统中的重要安全功能之一。

BIOS启动过程中会执行BootLoader来加载系统,最常用的就是GRUB,它可能是一个名为bootx64.efi的UEFI应用。BIOS启动的最后会将控制权交给这个bootx64.efi,并由后者来启动系统。但是这里存在一个问题,如何保证这个应用真的是我们需要的呢?如果该应用被修改甚至替换了,导致执行一些我们不希望其执行的代码,则是一个非常严重的安全漏洞。

安全启动流程介绍

在这里插入图片描述

在这里插入图片描述
Platform Key (PK) - PK 是用于在硬件平台层和硬件平台拥有者建立起的信任关系 ,规定一个硬件平台只能被一个拥有者所拥有,即 PK 只能存在一个 ,与拥有者相关的公钥被存储在 FLASH 里面的 PK 变量里面,同时,拥有者的私钥可以来对 PK, KEK, db, dbx 进行签名和管理。

Key Exchange Key (KEK) - KEK 是用于在硬件平台和操作系统之间建立信任关系 ,KEK 的公钥可以在主板的 FLASH 存在多个不同项,即 KEK 可以存在多个 ,每一项对应一种可以被启动的操作系统,同样,KEK 的私钥可以来对 db, dbx 进行签名和管理。

Database (db) - db 是用于对 被许可的 EFI 文件予以加载的数据签名库 ,和 KEK 一样, db 的公钥可以存在很多项 。(在 UEFI 平台里面,操作系统加载文件就是一个 EFI 文件)

Database Excluded (dbx) - dbx 是一个 黑名单数据签名库 ,只要谁的 EFI 签名在这,谁就被屏蔽掉, dbx 的公钥也可以存在很多项 。后面不会使用这个。

测试方法:
建立 PK,KEK,db 密钥对,同时还需要创建EFI list。

在这里插入图片描述
在这里插入图片描述

  1. 加载PK。 ROOTCA.cer

在这里插入图片描述
加载KEK.CER,同样方法加载DB.CER
众所周知,进入EFI SHELL下,当不开启Secure Boot的时候 是可以执行efi 文件的,但是当我们打开Secure Boot 就不是所有efi 文件可以加载
在这里插入图片描述

签名过程

我们怎么签名Efi文件和启动项,怎么导入对应的证书呢?


```bash
#!/bin/bashecho -n "请输入一个通用名,比如公司名称或个人名字: "
read NAMEopenssl req -new -x509 -newkey rsa:2048 -subj "/CN=$NAME PK/" -keyout PK.key \-out PK.crt -days 3650 -nodes -sha256
openssl req -new -x509 -newkey rsa:2048 -subj "/CN=$NAME KEK/" -keyout KEK.key \-out KEK.crt -days 3650 -nodes -sha256
openssl req -new -x509 -newkey rsa:2048 -subj "/CN=$NAME DB/" -keyout DB.key \-out DB.crt -days 3650 -nodes -sha256
openssl x509 -in PK.crt -out PK.cer -outform DER
openssl x509 -in KEK.crt -out KEK.cer -outform DER
openssl x509 -in DB.crt -out DB.cer -outform DERecho $(uuidgen) > myGUID.txtcert-to-efi-sig-list -g $GUID PK.crt PK.esl
cert-to-efi-sig-list -g $GUID KEK.crt KEK.esl
cert-to-efi-sig-list -g $GUID DB.crt DB.esl
rm -f noPK.esl
touch noPK.eslsign-efi-sig-list -t "$(date --date='1 second' +'%Y-%m-%d %H:%M:%S')" \-k PK.key -c PK.crt PK PK.esl PK.auth
sign-efi-sig-list -t "$(date --date='1 second' +'%Y-%m-%d %H:%M:%S')" \-k PK.key -c PK.crt PK noPK.esl noPK.auth
sign-efi-sig-list -t "$(date --date='1 second' +'%Y-%m-%d %H:%M:%S')" \-k PK.key -c PK.crt KEK KEK.esl KEK.auth
sign-efi-sig-list -t "$(date --date='1 second' +'%Y-%m-%d %H:%M:%S')" \-k KEK.key -c KEK.crt db DB.esl DB.auth
echo ""
echo "For use with KeyTool, copy the *.auth and *.esl files to a FAT USB"
echo "flash drive or to your EFI System Partition (ESP)."
echo "For use with most UEFIs' built-in key managers, copy the *.cer files."
echo ""
运行后生成一组密钥

`在这里插入图片描述
``

在这里插入图片描述
使用密钥签名Efi文件,对于SecurityBoot就时需要将Grub.efi Boot.efi 去签名 让BIOS去LoadImage 时通过校验

sbsign --key db.key --cert db.crt --output grubx64sign.efi.signed grub64.efi
apt-get install sbsigntool
在这里插入图片描述

导入证书后, Sign过的efi 才能运行 否则会返回无权限。
当不添加DB 时去加载签名过的EFI 会显示 Image被签名但是不在DB中 。 PK是可以去校验签名 但是DB时我们的签名白名单支持库。
在这里插入图片描述

BIOS实现

在BIOS中加载EFI File会使用gbs->LoadImage去加载镜像,调用的的函数原型是 CoreLoadImageCommon
该函数就包含了安全校验`
Security2StubAuthenticate -->Defer3rdPartyImageLoad
在这里插入图片描述
在这里插入图片描述
使用证书签名文件后,可以看到会在EFI文件后面加一段密钥相关的二进制内容 里面就包含了使用的证书公钥等一些信息

在这里插入图片描述
BIOS中校验File中是否由DB/DBX的Signature,主要使用IsSignatureFoundInDatabase 去检查。

///
/// Varialbe name with guid EFI_IMAGE_SECURITY_DATABASE_GUID
/// for the authorized signature database.
///
#define EFI_IMAGE_SECURITY_DATABASE  L"db"
///
/// Varialbe name with guid EFI_IMAGE_SECURITY_DATABASE_GUID
/// for the forbidden signature database.
///
#define EFI_IMAGE_SECURITY_DATABASE1  L"dbx"EFI_STATUS
IsSignatureFoundInDatabase (IN  CHAR16    *VariableName,IN  UINT8     *Signature,IN  EFI_GUID  *CertType,IN  UINTN     SignatureSize,OUT BOOLEAN   *IsFound)
{EFI_STATUS          Status;EFI_SIGNATURE_LIST  *CertList;EFI_SIGNATURE_DATA  *Cert;UINTN               DataSize;UINT8               *Data;UINTN               Index;UINTN               CertCount;//// Read signature database variable.//*IsFound = FALSE;Data     = NULL;DataSize = 0;Status   = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);if (Status != EFI_BUFFER_TOO_SMALL) {if (Status == EFI_NOT_FOUND) {//// No database, no need to search.//Status = EFI_SUCCESS;}return Status;}Data = (UINT8 *)AllocateZeroPool (DataSize);if (Data == NULL) {return EFI_OUT_OF_RESOURCES;}Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, Data);if (EFI_ERROR (Status)) {goto Done;}//// Enumerate all signature data in SigDB to check if signature exists for executable.//CertList = (EFI_SIGNATURE_LIST *)Data;while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;Cert      = (EFI_SIGNATURE_DATA *)((UINT8 *)CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);if ((CertList->SignatureSize == sizeof (EFI_SIGNATURE_DATA) - 1 + SignatureSize) && (CompareGuid (&CertList->SignatureType, CertType))) {for (Index = 0; Index < CertCount; Index++) {if (CompareMem (Cert->SignatureData, Signature, SignatureSize) == 0) {//// Find the signature in database.//*IsFound = TRUE;//// Entries in UEFI_IMAGE_SECURITY_DATABASE that are used to validate image should be measured//if (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) {SecureBootHook (VariableName, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, Cert);}break;}Cert = (EFI_SIGNATURE_DATA *)((UINT8 *)Cert + CertList->SignatureSize);}if (*IsFound) {break;}}DataSize -= CertList->SignatureListSize;CertList  = (EFI_SIGNATURE_LIST *)((UINT8 *)CertList + CertList->SignatureListSize);}
Done:if (Data != NULL) {FreePool (Data);}return Status;
}
  1. 首先,函数会尝试从变量中读取签名数据库的数据。
  2. 如果成功读取到数据,函数会遍历签名列表,逐个比较签名数据,查找是否存在与给定签名匹配的条目。
  3. 如果找到匹配的签名,函数会将 IsFound 设置为 TRUE,表示找到了该签名。
  4. 如果在 EFI_IMAGE_SECURITY_DATABASE 中找到了签名,还会调用 SecureBootHook 函数来处理安全启动相关的操作。
    主要是将变量度量信息存入到TPM PCR中
SECUREBOOT_CONFIG_PRIVATE_DATA         mSecureBootConfigPrivateDateTemplate = {SECUREBOOT_CONFIG_PRIVATE_DATA_SIGNATURE,{SecureBootExtractConfig,SecureBootRouteConfig,SecureBootCallback}
};HiiHandle = HiiAddPackages (&gSecureBootConfigFormSetGuid,DriverHandle,SecureBootConfigDxeStrings,SecureBootConfigBin,NULL);

Vfr中都使用Label 在C中动态更新页面:
多个Lable 都在C中去动态更新
label FORMID_ENROLL_PK_FORM;
label LABEL_END;

label FORMID_ENROLL_KEK_FORM;
label LABEL_END;

label SECUREBOOT_ENROLL_SIGNATURE_TO_DB;
label LABEL_END;

label SECUREBOOT_ENROLL_SIGNATURE_TO_DBX;
label LABEL_END;
label FORMID_ENROLL_PK_FORM;
label LABEL_END;

小结

Security Boot 就是一层对于LoadImage file 去进行签名验签的过程,来保证加载的系统是安全的
详细信息都可以参考EDKII 的源码

这篇关于EDKII之安全启动详细介绍的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1096892

相关文章

java中BigDecimal里面的subtract函数介绍及实现方法

《java中BigDecimal里面的subtract函数介绍及实现方法》在Java中实现减法操作需要根据数据类型选择不同方法,主要分为数值型减法和字符串减法两种场景,本文给大家介绍java中BigD... 目录Java中BigDecimal里面的subtract函数的意思?一、数值型减法(高精度计算)1.

Macos创建python虚拟环境的详细步骤教学

《Macos创建python虚拟环境的详细步骤教学》在macOS上创建Python虚拟环境主要通过Python内置的venv模块实现,也可使用第三方工具如virtualenv,下面小编来和大家简单聊聊... 目录一、使用 python 内置 venv 模块(推荐)二、使用 virtualenv(兼容旧版 P

Pytorch介绍与安装过程

《Pytorch介绍与安装过程》PyTorch因其直观的设计、卓越的灵活性以及强大的动态计算图功能,迅速在学术界和工业界获得了广泛认可,成为当前深度学习研究和开发的主流工具之一,本文给大家介绍Pyto... 目录1、Pytorch介绍1.1、核心理念1.2、核心组件与功能1.3、适用场景与优势总结1.4、优

MySQL启动报错:InnoDB表空间丢失问题及解决方法

《MySQL启动报错:InnoDB表空间丢失问题及解决方法》在启动MySQL时,遇到了InnoDB:Tablespace5975wasnotfound,该错误表明MySQL在启动过程中无法找到指定的s... 目录mysql 启动报错:InnoDB 表空间丢失问题及解决方法错误分析解决方案1. 启用 inno

Java实现本地缓存的常用方案介绍

《Java实现本地缓存的常用方案介绍》本地缓存的代表技术主要有HashMap,GuavaCache,Caffeine和Encahche,这篇文章主要来和大家聊聊java利用这些技术分别实现本地缓存的方... 目录本地缓存实现方式HashMapConcurrentHashMapGuava CacheCaffe

Python实现一键PDF转Word(附完整代码及详细步骤)

《Python实现一键PDF转Word(附完整代码及详细步骤)》pdf2docx是一个基于Python的第三方库,专门用于将PDF文件转换为可编辑的Word文档,下面我们就来看看如何通过pdf2doc... 目录引言:为什么需要PDF转Word一、pdf2docx介绍1. pdf2docx 是什么2. by

Spring Security介绍及配置实现代码

《SpringSecurity介绍及配置实现代码》SpringSecurity是一个功能强大的Java安全框架,它提供了全面的安全认证(Authentication)和授权(Authorizatio... 目录简介Spring Security配置配置实现代码简介Spring Security是一个功能强

Logback在SpringBoot中的详细配置教程

《Logback在SpringBoot中的详细配置教程》SpringBoot默认会加载classpath下的logback-spring.xml(推荐)或logback.xml作为Logback的配置... 目录1. Logback 配置文件2. 基础配置示例3. 关键配置项说明Appender(日志输出器

JSR-107缓存规范介绍

《JSR-107缓存规范介绍》JSR是JavaSpecificationRequests的缩写,意思是Java规范提案,下面给大家介绍JSR-107缓存规范的相关知识,感兴趣的朋友一起看看吧... 目录1.什么是jsR-1072.应用调用缓存图示3.JSR-107规范使用4.Spring 缓存机制缓存是每一

无法启动此程序因为计算机丢失api-ms-win-core-path-l1-1-0.dll修复方案

《无法启动此程序因为计算机丢失api-ms-win-core-path-l1-1-0.dll修复方案》:本文主要介绍了无法启动此程序,详细内容请阅读本文,希望能对你有所帮助... 在计算机使用过程中,我们经常会遇到一些错误提示,其中之一就是"api-ms-win-core-path-l1-1-0.dll丢失