blob: d9b933b977f99e2c93950a448b3d10418bf80c74 [file] [log] [blame]
Lorenz Bruna50e8452020-09-09 17:09:27 +02001// Copyright 2020 The Monogon Project Authors.
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17// Taken from go-attestation under Apache 2.0
18package internal
19
20import (
21 "bytes"
22 "encoding/binary"
23 "errors"
24 "fmt"
25 "io"
26 "unicode/utf16"
27
28 "github.com/google/certificate-transparency-go/asn1"
29 "github.com/google/certificate-transparency-go/x509"
30)
31
32const (
33 // maxNameLen is the maximum accepted byte length for a name field.
34 // This value should be larger than any reasonable value.
35 maxNameLen = 2048
36 // maxDataLen is the maximum size in bytes of a variable data field.
37 // This value should be larger than any reasonable value.
38 maxDataLen = 1024 * 1024 // 1 Megabyte.
39)
40
41// GUIDs representing the contents of an UEFI_SIGNATURE_LIST.
42var (
43 hashSHA256SigGUID = efiGUID{0xc1c41626, 0x504c, 0x4092, [8]byte{0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28}}
44 hashSHA1SigGUID = efiGUID{0x826ca512, 0xcf10, 0x4ac9, [8]byte{0xb1, 0x87, 0xbe, 0x01, 0x49, 0x66, 0x31, 0xbd}}
45 hashSHA224SigGUID = efiGUID{0x0b6e5233, 0xa65c, 0x44c9, [8]byte{0x94, 0x07, 0xd9, 0xab, 0x83, 0xbf, 0xc8, 0xbd}}
46 hashSHA384SigGUID = efiGUID{0xff3e5307, 0x9fd0, 0x48c9, [8]byte{0x85, 0xf1, 0x8a, 0xd5, 0x6c, 0x70, 0x1e, 0x01}}
47 hashSHA512SigGUID = efiGUID{0x093e0fae, 0xa6c4, 0x4f50, [8]byte{0x9f, 0x1b, 0xd4, 0x1e, 0x2b, 0x89, 0xc1, 0x9a}}
48 keyRSA2048SigGUID = efiGUID{0x3c5766e8, 0x269c, 0x4e34, [8]byte{0xaa, 0x14, 0xed, 0x77, 0x6e, 0x85, 0xb3, 0xb6}}
49 certRSA2048SHA256SigGUID = efiGUID{0xe2b36190, 0x879b, 0x4a3d, [8]byte{0xad, 0x8d, 0xf2, 0xe7, 0xbb, 0xa3, 0x27, 0x84}}
50 certRSA2048SHA1SigGUID = efiGUID{0x67f8444f, 0x8743, 0x48f1, [8]byte{0xa3, 0x28, 0x1e, 0xaa, 0xb8, 0x73, 0x60, 0x80}}
51 certX509SigGUID = efiGUID{0xa5c059a1, 0x94e4, 0x4aa7, [8]byte{0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72}}
52 certHashSHA256SigGUID = efiGUID{0x3bd2a492, 0x96c0, 0x4079, [8]byte{0xb4, 0x20, 0xfc, 0xf9, 0x8e, 0xf1, 0x03, 0xed}}
53 certHashSHA384SigGUID = efiGUID{0x7076876e, 0x80c2, 0x4ee6, [8]byte{0xaa, 0xd2, 0x28, 0xb3, 0x49, 0xa6, 0x86, 0x5b}}
54 certHashSHA512SigGUID = efiGUID{0x446dbf63, 0x2502, 0x4cda, [8]byte{0xbc, 0xfa, 0x24, 0x65, 0xd2, 0xb0, 0xfe, 0x9d}}
55)
56
57// EventType describes the type of event signalled in the event log.
58type EventType uint32
59
60// BIOS Events (TCG PC Client Specific Implementation Specification for Conventional BIOS 1.21)
61const (
62 PrebootCert EventType = 0x00000000
63 PostCode EventType = 0x00000001
64 unused EventType = 0x00000002
65 NoAction EventType = 0x00000003
66 Separator EventType = 0x00000004
67 Action EventType = 0x00000005
68 EventTag EventType = 0x00000006
69 SCRTMContents EventType = 0x00000007
70 SCRTMVersion EventType = 0x00000008
71 CpuMicrocode EventType = 0x00000009
72 PlatformConfigFlags EventType = 0x0000000A
73 TableOfDevices EventType = 0x0000000B
74 CompactHash EventType = 0x0000000C
75 Ipl EventType = 0x0000000D
76 IplPartitionData EventType = 0x0000000E
77 NonhostCode EventType = 0x0000000F
78 NonhostConfig EventType = 0x00000010
79 NonhostInfo EventType = 0x00000011
80 OmitBootDeviceEvents EventType = 0x00000012
81)
82
83// EFI Events (TCG EFI Platform Specification Version 1.22)
84const (
85 EFIEventBase EventType = 0x80000000
86 EFIVariableDriverConfig EventType = 0x80000001
87 EFIVariableBoot EventType = 0x80000002
88 EFIBootServicesApplication EventType = 0x80000003
89 EFIBootServicesDriver EventType = 0x80000004
90 EFIRuntimeServicesDriver EventType = 0x80000005
91 EFIGPTEvent EventType = 0x80000006
92 EFIAction EventType = 0x80000007
93 EFIPlatformFirmwareBlob EventType = 0x80000008
94 EFIHandoffTables EventType = 0x80000009
95 EFIHCRTMEvent EventType = 0x80000010
96 EFIVariableAuthority EventType = 0x800000e0
97)
98
99// ErrSigMissingGUID is returned if an EFI_SIGNATURE_DATA structure was parsed
100// successfully, however was missing the SignatureOwner GUID. This case is
101// handled specially as a workaround for a bug relating to authority events.
102var ErrSigMissingGUID = errors.New("signature data was missing owner GUID")
103
104var eventTypeNames = map[EventType]string{
105 PrebootCert: "Preboot Cert",
106 PostCode: "POST Code",
107 unused: "Unused",
108 NoAction: "No Action",
109 Separator: "Separator",
110 Action: "Action",
111 EventTag: "Event Tag",
112 SCRTMContents: "S-CRTM Contents",
113 SCRTMVersion: "S-CRTM Version",
114 CpuMicrocode: "CPU Microcode",
115 PlatformConfigFlags: "Platform Config Flags",
116 TableOfDevices: "Table of Devices",
117 CompactHash: "Compact Hash",
118 Ipl: "IPL",
119 IplPartitionData: "IPL Partition Data",
120 NonhostCode: "Non-Host Code",
121 NonhostConfig: "Non-HostConfig",
122 NonhostInfo: "Non-Host Info",
123 OmitBootDeviceEvents: "Omit Boot Device Events",
124
125 EFIEventBase: "EFI Event Base",
126 EFIVariableDriverConfig: "EFI Variable Driver Config",
127 EFIVariableBoot: "EFI Variable Boot",
128 EFIBootServicesApplication: "EFI Boot Services Application",
129 EFIBootServicesDriver: "EFI Boot Services Driver",
130 EFIRuntimeServicesDriver: "EFI Runtime Services Driver",
131 EFIGPTEvent: "EFI GPT Event",
132 EFIAction: "EFI Action",
133 EFIPlatformFirmwareBlob: "EFI Platform Firmware Blob",
134 EFIVariableAuthority: "EFI Variable Authority",
135 EFIHandoffTables: "EFI Handoff Tables",
136 EFIHCRTMEvent: "EFI H-CRTM Event",
137}
138
139func (e EventType) String() string {
140 if s, ok := eventTypeNames[e]; ok {
141 return s
142 }
143 return fmt.Sprintf("EventType(0x%x)", uint32(e))
144}
145
146// UntrustedParseEventType returns the event type indicated by
147// the provided value.
148func UntrustedParseEventType(et uint32) (EventType, error) {
149 // "The value associated with a UEFI specific platform event type MUST be in
150 // the range between 0x80000000 and 0x800000FF, inclusive."
151 if (et < 0x80000000 && et > 0x800000FF) || (et < 0x0 && et > 0x12) {
152 return EventType(0), fmt.Errorf("event type not between [0x0, 0x12] or [0x80000000, 0x800000FF]: got %#x", et)
153 }
154 if _, ok := eventTypeNames[EventType(et)]; !ok {
155 return EventType(0), fmt.Errorf("unknown event type %#x", et)
156 }
157 return EventType(et), nil
158}
159
160// efiGUID represents the EFI_GUID type.
161// See section "2.3.1 Data Types" in the specification for more information.
162// type efiGUID [16]byte
163type efiGUID struct {
164 Data1 uint32
165 Data2 uint16
166 Data3 uint16
167 Data4 [8]byte
168}
169
170func (d efiGUID) String() string {
171 var u [8]byte
172 binary.BigEndian.PutUint32(u[:4], d.Data1)
173 binary.BigEndian.PutUint16(u[4:6], d.Data2)
174 binary.BigEndian.PutUint16(u[6:8], d.Data3)
175 return fmt.Sprintf("%x-%x-%x-%x-%x", u[:4], u[4:6], u[6:8], d.Data4[:2], d.Data4[2:])
176}
177
178// UEFIVariableDataHeader represents the leading fixed-size fields
179// within UEFI_VARIABLE_DATA.
180type UEFIVariableDataHeader struct {
181 VariableName efiGUID
182 UnicodeNameLength uint64 // uintN
183 VariableDataLength uint64 // uintN
184}
185
186// UEFIVariableData represents the UEFI_VARIABLE_DATA structure.
187type UEFIVariableData struct {
188 Header UEFIVariableDataHeader
189 UnicodeName []uint16
190 VariableData []byte // []int8
191}
192
193// ParseUEFIVariableData parses the data section of an event structured as
194// a UEFI variable.
195//
196// https://trustedcomputinggroup.org/wp-content/uploads/TCG_PCClient_Specific_Platform_Profile_for_TPM_2p0_1p04_PUBLIC.pdf#page=100
197func ParseUEFIVariableData(r io.Reader) (ret UEFIVariableData, err error) {
198 err = binary.Read(r, binary.LittleEndian, &ret.Header)
199 if err != nil {
200 return
201 }
202 if ret.Header.UnicodeNameLength > maxNameLen {
203 return UEFIVariableData{}, fmt.Errorf("unicode name too long: %d > %d", ret.Header.UnicodeNameLength, maxNameLen)
204 }
205 ret.UnicodeName = make([]uint16, ret.Header.UnicodeNameLength)
206 for i := 0; uint64(i) < ret.Header.UnicodeNameLength; i++ {
207 err = binary.Read(r, binary.LittleEndian, &ret.UnicodeName[i])
208 if err != nil {
209 return
210 }
211 }
212 if ret.Header.VariableDataLength > maxDataLen {
213 return UEFIVariableData{}, fmt.Errorf("variable data too long: %d > %d", ret.Header.VariableDataLength, maxDataLen)
214 }
215 ret.VariableData = make([]byte, ret.Header.VariableDataLength)
216 _, err = io.ReadFull(r, ret.VariableData)
217 return
218}
219
220func (v *UEFIVariableData) VarName() string {
221 return string(utf16.Decode(v.UnicodeName))
222}
223
224func (v *UEFIVariableData) SignatureData() (certs []x509.Certificate, hashes [][]byte, err error) {
225 return parseEfiSignatureList(v.VariableData)
226}
227
228// UEFIVariableAuthority describes the contents of a UEFI variable authority
229// event.
230type UEFIVariableAuthority struct {
231 Certs []x509.Certificate
232}
233
234// ParseUEFIVariableAuthority parses the data section of an event structured as
235// a UEFI variable authority.
236//
237// https://uefi.org/sites/default/files/resources/UEFI_Spec_2_8_final.pdf#page=1789
238func ParseUEFIVariableAuthority(r io.Reader) (UEFIVariableAuthority, error) {
239 v, err := ParseUEFIVariableData(r)
240 if err != nil {
241 return UEFIVariableAuthority{}, err
242 }
243 certs, err := parseEfiSignature(v.VariableData)
244 return UEFIVariableAuthority{Certs: certs}, err
245}
246
247// efiSignatureData represents the EFI_SIGNATURE_DATA type.
248// See section "31.4.1 Signature Database" in the specification for more information.
249type efiSignatureData struct {
250 SignatureOwner efiGUID
251 SignatureData []byte // []int8
252}
253
254// efiSignatureList represents the EFI_SIGNATURE_LIST type.
255// See section "31.4.1 Signature Database" in the specification for more information.
256type efiSignatureListHeader struct {
257 SignatureType efiGUID
258 SignatureListSize uint32
259 SignatureHeaderSize uint32
260 SignatureSize uint32
261}
262
263type efiSignatureList struct {
264 Header efiSignatureListHeader
265 SignatureData []byte
266 Signatures []byte
267}
268
269// parseEfiSignatureList parses a EFI_SIGNATURE_LIST structure.
270// The structure and related GUIDs are defined at:
271// https://uefi.org/sites/default/files/resources/UEFI_Spec_2_8_final.pdf#page=1790
272func parseEfiSignatureList(b []byte) ([]x509.Certificate, [][]byte, error) {
273 if len(b) < 28 {
274 // Being passed an empty signature list here appears to be valid
275 return nil, nil, nil
276 }
277 signatures := efiSignatureList{}
278 buf := bytes.NewReader(b)
279 certificates := []x509.Certificate{}
280 hashes := [][]byte{}
281
282 for buf.Len() > 0 {
283 err := binary.Read(buf, binary.LittleEndian, &signatures.Header)
284 if err != nil {
285 return nil, nil, err
286 }
287
288 if signatures.Header.SignatureHeaderSize > maxDataLen {
289 return nil, nil, fmt.Errorf("signature header too large: %d > %d", signatures.Header.SignatureHeaderSize, maxDataLen)
290 }
291 if signatures.Header.SignatureListSize > maxDataLen {
292 return nil, nil, fmt.Errorf("signature list too large: %d > %d", signatures.Header.SignatureListSize, maxDataLen)
293 }
294
295 signatureType := signatures.Header.SignatureType
296 switch signatureType {
297 case certX509SigGUID: // X509 certificate
298 for sigOffset := 0; uint32(sigOffset) < signatures.Header.SignatureListSize-28; {
299 signature := efiSignatureData{}
300 signature.SignatureData = make([]byte, signatures.Header.SignatureSize-16)
301 err := binary.Read(buf, binary.LittleEndian, &signature.SignatureOwner)
302 if err != nil {
303 return nil, nil, err
304 }
305 err = binary.Read(buf, binary.LittleEndian, &signature.SignatureData)
306 if err != nil {
307 return nil, nil, err
308 }
309 cert, err := x509.ParseCertificate(signature.SignatureData)
310 if err != nil {
311 return nil, nil, err
312 }
313 sigOffset += int(signatures.Header.SignatureSize)
314 certificates = append(certificates, *cert)
315 }
316 case hashSHA256SigGUID: // SHA256
317 for sigOffset := 0; uint32(sigOffset) < signatures.Header.SignatureListSize-28; {
318 signature := efiSignatureData{}
319 signature.SignatureData = make([]byte, signatures.Header.SignatureSize-16)
320 err := binary.Read(buf, binary.LittleEndian, &signature.SignatureOwner)
321 if err != nil {
322 return nil, nil, err
323 }
324 err = binary.Read(buf, binary.LittleEndian, &signature.SignatureData)
325 if err != nil {
326 return nil, nil, err
327 }
328 hashes = append(hashes, signature.SignatureData)
329 sigOffset += int(signatures.Header.SignatureSize)
330 }
331 case keyRSA2048SigGUID:
332 err = errors.New("unhandled RSA2048 key")
333 case certRSA2048SHA256SigGUID:
334 err = errors.New("unhandled RSA2048-SHA256 key")
335 case hashSHA1SigGUID:
336 err = errors.New("unhandled SHA1 hash")
337 case certRSA2048SHA1SigGUID:
338 err = errors.New("unhandled RSA2048-SHA1 key")
339 case hashSHA224SigGUID:
340 err = errors.New("unhandled SHA224 hash")
341 case hashSHA384SigGUID:
342 err = errors.New("unhandled SHA384 hash")
343 case hashSHA512SigGUID:
344 err = errors.New("unhandled SHA512 hash")
345 case certHashSHA256SigGUID:
346 err = errors.New("unhandled X509-SHA256 hash metadata")
347 case certHashSHA384SigGUID:
348 err = errors.New("unhandled X509-SHA384 hash metadata")
349 case certHashSHA512SigGUID:
350 err = errors.New("unhandled X509-SHA512 hash metadata")
351 default:
352 err = fmt.Errorf("unhandled signature type %s", signatureType)
353 }
354 if err != nil {
355 return nil, nil, err
356 }
357 }
358 return certificates, hashes, nil
359}
360
361// EFISignatureData represents the EFI_SIGNATURE_DATA type.
362// See section "31.4.1 Signature Database" in the specification
363// for more information.
364type EFISignatureData struct {
365 SignatureOwner efiGUID
366 SignatureData []byte // []int8
367}
368
369func parseEfiSignature(b []byte) ([]x509.Certificate, error) {
370 certificates := []x509.Certificate{}
371
372 if len(b) < 16 {
373 return nil, fmt.Errorf("invalid signature: buffer smaller than header (%d < %d)", len(b), 16)
374 }
375
376 buf := bytes.NewReader(b)
377 signature := EFISignatureData{}
378 signature.SignatureData = make([]byte, len(b)-16)
379
380 if err := binary.Read(buf, binary.LittleEndian, &signature.SignatureOwner); err != nil {
381 return certificates, err
382 }
383 if err := binary.Read(buf, binary.LittleEndian, &signature.SignatureData); err != nil {
384 return certificates, err
385 }
386
387 cert, err := x509.ParseCertificate(signature.SignatureData)
388 if err == nil {
389 certificates = append(certificates, *cert)
390 } else {
391 // A bug in shim may cause an event to be missing the SignatureOwner GUID.
392 // We handle this, but signal back to the caller using ErrSigMissingGUID.
393 if _, isStructuralErr := err.(asn1.StructuralError); isStructuralErr {
394 var err2 error
395 cert, err2 = x509.ParseCertificate(b)
396 if err2 == nil {
397 certificates = append(certificates, *cert)
398 err = ErrSigMissingGUID
399 }
400 }
401 }
402 return certificates, err
403}