talm
135 строк · 3.4 Кб
1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
5// Package uki creates the UKI file out of the sd-stub and other sections.
6package uki
7
8import (
9"fmt"
10"log"
11"os"
12
13"github.com/aenix-io/talm/internal/pkg/secureboot"
14"github.com/aenix-io/talm/internal/pkg/secureboot/measure"
15"github.com/aenix-io/talm/internal/pkg/secureboot/pesign"
16)
17
18// section is a UKI file section.
19type section struct {
20// Section name.
21Name secureboot.Section
22// Path to the contents of the section.
23Path string
24// Should the section be measured to the TPM?
25Measure bool
26// Should the section be appended, or is it already in the PE file.
27Append bool
28// Size & VMA of the section.
29Size uint64
30VMA uint64
31}
32
33// Builder is a UKI file builder.
34type Builder struct {
35// Source options.
36//
37// Arch of the UKI file.
38Arch string
39// Version of Talos.
40Version string
41// Path to the sd-stub.
42SdStubPath string
43// Path to the sd-boot.
44SdBootPath string
45// Path to the kernel image.
46KernelPath string
47// Path to the initrd image.
48InitrdPath string
49// Kernel cmdline.
50Cmdline string
51// SecureBoot certificate and signer.
52SecureBootSigner pesign.CertificateSigner
53// PCR signer.
54PCRSigner measure.RSAKey
55
56// Output options:
57//
58// Path to the signed sd-boot.
59OutSdBootPath string
60// Path to the output UKI file.
61OutUKIPath string
62
63// fields initialized during build
64sections []section
65scratchDir string
66peSigner *pesign.Signer
67unsignedUKIPath string
68}
69
70// Build the UKI file.
71//
72// Build process is as follows:
73// - sign the sd-boot EFI binary, and write it to the OutSdBootPath
74// - build ephemeral sections (uname, os-release), and other proposed sections
75// - measure sections, generate signature, and append to the list of sections
76// - assemble the final UKI file starting from sd-stub and appending generated section.
77func (builder *Builder) Build(printf func(string, ...any)) error {
78var err error
79
80builder.scratchDir, err = os.MkdirTemp("", "talos-uki")
81if err != nil {
82return err
83}
84
85defer func() {
86if err = os.RemoveAll(builder.scratchDir); err != nil {
87log.Printf("failed to remove scratch dir: %v", err)
88}
89}()
90
91printf("signing systemd-boot")
92
93builder.peSigner, err = pesign.NewSigner(builder.SecureBootSigner)
94if err != nil {
95return fmt.Errorf("error initializing signer: %w", err)
96}
97
98// sign sd-boot
99if err = builder.peSigner.Sign(builder.SdBootPath, builder.OutSdBootPath); err != nil {
100return fmt.Errorf("error signing sd-boot: %w", err)
101}
102
103printf("generating UKI sections")
104
105// generate and build list of all sections
106for _, generateSection := range []func() error{
107builder.generateOSRel,
108builder.generateCmdline,
109builder.generateInitrd,
110builder.generateSplash,
111builder.generateUname,
112builder.generateSBAT,
113builder.generatePCRPublicKey,
114// append kernel last to account for decompression
115builder.generateKernel,
116// measure sections last
117builder.generatePCRSig,
118} {
119if err = generateSection(); err != nil {
120return fmt.Errorf("error generating sections: %w", err)
121}
122}
123
124printf("assembling UKI")
125
126// assemble the final UKI file
127if err = builder.assemble(); err != nil {
128return fmt.Errorf("error assembling UKI: %w", err)
129}
130
131printf("signing UKI")
132
133// sign the UKI file
134return builder.peSigner.Sign(builder.unsignedUKIPath, builder.OutUKIPath)
135}
136