EDKII之安全启动详细介绍

news2025/1/10 11:22:18

文章目录

    • 安全启动简介
    • 安全启动流程介绍
    • 签名过程
    • 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/bash

echo -n "请输入一个通用名,比如公司名称或个人名字: "
read NAME

openssl 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 DER

echo $(uuidgen) > myGUID.txt

cert-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.esl

sign-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 的源码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2065302.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构之串与KMP算法详解

串 一. 定义&#xff08;了解&#xff09; 串&#xff0c;即字符串&#xff0c;是计算机系统和网络传输中最常用的数据类型&#xff0c;任何非数值型的处理都会以字符串的形式存储和使用。 串&#xff08;String&#xff09;是由零个或多个字符组成的有限序列&#xff0c;一…

多选类型项,点击亮或不亮

用于菜单下拉 多选项 。 <div style"display: flex; flex-wrap: wrap;margin: 0 auto;"><div v-for"(item, index) in prpductnames" :key"item.id"><span :class"{ selected: selectArr.includes(item.id) }" click&q…

《计算机操作系统》(第4版)第7章 文件管理 复习笔记

第7章 文件管理 一、文件和文件系统 1. 数据项、记录和文件 数据组成可分为数据项、记录和文件三级&#xff0c;它们之间的层次关系如图7-1所示。 图7-1 文件、记录和数据项之间的层次关系 (1)数据项 在文件系统中&#xff0c;数据项是最低级的数据组织形式&#xff0c;可以分为…

Grove Vision AI V2之GPIO

一、说明 实现一个LED闪烁的Demo&#xff0c;Grove Vision AI V2开发板上有一个USER_LED&#xff0c;由GPIO SEN_D2驱动&#xff0c;SEN_D2为高电平是USER_LED亮&#xff0c;SEN_D2为低电平时USER_LED灭。 USER_LED部分电路如下&#xff1a; 二、创建例程 1、创建文件 在See…

MySQL的源码安装及基本部署(基于RHEL7.9)

这里源码安装mysql的5.7.44版本 一、源码安装 1.下载并解压mysql , 进入目录: wget https://downloads.mysql.com/archives/get/p/23/file/mysql-boost-5.7.44.tar.gz tar xf mysql-boost-5.7.44.tar.gz cd mysql-5.7.44/ 2.准备好mysql编译安装依赖: yum install cmake g…

上线eleme项目

&#xff08;一&#xff09;搭建主从从数据库 主服务器master 首先下载mysql57安装包&#xff0c;然后解压 复制改目录到/usr/local底下并且改个名字 cp -r mysql-5.7.44-linux-glibc2.12-x86_64 /usr/local/mysql 删掉/etc/my.cnf 这个会影响mysql57的启动 rm -rf /etc…

浪潮服务器主板集成RAID常见问题

★主板集成RAID出现Initialize初始化&#xff0c;如下图 判断及解决方案&#xff1a; 1.机器是否有过插拔硬盘等操作。 2.系统初始化-系统启动会非常的慢。一般为非法关机或者断电导致。 3.出现此情况耐心等待磁盘初始化完成即可。系统初始化时间以具体的数据大小来决定&#…

CLion IDE用MSVC和cmake编译darknet(带GPU)

这个配置教程给用过pytorch&#xff0c;懂得深度学习代码的基本流程&#xff0c;但又不熟悉windows c开发环境的宝子们使用。 安装CUDA&#xff0c;CUDNN 一般都有&#xff0c;不说了。注意上nvidia官网看一下显卡架构&#xff0c;后面要用&#xff0c;比如我的丽台M2000架构…

从零开始Dify本地部署|Windows

参考官方文档部署 Dify本地源码启动 windows最好结合WSL使用&#xff0c;懒得配置WSL&#xff0c;就是硬肝&#xff01; 1.Clone Dify 代码 先找到项目GitHub 开源链接clone 下来&#xff0c;使用docker部署运行&#xff08;Windows配置docker环境这里不赘述&#xff09; gi…

Prometheus Alertmanager告警之邮件、钉钉群、企业微信群机器人报警

文章目录 一、部署alertmanager相关组件1.alertmanager-config2.alertmanager-message-tmpl3.alertmanager 二、调试邮件告警三、钉钉群/企业微信群 报警3.1添加钉钉群机器人3.2添加企业微信群机器人3.3部署alertmanager-webhook-adaptermessage-tmplalertmanager-webhook-adap…

Windows环境下,使用bat脚本配置本地域名解析(含新增、修改、清理)

适用场景&#xff1a; 1.内部不存在DNS服务器的客户&#xff1b; 2.客户电脑不知道前期是否过某域名的本地解析。 整体思路&#xff1a; 1.备份原始hosts配置文件&#xff1b; 2.将hosts配置文件中包含xxxxxxxxxx.com域名的解析清空&#xff1b; 3.写入正确的解析到hosts配置文…

发布MindSearch到ModelScope创空间

一、创建空间 1.点击【我要创建】来创建一个应用 2.填写完基础信息 会出现一个未发布的应用 二、上传代码 1.参照当前页的指示一步一步将MindSearch部署需要的文件上传到指定的repo即可 2.在当前页点击【空间文件】查看刚才通过命令上传的文件 三、上线应用 1.点击【设置】可…

【论文阅读】A Closer Look at Parameter-Efficient Tuning in Diffusion Models

Abstract 大规模扩散模型功能强大&#xff0c;但微调定制这些模型&#xff0c;内存和时间效率都很低。 本文通过向大规模扩散模型中插入小的学习器(称为adapters)&#xff0c;实现有效的参数微调。 特别地&#xff0c;将适配器的设计空间分解为输入位置、输出位置、函数形式的…

什么是ConcurrentHashMap?实现原理是什么?

什么是ConcurrentHashMap&#xff1f;实现原理是什么&#xff1f; 在多线程环境下&#xff0c;使用HashMap进行put操作时存在丢失数据的情况&#xff0c;为了避免这种bug的隐患&#xff0c;强烈建议使用ConcurrentHashMap代替HashMap。 HashTable是一个线程安全的类&#xff…

HashMap是线程安全的吗?为什么呢?

HashMap是线程安全的吗&#xff1f;为什么呢&#xff1f; HashMap是线程不安全的&#xff01; 线程不安全体现在JDK.1.7时在多线程的情况下扩容可能会出现死循环或数据丢失的情况&#xff0c;主要是在于扩容的transfer方法采用的头插法&#xff0c;头插法会把链表的顺序给颠倒…

【亲测有效】JS Uncaught TypeError: [function] is not a constructor

【亲测有效】JS Uncaught TypeError: [function] is not a constructor 在JavaScript编程中&#xff0c;Uncaught TypeError: [function] is not a constructor 是一个相对常见的错误&#xff0c;通常发生在尝试使用某个值作为构造函数&#xff0c;但实际上它不是构造函数的情况…

鸿蒙卡片服务开发

首先先创建一个项目 在该项目下创建一个卡片服务 在module.json5文件下配置 {"module": {..."extensionAbilities": [{"name": "EntryFormAbility","srcEntry": "./ets/entryformability/EntryFormAbility.ets",…

Linux文件操作:文件描述符fd

文章目录 前言&#xff1a;回顾一下文件提炼一下关于文件的理解&#xff1a; 理解文件&#xff1a;通过系统调用操作文件&#xff1a;理解标志位传参&#xff1a;打开文件 open写入信息 write 理解文件描述符&#xff1a;对于open的返回值&#xff1a;文件描述fd的本质是什么呢…

设计模式之Decorator装饰者、Facade外观、Adapter适配器(Java)

装饰者模式 设计模式的基本原则&#xff0c;对内关闭修改。 Decorator Pattern&#xff0c;装饰者模式&#xff0c;也叫包装器模式(Wrapper Pattern)&#xff1a;将一个对象包装起来&#xff0c;增加新的行为和责任。一定是从外部传入&#xff0c;并且可以没有顺序&#xff0…

Qml 实现仿前端的 Notification (悬浮出现页面上的通知消息)

【写在前面】 经常接触前端的朋友应该经常见到下面的控件&#xff1a; 在前端中一般称它为 Notification 或 Message&#xff0c;但本质是一种东西&#xff0c;即&#xff1a;悬浮弹出式的消息提醒框。 这种组件一般具有以下特点&#xff1a; 1、全局/局部显示&#xff1a;它不…