forked from canonical/snapd
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsecboot.go
228 lines (204 loc) · 7.57 KB
/
secboot.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
// -*- Mode: Go; indent-tabs-mode: t -*-
/*
* Copyright (C) 2021-2022 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package secboot
// This file must not have a build-constraint and must not import
// the github.com/snapcore/secboot repository. That will ensure
// it can be build as part of the debian build without secboot.
// Debian does run "go list" without any support for passing -tags.
import (
"crypto/ecdsa"
"github.com/snapcore/snapd/asserts"
"github.com/snapcore/snapd/bootloader"
"github.com/snapcore/snapd/dirs"
"github.com/snapcore/snapd/gadget/device"
"github.com/snapcore/snapd/secboot/keys"
)
const (
// Handles are in the block reserved for TPM owner objects (0x01800000 - 0x01bfffff).
//
// Handles are rotated during factory reset, depending on the PCR handle
// thet was used when sealing key objects during installation (or a
// previous factory reset).
RunObjectPCRPolicyCounterHandle = uint32(0x01880001)
FallbackObjectPCRPolicyCounterHandle = uint32(0x01880002)
AltRunObjectPCRPolicyCounterHandle = uint32(0x01880003)
AltFallbackObjectPCRPolicyCounterHandle = uint32(0x01880004)
)
// WithSecbootSupport is true if this package was built with githbu.com/snapcore/secboot.
var WithSecbootSupport = false
type LoadChain struct {
*bootloader.BootFile
// Next is a list of alternative chains that can be loaded
// following the boot file.
Next []*LoadChain
}
// NewLoadChain returns a LoadChain corresponding to loading the given
// BootFile before any of the given next chains.
func NewLoadChain(bf bootloader.BootFile, next ...*LoadChain) *LoadChain {
return &LoadChain{
BootFile: &bf,
Next: next,
}
}
type SealKeyRequest struct {
// The key to seal
Key keys.EncryptionKey
// The key name; identical keys should have identical names
KeyName string
// The path to store the sealed key file. The same Key/KeyName
// can be stored under multiple KeyFile names for safety.
KeyFile string
}
// ModelForSealing provides information about the model for use in the context
// of (re)sealing the encryption keys.
type ModelForSealing interface {
Series() string
BrandID() string
Model() string
Classic() bool
Grade() asserts.ModelGrade
SignKeyID() string
}
type SealKeyModelParams struct {
// The snap model
Model ModelForSealing
// The set of EFI binary load chains for the current device
// configuration
EFILoadChains []*LoadChain
// The kernel command line
KernelCmdlines []string
}
type TPMProvisionMode int
const (
TPMProvisionNone TPMProvisionMode = iota
// TPMProvisionFull indicates a full provisioning of the TPM
TPMProvisionFull
// TPMPartialReprovision indicates a partial reprovisioning of the TPM
// which was previously already provisioned by secboot. Existing lockout
// authorization data from TPMLockoutAuthFile will be used to authorize
// provisioning and will get overwritten in the process.
TPMPartialReprovision
// TPMProvisionFullWithoutLockout indicates full provisioning
// without using lockout authorization data, as currently used
// by Azure CVM
TPMProvisionFullWithoutLockout
)
type SealKeysParams struct {
// The parameters we're sealing the key to
ModelParams []*SealKeyModelParams
// The authorization policy update key file (only relevant for TPM)
TPMPolicyAuthKey *ecdsa.PrivateKey
// The path to the authorization policy update key file (only relevant for TPM,
// if empty the key will not be saved)
TPMPolicyAuthKeyFile string
// The handle at which to create a NV index for dynamic authorization policy revocation support
PCRPolicyCounterHandle uint32
}
type SealKeysWithFDESetupHookParams struct {
// Initial model to bind sealed keys to.
Model ModelForSealing
// AuxKey is the auxiliary key used to bind models.
AuxKey keys.AuxKey
// The path to the aux key file (if empty the key will not be
// saved)
AuxKeyFile string
}
type ResealKeysParams struct {
// The snap model parameters
ModelParams []*SealKeyModelParams
// The path to the sealed key files
KeyFiles []string
// The path to the authorization policy update key file (only relevant for TPM)
TPMPolicyAuthKeyFile string
}
// UnlockVolumeUsingSealedKeyOptions contains options for unlocking encrypted
// volumes using keys sealed to the TPM.
type UnlockVolumeUsingSealedKeyOptions struct {
// AllowRecoveryKey when true indicates activation with the recovery key
// will be attempted if activation with the sealed key failed.
AllowRecoveryKey bool
// WhichModel if invoked should return the device model
// assertion for which the disk is being unlocked.
WhichModel func() (*asserts.Model, error)
}
// UnlockMethod is the method that was used to unlock a volume.
type UnlockMethod int
const (
// NotUnlocked indicates that the device was either not unlocked or is not
// an encrypted device.
NotUnlocked UnlockMethod = iota
// UnlockedWithSealedKey indicates that the device was unlocked with the
// provided sealed key object.
UnlockedWithSealedKey
// UnlockedWithRecoveryKey indicates that the device was unlocked by the
// user providing the recovery key at the prompt.
UnlockedWithRecoveryKey
// UnlockedWithKey indicates that the device was unlocked with the provided
// key, which is not sealed.
UnlockedWithKey
// UnlockStatusUnknown indicates that the unlock status of the device is not clear.
UnlockStatusUnknown
)
// UnlockResult is the result of trying to unlock a volume.
type UnlockResult struct {
// FsDevice is the device with filesystem ready to mount.
// It is the activated device if encrypted or just
// the underlying device (same as PartDevice) if non-encrypted.
// FsDevice can be empty when none was found.
FsDevice string
// PartDevice is the underlying partition device.
// PartDevice can be empty when no device was found.
PartDevice string
// IsEncrypted indicates that PartDevice is encrypted.
IsEncrypted bool
// UnlockMethod is the method used to unlock the device. Valid values are
// - NotUnlocked
// - UnlockedWithRecoveryKey
// - UnlockedWithSealedKey
// - UnlockedWithKey
UnlockMethod UnlockMethod
}
// EncryptedPartitionName returns the name/label used by an encrypted partition
// corresponding to a given name.
func EncryptedPartitionName(name string) string {
return name + "-enc"
}
// MarkSuccessful marks the secure boot parts of the boot as
// successful.
//
// This means that the dictionary attack (DA) lockout counter is reset.
func MarkSuccessful() error {
sealingMethod, err := device.SealedKeysMethod(dirs.GlobalRootDir)
if err != nil && err != device.ErrNoSealedKeys {
return err
}
if sealingMethod == device.SealingMethodTPM {
lockoutAuthFile := device.TpmLockoutAuthUnder(dirs.SnapFDEDirUnderSave(dirs.SnapSaveDir))
// each unclean shtutdown will increase the DA lockout
// counter. So on a successful boot we need to clear
// this counter to avoid eventually hitting the
// snapcore/secboot:tpm2/provisioning.go limit of
// maxTries=32. Note that on a clean shtudown linux
// will call TPM2_Shutdown which ensure no DA lockout
// is increased.
if err := resetLockoutCounter(lockoutAuthFile); err != nil {
return err
}
}
return nil
}