mirror of
https://github.com/siderolabs/talos.git
synced 2025-10-26 14:01:39 +01:00
This patch adds a flag to `secureboot.database.Generate` to append the Microsoft UEFI secure boot DB and KEK certificates to the appropriate ESLs, in addition to complimentary command line flags. This patch also includes a copy of said Microsoft certificates. The certificates are downloaded from an official Microsoft repo. Signed-off-by: Jean-Francois Roy <jf@devklog.net> Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com>
176 lines
4.4 KiB
Go
176 lines
4.4 KiB
Go
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
// Package database generates SecureBoot auto-enrollment database.
|
|
package database
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"crypto/x509"
|
|
"embed"
|
|
"path/filepath"
|
|
"sync"
|
|
|
|
"github.com/foxboron/go-uefi/efi/signature"
|
|
"github.com/foxboron/go-uefi/efi/util"
|
|
"github.com/foxboron/go-uefi/efivar"
|
|
"github.com/google/uuid"
|
|
|
|
"github.com/siderolabs/talos/internal/pkg/secureboot/pesign"
|
|
"github.com/siderolabs/talos/pkg/machinery/constants"
|
|
)
|
|
|
|
// Entry is a UEFI database entry.
|
|
type Entry struct {
|
|
Name string
|
|
Contents []byte
|
|
}
|
|
|
|
const (
|
|
microsoftSignatureOwnerGUID = "77fa9abd-0359-4d32-bd60-28f4e78f784b"
|
|
)
|
|
|
|
// Well-known UEFI DB certificates (DER data).
|
|
//
|
|
//go:embed certs/db/*.der
|
|
var wellKnownDB embed.FS
|
|
|
|
// Well-known UEFI KEK certificates (PEM data).
|
|
//
|
|
//go:embed certs/kek/*.der
|
|
var wellKnownKEK embed.FS
|
|
|
|
func loadWellKnownCertificates(fs embed.FS, path string) ([]*x509.Certificate, error) {
|
|
certs := []*x509.Certificate{}
|
|
|
|
files, err := fs.ReadDir(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, file := range files {
|
|
data, err := fs.ReadFile(filepath.Join(path, file.Name()))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
cert, err := x509.ParseCertificate(data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
certs = append(certs, cert)
|
|
}
|
|
|
|
return certs, nil
|
|
}
|
|
|
|
var wellKnownDBCertificates = sync.OnceValue(func() []*x509.Certificate {
|
|
certs, err := loadWellKnownCertificates(wellKnownDB, "certs/db")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return certs
|
|
})
|
|
|
|
var wellKnownKEKCertificates = sync.OnceValue(func() []*x509.Certificate {
|
|
certs, err := loadWellKnownCertificates(wellKnownKEK, "certs/kek")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return certs
|
|
})
|
|
|
|
// Options for Generate.
|
|
type Options struct {
|
|
IncludeWellKnownCertificates bool
|
|
}
|
|
|
|
// Option is a functional option for Generate.
|
|
type Option func(*Options)
|
|
|
|
// IncludeWellKnownCertificates is an option to include well-known certificates.
|
|
func IncludeWellKnownCertificates(v bool) Option {
|
|
return func(o *Options) {
|
|
o.IncludeWellKnownCertificates = v
|
|
}
|
|
}
|
|
|
|
// Generate generates a UEFI database to enroll the signing certificate.
|
|
//
|
|
// ref: https://blog.hansenpartnership.com/the-meaning-of-all-the-uefi-keys/
|
|
//
|
|
//nolint:gocyclo
|
|
func Generate(enrolledCertificate []byte, signer pesign.CertificateSigner, opts ...Option) ([]Entry, error) {
|
|
var options Options
|
|
|
|
for _, opt := range opts {
|
|
opt(&options)
|
|
}
|
|
|
|
// derive UUID from enrolled certificate
|
|
uuid := uuid.NewHash(sha256.New(), uuid.NameSpaceX500, enrolledCertificate, 4)
|
|
|
|
efiGUID := util.StringToGUID(uuid.String())
|
|
|
|
// Create PK ESL
|
|
pk := signature.NewSignatureDatabase()
|
|
if err := pk.Append(signature.CERT_X509_GUID, *efiGUID, enrolledCertificate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
_, signedPK, err := signature.SignEFIVariable(efivar.PK, pk, signer.Signer(), signer.Certificate())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Create KEK ESL
|
|
kek := signature.NewSignatureDatabase()
|
|
if err := kek.Append(signature.CERT_X509_GUID, *efiGUID, enrolledCertificate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if options.IncludeWellKnownCertificates {
|
|
owner := util.StringToGUID(microsoftSignatureOwnerGUID)
|
|
for _, cert := range wellKnownKEKCertificates() {
|
|
if err := kek.Append(signature.CERT_X509_GUID, *owner, cert.Raw); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
}
|
|
|
|
_, signedKEK, err := signature.SignEFIVariable(efivar.KEK, kek, signer.Signer(), signer.Certificate())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Create db ESL
|
|
db := signature.NewSignatureDatabase()
|
|
if err := db.Append(signature.CERT_X509_GUID, *efiGUID, enrolledCertificate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if options.IncludeWellKnownCertificates {
|
|
owner := util.StringToGUID(microsoftSignatureOwnerGUID)
|
|
for _, cert := range wellKnownDBCertificates() {
|
|
if err := db.Append(signature.CERT_X509_GUID, *owner, cert.Raw); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
}
|
|
|
|
_, signedDB, err := signature.SignEFIVariable(efivar.Db, db, signer.Signer(), signer.Certificate())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return []Entry{
|
|
{Name: constants.SignatureKeyAsset, Contents: signedDB.Bytes()},
|
|
{Name: constants.KeyExchangeKeyAsset, Contents: signedKEK.Bytes()},
|
|
{Name: constants.PlatformKeyAsset, Contents: signedPK.Bytes()},
|
|
}, nil
|
|
}
|