forked from snapcore/snapd
/
fde_setup.go
139 lines (112 loc) · 4.1 KB
/
fde_setup.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
// -*- Mode: Go; indent-tabs-mode: t -*-
/*
* Copyright (C) 2020 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 ctlcmd
import (
"encoding/json"
"fmt"
"github.com/snapcore/snapd/i18n"
"github.com/snapcore/snapd/kernel/fde"
)
type fdeSetupRequestCommand struct {
baseCommand
}
var shortFdeSetupRequestHelp = i18n.G("Obtain full disk encryption setup request")
var longFdeSetupRequestHelp = i18n.G(`
The fde-setup-request command is used inside the fde-setup hook. It will
return information about what operation for full-disk encryption is
requested and auxiliary data to complete this operation.
The fde-setup hook should do what is requested and then call
"snapctl fde-setup-result" and pass the result data to stdin.
Here is an example for how the fde-setup hook is called initially:
$ snapctl fde-setup-request
{"op":"features"}
$ echo '{"features": []}' | snapctl fde-setup-result
Alternatively the hook could reply with:
$ echo '{"error":"hardware-unsupported"}' | snapctl fde-setup-result
And then it is called again with a request to do the initial key setup:
$ snapctl fde-setup-request
{"op":"initial-setup", "key": "key-to-seal"}
$ echo "{\"sealed-key\":\"$base64_encoded_sealed_key\"}" | snapctl fde-setup-result
`)
func init() {
addCommand("fde-setup-request", shortFdeSetupRequestHelp, longFdeSetupRequestHelp, func() command { return &fdeSetupRequestCommand{} })
}
func (c *fdeSetupRequestCommand) Execute(args []string) error {
context := c.context()
if context == nil {
return fmt.Errorf("cannot run fde-setup-request without a context")
}
context.Lock()
defer context.Unlock()
if context.HookName() != "fde-setup" {
return fmt.Errorf("cannot use fde-setup-request outside of the fde-setup hook")
}
var fdeSetup fde.SetupRequest
if err := context.Get("fde-setup-request", &fdeSetup); err != nil {
return fmt.Errorf("cannot get fde-setup-op from context: %v", err)
}
// Op is either "initial-setup" or "features"
switch fdeSetup.Op {
case "features", "initial-setup":
// fine
default:
return fmt.Errorf("unknown fde-setup-request op %q", fdeSetup.Op)
}
bytes, err := json.Marshal(fdeSetup)
if err != nil {
return fmt.Errorf("cannot json print fde key: %v", err)
}
c.printf("%s\n", string(bytes))
return nil
}
type fdeSetupResultCommand struct {
baseCommand
}
var shortFdeSetupResultHelp = i18n.G("Set result for full disk encryption")
var longFdeSetupResultHelp = i18n.G(`
The fde-setup-result command sets the result data for a fde-setup hook
reading it from stdin.
For example:
When the fde-setup hook is called with "op":"features:
$ echo '{"features": []}' | snapctl fde-setup-result
When the fde-setup hook is called with "op":"initial-setup":
$ echo "{\"sealed-key\":\"$base64_encoded_sealed_key\"}" | snapctl fde-setup-result
`)
func init() {
addCommand("fde-setup-result", shortFdeSetupResultHelp, longFdeSetupResultHelp, func() command { return &fdeSetupResultCommand{} })
}
func (c *fdeSetupResultCommand) Execute(args []string) error {
context := c.context()
if context == nil {
return fmt.Errorf("cannot run fde-setup-result without a context")
}
context.Lock()
defer context.Unlock()
if context.HookName() != "fde-setup" {
return fmt.Errorf("cannot use fde-setup-result outside of the fde-setup hook")
}
var fdeSetupResult []byte
if err := context.Get("stdin", &fdeSetupResult); err != nil {
return fmt.Errorf("internal error: cannot get result from stdin: %v", err)
}
if fdeSetupResult == nil {
return fmt.Errorf("no result data found from stdin")
}
context.Set("fde-setup-result", fdeSetupResult)
return nil
}