跳转至

密码学

iPXE 支持 HTTPS 协议,允许你加密与 Web 服务器之间的所有通信,并验证服务器的身份。要启用 HTTPS 协议支持,必须启用 DOWNLOAD_PROTO_HTTPS 构建配置选项。

iPXE 支持代码签名,允许你验证 iPXE 下载的文件的真实性和完整性。要启用代码签名支持,必须启用 IMAGE_TRUST_CMD 构建配置选项,并在嵌入式脚本中使用 imgtrust 命令。

iPXE 支持文件解密,允许你解密 iPXE 下载的加密文件。要启用文件解密支持,必须启用 IMAGE_CRYPT_CMD 构建配置选项。

支持的配置

协议版本 TLSv1.0 TLSv1.1 TLSv1.2
公钥算法 RSA ECDSA
密钥交换算法 RSA DHE ECDHE
分组密码算法 AES-128-GCM AES-256-GCM AES-128-CBC AES-256-CBC
散列算法 MD5 SHA-1 SHA-224 SHA-256 SHA-384 SHA-512 SHA-512/224 SHA-512/256
命名曲线 X25519 P-256 P-384

支持的密码套件完整列表如下:

  • TLS_RSA_WITH_AES_128_CBC_SHA
  • TLS_DHE_RSA_WITH_AES_128_CBC_SHA
  • TLS_RSA_WITH_AES_256_CBC_SHA
  • TLS_DHE_RSA_WITH_AES_256_CBC_SHA
  • TLS_RSA_WITH_AES_128_CBC_SHA256
  • TLS_RSA_WITH_AES_256_CBC_SHA256
  • TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
  • TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
  • TLS_RSA_WITH_AES_128_GCM_SHA256
  • TLS_RSA_WITH_AES_256_GCM_SHA384
  • TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
  • TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
  • TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
  • TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
  • TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
  • TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
  • TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
  • TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
  • TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
  • TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
  • TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
  • TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
  • TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
  • TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

受信任的根证书

在默认配置下,iPXE 只信任一个根证书:"iPXE root CA" 证书。这个根证书用于对标准的 Mozilla 公共 CA 证书列表进行交叉签名。

因此在默认配置下,iPXE 会自动信任与 Firefox 浏览器相同的一组证书。

如果你希望对信任链有更多的控制,可以用以下命令生成自己的私有根证书 ca.crt

  openssl req -x509 -newkey rsa:2048 -out ca.crt -keyout ca.key -days 1000

构建 iPXE 时,你可以使用 TRUST=... 构建参数修改受信任的根证书列表。例如,信任你的私有根证书 ca.crt

  make bin/ipxe.iso TRUST=ca.crt

这会生成一个信任你的私有根证书 ca.crt 的定制版 iPXE 二进制文件 ipxe.iso

你可以指定多个要信任的根证书。例如:

  make bin/ipxe.iso TRUST=/path/to/ca1.crt,/path/to/ca2.crt

证书必须是 PEM 格式。

Warning

完整的根证书通常太大,无法嵌入 iPXE 二进制文件中,因此默认只包含其 SHA-256 指纹。如果你使用默认的 "iPXE root CA" 证书,iPXE 会在需要时自动从 http://ca.ipxe.org/ca.crt(或从 crosscert 设置指定的镜像)下载完整的根证书。

如果你使用私有根证书,则必须通过以下方式之一让 iPXE 能够获取该证书:搭建自己的 crosscert 服务器;把根证书包含在所有提交给 iPXE 的证书链中(如下文所述);或者显式地把完整的根证书嵌入到 iPXE 二进制文件中。

Some books

签发证书

你可以使用私有根证书 ca.crt 签发会被 iPXE 信任的证书。为此,你必须创建一个最小的私有 CA 基础设施:

  echo 01 > ca.srl
  touch ca.idx
  mkdir signed

你还必须创建一个最小的 CA 配置文件 ca.cnf,内容如下:

  [ ca ]
  default_ca             = ca_default

  [ ca_default ]
  certificate            = ca.crt
  private_key            = ca.key
  serial                 = ca.srl
  database               = ca.idx
  new_certs_dir          = signed
  default_md             = default
  policy                 = policy_anything
  preserve               = yes
  default_days           = 90
  unique_subject         = no

  [ policy_anything ]
  countryName            = optional
  stateOrProvinceName    = optional
  localityName           = optional
  organizationName       = optional
  organizationalUnitName = optional
  commonName             = optional
  emailAddress           = optional

  [ cross ]
  basicConstraints       = critical,CA:true
  keyUsage               = critical,cRLSign,keyCertSign

  [ codesigning ]
  keyUsage                = digitalSignature
  extendedKeyUsage        = codeSigning

现在你就可以生成新的服务器证书 server.crt 和对应的私钥 server.key 了:

  openssl req -newkey rsa -keyout server.key -out server.req
  openssl ca -config ca.cnf -in server.req -out server.crt

这会创建一个由你的私有根证书签名的服务器证书 server.crt。你还可以选择创建一个包含 server.crt 和你的私有根证书 ca.crt 的完整证书链:

  cat server.crt ca.crt > server-full.crt

交叉签名证书

你可以使用私有 CA 基础设施对现有的公共 CA 根证书进行交叉签名。例如,对 StartCom 根证书进行交叉签名:

  openssl ca -config ca.cnf -extensions cross -notext -preserveDN -ss_cert startcom.crt -out startcom-cross.crt

这会创建一个交叉签名的证书 startcom-cross.crt。这样你就可以把信任从你的私有根证书扩展到由 startcom.crt 签名的证书,而无需直接把 startcom.crt 列为 iPXE 受信任的根证书。

代码签名

你可以使用代码签名证书对二进制文件进行签名,使其被 iPXE 信任。用于代码签名的证书必须包含 digitalSignature 密钥用法扩展和 codeSigning 扩展密钥用法扩展。你可以用以下命令生成新的代码签名证书 codesign.crt 和对应的私钥 codesign.key

  openssl req -newkey rsa -keyout codesign.key -out codesign.req
  openssl ca -config ca.cnf -extensions codesigning -in codesign.req -out codesign.crt

现在就可以用这个证书对二进制文件签名,使其被 iPXE 信任。例如,对二进制文件 vmlinuz 签名:

  openssl cms -sign -binary -noattr -in vmlinuz \
              -signer codesign.crt -inkey codesign.key -certfile ca.crt \
              -outform DER -out vmlinuz.sig

这会创建签名文件 vmlinuz.sig,你可以配合 imgverify 命令来验证二进制文件 vmlinuz。例如,假设你想用嵌入式脚本通过不可信的网络下载 vmlinuz

  #!ipxe

  imgtrust --permanent
  dhcp
  kernel http://${next-server}/boot/vmlinuz
  imgverify vmlinuz http://${next-server}/boot/vmlinuz.sig
  boot vmlinuz

这个嵌入式脚本只有在下载的 vmlinuz 能够通过签名文件 vmlinuz.sig 成功验证时才会引导,否则会拒绝引导。

嵌入式证书

构建 iPXE 时,你可以使用 CERT=... 构建参数嵌入一个或多个完整的证书。例如:

make bin/ipxe.iso CERT=cert1.crt,cert2.crt

Warning

嵌入式证书不会被自动信任;你需要使用 TRUST=... 构建参数显式指定任何受信任的根证书。例如:

make bin/ipxe.iso CERT=ca.crt TRUST=ca.crt

注意,嵌入式证书通常相当大,只有在无法从其他来源获取证书时(例如通过配置 crosscert 服务器)才应该嵌入证书。

外部提供的证书

iPXE 会自动获取固件平台提供的任何证书。例如,在 UEFI 平台上运行时,iPXE 会自动获取存储在 UEFI TlsCaCertificate 变量中的所有证书。

这些外部提供的证书默认会被信任。总体效果是:iPXE 会自动获取并信任固件平台所信任的任何证书。如果你是使用 UEFI HTTPS 引导来下载 iPXE 的,那么你就能自动使用 iPXE 从同一个 HTTPS 服务器下载文件。

你可以使用 certstat 命令查看任何外部提供的证书。

默认行为是信任外部提供的证书,除非你使用了自定义的受信任根证书。你可以使用 TRUST_EXT=... 构建参数显式控制是否信任外部提供的证书。例如:

# 使用默认根证书,不信任外部证书
make bin/ipxe.iso TRUST_EXT=0

# 使用自定义根证书,同时信任外部证书
make bin/ipxe.iso TRUST=ca.crt TRUST_EXT=1

客户端证书

你可以用以下命令生成客户端证书 client.crt 和对应的私钥 client.key

  openssl req -newkey rsa -keyout client.key -out client.req
  openssl ca -config ca.cnf -in client.req -out client.crt

构建 iPXE 时,你可以使用 CERT=...PRIVKEY=... 构建参数嵌入这个客户端证书(及对应的私钥)。例如:

make bin/ipxe.iso CERT=client.crt PRIVKEY=client.key

这会生成一个包含你的客户端证书(及对应私钥)的定制版 iPXE 二进制文件。然后你就可以配置 Web 服务器,要求使用这个客户端证书进行身份验证。

证书和私钥都必须是 PEM 格式。

Warning

注意,私钥以未加密的形式存储在 iPXE 二进制文件中。因此你应当把 iPXE 二进制文件视为机密信息。

使用客户端证书会给每个 HTTPS 连接带来明显的延迟(约一秒)。

文件解密

你可以使用客户端证书加密文件,然后在 iPXE 中解密。例如,加密二进制文件 vmlinuz

  openssl cms -encrypt -binary -aes-256-gcm -recip client.crt \
              -in vmlinuz -outform DER -out vmlinuz.cms

  ./contrib/crypto/cmsdetach vmlinuz.cms -d vmlinuz.dat -e vmlinuz.env

这里使用了 cmsdetach 工具,它位于 iPXE 的 contrib/crypto 目录中,因为当前版本的 openssl cms 尚不支持分离式加密数据。

然后你可以使用 imgdecrypt 命令解密镜像。例如:

  #!ipxe

  dhcp
  imgfetch http://${next-server}/boot/vmlinuz.dat
  imgfetch http://${next-server}/boot/vmlinuz.env
  imgdecrypt vmlinuz.dat vmlinuz.env
  boot vmlinuz