// -*- 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 . * */ 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 ( "crypto/ecdsa" "github.com/snapcore/snapd/asserts" "github.com/snapcore/snapd/bootloader" "github.com/snapcore/snapd/dirs" "github.com/snapcore/snapd/gadget/device" "github.com/snapcore/snapd/secboot/keys" ) const ( // 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 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 key to seal Key keys.EncryptionKey // The key name; identical keys should have identical names KeyName string // The path to store the sealed key file. The same Key/KeyName // can be stored under multiple KeyFile names for safety. KeyFile 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 } 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 } 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 authorization policy update key file (only relevant for TPM) TPMPolicyAuthKey *ecdsa.PrivateKey // The path to the authorization policy update key file (only relevant for TPM, // if empty the key will not be saved) TPMPolicyAuthKeyFile string // The handle at which to create a NV index for dynamic authorization policy revocation support PCRPolicyCounterHandle uint32 } type SealKeysWithFDESetupHookParams struct { // Initial model to bind sealed keys to. Model ModelForSealing // AuxKey is the auxiliary key used to bind models. AuxKey keys.AuxKey // The path to the aux key file (if empty the key will not be // saved) AuxKeyFile string } type ResealKeysParams struct { // The snap model parameters ModelParams []*SealKeyModelParams // The path to the sealed key files KeyFiles []string // The path to the authorization policy update key file (only relevant for TPM) TPMPolicyAuthKeyFile string } // 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) } // 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 }