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, err := c.ensureContext()
if err != nil {
return err
}
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, err := c.ensureContext()
if err != nil {
return err
}
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
}
|