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