-
Notifications
You must be signed in to change notification settings - Fork 574
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
daemon: add /v2/system-secureboot endpoint for pushing updates to sec…
…ureboot key DBs Add a new endpoint for integration with a local manager of EFI secureboot key databases. Signed-off-by: Maciej Borzecki <[email protected]>
- Loading branch information
Showing
4 changed files
with
470 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -85,6 +85,7 @@ var api = []*Command{ | |
registryCmd, | ||
noticesCmd, | ||
noticeCmd, | ||
systemSecurebootCmd, | ||
} | ||
|
||
const ( | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
// -*- Mode: Go; indent-tabs-mode: t -*- | ||
|
||
/* | ||
* Copyright (C) 2024 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 daemon | ||
|
||
import ( | ||
"encoding/base64" | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
"net/http" | ||
|
||
"github.com/snapcore/snapd/overlord/auth" | ||
"github.com/snapcore/snapd/overlord/fdestate" | ||
) | ||
|
||
var systemSecurebootCmd = &Command{ | ||
// TODO GET returning whether secure boot is relevant for the system? | ||
|
||
Path: "/v2/system-secureboot", | ||
POST: postSystemSecurebootAction, | ||
WriteAccess: interfaceProviderRootAccess{ | ||
// TODO find a specialized interface for this, but for now assume that | ||
// requests will come only from snaps plugging fwupd interface on the | ||
// slot side, which also allows manipulation of EFI variables | ||
Interfaces: []string{"fwupd"}, | ||
}, | ||
} | ||
|
||
func postSystemSecurebootAction(c *Command, r *http.Request, user *auth.UserState) Response { | ||
contentType := r.Header.Get("Content-Type") | ||
|
||
switch contentType { | ||
case "application/json": | ||
return postSystemSecurebootActionJSON(c, r) | ||
default: | ||
return BadRequest("unexpected content type: %q", contentType) | ||
} | ||
} | ||
|
||
type securebootRequest struct { | ||
Action string `json:"action,omitempty"` | ||
|
||
// Payload is a base64 encoded binary blob, is used in | ||
// efi-secureboot-db-prepare action, and carries the DBX update content. The | ||
// blob is in the range from few kB to tens of kBs | ||
Payload string `json:"payload,omitempty"` | ||
|
||
// DB is used with efi-secureboot-db-prepare action, and indicates the | ||
// secureboot keys DB which is a target of the action, possible values are | ||
// PK, KEK, DB, DBX | ||
DB string `json:"db,omitempty"` | ||
} | ||
|
||
func (r *securebootRequest) Validate() error { | ||
switch r.Action { | ||
case "efi-secureboot-update-startup", "efi-secureboot-update-db-cleanup": | ||
if r.DB != "" { | ||
return fmt.Errorf("unexpected key DB for action %q", r.Action) | ||
} | ||
|
||
if len(r.Payload) > 0 { | ||
return fmt.Errorf("unexpected payload for action %q", r.Action) | ||
} | ||
case "efi-secureboot-update-db-prepare": | ||
switch r.DB { | ||
case "PK", "KEK", "DB", "DBX": | ||
default: | ||
return fmt.Errorf("invalid key DB %q", r.DB) | ||
} | ||
|
||
if len(r.Payload) == 0 { | ||
return errors.New("update payload not provided") | ||
} | ||
default: | ||
return fmt.Errorf("unsupported EFI secure boot action %q", r.Action) | ||
} | ||
return nil | ||
} | ||
|
||
func postSystemSecurebootActionJSON(c *Command, r *http.Request) Response { | ||
var req securebootRequest | ||
|
||
decoder := json.NewDecoder(r.Body) | ||
|
||
if err := decoder.Decode(&req); err != nil { | ||
return BadRequest("cannot decode request body: %v", err) | ||
} | ||
|
||
if decoder.More() { | ||
return BadRequest("extra content found in request body") | ||
} | ||
|
||
if err := req.Validate(); err != nil { | ||
return BadRequest(err.Error()) | ||
} | ||
|
||
switch req.Action { | ||
case "efi-secureboot-update-startup": | ||
return postSystemActionEFISecurebootUpdateStartup(c) | ||
case "efi-secureboot-update-db-cleanup": | ||
return postSystemActionEFISecurebootUpdateDBCleanup(c) | ||
case "efi-secureboot-update-db-prepare": | ||
return postSystemActionEFISecurebootUpdateDBPrepare(c, &req) | ||
default: | ||
return InternalError("support for EFI secure boot action %q is not implemented", req.Action) | ||
} | ||
} | ||
|
||
var fdestateEFISecureBootDBUpdatePrepare = fdestate.EFISecureBootDBUpdatePrepare | ||
|
||
func postSystemActionEFISecurebootUpdateDBPrepare(c *Command, req *securebootRequest) Response { | ||
if req.DB != "DBX" { | ||
return InternalError("support for key DB %q is not implemented", req.DB) | ||
} | ||
|
||
payload, err := base64.StdEncoding.DecodeString(req.Payload) | ||
if err != nil { | ||
return BadRequest("cannot decode payload: %v", err) | ||
} | ||
|
||
err = fdestateEFISecureBootDBUpdatePrepare(c.d.state, | ||
fdestate.EFISecurebootDBX, // only DBX updates are supported | ||
payload) | ||
if err != nil { | ||
return BadRequest("cannot notify of update prepare: %v", err) | ||
} | ||
|
||
return SyncResponse(nil) | ||
} | ||
|
||
var fdestateEFISecureBootDBUpdateCleanup = fdestate.EFISecureBootDBUpdateCleanup | ||
|
||
func postSystemActionEFISecurebootUpdateDBCleanup(c *Command) Response { | ||
if err := fdestateEFISecureBootDBUpdateCleanup(c.d.state); err != nil { | ||
return BadRequest("cannot notify of update cleanup: %v", err) | ||
} | ||
|
||
return SyncResponse(nil) | ||
} | ||
|
||
var fdestateEFISecureBootDBManagerStartup = fdestate.EFISecureBootDBManagerStartup | ||
|
||
func postSystemActionEFISecurebootUpdateStartup(c *Command) Response { | ||
if err := fdestateEFISecureBootDBManagerStartup(c.d.state); err != nil { | ||
return BadRequest("cannot notify of manager startup: %v", err) | ||
} | ||
|
||
return SyncResponse(nil) | ||
} |
Oops, something went wrong.