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 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
|
// -*- 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 (
"errors"
"github.com/snapcore/snapd/asserts"
"github.com/snapcore/snapd/bootloader"
"github.com/snapcore/snapd/dirs"
"github.com/snapcore/snapd/gadget/device"
)
const (
// The range 0x01880005-0x0188000F
//
// TODO:FDEM: we should apply for a subrange from UAPI group once
// they got a range assigned by TCG. See
// https://github.com/uapi-group/specifications/pull/118
// For now we use a sub range on the unassigned owner handles
PCRPolicyCounterHandleStart = uint32(0x01880005)
PCRPolicyCounterHandleRange = uint32(0x01880010 - 0x01880005)
// These handles are legacy, do not use them in new code.
//
// 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
var ErrKernelKeyNotFound = errors.New("kernel key not found")
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 installation key to enroll a new key slot
BootstrappedContainer BootstrappedContainer
// The key name; identical keys should have identical names
KeyName string
// The name of the slot where they key will be saved.
SlotName string
// The file to store the key data. If empty, the key data will
// be saved to the token.
KeyFile string
// The boot modes allowed (i.e. snapd_recovery_mode kernel parameter)
BootModes []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
}
// TODO:FDEM: rename and drop Model from the name?
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
// TODO:FDEM: move this somewhere else?
// The content of an update to EFI DBX
EFISignatureDbxUpdate []byte
}
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 primary key to use, nil if needs to be generated
PrimaryKey []byte
// The handle at which to create a NV index for dynamic authorization policy revocation support
PCRPolicyCounterHandle uint32
// The path to the authorization policy update key file (only relevant for TPM,
// if empty the key will not be saved)
TPMPolicyAuthKeyFile string
// Optional volume authentication options
VolumesAuth *device.VolumesAuthOptions
// The key role (run, run+recover, recover)
KeyRole string
// Whether to allow disabled DMA protection
AllowInsufficientDmaProtection bool
}
type SealKeysWithFDESetupHookParams struct {
// Initial model to bind sealed keys to.
Model ModelForSealing
// The path to the aux key file (if empty the key will not be
// saved)
AuxKeyFile string
// The primary key to use, nil if needs to be generated
PrimaryKey []byte
}
// KeyDataLocation represents the possible places where key data
// might be saved.
//
// This is used for resealing keys in key data. The resealing will be
// responsible of finding which one is in use. The basic strategy is
// if a key data is found in the token, then this will be used and the
// key file will be ignored.
type KeyDataLocation struct {
// KeyFile is the path to the file that contains either the key data or sealed key object.
KeyFile string
// DevicePath is the LUKS2 device which contains a token with they key data
DevicePath string
// SlotName is the name of the token that contains the key data
SlotName string
}
// KeyData represents a disk unlock key protected by a platform's secure device.
type KeyData interface {
PlatformName() string
Roles() []string
AuthMode() device.AuthMode
// ChangePassphrase changes passphrase given old passphrase.
// AuthMode must be device.AuthModePassphrase.
ChangePassphrase(oldPassphrase, newPassphrase string) error
// WriteTokenAtomic saves this key data to the specified LUKS2 token.
WriteTokenAtomic(devicePath, slotName string) error
}
// SerializedPCRProfile wraps a serialized PCR profile which is treated as an
// opaque binary blob outside of secboot package.
type SerializedPCRProfile []byte
type ResealKeysParams struct {
// The snap model parameters
PCRProfile SerializedPCRProfile
// The locations to the key data
Keys []KeyDataLocation
// The primary key
PrimaryKey []byte
}
// 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)
// BootMode is the current boot mode (i.e. snapd_recovery_mode kernel parameter)
BootMode string
}
// 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
}
const (
defaultKeyringPrefix = "ubuntu-fde"
)
|