forked from canonical/snapd
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathencrypt_sb.go
245 lines (215 loc) · 7.54 KB
/
encrypt_sb.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
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
// -*- Mode: Go; indent-tabs-mode: t -*-
//go:build !nosecboot
/*
* Copyright (C) 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
import (
"bytes"
"encoding/json"
"fmt"
"io"
"path/filepath"
sb "github.com/snapcore/secboot"
"github.com/snapcore/snapd/logger"
"github.com/snapcore/snapd/osutil/disks"
"github.com/snapcore/snapd/secboot/keymgr"
"github.com/snapcore/snapd/secboot/keys"
"github.com/snapcore/snapd/snapdtool"
"github.com/snapcore/snapd/systemd"
)
var (
sbInitializeLUKS2Container = sb.InitializeLUKS2Container
sbAddRecoveryKeyToLUKS2Container = sb.AddRecoveryKeyToLUKS2Container
)
const keyslotsAreaKiBSize = 2560 // 2.5MB
const metadataKiBSize = 2048 // 2MB
// FormatEncryptedDevice initializes an encrypted volume on the block device
// given by node, setting the specified label. The key used to unlock the volume
// is provided using the key argument.
func FormatEncryptedDevice(key keys.EncryptionKey, encType EncryptionType, label, node string) error {
if !encType.IsLUKS() {
return fmt.Errorf("internal error: FormatEncryptedDevice for %q expects a LUKS encryption type, not %q", node, encType)
}
useICE := encType == EncryptionTypeLUKSWithICE
logger.Debugf("node %q uses ICE: %v", node, useICE)
opts := &sb.InitializeLUKS2ContainerOptions{
// use a lower, but still reasonable size that should give us
// enough room
MetadataKiBSize: metadataKiBSize,
KeyslotsAreaKiBSize: keyslotsAreaKiBSize,
// Use fixed parameters for the KDF to avoid the
// benchmark. This is okay because we have a high
// entropy key and the KDF does not gain us much.
KDFOptions: &sb.KDFOptions{
MemoryKiB: 32,
ForceIterations: 4,
},
InlineCryptoEngine: useICE,
}
return sbInitializeLUKS2Container(node, label, key[:], opts)
}
// AddRecoveryKey adds a fallback recovery key rkey to the existing encrypted
// volume created with FormatEncryptedDevice on the block device given by node.
// The existing key to the encrypted volume is provided in the key argument.
func AddRecoveryKey(key keys.EncryptionKey, rkey keys.RecoveryKey, node string) error {
return keymgr.AddRecoveryKeyToLUKSDeviceUsingKey(rkey, key, node)
}
func runSnapFDEKeymgr(args []string, stdin io.Reader) error {
toolPath, err := snapdtool.InternalToolPath("snap-fde-keymgr")
if err != nil {
return fmt.Errorf("cannot find keymgr tool: %v", err)
}
sysd := systemd.New(systemd.SystemMode, nil)
command := []string{
toolPath,
}
command = append(command, args...)
_, err = sysd.Run(command, &systemd.RunOptions{
KeyringMode: systemd.KeyringModeInherit,
Stdin: stdin,
})
return err
}
// EnsureRecoveryKey makes sure the encrypted block devices have a recovery key.
// It takes the path where to store the key and encrypted devices to operate on.
func EnsureRecoveryKey(keyFile string, rkeyDevs []RecoveryKeyDevice) (keys.RecoveryKey, error) {
// support multiple devices with the same key
command := []string{
"add-recovery-key",
"--key-file", keyFile,
}
for _, rkeyDev := range rkeyDevs {
dev, err := devByPartUUIDFromMount(rkeyDev.Mountpoint)
if err != nil {
return keys.RecoveryKey{}, fmt.Errorf("cannot find matching device for: %v", err)
}
logger.Debugf("ensuring recovery key on device: %v", dev)
authzMethod := "keyring"
if rkeyDev.AuthorizingKeyFile != "" {
authzMethod = "file:" + rkeyDev.AuthorizingKeyFile
}
command = append(command, []string{
"--devices", dev,
"--authorizations", authzMethod,
}...)
}
if err := runSnapFDEKeymgr(command, nil); err != nil {
return keys.RecoveryKey{}, fmt.Errorf("cannot run keymgr tool: %v", err)
}
rk, err := keys.RecoveryKeyFromFile(keyFile)
if err != nil {
return keys.RecoveryKey{}, fmt.Errorf("cannot read recovery key: %v", err)
}
return *rk, nil
}
func devByPartUUIDFromMount(mp string) (string, error) {
partUUID, err := disks.PartitionUUIDFromMountPoint(mp, &disks.Options{
IsDecryptedDevice: true,
})
if err != nil {
return "", fmt.Errorf("cannot partition for mount %v: %v", mp, err)
}
dev := filepath.Join("/dev/disk/by-partuuid", partUUID)
return dev, nil
}
// RemoveRecoveryKeys removes any recovery key from all encrypted block devices.
// It takes a map from the recovery key device to where their recovery key is
// stored, mount points might share the latter.
func RemoveRecoveryKeys(rkeyDevToKey map[RecoveryKeyDevice]string) error {
// support multiple devices and key files
command := []string{
"remove-recovery-key",
}
for rkeyDev, keyFile := range rkeyDevToKey {
dev, err := devByPartUUIDFromMount(rkeyDev.Mountpoint)
if err != nil {
return fmt.Errorf("cannot find matching device for: %v", err)
}
logger.Debugf("removing recovery key from device: %v", dev)
authzMethod := "keyring"
if rkeyDev.AuthorizingKeyFile != "" {
authzMethod = "file:" + rkeyDev.AuthorizingKeyFile
}
command = append(command, []string{
"--devices", dev,
"--authorizations", authzMethod,
"--key-files", keyFile,
}...)
}
if err := runSnapFDEKeymgr(command, nil); err != nil {
return fmt.Errorf("cannot run keymgr tool: %v", err)
}
return nil
}
// StageEncryptionKeyChange stages a new encryption key for a given encrypted
// device. The new key is added into a temporary slot. To complete the
// encryption key change process, a call to TransitionEncryptionKeyChange is
// needed.
func StageEncryptionKeyChange(node string, key keys.EncryptionKey) error {
partitionUUID, err := disks.PartitionUUID(node)
if err != nil {
return fmt.Errorf("cannot get UUID of partition %v: %v", node, err)
}
dev := filepath.Join("/dev/disk/by-partuuid", partitionUUID)
logger.Debugf("stage encryption key change on device: %v", dev)
var buf bytes.Buffer
err = json.NewEncoder(&buf).Encode(struct {
Key []byte `json:"key"`
}{
Key: key,
})
if err != nil {
return fmt.Errorf("cannot encode key for the FDE key manager tool: %v", err)
}
command := []string{
"change-encryption-key",
"--device", dev,
"--stage",
}
if err := runSnapFDEKeymgr(command, &buf); err != nil {
return fmt.Errorf("cannot run FDE key manager tool: %v", err)
}
return nil
}
// TransitionEncryptionKeyChange transitions the encryption key on an encrypted
// device corresponding to the given mount point. The change is authorized using
// the new key, thus a prior call to StageEncryptionKeyChange must be done.
func TransitionEncryptionKeyChange(mountpoint string, key keys.EncryptionKey) error {
dev, err := devByPartUUIDFromMount(mountpoint)
if err != nil {
return fmt.Errorf("cannot find matching device: %v", err)
}
logger.Debugf("transition encryption key change on device: %v", dev)
var buf bytes.Buffer
err = json.NewEncoder(&buf).Encode(struct {
Key []byte `json:"key"`
}{
Key: key,
})
if err != nil {
return fmt.Errorf("cannot encode key for the FDE key manager tool: %v", err)
}
command := []string{
"change-encryption-key",
"--device", dev,
"--transition",
}
if err := runSnapFDEKeymgr(command, &buf); err != nil {
return fmt.Errorf("cannot run FDE key manager tool: %v", err)
}
return nil
}