secboot

package module
v0.0.0-...-33c8514 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 23, 2026 License: GPL-3.0 Imports: 50 Imported by: 30

README

secboot

A Go library for managing TPM-backed encrypted disks on Linux operating systems.

Features

  • System installation & maintenance:

    • Do pre-install platform compatibility checks
    • Initialize the TPM
    • Seal a LUKS passphrase within the TPM
    • Update sealing policy (typically after platform or software update)
    • Manage TPM lockout (set authValue, reset)
    • Compute PCR profiles
    • Manage recovery keys of LUKS containers (create, list, delete)
  • System boot:

    • Unseal
    • Attempt various unlocking paths (TPM-backed, with PIN, with passphrase, recovery...)
  • Other useful functions

    • Get entropy of a PIN or passphrase
    • Access to UEFI variables PK, KEK, Db, Dbx

License

Secboot is licensed under the GNU General Public License version 3.

See the COPYING file for more details.

Documentation

Index

Constants

View Source
const (
	// Argon2Default is used by Argon2Options to select the default
	// Argon2 mode, which is currently Argon2id.
	Argon2Default Argon2Mode = ""

	// Argon2i is the data-independent mode of Argon2.
	Argon2i = argon2.ModeI

	// Argon2id is the hybrid mode of Argon2.
	Argon2id = argon2.ModeID
)
View Source
const ClassicModelGradeMask uint32 = 0x80000000

ClassicModelGradeMask is ORed with the model grade code when measuring a classic snap model.

Variables

View Source
var (
	ErrStorageContainerClosed    = errors.New("storage container reader/writer is already closed")
	ErrKeyslotNotFound           = errors.New("keyslot not found")
	ErrStorageContainerNotActive = errors.New("storage container is not active")
	ErrNoStorageContainer        = errors.New("no storage container for path")
)
View Source
var (
	// KeyDataGeneration describes the generation number of new keys created by NewKeyData.
	// This will be supplied via PlatformKeyDataHandler and should generally be
	// authenticated by the platform code in order to protect against future key format
	// changes that might have security relevant implications.
	KeyDataGeneration = 2

	// ErrNoPlatformHandlerRegistered is returned from KeyData methods if no
	// appropriate platform handler is registered using the
	// RegisterPlatformKeyDataHandler API.
	ErrNoPlatformHandlerRegistered = errors.New("no appropriate platform handler is registered")

	// ErrInvalidPassphrase is returned from KeyData methods that require
	// knowledge of a passphrase and the supplied passphrase is incorrect.
	ErrInvalidPassphrase = errors.New("the supplied passphrase is incorrect")

	// ErrInvalidPIN is returned from KeyData methods that require
	// knowledge of a PIN and the supplied passphrase is incorrect.
	ErrInvalidPIN = errors.New("the supplied PIN is incorrect")
)
View Source
var ErrAuthRequestorNotAvailable = errors.New("the auth requestor is not available")

ErrAuthRequestorNotAvailable can be returned from any method of AuthRequestor to indicate that the underlying mechanism is not available.

View Source
var (
	// ErrCannotActivate is returned from ActivateContext.ActivateContainer
	// if a storage container cannot be activated because there are no valid
	// keyslots and / or there are no more passphrase, PIN or recovery key
	// attempts remaining.
	ErrCannotActivate = errors.New("cannot activate: no valid keyslots and / or no more passphrase, PIN or recovery key tries remaining")
)
View Source
var ErrKernelKeyNotFound = errors.New("cannot find key in kernel keyring")

ErrKernelKeyNotFound indicates that a key with the supplied parameters could not be found in the expected location in the keyring.

View Source
var (
	// ErrMissingCryptsetupFeature is returned from some functions that make
	// use of the system's cryptsetup binary, if that binary is missing some
	// required features.
	ErrMissingCryptsetupFeature = luks2.ErrMissingCryptsetupFeature
)
View Source
var ErrRecoveryKeyUsed = errors.New("cannot activate with platform protected keys but activation with the recovery key was successful")

ErrRecoveryKeyUsed is returned from ActivateVolumeWithKeyData if the volume could not be activated with any platform protected keys but activation with the recovery key was successful.

View Source
var InProcessArgon2KDF = inProcessArgon2KDFImpl{}

InProcessArgon2KDF is the in-process implementation of the Argon2 KDF.

This shouldn't be used in long-lived system processes. As Argon2 intentionally allocates a lot of memory and go is garbage collected, it may be some time before the large amounts of memory it allocates are freed and made available to other code or other processes on the system. Consecutive calls can rapidly result in the application being unable to allocate more memory, and even worse, may trigger the kernel's OOM killer. Whilst implementations can call runtime.GC between calls, go's sweep implementation stops the world, which makes interaction with goroutines and the scheduler poor, and will likely result in noticeable periods of unresponsiveness. Rather than using this directly, it's better to pass requests to a short-lived helper process where this can be used, and let the kernel deal with reclaiming memory when the short-lived process exits instead.

This package provides APIs to support this architecture already - NewOutOfProcessArgon2KDF for the parent side, and WaitForAndRunArgon2OutOfProcessRequest for the remote side, which runs in a short-lived process. In order to save storage space that would be consumed by another go binary, it is reasonable that the parent side (the one that calls SetArgon2KDF) and the remote side (which calls WaitForAndRunArgon2OutOfProcessRequest) could live in the same executable that is invoked with different arguments depending on which function is required.

View Source
var KeyslotAlreadyHasANameErr = errors.New("keyslot already has a name")

KeyslotAlreadyHasANameErr may be returned by NameLegacyLUKS2ContainerKey when trying to create a token for a keyslot that already used by a token.

Functions

func ActivateConfigGet

func ActivateConfigGet[V any, K comparable](c ActivateConfigGetter, key K) (val V, exists bool)

ActivateConfigGet is a generic implementation of [ActivateConfig.Get]. If a value for the specified key doesn't exist, the zero value is returned along with false. If a value for the specified key exists but it is of the wrong type, this function will panic.

func ActivateVolumeWithKey

func ActivateVolumeWithKey(volumeName, sourceDevicePath string, key []byte, options *ActivateVolumeOptions) error

ActivateVolumeWithKey attempts to activate the LUKS encrypted volume at sourceDevicePath and create a mapping with the name volumeName, using the provided key. This makes use of systemd-cryptsetup.

func ActivateVolumeWithKeyData

func ActivateVolumeWithKeyData(volumeName, sourceDevicePath string, authRequestor AuthRequestor, options *ActivateVolumeOptions, keys ...*KeyData) error

ActivateVolumeWithKeyData attempts to activate the LUKS encrypted container at sourceDevicePath and create a mapping with the name volumeName, using one of the KeyData objects stored in the container's metadata area to recover the disk unlock key from the platform's secure device. This makes use of systemd-cryptsetup.

External KeyData objects can be supplied via the keys argument, and these will be attempted first.

If activation with all of the KeyData objects fails, this function will attempt to activate it with the fallback recovery key instead. The fallback recovery key is requested via the supplied authRequestor. If an AuthRequestor is not supplied, an error will be returned if the fallback recovery key is required. The RecoveryKeyTries field of options specifies how many attemps to request and use the recovery key will be made before failing. If it is set to 0, then no attempts will be made to request and use the fallback recovery key.

If either the PassphraseTries or RecoveryKeyTries fields of options are less than zero, an error will be returned. If the Model field of options is nil, an error will be returned.

If the fallback recovery key is used for successfully for activation, an ErrRecoveryKeyUsed error will be returned.

If activation fails, an error will be returned.

If activation with one of the KeyData objects succeeds (ie, no error is returned), then the supplied SnapModel is authorized to access the data on this volume.

func ActivateVolumeWithRecoveryKey

func ActivateVolumeWithRecoveryKey(volumeName, sourceDevicePath string, authRequestor AuthRequestor, options *ActivateVolumeOptions) error

ActivateVolumeWithRecoveryKey attempts to activate the LUKS encrypted volume at sourceDevicePath and create a mapping with the name volumeName, using the fallback recovery key. This makes use of systemd-cryptsetup.

The recovery key is requested via the supplied AuthRequestor. If an AuthRequestor is not supplied, an error will be returned. The RecoveryKeyTries field of options specifies how many attempts to request and use the recovery key will be made before failing.

If the RecoveryKeyTries field of options is less than zero, an error will be returned.

func AddLUKS2ContainerRecoveryKey

func AddLUKS2ContainerRecoveryKey(devicePath, keyslotName string, existingKey DiskUnlockKey, recoveryKey RecoveryKey) error

AddLUKS2ContainerRecoveryKey creates a fallback recovery keyslot with the specified name on the LUKS2 container at the specified path and uses it to protect the LUKS master key with the supplied recovery key. The keyslot can be used to unlock the container in scenarios where it cannot be unlocked using a platform protected key.

If the specified name is empty, the name "default-recovery" will be used.

The recovery key must be generated by a cryptographically strong random number source.

If a keyslot with the supplied name already exists, an error will be returned. The keyslot must first be deleted with DeleteLUKS2ContainerKey or renamed with RenameLUKS2ContainerKey.

In order to perform this action, an existing key must be supplied.

func AddLUKS2ContainerUnlockKey

func AddLUKS2ContainerUnlockKey(devicePath, keyslotName string, existingKey, newKey DiskUnlockKey) error

AddLUKS2ContainerUnlockKey creates a keyslot with the specified name on the LUKS2 container at the specified path, and uses it to protect the master key with the supplied key. The created keyslot is one that will normally be used for unlocking the specified LUKS2 container.

If the specified name is empty, the name "default" will be used.

The new key should be a cryptographically strong random number of at least 32-bytes.

If a keyslot with the supplied name already exists, an error will be returned. The keyslot must first be deleted with DeleteLUKS2ContainerKey or renamed with RenameLUKS2ContainerKey.

In order to perform this action, an existing key must be supplied.

The new key should be protected by some platform-specific mechanism in order to create a KeyData object. The KeyData object can be saved to the keyslot using LUKS2KeyDataWriter.

func AllowNonAtomicOperation

func AllowNonAtomicOperation() *nonAtomicOperationAllowedFlag

AllowNonAtomicOperation gives a flag to allow some operations that are not atomic. Those can be dangerous depending on usage context, they should be used with care and intentionally (that's why the extra hoops).

func CopyAndRemoveLUKS2ContainerKey

func CopyAndRemoveLUKS2ContainerKey(nonAtomic *nonAtomicOperationAllowedFlag, devicePath, oldName, newName string) error

CopyAndRemoveLUKS2ContainerKey key renames the keyslot with the specified oldName on the LUKS2 container at the specified path. It does not use new feature from cryptsetup. However it is not atomic. This must be used with care and intentionally. AllowNontAtomicOperation result must be provided to allow for its use.

func DeactivateVolume

func DeactivateVolume(volumeName string) error

DeactivateVolume attempts to deactivate the LUKS encrypted volumeName. This makes use of systemd-cryptsetup.

func DeleteLUKS2ContainerKey

func DeleteLUKS2ContainerKey(devicePath, keyslotName string) error

DeleteLUKS2ContainerKey deletes the keyslot with the specified name from the LUKS2 container at the specified path. This will return an error if the container only has a single keyslot remaining.

func GetKeyFromKernel

func GetKeyFromKernel(ctx context.Context, container StorageContainer, purpose KeyringKeyPurpose, prefix string) ([]byte, error)

GetKeyFromKernel retrieves the key with the supplied purpose and associated with the storage container with the specified path from the user keyring. The value of prefix must match the prefix that was used whe the key was added.

If no key is found, a ErrKernelKeyNotFound error will be returned.

func InitializeLUKS2Container

func InitializeLUKS2Container(devicePath, label string, key DiskUnlockKey, options *InitializeLUKS2ContainerOptions) error

InitializeLUKS2Container will initialize the partition at the specified devicePath as a new LUKS2 container. This can only be called on a partition that isn't mapped. The label for the new LUKS2 container is provided via the label argument.

The container will be configured to encrypt data with AES-256 and XTS block cipher mode.

The initial key used for unlocking the container is provided via the key argument, and must be a cryptographically secure random number of at least 32-bytes.

The initial keyslot will be created with the name specified in the InitialKeyslotName field of options. If this is empty, "default" will be used.

The initial key should be protected by some platform-specific mechanism in order to create a KeyData object. The KeyData object can be saved to the keyslot using LUKS2KeyDataWriter.

On failure, this will return an error containing the output of the cryptsetup command.

WARNING: This function is destructive. Calling this on an existing LUKS container will make the data contained inside of it irretrievable.

func ListLUKS2ContainerRecoveryKeyNames

func ListLUKS2ContainerRecoveryKeyNames(devicePath string) ([]string, error)

ListLUKS2ContainerRecoveryKeyNames lists the names of keyslots on the specified LUKS2 container configured as recovery slots.

func ListLUKS2ContainerUnlockKeyNames

func ListLUKS2ContainerUnlockKeyNames(devicePath string) ([]string, error)

ListLUKS2ContainerUnlockKeyNames lists the names of keyslots on the specified LUKS2 container configured as normal unlock slots (the keys associated with these should be protected by the platform's secure device).

func ListRegisteredKeyDataPlatforms

func ListRegisteredKeyDataPlatforms() []string

ListRegisteredKeyDataPlatforms returns a list of the names of all of the registered PlatformKeyDataHandlers.

func MockRunArgon2OutOfProcessRequestForTest

func MockRunArgon2OutOfProcessRequestForTest(fn func(*Argon2OutOfProcessRequest) (*Argon2OutOfProcessResponse, func())) (restore func())

MockRunArgon2OutOfProcessRequestForTest mocks the call to RunArgon2OutOfProcessRequest from WaitForAndRunArgon2OutOfProcessRequest. This can only be used in test binaries, and will panic otherwise.

func NameLegacyLUKS2ContainerKey

func NameLegacyLUKS2ContainerKey(devicePath string, keyslot int, newName string) error

NameLegacyLUKS2ContainerKey will add a token for a recovery key for a specified keyslot. That keyslot must not be in use in any existing token. If the keyslot does not exist, this function will do nothing. This function is intended to be used to name keys on an old container.

func RegisterPlatformKeyDataHandler

func RegisterPlatformKeyDataHandler(name string, handler PlatformKeyDataHandler, flags PlatformKeyDataHandlerFlags)

RegisterPlatformKeyDataHandler registers a handler for the specified platform name. The platform can also specify a set of feature flags.

Supplying a nil handler will unregister the handler for the specified platform name, if one exists.

func RegisterStorageContainerBackend

func RegisterStorageContainerBackend(name string, backend StorageContainerBackend)

RegisterStorageContainerBackend permits a backend that manages storage containers with keyslots to be registered with and used by this package. Specifying a nil backend will delete the previously registered backend.

XXX(chrisccoulson): Should we use a string to identify a backend or use any arbitrary comparable go type instead (in the same way that context.Context works)? I think I would prefer this (but perhaps it should be considered as these abstractions evolve). We can't do this for RegisteredPlatformKeyDataHandler because the platform name is serialized as a string in the keyslot metadata and has to be decoded later on in order to identify the platform - it's not possible to preserve go types in this case.

func RegisteredPlatformKeyDataHandler

func RegisteredPlatformKeyDataHandler(name string) (handler PlatformKeyDataHandler, flags PlatformKeyDataHandlerFlags, err error)

RegisteredPlatformKeyDataHandler returns the handler and its flags, for the specified platform name.

If no platform with the specified name is registered, a ErrNoPlatformHandlerRegistered error will be returned.

func RenameLUKS2ContainerKey

func RenameLUKS2ContainerKey(devicePath, oldName, newName string) error

RenameLUKS2Container key renames the keyslot with the specified oldName on the LUKS2 container at the specified path.

func TestLUKS2ContainerKey

func TestLUKS2ContainerKey(devicePath string, key []byte) bool

Check if key is valid key for LUKS2 container at devicePath.

func WaitForAndRunArgon2OutOfProcessRequest

func WaitForAndRunArgon2OutOfProcessRequest(in io.Reader, out io.WriteCloser, watchdog Argon2OutOfProcessWatchdogHandler) (lockRelease func(), err error)

WaitForAndRunArgon2OutOfProcessRequest waits for a Argon2OutOfProcessRequest request on the supplied io.Reader before running it and sending a Argon2OutOfProcessResponse response back via the supplied io.WriteCloser. These will generally be connected to the process's os.Stdin and os.Stdout - at least they will need to be when using NewOutOfProcessArgon2KDF on the parent side, which this function is intended to be compatible with.

This function will service watchdog requests from the parent process if a watchdog handler is supplied. If supplied, it must match the corresponding monitor in the parent process. If not supplied, the default NoArgon2OutOfProcessWatchdogHandler will be used.

This won't process more than one request, and in general is intended to be executed once in a process, before the process is discarded. This is how the function is used with NewOutOfProcessArgon2KDF.

Note that Argon2 requests are serialized using a system-wide lock, which this function does not explicitly release. If the lock is acquired, it returns a callback that the caller may choose to execute in order to explicitly release the lock, or the caller can just leave it to be implicitly released on process exit. If the lock is explicitly released, the caller must be sure that the large amount of memory allocated for the Argon2 operation has been freed and returned back to the OS, else this defeats the point of having a system-wide lock (to avoid having multiple processes with high physical memory requirements running at the same time). If the lock wasn't acquired, no release callback will be returned.

This function may return a callback to release the system wide lock even if an error is returned, which will happen if an error occurs after the lock is acquired.

Unfortunately, KDF requests cannot be interrupted once they have started because the low-level crypto library does not provide this functionality, although watchdog requests can still be serviced to provide assurance that a response will be received as long as the crypto algorithm completes. The ability to interrupt a KDF request in the future may be desired, although it may require replacing the existing library we use for Argon2.

Most errors are sent back to the parent process via the supplied io.Writer. In some limited cases, errors returned from goroutines that are created during the handling of a request may be returned directly from this function to be handled by the current process. These limited examples are where the function receives input it can't decode, where a response cannot be encoded and sent to the parent, if the watchdog handler function returns an error, or if the supplied response channel returns an error when closing.

Note that this function won't return until the supplied io.Reader is closed by the parent, or an internal error occurs in one of the goroutines created by this function. It will close the supplied io.WriteCloser before returning.

Types

type ActivateConfig

type ActivateConfig interface {
	ActivateConfigGetter

	// Set is used to set the value of the specified key to the specified value.
	// If value is nil, the key is erased from the config.
	Set(key, value any)
}

ActivateConfig is used for gathering configuration options from [ActivateContextOption]s supplied to NewActivateContext or [ActivateOption]s supplied to ActivateContext.ActivateContainer.

type ActivateConfigGetter

type ActivateConfigGetter interface {
	// Get is used to get the value of the specified key, if one exists.
	Get(key any) (value any, exists bool)
}

ActivateConfigGetter provides read-only access to configuration options that were added to a ActivateConfig.

type ActivateContext

type ActivateContext struct {
	// contains filtered or unexported fields
}

ActivateContext maintains context related to StorageContainer activation during early boot. It is not safe to use from multiple goroutines.

func NewActivateContext

func NewActivateContext(ctx context.Context, state *ActivateState, opts ...ActivateContextOption) (*ActivateContext, error)

NewActivateContext returns a new ActivateContext. The optional state argument makes it possible to perform activation in multiple processes, permitting them to share state. Note that ActivateContext usage must be serialized because state from the previous ActivateContext must propagate to the next one via the state argument. The caller can supply options that are common to all calls to ActivateContext.ActivateContainer.

func (*ActivateContext) ActivateContainer

func (c *ActivateContext) ActivateContainer(ctx context.Context, container StorageContainer, opts ...ActivateOption) error

ActivateContainer unlocks the supplied StorageContainer. The caller can supply options that are specific to this invocation, but which inherit from those options already supplied to NewActivateContext.

If there are no keyslots that can be used to unlock the storage container, a ErrCannotActivate error is returned.

Note that it is important that all unlocked storage containers are part of the same install to prevent an attack where an adversary replaces a storage container with one that contains their own credentials, in order to use those credentials to gain access to confidential data on another storage container that has keyslots which unlock automatically. This "binding" is enforced using 1 of 2 mechanisms:

  1. As the unlock key for each keyslot is derived from a primary key that is common for all keyslots, and a keyslot unique key, there is a cryptographic binding between the unlock key and the primary key. If a keyslot is used successfully, then verifying that the primary key matches the primary key from keyslots used to unlock other containers is sufficient to determine that the storage containers are related to the same install. Where a previous storage container has been unlocked using a platform keyslot, any keyslots that do not have a matching primary key will be dismissed as being unsuitable for unlocking its associated storage container.
  2. If the first container is unlocked using a recovery key, then there is no primary key to which keyslots from subsequent containers can be compared. In this case, subsequent containers must either be unlocked using a recovery key, or must be unlocked using a platform keyslot protected by a platform that is registered with the PlatformProtectedByStorageContainer flag (the "plainkey" platform is registered with this), as these keyslots are protected using a key that must be stored inside the first unlocked storage container. If unlocking succeeds using a keyslot protected by a platform registered with this flag, then this is sufficient to determine that the storage container is part of the same install as the first container. The recovered primary key can be used to check the binding of subsequent storage containers using the first method.

func (*ActivateContext) DeactivateContainer

func (c *ActivateContext) DeactivateContainer(ctx context.Context, container StorageContainer, reason DeactivationReason) error

DeactivateContainer locks the supplied StorageContainer. The caller can supply a reason for the container being locked again which will be added to the state.

func (*ActivateContext) State

func (c *ActivateContext) State() *ActivateState

State returns a pointer to the current state. Note that this is a pointer to the state object used by this context, so it will be updated by calls to ActivateContainer and DeactivateContainer.

type ActivateContextOption

type ActivateContextOption interface {
	ActivateOption

	// ApplyContextOptionToConfig is called to make changes to the supplied ActivateConfig.
	ApplyContextOptionToConfig(ActivateConfig)
}

ActivateContextOption represents an option that can be supplied to NewActivateContext or ActivateContext.ActivateContainer.

func WithAuthRequestor

func WithAuthRequestor(req AuthRequestor) ActivateContextOption

WithAuthRequestor allows the caller to specify an instance of AuthRequestor when using the ActivateContext API. Without this, functionality that requires asking for user credentials will not work.

func WithDiscardStderrLogger

func WithDiscardStderrLogger() ActivateContextOption

WithDiscardStderrLogger is a shortcut for WithStderrLogger(io.Discard).

func WithKeyringDescriptionPrefix

func WithKeyringDescriptionPrefix(prefix string) ActivateContextOption

WithKeyringDescriptionPrefix permits the prefix in the description for keys added to the kernel keyring during storage container activation to be customized. The API that the OS uses to retrieve these keys GetKeyFromKernel searches for keys with a specific description format, and part of that description includes a prefix that can be customized using this option. Without this option, the default prefix is "ubuntu-fde".

In order for the OS to be able to retrieve keys added during early boot, the prefix passed to GetKeyFromKernel must match the prefix passed to this option (or be empty if this option isn't used, in which case, the default prefix value is used).

func WithPINTries

func WithPINTries(n uint) ActivateContextOption

WithPINTries defines how many attempts the user has to enter a correct PIN.

func WithPassphraseTries

func WithPassphraseTries(n uint) ActivateContextOption

WithPassphraseTries defines how many attempts the user has to enter a correct passphrase.

func WithRecoveryKeyTries

func WithRecoveryKeyTries(n uint) ActivateContextOption

WithRecoveryKeyTries defines how many attempts the user has to enter a correct recovery key.

func WithStderrLogger

func WithStderrLogger(w io.Writer) ActivateContextOption

WithStderrLogger allows the caller to customize the default io.Writer for which to log errors to (in this case, these are errors that aren't fatal enough to give up with the activation and return an error to the caller). The calling application can use this to integrate it with its standard logging framework.

Note that writes to the supplied writer may happen from multiple gorountines. XXX(chrisccoulson) - should we serialize access to this rather than requiring the application to do it? In the normal case, were the stderr io.Wrtier is the default os.File, then there is no locking to serialize the logging of messages, resulting in logging output that can be a bit of a mess.

type ActivateOption

type ActivateOption interface {
	// ApplyOptionToConfig is called to make changes to the supplied ActivateConfig.
	ApplyOptionToConfig(ActivateConfig)
}

ActivateOption represents an option that can be supplied to ActivateContext.ActivateContainer.

func WillCheckStorageContainerBinding

func WillCheckStorageContainerBinding() ActivateOption

WillCheckStorageContainerBinding indicates that the caller will verify that a storage container is bound to those that have already been unlocked, rather than relying on this to be performed by cross checking the primary key.

Note that this disables the primary key check performed by ActivateContext. This should only be used when it is known that unlocking will happen with a KeyData with a generation older than 2. It should not be used in any other circumstance. When used, the caller must take steps to verify that the storage container being unlocked is bound to those that have already been unlocked (XXX: This doesn't apply if a recovery key is used - the ActivateContext.ActivateContainer API will be updated in another PR to indicate what type of key was used).

If the external binding check fails, the unlocked storage container must be locked again. The caller can then repeat the attempt without this option.

func WithActivateStateCustomData

func WithActivateStateCustomData(data json.RawMessage) ActivateOption

WithActivateStateCustomData can be supplied to [ActivateContext.ActivatePath] to permit the caller to supply arbitrary data that will appear in the ContainerActivateState associated with an activation.

func WithAuthRequestorUserVisibleName

func WithAuthRequestorUserVisibleName(name string) ActivateOption

WithAuthRequestorUserVisibleName allows the caller to customize the name passed to AuthRequestor.RequestUserCredential.

func WithExternalKeyData

func WithExternalKeyData(name string, data *KeyData) ActivateOption

WithExternalKeyData makes it possible for callers of ActivateContext.ActivateContainer to supply extra key metadata that is not part of the associated StorageContainer. These keys have a hardcoded priority of 100 so that they are tried before StorageContainer keyslots with the default priority (0). External keys are tried in order of name. This option can be supplied multiple times.

func WithExternalKeyDataFromReader

func WithExternalKeyDataFromReader(name string, r KeyDataReader) ActivateOption

WithExternalKeyDataFromReader makes it possible for callers of ActivateContext.ActivateContainer to supply extra key metadata that is not part of the associated StorageContainer. These keys have a hardcoded priority of 100 so that they are tried before StorageContainer keyslots with the default priority (0). External keys are tried in order of name. Note that the KeyDataReader argument will eventually be replaced by io.Reader. This option can be supplied multiple times.

func WithExternalUnlockKey

func WithExternalUnlockKey(name string, key DiskUnlockKey, src ExternalUnlockKeySource) ActivateOption

WithExternalUnlockKey makesit possible for callers of ActivateContext.ActivateContainer to supply plain unlock keys that can be used to try to unlock the storage container. These keys have a hardcoded priority of 100 so that they are tried before StorageContainer keyslots with the default priority (0) and no user authentication. External keys are tried in order of name. This option can be supplied multiple times.

func WithLegacyKeyringKeyDescriptionPaths

func WithLegacyKeyringKeyDescriptionPaths(paths ...string) ActivateOption

WithLegacyKeyringKeyDescriptionPaths tells ActivateContext.ActivateContainer to add keys to the kernel keyrings with descriptions derived from the supplied paths, emulating the legacy behaviour associated with the older activation API in order to maintain compatibility with older versions of snapd.

If the StorageContainer being activated isn't a block device, this option will be ignored. If any of the supplied paths do not point to the same block device as the StorageContainer, they will be ignored.

type ActivateState

type ActivateState struct {
	// PrimaryKeyID is used to allow the primary key to be shared between
	// different ActivateContexts without storing the key in the state.
	PrimaryKeyID int32 `json:"primary-key-id"`

	// Activations contains state for each StorageContainer, keyed by
	// the credential name of the container.
	Activations map[string]*ContainerActivateState `json:"activations"`
}

ActivateState contains the global activation state.

func (*ActivateState) NumActivatedContainersWithPlatformKey

func (s *ActivateState) NumActivatedContainersWithPlatformKey() (n int)

NumActivatedContainersWithPlatformKey returns the number of storage containers activated with a platform key.

func (*ActivateState) NumActivatedContainersWithRecoveryKey

func (s *ActivateState) NumActivatedContainersWithRecoveryKey() (n int)

NumActivatedContainersWithPlatformKey returns the number of storage containers activated with a recovery key.

func (*ActivateState) TotalActivatedContainers

func (s *ActivateState) TotalActivatedContainers() (n int)

TotalActivatedContainers returns the total number of activated storage containers.

type ActivateVolumeOptions

type ActivateVolumeOptions struct {
	// PassphraseTries specifies the maximum number of times
	// that activation with a user passphrase should be attempted
	// before failing with an error and falling back to activating
	// with the recovery key (see RecoveryKeyTries).
	//
	// Setting this to zero disables activation with a user
	// passphrase - in this case, any protected keys that require
	// a passphrase are ignored and activation will fall back to
	// requesting a recovery key.
	//
	// For each passphrase attempt, the supplied passphrase is
	// tested against every protected key that requires a passphrase.
	//
	// The actual number of available passphrase attempts may be
	// limited by the platform to a number that is lower than this
	// value (eg, in the TPM case because of the current auth fail
	// counter value which means the dictionary attack protection
	// might be triggered first).
	//
	// It is ignored by ActivateVolumeWithRecoveryKey.
	PassphraseTries int

	// RecoveryKeyTries specifies the maximum number of times that
	// activation with the fallback recovery key should be
	// attempted.
	//
	// It is used directly by ActivateVolumeWithRecoveryKey and
	// indirectly with other methods upon failure, for example
	// in the case where no other keys can be recovered.
	//
	// Setting this to zero will disable attempts to activate with
	// the fallback recovery key.
	RecoveryKeyTries int

	// KeyringPrefix is the prefix used for the description of any
	// kernel keys created during activation.
	KeyringPrefix string

	// LegacyDevicePaths are the device paths to register keys to
	// keyring. This is useful when snap-bootstrap boots to an
	// older version of snapd.
	LegacyDevicePaths []string
}

ActivateVolumeOptions provides options to the ActivateVolumeWith* family of functions.

type ActivationStatus

type ActivationStatus string

ActivationStatus describes the activation status for a storage container.

const (
	ActivationFailed                   ActivationStatus = "failed"       // The container could not be unlocked
	ActivationSucceededWithPlatformKey ActivationStatus = "platform-key" // The container was unlocked with a normal platform key
	ActivationSucceededWithRecoveryKey ActivationStatus = "recovery-key" // The container was unlocked with a recovery key
	ActivationDeactivated              ActivationStatus = "deactivated"  // The container was subsequently deactivated.
)

type Argon2CostParams

type Argon2CostParams struct {
	// Time corresponds to the number of iterations of the algorithm
	// that the key derivation will use.
	Time uint32

	// MemoryKiB is the amount of memory in KiB that the key derivation
	// will use.
	MemoryKiB uint32

	// Threads is the number of parallel threads that will be used
	// for the key derivation.
	Threads uint8
}

Argon2CostParams defines the cost parameters for key derivation using Argon2.

type Argon2KDF

type Argon2KDF interface {
	// Derive derives a key of the specified length in bytes, from the supplied
	// passphrase and salt and using the supplied mode and cost parameters.
	Derive(passphrase string, salt []byte, mode Argon2Mode, params *Argon2CostParams, keyLen uint32) ([]byte, error)

	// Time measures the amount of time the KDF takes to execute with the
	// specified cost parameters and mode.
	Time(mode Argon2Mode, params *Argon2CostParams) (time.Duration, error)
}

Argon2KDF is an interface to abstract use of the Argon2 KDF to make it possible to delegate execution to a short-lived handler process where required. See SetArgon2KDF and InProcessArgon2KDF. Implementations should be thread-safe (ie, they should be able to handle calls from different goroutines).

func NewOutOfProcessArgon2KDF

func NewOutOfProcessArgon2KDF(newHandlerCmd func() (*exec.Cmd, error), timeout time.Duration, watchdog Argon2OutOfProcessWatchdogMonitor) Argon2KDF

NewOutOfProcessArgonKDF returns a new Argon2KDF that runs each KDF invocation in a short-lived handler process, using a *exec.Cmd created by the supplied function, and using a protocol compatibile with WaitForAndRunArgon2OutOfProcessRequest, which will be expected to run in the remote handler process.

The supplied function must not start the process, nor should it set the Stdin or Stdout fields of the exec.Cmd structure, as 2 pipes will be created for sending the request to the process via its stdin and receiving the response from the process via its stdout.

KDF requests are serialized system-wide so that only 1 runs at a time. The supplied timeout specifies the maximum amount of time a request will wait to be started before giving up with an error.

The optional watchdog field makes it possible to send periodic pings to the remote process to ensure that it is still alive and still processing IPC requests, given that the KDF may be asked to run for a long time, and the KDF itself is not interruptible. The supplied monitor must be paired with a matching handler on the remote side (passed to WaitForAndRunArgon2OutOfProcessRequest for this to work properly. If no monitor is supplied, NoArgon2OutOfProcessWatchdogMonitor is used, which provides no watchdog monitor functionality.

The watchdog functionality is recommended for KDF uses that are more than 1 second long.

The errors returned from methods of the returned Argon2KDF may be instances of *Argon2OutOfProcessError.

func SetArgon2KDF

func SetArgon2KDF(kdf Argon2KDF) Argon2KDF

SetArgon2KDF sets the KDF implementation for Argon2 use from within secboot. The default here is a null implementation which returns an error, so this will need to be configured explicitly in order to be able to use Argon2 from within secboot.

Passing nil will configure the null implementation as well.

This function returns the previously configured Argon2KDF instance.

This exists to facilitate running Argon2 operations in short-lived helper processes (see InProcessArgon2KDF), because Argon2 doesn't interact very well with Go's garbage collector, and is an algorithm that is only really suited to languages / runtimes with explicit memory allocation and de-allocation primitves.

type Argon2Mode

type Argon2Mode = argon2.Mode

Argon2Mode describes the Argon2 mode to use. Note that the fully data-dependent mode is not supported because the underlying argon2 implementation lacks support for it.

type Argon2Options

type Argon2Options struct {
	// Mode specifies the KDF mode to use.
	Mode Argon2Mode

	// MemoryKiB specifies the maximum memory cost in KiB when ForceIterations
	// is zero. In this case, it will be capped at 4GiB or half of the available
	// memory, whichever is less. If ForceIterations is not zero, then this is
	// used as the memory cost and is not limited.
	MemoryKiB uint32

	// TargetDuration specifies the target duration for the KDF which
	// is used to benchmark the time and memory cost parameters. If it
	// is zero then the default is used. If ForceIterations is not zero
	// then this field is ignored.
	TargetDuration time.Duration

	// ForceIterations can be used to turn off KDF benchmarking by
	// setting the time cost directly. If this is zero then the cost
	// parameters are benchmarked based on the value of TargetDuration.
	ForceIterations uint32

	// Parallel sets the maximum number of parallel threads for the KDF. If
	// it is zero, then it is set to the number of CPUs or 4, whichever is
	// less. This will always be automatically limited to 4 when ForceIterations
	// is zero.
	Parallel uint8
}

Argon2Options specifies parameters for the Argon2 KDF used for passphrase support.

type Argon2OutOfProcessCommand

type Argon2OutOfProcessCommand string

Argon2OutOfProcessCommand represents an argon2 command to run out of process.

const (
	// Argon2OutOfProcessCommandDerive requests to derive a key from a passphrase
	Argon2OutOfProcessCommandDerive Argon2OutOfProcessCommand = "derive"

	// Argon2OutOfProcessCommandTime requests the duration that the KDF took to
	// execute. This excludes additional costs such as process startup.
	Argon2OutOfProcessCommandTime Argon2OutOfProcessCommand = "time"

	// Argon2OutOfProcessCommandWatchdog requests a watchdog ping, when using
	// WaitForAndRunArgon2OutOfProcessRequest. This does not work with
	// RunArgon2OutOfProcessRequest, which runs the supplied request synchronously
	// in the current go routine.
	Argon2OutOfProcessCommandWatchdog Argon2OutOfProcessCommand = "watchdog"
)

type Argon2OutOfProcessError

type Argon2OutOfProcessError struct {
	ErrorType   Argon2OutOfProcessErrorType
	ErrorString string
}

Argon2OutOfProcessError is returned from Argon2OutOfProcessResponse.Err if the response indicates an error, or directly from methods of the Argon2KDF implementation created by NewOutOfProcessArgon2KDF when the received response indicates that an error ocurred.

func (*Argon2OutOfProcessError) Error

func (e *Argon2OutOfProcessError) Error() string

Error implements the error interface.

type Argon2OutOfProcessErrorType

type Argon2OutOfProcessErrorType string

Argon2OutOfProcessErrorType describes the type of error produced by RunArgon2OutOfProcessRequest or WaitForAndRunArgon2OutOfProcessRequest.

const (
	// Argon2OutOfProcessErrorInvalidCommand means that an invalid command was supplied.
	Argon2OutOfProcessErrorInvalidCommand Argon2OutOfProcessErrorType = "invalid-command"

	// Argon2OutOfProcessErrorInvalidMode means that an invalid mode was supplied.
	Argon2OutOfProcessErrorInvalidMode Argon2OutOfProcessErrorType = "invalid-mode"

	// Argon2OutOfProcessErrorInvalidTimeCost means that an invalid time cost was supplied.
	Argon2OutOfProcessErrorInvalidTimeCost Argon2OutOfProcessErrorType = "invalid-time-cost"

	// Argon2OutOfProcessErrorInvalidThreads means that an invalid number of threads was supplied.
	Argon2OutOfProcessErrorInvalidThreads Argon2OutOfProcessErrorType = "invalid-threads"

	// Argon2OutOfProcessErrorUnexpectedInput means that there was an error with the combination
	// of inputs associated with the supplied request.
	Argon2OutOfProcessErrorUnexpectedInput Argon2OutOfProcessErrorType = "unexpected-input"

	// Argon2OutOfProcessErrorTimeout means that the specified command timeout expired before
	// the request was given a chance to start.
	Argon2OutOfProcessErrorKDFTimeout Argon2OutOfProcessErrorType = "timeout-error"

	// Argon2OutOfProcessErrorUnexpected means that an unexpected error occurred without
	// a more specific error type, eg, an unexpected failure to acquire the system-wide
	// lock or an unexpected error returned from the underlying Argon2 KDF implementation.
	Argon2OutOfProcessErrorUnexpected Argon2OutOfProcessErrorType = "unexpected-error"
)

type Argon2OutOfProcessRequest

type Argon2OutOfProcessRequest struct {
	Command           Argon2OutOfProcessCommand `json:"command"`                      // The command to run
	Timeout           time.Duration             `json:"timeout"`                      // The maximum amount of time to wait for the request to start before aborting it
	Passphrase        string                    `json:"passphrase,omitempty"`         // If the command is "derive, the passphrase
	Salt              []byte                    `json:"salt,omitempty"`               // If the command is "derive", the salt
	Keylen            uint32                    `json:"keylen,omitempty"`             // If the command is "derive", the key length in bytes
	Mode              Argon2Mode                `json:"mode"`                         // The Argon2 mode
	Time              uint32                    `json:"time"`                         // The time cost
	MemoryKiB         uint32                    `json:"memory"`                       // The memory cost in KiB
	Threads           uint8                     `json:"threads"`                      // The number of threads to use
	WatchdogChallenge []byte                    `json:"watchdog-challenge,omitempty"` // A challenge value for watchdog pings (when the command is "watchdog")
}

Argon2OutOfProcessRequest is an input request for an argon2 operation in a remote process.

type Argon2OutOfProcessResponse

type Argon2OutOfProcessResponse struct {
	Command          Argon2OutOfProcessCommand   `json:"command"`                     // The input command
	Key              []byte                      `json:"key,omitempty"`               // The derived key, if the input command was "derive"
	Duration         time.Duration               `json:"duration,omitempty"`          // The duration, if the input command was "duration"
	WatchdogResponse []byte                      `json:"watchdog-response,omitempty"` // The response to a watchdog ping, if the input command was "watchdog"
	ErrorType        Argon2OutOfProcessErrorType `json:"error-type,omitempty"`        // The error type, if an error occurred
	ErrorString      string                      `json:"error-string,omitempty"`      // The error string, if an error occurred
}

Argon2OutOfProcessResponse is the response to a request for an argon2 operation in a remote process.

func RunArgon2OutOfProcessRequest

func RunArgon2OutOfProcessRequest(request *Argon2OutOfProcessRequest) (response *Argon2OutOfProcessResponse, lockRelease func())

RunArgon2OutOfProcessRequest runs the specified Argon2 request, and returns a response.

In general, this is intended to be executed once in a short-lived process, before the process is discarded. It could be executed more than once in the same process, as long as the caller takes steps to ensure that memory consumed by previous calls has been reclaimed by the GC before calling this function again, but this isn't advised.

Note that Argon2 requests are serialized using a system-wide lock, which this function does not explicitly release. If the lock is acquired, it returns a callback that the caller may choose to execute in order to explicitly release the lock, or the caller can just leave it to be implicitly released on process exit. If the lock is explicitly released, the caller must be sure that the large amount of memory allocated for the Argon2 operation has been reclaimed by the GC, else this defeats the point of having a system-wide lock (to avoid multiple operations consuming too much memory). If the process is re-used by calling this function more than once, the lock will have to be explcitly released. If the lock wasn't acquired, no release callback will be returned.

This is quite a low-level function, suitable for implementations that want to manage their own transport and their own remote process management. In general, implementations will use WaitForAndRunArgon2OutOfProcessRequest in the remote process and [NewOutOfProcessArgonKDF] for process management in the parent process.

This function does not service watchdog requests, as the KDF request happens synchronously in the current goroutine. If this is required, it needs to be implemented in supporting code that makes use of other go routines, noting that the watchdog handler should test that the input request and output response processing continues to function. WaitForAndRunArgon2OutOfProcessRequest already does this correctly, and most implementations should just use this.

Unfortunately, there is no way to interrupt this function once the key derivation is in progress, because the low-level crypto library does not support this. This feature may be desired in the future, which might require replacing the existing library we use for Argon2.

func (*Argon2OutOfProcessResponse) Err

Err returns an error associated with the response if one occurred (if the ErrorType field is not empty), or nil if no error occurred. If the response indicates an error, the returned error will be a *Argon2OutOfProcessError.

type Argon2OutOfProcessResponseCommandInvalidError

type Argon2OutOfProcessResponseCommandInvalidError struct {
	Response Argon2OutOfProcessCommand
	Expected Argon2OutOfProcessCommand
}

Argon2OutOfProcessResponseCommandInvalidError is returned from Argon2KDF instances created by NewOutOfProcessArgon2KDF if the response contains an unexpected command field value.

func (*Argon2OutOfProcessResponseCommandInvalidError) Error

Error implements the error interface

type Argon2OutOfProcessWatchdogError

type Argon2OutOfProcessWatchdogError struct {
	// contains filtered or unexported fields
}

Argon2OutOfProcessWatchdogError is returned from Argon2KDF instances created by NewOutOfProcessArgon2KDF in the event of a watchdog failure.

func (*Argon2OutOfProcessWatchdogError) Error

Error implements the error interface

func (*Argon2OutOfProcessWatchdogError) Unwrap

type Argon2OutOfProcessWatchdogHandler

type Argon2OutOfProcessWatchdogHandler func(challenge []byte) (response []byte, err error)

Argon2OutOfProcessWatchdogHandler defines the behaviour of a watchdog handler for the remote side of an out-of-process Argon2KDF implementation, using WaitForAndRunArgon2OutOfProcessRequest.

If is called periodically on the same go routine that processes incoming requests to ensure that this routine is functioning correctly. The response makes use of the same code path that the eventual KDF response will be sent via, so that the watchdog handler tests all of the code associated with this and so the parent process can be assured that it will eventually receive a KDF response and won't be left waiting indefinitely for one.

Implementations define their own protocol, with limitations. All requests and responses use the watchdog command Argon2OutOfProcessCommandWatchdog. The Argon2OutOfProcessRequest type has a WatchdogChallenge field (which is supplied as an argument to this function. The Argon2OutOfProcessResponse type has a WatchdogResponse field (which the response of this function is used for). It's up to the implementation how they choose to use these fields.

If the implementation returns an error, it begins the shutdown of the processing of commands and the eventual return of WaitForAndRunArgon2OutOfProcessRequest.

The implementation is expected to be paired with an equivalent implementation of Argon2OutOfProcessWatchdogMonitor in the parent process.

func HMACArgon2OutOfProcessWatchdogHandler

func HMACArgon2OutOfProcessWatchdogHandler(alg crypto.Hash) Argon2OutOfProcessWatchdogHandler

HMACArgon2OutOfProcessWatchdogHandler returns the remote process counterpart to HMACArgon2OutOfProcessWatchdogMonitor. It receives a challenge from the monitor, computes a HMAC of this challenge, keyed with previously sent response. Both implementations must use the same algorithm.

This implementation of Argon2OutOfProcessWatchdogHandler never returns an error.

func NoArgon2OutOfProcessWatchdogHandler

func NoArgon2OutOfProcessWatchdogHandler() Argon2OutOfProcessWatchdogHandler

NoArgon2OutOfProcessWatchdogHandler is an implmenentation of Argon2OutOfProcessWatchdogHandler that provides no watchdog functionality. It is paired with NoArgon2OutOfProcessWatchdogMonitor on the parent side. This implementation will return an error if a watchdog request is received.

type Argon2OutOfProcessWatchdogMonitor

type Argon2OutOfProcessWatchdogMonitor func(tmb *tomb.Tomb, reqChan chan<- *Argon2OutOfProcessRequest, rspChan <-chan *Argon2OutOfProcessResponse) error

Argon2OutOfProcessWatchdogMonitor defines the behaviour of a watchdog monitor for out-of-process Argon2KDF implementations created by NewOutOfProcessArgon2KDF, and is managed on the parent side of an implementation of Argon2KDF.

It will be called in its own dedicated go routine that is tracked by the supplied tomb.

Implementations define their own protocol, with limitations. All requests and responses use the watchdog command Argon2OutOfProcessCommandWatchdog. The Argon2OutOfProcessRequest type has a WatchdogChallenge field. The Argon2OutOfProcessResponse type has a WatchdogResponse field. It's up to the implementation how they choose to use these fields.

If the watchdog isn't serviced by the remote process correctly or within some time limit, the implementation is expected to return an error.

The Argon2KDF implementation created by NewOutOfProcessArgon2KDF will terminate the remote process in the event that the monitor implementation returns an error. It also kills the supllied tomb, resuling in the eventual return of an error to the caller.

The implementation of this should not close reqChan. The Argon2KDF implementation created by NewOutOfProcessArgon2KDF will not close rspChan.

The Argon2KDF implementation created by NewOutOfProcessArgon2KDF will only send watchdog requests via rspChan.

The supplied reqChan is unbuffered, but the Argon2KDF implementation created by NewOutOfProcessArgon2KDF guarantees there is a reader until the tomb enters a dying state.

The supplied rspChan is unbuffered. The monitor implementation should guarantee that there is a reader as long as the supplied tomb is alive.

func HMACArgon2OutOfProcessWatchdogMonitor

func HMACArgon2OutOfProcessWatchdogMonitor(alg crypto.Hash, period time.Duration) Argon2OutOfProcessWatchdogMonitor

HMACArgon2OutOfProcessWatchdogMonitor returns a watchdog monitor that generates a challenge every period, computes a HMAC of this challenge, keyed with previously received watchdog response. It stops and returns an error if it doen't receive a valid response before the next cycle is meant to run. This is intended be paired with HMACArgon2OutOfProcessWatchdogHandler on the remote side.

func NoArgon2OutOfProcessWatchdogMonitor

func NoArgon2OutOfProcessWatchdogMonitor() Argon2OutOfProcessWatchdogMonitor

NoArgon2OutOfProcessWatchdogMonitor is an implmenentation of Argon2OutOfProcessWatchdogMonitor that provides no watchdog functionality. It is paired with NoArgon2OutOfProcessWatchdogHandler on the remote side. It holds the watchdog goroutine in a parked state for the lifetime of the tomb.

type AuthMode

type AuthMode uint8

AuthMode corresponds to an authentication mechanism supported by a KeyData. Only one mode is supported at a time.

const (
	AuthModeNone AuthMode = iota
	AuthModePassphrase
	AuthModePIN
)

func (AuthMode) String

func (m AuthMode) String() string

String implements fmt.Stringer.

type AuthRequestor

type AuthRequestor interface {
	// RequestUserCredential is used to request a user credential that is
	// required to unlock the container at the specified path. The optional
	// name argument permits the caller to supply a more human friendly name,
	// and can be supplied via the ActivateContext API using the
	// WithAuthRequestorUserVisibleName option. The authTypes argument is used
	// to indicate what types of credential are being requested.
	//
	// The implementation returns the requested credential and its type, which
	// may be a subset of the requested credential types. It may return
	// ErrAuthRequestorNotAvailable if the corresponding mechanism is not
	// available.
	RequestUserCredential(ctx context.Context, name, path string, authTypes UserAuthType) (string, UserAuthType, error)

	// NotifyUserAuthResult is used to inform the user about the result of an
	// authentication attempt.
	//
	// If the result is UserAuthResultSuccess, the supplied authTypes argument
	// indicates the credential type that was successfully used. The
	// exhaustedAuthTypes argument is unused.
	//
	// If the result is UserAuthResultFailed, the supplied authTypes argument
	// indicates the credential types that were attempted but failed. The
	// exhaustedAuthTypes argument indicates the credential types that
	// will no longer be available following the last attempt because there are
	// no more tries permitted.
	//
	// If the result is UserAuthResultInvalidFormat, the supplied
	// authTypes argument indicates the credential types that the user supplied
	// credential was badly formatted for. The exhaustedAuthTypes argument
	// is unused.
	//
	// It may return ErrAuthRequestorNotAvailable if the corresponding mechanism
	// is not available.
	NotifyUserAuthResult(ctx context.Context, result UserAuthResult, authTypes, exhaustedAuthTypes UserAuthType) error
}

AuthRequestor is an interface for requesting credentials.

func NewAutoAuthRequestor

func NewAutoAuthRequestor(stderr io.Writer, stringer AuthRequestorStringer) (AuthRequestor, error)

NewAutoAuthRequestor creates an implementation of AuthRequestor that automatically selects the first available implementation in the following order: - Plymouth. - systemd-ask-password.

The returned implementation selects the underlying implementation on each call to AuthRequestor.RequestUserCredential by skipping any that return ErrAuthRequestorNotAvailable. The selected implementation is used in the subsequent call to AuthRequestor.NotifyUserAuthResult. Note that if the selected implementation returns ErrAuthRequestorNotAvailable here, then this is returned directly.

The caller supplies an implementation of AuthRequestorStringer that returns messages. The console argument is used by the systemd-ask-password implementation of AuthRequestor.NotifyUserAuthResult where result is not UserAuthResultSuccess. If not provided, it defaults to os.Stderr.

func NewPlymouthAuthRequestor

func NewPlymouthAuthRequestor(stringer AuthRequestorStringer) (AuthRequestor, error)

NewPlymouthAuthRequestor creates an implementation of AuthRequestor that communicates directly with Plymouth.

This will return ErrAuthRequestorNotAvailable if the plymouth client is not available. The returned AuthRequestor implementation will return the same error on any method if it is called whilst Plymouth isn't running.

func NewSystemdAuthRequestor

func NewSystemdAuthRequestor(console io.Writer, stringFn SystemdAuthRequestorStringFn) (AuthRequestor, error)

NewSystemdAuthRequestor creates an implementation of AuthRequestor that delegates to the systemd-ask-password binary. The caller supplies a callback to supply messages for user auth requests. The console argument is used by the implementation of AuthRequestor.NotifyUserAuthResult where result is not UserAuthResultSuccess. If not provided, it defaults to os.Stderr.

This will return ErrAuthRequestorNotAvailable if systemd-ask-password is not available.

type AuthRequestorStringer

type AuthRequestorStringer interface {
	// RequestUserCredentialString returns messages used by RequestUserCredential. The
	// name is a string supplied via the WithAuthRequestorUserVisibleName option, and the
	// path is the storage container path.
	RequestUserCredentialString(name, path string, authTypes UserAuthType) (string, error)

	// NotifyUserAuthResultString returns messages used by NotifyUserAuthResult.
	NotifyUserAuthResultString(name, path string, result UserAuthResult, authTypes, exhaustedAuthTypes UserAuthType) (string, error)
}

AuthRequestorStringer is used by the some implementation of AuthRequestor to obtain translated strings.

type ContainerActivateState

type ContainerActivateState struct {
	Status             ActivationStatus            `json:"status"`                      // The overall activation status for this storage container.
	Keyslot            string                      `json:"keyslot,omitempty"`           // If the container was activated, the name of the keyslot used.
	DeactivateReason   DeactivationReason          `json:"deactivate-reason,omitempty"` // An argument supplied to ActivateContext.DeactivateContainer.
	KeyslotErrors      map[string]KeyslotErrorType `json:"keyslot-errors"`              // A map of errors for tried keyslots, keyed by name.
	KeyslotErrorsOrder []string                    `json:"keyslot-errors-order"`        // A list of keyslot names in order of failure.

	// CustomData provides a way for the user of the ActivateContext API
	// to save arbitrary custom JSON data, using the
	// WithCustomActivateStateData option.
	CustomData json.RawMessage `json:"custom-data,omitempty"`
}

ContainerActivateState contains the activation state for a single StorageContainer.

type DeactivationReason

type DeactivationReason string

DeactivationReason permits the user of the ActivateContext API to define and supply reasons for calling ActivateContext.DeactivateContainer on a successfully unlocked storage container. This is intended to be used like an enum, with the user of the ActivateContext API defining the values.

type DiskUnlockKey

type DiskUnlockKey []byte

DiskUnlockKey is the key used to unlock a LUKS volume.

func GetDiskUnlockKeyFromKernel

func GetDiskUnlockKeyFromKernel(prefix, devicePath string, remove bool) (DiskUnlockKey, error)

GetDiskUnlockKeyFromKernel retrieves the key that was used to unlock the encrypted container at the specified path. The value of prefix must match the prefix that was supplied via ActivateVolumeOptions during unlocking.

If remove is true, the key will be removed from the kernel keyring prior to returning.

If no key is found, a ErrKernelKeyNotFound error will be returned.

func MakeDiskUnlockKey

func MakeDiskUnlockKey(rand io.Reader, alg crypto.Hash, primaryKey PrimaryKey) (unlockKey DiskUnlockKey, cleartextPayload []byte, err error)

MakeDiskUnlockKey derives a disk unlock key from a passed primary key and a random salt. It returns that key as well as a payload in cleartext containing the primary key and the generated salt.

type ExternalUnlockKeySource

type ExternalUnlockKeySource int

ExternalUnlockKeySource provides a hint about where a key supplied to WithExternalUnlockKey comes from.

const (
	// ExternalUnlockKeyFromPlatformDevice indicates that a key was recovered
	// from some platform device.
	ExternalUnlockKeyFromPlatformDevice ExternalUnlockKeySource = iota

	// ExternalUnlockKeyFromStorageContainer indicates that a key was recovered
	// from some encrypted storage container.
	ExternalUnlockKeyFromStorageContainer
)

type FileKeyDataReader

type FileKeyDataReader struct {
	*bytes.Reader
	// contains filtered or unexported fields
}

FileKeyDataReader provides a mechanism to read a KeyData from a file. This type will eventually just embed *[ExternalKeyData].

func NewFileKeyDataReader

func NewFileKeyDataReader(path string) (*FileKeyDataReader, error)

NewFileKeyDataReader is used to read a file containing key data at the specified path.

func (*FileKeyDataReader) ReadableName

func (r *FileKeyDataReader) ReadableName() string

ReadableName implements KeyDataReader.ReadableName.

XXX: This will be eventually be deleted along with KeyDataReader when the legacy activation API is deleted.

type FileKeyDataWriter

type FileKeyDataWriter struct {
	*bytes.Buffer
	// contains filtered or unexported fields
}

FileKeyDataWriter provides a mechanism to write a KeyData to a file.

func NewFileKeyDataWriter

func NewFileKeyDataWriter(path string) *FileKeyDataWriter

NewFileKeyDataWriter creates a new FileKeyDataWriter for atomically writing a KeyData to a file.

func (*FileKeyDataWriter) Commit

func (w *FileKeyDataWriter) Commit() error

type HashAlg

type HashAlg crypto.Hash

HashAlg provides an abstraction for crypto.Hash that can be serialized to JSON and DER.

func (HashAlg) Available

func (a HashAlg) Available() bool

func (HashAlg) HashFunc

func (a HashAlg) HashFunc() crypto.Hash

func (HashAlg) MarshalASN1

func (a HashAlg) MarshalASN1(b *cryptobyte.Builder)

func (HashAlg) MarshalJSON

func (a HashAlg) MarshalJSON() ([]byte, error)

func (HashAlg) New

func (a HashAlg) New() hash.Hash

func (HashAlg) Size

func (a HashAlg) Size() int

func (*HashAlg) UnmarshalJSON

func (a *HashAlg) UnmarshalJSON(b []byte) error

type IncompatibleKeyDataRoleParamsError

type IncompatibleKeyDataRoleParamsError struct {
	// contains filtered or unexported fields
}

IncompatibleKeyDataRoleParamsError is returned from KeyData methods when trying to recover keys if the data that associates the metadata with a role is incompatible with the current boot settings.

func (*IncompatibleKeyDataRoleParamsError) Error

func (*IncompatibleKeyDataRoleParamsError) Unwrap

type InitializeLUKS2ContainerOptions

type InitializeLUKS2ContainerOptions struct {
	// MetadataKiBSize sets the size of the metadata area in KiB. This
	//
	// MetadataKiBSize sets the size of the metadata area in KiB. 4KiB of
	// this is used for the fixed-size binary header, with the remaining
	// space being used for the JSON area. Setting this to zero causes
	// the container to be initialized with the default metadata area size.
	// If set to a non zero value, it must be a power of 2 between 16KiB
	// and 4MiB.
	MetadataKiBSize uint32

	// KeyslotsAreaKiBSize sets the size of the binary keyslot area in KiB.
	// Setting this to zero causes the container to be initialized with
	// the default keyslots area size. If set to a non-zero value, the
	// value must be a multiple of 4KiB up to a maximum of 128MiB.
	KeyslotsAreaKiBSize uint32

	// InitialKeyslotName sets the name that will be used to identify
	// the initial keyslot. If this is empty, then the name will be
	// set to "default".
	InitialKeyslotName string

	// InlineCryptoEngine set flag if to use Inline Crypto Engine
	InlineCryptoEngine bool
}

InitializeLUKS2ContainerOptions carries options for initializing LUKS2 containers.

type InvalidKeyDataError

type InvalidKeyDataError struct {
	// contains filtered or unexported fields
}

InvalidKeyDataError is returned from KeyData methods if the key data is invalid in some way.

func (*InvalidKeyDataError) Error

func (e *InvalidKeyDataError) Error() string

func (*InvalidKeyDataError) Unwrap

func (e *InvalidKeyDataError) Unwrap() error

type InvalidKeyDataRoleParamsError

type InvalidKeyDataRoleParamsError struct {
	// contains filtered or unexported fields
}

InvalidKeyDataRoleParamsError is returned from KeyData methods when trying to recover keys if the data that associates the metadata with a role is invalid.

func (*InvalidKeyDataRoleParamsError) Error

func (*InvalidKeyDataRoleParamsError) Unwrap

type KDFOptions

type KDFOptions interface {
	// contains filtered or unexported methods
}

KDFOptions is an interface for supplying options for different key derivation functions

type KeyData

type KeyData struct {
	// contains filtered or unexported fields
}

KeyData represents a disk unlock key and auxiliary key protected by a platform's secure device.

func NewKeyData

func NewKeyData(params *KeyParams) (*KeyData, error)

NewKeyData creates a new KeyData object using the supplied KeyParams, which should be created by a platform-specific package, containing a payload encrypted by the platform's secure device and the associated handle required for subsequent recovery of the keys.

func NewKeyDataWithPIN

func NewKeyDataWithPIN(params *KeyWithPINParams, pin PIN) (*KeyData, error)

NewKeyDataWithPIN is similar to NewKeyData but creates KeyData objects that are supported by a PIN, which is passed as an extra argument. The supplied KeyWithPINParams include in addition to the KeyParams fields, the KDFOptions and AuthKeySize fields which are used in the key derivation process.

func NewKeyDataWithPassphrase

func NewKeyDataWithPassphrase(params *KeyWithPassphraseParams, passphrase string) (*KeyData, error)

NewKeyDataWithPassphrase is similar to NewKeyData but creates KeyData objects that are supported by a passphrase, which is passed as an extra argument. The supplied KeyWithPassphraseParams include in addition to the KeyParams fields, the KDFOptions and AuthKeySize fields which are used in the key derivation process.

func ReadKeyData

func ReadKeyData(r KeyDataReader) (*KeyData, error)

ReadKeyData reads the key data from the supplied KeyDataReader, returning a new KeyData object.

XXX: This API will take eventually take a io.Reader type instead when KeyDataReader is removed along with the legacy activation API.

func (*KeyData) AuthMode

func (d *KeyData) AuthMode() (out AuthMode)

AuthMode indicates the authentication mechanism enabled for this key data.

func (*KeyData) ChangePIN

func (d *KeyData) ChangePIN(oldPIN, newPIN PIN) error

ChangePIN updates the PIN used to recover the keys from this key data via the KeyData.RecoverKeysWithPIN API. This can only be called if a PIN has been set previously (KeyData.AuthMode returns AuthModePIN).

The current PIN must be supplied via the oldPIN argument.

func (*KeyData) ChangePassphrase

func (d *KeyData) ChangePassphrase(oldPassphrase, newPassphrase string) error

ChangePassphrase updates the passphrase used to recover the keys from this key data via the KeyData.RecoverKeysWithPassphrase API. This can only be called if a passhphrase has been set previously (KeyData.AuthMode returns AuthModePassphrase).

The current passphrase must be supplied via the oldPassphrase argument.

func (*KeyData) Generation

func (d *KeyData) Generation() int

Generation returns this keydata's generation. Since the generation field didn't exist for older keydata with generation < 2, we fake the generation returned to 1.

func (*KeyData) IsSnapModelAuthorized

func (d *KeyData) IsSnapModelAuthorized(key PrimaryKey, model SnapModel) (bool, error)

IsSnapModelAuthorized indicates whether the supplied Snap device model is trusted to access the data on the encrypted volume protected by this key data.

The supplied key is obtained using one of the RecoverKeys* functions.

This is deprecated where [Generation] returns greater than 1, and will return an error. The value returned by [Generation] is indirectly protected because its used to decide how to decode the payload returned by [RecoverKeys].

func (*KeyData) MarshalAndUpdatePlatformHandle

func (d *KeyData) MarshalAndUpdatePlatformHandle(handle interface{}) error

MarshalAndUpdatePlatformHandle marshals the supplied platform handle to JSON and updates this KeyData object. The changes will need to persisted afterwards using WriteAtomic.

func (*KeyData) PlatformName

func (d *KeyData) PlatformName() string

PlatformName returns the name of the platform that handles this key data.

func (*KeyData) ReadableName

func (d *KeyData) ReadableName() string

ReadableName returns a human-readable name for this key data, useful for including in errors.

XXX: This is only used by the legacy activation API and will eventuall be removed along with it and KeyDataReader.

func (*KeyData) RecoverKeys

func (d *KeyData) RecoverKeys() (DiskUnlockKey, PrimaryKey, error)

RecoverKeys recovers the disk unlock key and primary key associated with this key data from the platform's secure device, for key data that doesn't have any additional authentication modes enabled (AuthMode returns AuthModeNone).

If AuthMode returns anything other than AuthModeNone, then this will return an error.

If no platform handler has been registered for this key data, an ErrNoPlatformHandlerRegistered error will be returned.

If the keys cannot be recovered because the key data is invalid, a *InvalidKeyDataError error will be returned.

If the keys cannot be recovered because the platform's secure device is not properly initialized, a *PlatformUninitializedError error will be returned.

If the keys cannot be recovered because the platform's secure device is not available, a *PlatformDeviceUnavailableError error will be returned.

func (*KeyData) RecoverKeysWithPIN

func (d *KeyData) RecoverKeysWithPIN(pin PIN) (DiskUnlockKey, PrimaryKey, error)

RecoverKeysWithPIN recovers the disk unlock key and primary key associated with this key data from the platform's secure device, for key data that has been configured with a PIN (AuthMode returns AuthModePIN). The correct PIN has to be supplied.

If AuthMode returns anything other than AuthModePIN, then this will return an error.

If no platform handler has been registered for this key data, an ErrNoPlatformHandlerRegistered error will be returned.

If the keys cannot be recovered because the key data is invalid, a *InvalidKeyDataError error will be returned.

If the keys cannot be recovered because the platform's secure device is not properly initialized, a *PlatformUninitializedError error will be returned.

If the keys cannot be recovered because the platform's secure device is not available, a *PlatformDeviceUnavailableError error will be returned.

If the key cannot be recovered because the wrong PIN is supplied, an ErrInvalidPIN error will be returned.

func (*KeyData) RecoverKeysWithPassphrase

func (d *KeyData) RecoverKeysWithPassphrase(passphrase string) (DiskUnlockKey, PrimaryKey, error)

RecoverKeysWithPassphrase recovers the disk unlock key and primary key associated with this key data from the platform's secure device, for key data that has been configured with a passphrase (AuthMode returns AuthModeNone). The correct passphrase has to be supplied.

If AuthMode returns anything other than AuthModePassphrase, then this will return an error.

If no platform handler has been registered for this key data, an ErrNoPlatformHandlerRegistered error will be returned.

If the keys cannot be recovered because the key data is invalid, a *InvalidKeyDataError error will be returned.

If the keys cannot be recovered because the platform's secure device is not properly initialized, a *PlatformUninitializedError error will be returned.

If the keys cannot be recovered because the platform's secure device is not available, a *PlatformDeviceUnavailableError error will be returned.

If the key cannot be recovered because the wrong passphrase is supplied, an ErrInvalidPassphrase error will be returned.

func (*KeyData) Role

func (d *KeyData) Role() string

func (*KeyData) SetAuthorizedSnapModels

func (d *KeyData) SetAuthorizedSnapModels(key PrimaryKey, models ...SnapModel) (err error)

SetAuthorizedSnapModels marks the supplied Snap device models as trusted to access the data on the encrypted volume protected by this key data. This function replaces all previously trusted models.

This makes changes to the key data, which will need to persisted afterwards using WriteAtomic.

The supplied key is obtained using one of the RecoverKeys* functions. If the supplied auxKey is incorrect, then an error will be returned.

This is deprecated where [Generation] returns greater than 1, and will return an error.

func (*KeyData) UniqueID

func (d *KeyData) UniqueID() (KeyID, error)

UniqueID returns the unique ID for this key data.

func (*KeyData) UnmarshalPlatformHandle

func (d *KeyData) UnmarshalPlatformHandle(handle interface{}) error

UnmarshalPlatformHandle unmarshals the JSON platform handle payload into the supplied handle, which must be a non-nil pointer.

func (*KeyData) WriteAtomic

func (d *KeyData) WriteAtomic(w KeyDataWriter) error

WriteAtomic saves this key data to the supplied KeyDataWriter.

type KeyDataReader

type KeyDataReader interface {
	io.Reader
	ReadableName() string
}

KeyDataReader is an interface used to read and decode a KeyData from persistent storage.

XXX: This will eventually be removed when the legacy activation API is removed.

type KeyDataWriter

type KeyDataWriter interface {
	io.Writer
	Commit() error
}

KeyDataWriter is an interface used by KeyData to write the data to persistent storage in an atomic way.

type KeyID

type KeyID []byte

KeyID is the unique ID for a KeyData object. It is used to facilitate the sharing of state between the early boot environment and OS runtime.

type KeyParams

type KeyParams struct {
	// Handle contains metadata required by the platform in order to recover
	// this key. It is opaque to this go package. It should be a value that can
	// be encoded to JSON using go's encoding/json package, which could be
	// something as simple as binary data stored in a byte slice or a more complex
	// JSON object, depending on the requirements of the implementation. A handle
	// already encoded to JSON can be supplied using the json.RawMessage type.
	Handle interface{}

	Role string

	// EncryptedPayload contains the encrypted and authenticated payload. The
	// plaintext payload should be created with [MakeDiskUnlockKey].
	EncryptedPayload []byte

	PlatformName string // Name of the platform that produced this data

	// KDFAlg is the digest algorithm used to derive additional keys during
	// the use of the created KeyData. It must match the algorithm passed to
	// [MakeDiskUnlockKey]. The zero value here has a special meaning which
	// is reserved to support legacy TPM2 key data files, and tells the
	// KeyData to use the unique key as the unlock key rather than using it
	// to derive the unlock key.
	KDFAlg crypto.Hash
}

KeyParams provides parameters required to create a new KeyData object. It should be produced by a platform implementation.

type KeyWithPINParams

type KeyWithPINParams struct {
	KeyParams
	KDFOptions *PBKDF2Options // The PIN KDF options

	// AuthKeySize is the size of key to derive from the PIN for
	// use by the platform implementation.
	AuthKeySize int

	// ChangeAuthKeyContext can be set to the caller to any arbitrary value
	// that should be passed to the initial call to
	// [PlatformKeyDataHandler.ChangeAuthKey]. The main use for this is to
	// permit the tpm2 package to supply an open TPM connection.
	ChangeAuthKeyContext any
}

KeyWithPINParams provides parameters required to create a new KeyData object with a PIN enabled. It should be produced by a platform implementation.

type KeyWithPassphraseParams

type KeyWithPassphraseParams struct {
	KeyParams
	KDFOptions KDFOptions // The passphrase KDF options

	// AuthKeySize is the size of key to derive from the passphrase for
	// use by the platform implementation.
	AuthKeySize int

	// ChangeAuthKeyContext can be set to the caller to any arbitrary value
	// that should be passed to the initial call to
	// [PlatformKeyDataHandler.ChangeAuthKey]. The main use for this is to
	// permit the tpm2 package to supply an open TPM connection.
	ChangeAuthKeyContext any
}

KeyWithPassphraseParams provides parameters required to create a new KeyData object with a passphrase enabled. It should be produced by a platform implementation.

type KeyringKeyPurpose

type KeyringKeyPurpose string

KeyringKeyPurpose describes the purpose of a key stored in the kyring.

const (

	// KeyringKeyPurposePrimary references the primary key recovered from
	// the metadata for a normal keyslot. Any container unlocked with a
	// normal keyslot will have one of these.
	KeyringKeyPurposePrimary KeyringKeyPurpose = "primary"

	// KeyringKeyPurposeUnique references the unique key recovered from the
	// metadata for a normal keyslot. This and the primary key are used to
	// derive the unlock key, and can be used to derive keys for other
	// purposes.
	//
	// XXX: This key will not initially be present in the keyring because
	// it isn't exposed from [KeyData.RecoverKeys]. It may be added later.
	// In any case, the presence of both the primary and unlock keys will be
	// sufficient for now in order for us to add new keyslots or update
	// existing ones.
	KeyringKeyPurposeUnique KeyringKeyPurpose = "unique"

	// KeyringKeyPurposeUnlock references the unlock key used to unlock a
	// keyslot. It can be recovered from the metadata for a normal keyslot,
	// or be supplied as a recovery key. All unlocked containers will have
	// one of these.
	KeyringKeyPurposeUnlock KeyringKeyPurpose = "unlock"
)

type Keyslot

type Keyslot interface {
	Type() KeyslotType
	Name() string
	Priority() int
	Data() KeyDataReader // TODO: This will eventually just be a io.Reader.
}

Keyslot provides information about a keyslot.

type KeyslotErrorType

type KeyslotErrorType string

KeyslotErrorType describes the reason a keyslot failed when it was attempted.

const (
	KeyslotErrorNone                   KeyslotErrorType = ""
	KeyslotErrorIncompatibleRoleParams KeyslotErrorType = "incompatible-role-params" // The role parameters for the keyslot are not compatible with the current boot configuration.
	KeyslotErrorInvalidRoleParams      KeyslotErrorType = "invalid-role-params"      // The role parameters for the keyslot are invalid.
	KeyslotErrorInvalidKeyData         KeyslotErrorType = "invalid-key-data"         // The keyslot metadata is invalid.
	KeyslotErrorInvalidPrimaryKey      KeyslotErrorType = "invalid-primary-key"      // The keyslot's primary key failed the primary key crosscheck.
	KeyslotErrorIncorrectUserAuth      KeyslotErrorType = "incorrect-user-auth"      // An incorrect user authorization was provided.
	KeyslotErrorUserAuthUnavailable    KeyslotErrorType = "user-auth-unavailable"    // User authorization was not attempted because it is unavailable.
	KeyslotErrorPlatformFailure        KeyslotErrorType = "platform-failure"         // There was an error with the platform device.
	KeyslotErrorUnknown                KeyslotErrorType = "unknown"
)

type KeyslotType

type KeyslotType string

KeyslotType describes the type of a keyslot.

const (
	KeyslotTypePlatform KeyslotType = "platform"
	KeyslotTypeRecovery KeyslotType = "recovery"

	KeyslotTypeUnknown KeyslotType = ""
)

type LUKS2KeyDataReader

type LUKS2KeyDataReader struct {
	*bytes.Reader
	// contains filtered or unexported fields
}

LUKS2KeyDataReader provides a mechanism to read a KeyData from a LUKS2 token.

XXX: This will eventually be deleted when the legacy activation API has been deleted, StorageContainer has write support and snapd has migrated to that new write support.

func NewLUKS2KeyDataReader

func NewLUKS2KeyDataReader(devicePath, name string) (*LUKS2KeyDataReader, error)

NewLUKS2KeyDataReader is used to read a LUKS2 token containing key data with the specified name on the specified LUKS2 container.

XXX: This will eventually be deleted when the legacy activation API has been deleted, StorageContainer has write support and snapd has migrated to that new write support.

func (*LUKS2KeyDataReader) KeyslotID

func (r *LUKS2KeyDataReader) KeyslotID() int

KeyslotID indicates the keyslot ID associated with the token from which this KeyData is read.

func (*LUKS2KeyDataReader) Priority

func (r *LUKS2KeyDataReader) Priority() int

Priority indicates the priority of the keyslot associated with the token from which this KeyData is read. The default priority is 0 with higher numbers indicating a higher priority.

func (*LUKS2KeyDataReader) ReadableName

func (r *LUKS2KeyDataReader) ReadableName() string

type LUKS2KeyDataWriter

type LUKS2KeyDataWriter struct {
	*bytes.Buffer
	// contains filtered or unexported fields
}

LUKS2KeyDataWriter provides a mechanism to write a KeyData to a LUKS2 token.

func NewLUKS2KeyDataWriter

func NewLUKS2KeyDataWriter(devicePath, name string) (*LUKS2KeyDataWriter, error)

NewLUKS2KeyDataWriter creates a new LUKS2KeyDataWriter for atomically writing a KeyData to a LUKS2 token with the specicied name and priority on the specified LUKS2 container.

The container must already contain a token of the correct type with the supplied name. The initial token is bootstrapped by InitializeLUKS2Container or SetLUKS2ContainerUnlockKey.

func (*LUKS2KeyDataWriter) Commit

func (w *LUKS2KeyDataWriter) Commit() error

func (*LUKS2KeyDataWriter) SetPriority

func (w *LUKS2KeyDataWriter) SetPriority(priority int)

SetPriority sets the priority for the updated KeyData that is written using this writer. It must be called before Commit.

Zero is the default priority, with higher numbers indicating a higher priority. A negative priority indicates that the KeyData shouldn't be used for activation unless referred to explicitly.

type PBKDF2Options

type PBKDF2Options struct {
	TargetDuration time.Duration

	ForceIterations uint32

	HashAlg crypto.Hash
}

type PIN

type PIN struct {
	// contains filtered or unexported fields
}

PIN represents a numeric PIN.

func ParsePIN

func ParsePIN(s string) (PIN, error)

ParsePIN parses the supplied string and returns a PIN. If the supplied string has a length of zero, or more than 256, or contains anything other than ASCII base-10 digits, an error will be returned.

func (PIN) Bytes

func (p PIN) Bytes() []byte

Bytes provides a binary representation of this PIN which can be used as low-entropy key material. The binary representation is a variable-length quantity of the original PIN encoded in a way that preserves any leading zeroes.

func (PIN) String

func (p PIN) String() string

String implements fmt.Stringer.

type PassphraseEntropyStats

type PassphraseEntropyStats struct {
	SymbolPoolSize  uint32
	NumberOfSymbols uint32
	EntropyBits     uint32
}

func CheckPassphraseEntropy

func CheckPassphraseEntropy(passphrase string) (*PassphraseEntropyStats, error)

CheckPassphraseEntropy calculates entropy for PINs and passphrases (PINs will be supplied as a numeric passphrase).

type PlatformDeviceUnavailableError

type PlatformDeviceUnavailableError struct {
	// contains filtered or unexported fields
}

PlatformDeviceUnavailableError is returned from KeyData methods if the platform's secure device is currently unavailable.

func (*PlatformDeviceUnavailableError) Error

func (*PlatformDeviceUnavailableError) Unwrap

type PlatformHandlerError

type PlatformHandlerError struct {
	Type PlatformHandlerErrorType // type of the error
	Err  error                    // underlying error
}

PlatformHandlerError is returned from a PlatformKeyDataHandler implementation when the type of error can be categorized as one of the types supported by PlatformHandlerErrorType.

func (*PlatformHandlerError) Error

func (e *PlatformHandlerError) Error() string

func (*PlatformHandlerError) Unwrap

func (e *PlatformHandlerError) Unwrap() error

type PlatformHandlerErrorType

type PlatformHandlerErrorType int

PlatformHandlerErrorType indicates the type of error that PlatformHandlerError is associated with.

const (
	// PlatformHandlerErrorInvalidData indicates that an action could not be
	// performed by PlatformKeyDataHandler because the supplied key data is
	// invalid.
	PlatformHandlerErrorInvalidData PlatformHandlerErrorType = iota + 1

	// PlatformHandlerErrorUninitialized indicates that an action could not
	// be performed by PlatformKeyDataHandler because the platform's secure
	// device is not properly initialized.
	PlatformHandlerErrorUninitialized

	// PlatformHandlerErrorUnavailable indicates that an action could not be
	// be performed by PlatformKeyDataHandler because the platform's secure
	// device is unavailable.
	PlatformHandlerErrorUnavailable

	// PlatformHandlerErrorInvalidAuthKey indicates that an action could not
	// be performed by PlatformKeyDataHandler because the supplied
	// authorization key was incorrect.
	// TODO: Rename this to PlatformHandlerErrorInvalidUserAuthKey
	PlatformHandlerErrorInvalidAuthKey

	// PlatformHandlerErrorUserAuthUnavailable indicates that an action could
	// not be performed by PlatformKeyDataHandler because user authorization
	// is currently unavailable.
	PlatformHandlerErrorUserAuthUnavailable

	// PlatformHandlerErrorIncompatibleRole indicates that an action could
	// not be performed by PlatformKeyDataHandler because the key data's
	// role is incompatible with the current boot configuration.
	PlatformHandlerErrorIncompatibleRole

	// PlatformHandlerInvalidRoleParams indicates that an action could
	// not be performed by PlatformKeyDataHandler because the key data's
	// role parameters are invalid.
	PlatformHandlerErrorInvalidRoleParams
)

type PlatformKeyData

type PlatformKeyData struct {
	Generation    int
	EncodedHandle []byte // The JSON encoded platform handle
	Role          string
	KDFAlg        crypto.Hash

	AuthMode AuthMode
}

PlatformKeyData represents the data exchanged between this package and platform implementations via the PlatformKeyDataHandler.

type PlatformKeyDataHandler

type PlatformKeyDataHandler interface {
	// RecoverKeys attempts to recover the cleartext keys from the supplied encrypted
	// payload using this platform's secure device.
	RecoverKeys(data *PlatformKeyData, encryptedPayload []byte) ([]byte, error)

	// RecoverKeysWithAuthKey attempts to recover the cleartext keys from the
	// encrypted payload using this platform's secure device. The key parameter
	// is a passphrase derived key to enable passphrase support to be integrated
	// with the secure device. The platform implementation doesn't provide the primary
	// mechanism of protecting keys with a passphrase - this is done in the platform
	// agnostic API. Some devices (such as TPMs) support this integration natively. For
	// other devices, the integration should provide a way of validating the key in
	// a way that requires the use of the secure device (eg, such as computing a HMAC of
	// it using a hardware backed key).
	RecoverKeysWithAuthKey(data *PlatformKeyData, encryptedPayload, key []byte) ([]byte, error)

	// ChangeAuthKey is called to notify the platform implementation that the
	// passphrase is being changed. The old and new parameters are passphrase derived
	// keys. Either value can be nil if passphrase authentication is being enabled (
	// where old will be nil) or disabled (where new will be nil).
	//
	// The use of the context argument isn't defined here - it's passed during
	// key construction and the platform is free to use it however it likes.
	//
	// On success, it should return an updated handle.
	ChangeAuthKey(data *PlatformKeyData, old, new []byte, context any) ([]byte, error)
}

PlatormKeyDataHandler is the interface that this go package uses to interact with a platform's secure device for the purpose of recovering keys.

type PlatformKeyDataHandlerFlags

type PlatformKeyDataHandlerFlags uint64

PlatformKeyDataHandlerFlags can be used to describe features supported by a registered platform.

The lower 40 bits are for use and defined by the platform, and the platform can choose to use them however it wants to (eg, it may use some bits as a version number). This package does not use or interpret these 40 bits.

The upper 24 bits are reserved for common flags defined by this package, although there aren't any defined right now.

const (

	// PlatformProtectedByStorageContainer indicates that a platform protects
	// its keys inside an encrypted storage container rather than a hardware
	// device.
	PlatformProtectedByStorageContainer PlatformKeyDataHandlerFlags = 1 << 40
)

func (PlatformKeyDataHandlerFlags) AddPlatformFlags

AddPlatformFlags adds the platform defined flags to the common flags, returning a new flags value. This package doesn't define the meaning of the specified flags and it does not use or interpret them in any way.

This will panic if it uses any of the upper 24 bits reserved for common flags defined by this package.

type PlatformUninitializedError

type PlatformUninitializedError struct {
	// contains filtered or unexported fields
}

PlatformUninitializedError is returned from KeyData methods if the platform's secure device has not been initialized properly.

func (*PlatformUninitializedError) Error

func (*PlatformUninitializedError) Unwrap

func (e *PlatformUninitializedError) Unwrap() error

type PrimaryKey

type PrimaryKey []byte

PrimaryKey is an additional key used to modify properties of a KeyData object without having to create a new object.

func GetPrimaryKeyFromKernel

func GetPrimaryKeyFromKernel(prefix, devicePath string, remove bool) (PrimaryKey, error)

GetPrimaryKeyFromKernel retrieves the auxiliary key associated with the KeyData that was used to unlock the encrypted container at the specified path. The value of prefix must match the prefix that was supplied via ActivateVolumeOptions during unlocking.

If remove is true, the key will be removed from the kernel keyring prior to returning.

If no key is found, a ErrKernelKeyNotFound error will be returned.

type RecoveryKey

type RecoveryKey [16]byte

RecoveryKey corresponds to a 16-byte recovery key in its binary form.

func ParseRecoveryKey

func ParseRecoveryKey(s string) (out RecoveryKey, err error)

ParseRecoveryKey interprets the supplied string and returns the corresponding RecoveryKey. The recovery key is a 16-byte number, and the formatted version of this is represented as 8 5-digit zero-extended base-10 numbers (each with a range of 00000-65535) which may be separated by an optional '-', eg:

"61665-00531-54469-09783-47273-19035-40077-28287"

The formatted version of the recovery key is designed to be able to be inputted on a numeric keypad.

func (RecoveryKey) String

func (k RecoveryKey) String() string

type SnapModel

type SnapModel interface {
	Series() string
	BrandID() string
	Model() string
	Classic() bool
	Grade() asserts.ModelGrade
	SignKeyID() string
}

SnapModel exposes the details of a snap device model that are bound to an encrypted container.

type StorageContainer

type StorageContainer interface {
	Path() string // The path of this storage container.

	// BackendName is the name of the backend that created this
	// StorageContainer instance.
	//
	// XXX: See the comment for RegisterStorageContainerBackend about
	// using something other than a string for identifying the storage
	// backend.
	BackendName() string

	// CredentialName returns a string that can be used to identify
	// a credential associated with this container that is passed from
	// the early boot environment
	CredentialName() string

	// Activate unlocks this container with the specified key.
	// The caller can choose to supply the Keyslot instance
	// related to the keyslot from which the supplied key is
	// associated with (obtained from StorageContainerReader.ReadKeyslot).
	// If supplied, the backend can use this to target the supplied
	// key at a specific keyslot. If keyslotInfo nil is supplied, the
	// backend will have to test all keyslots with the supplied key.
	// The caller can specify a configuration, which is a map of keys
	// or arbitrary types to values of arbitrary types.
	Activate(ctx context.Context, ks Keyslot, key []byte, cfg ActivateConfigGetter) error

	// Deactivate locks this storage container.
	Deactivate(ctx context.Context) error

	// OpenRead opens this storage container in order to perform
	// operations to keyslots that only require read access. The backend
	// should permit as many of these to be opened as is requested, but
	// must not allow a combination of StorageContainerReader and
	// StorageContainerReadWriter (when it exists) to be open at the same
	// time (and the backend should only permit one StorageContainerReadWriter
	// to be open at a time).
	OpenRead(ctx context.Context) (StorageContainerReader, error)
}

StorageContainer represents some type of storage container that can store keyslots, making the core code in secboot agnostic to the storage backend. Implementation of this should be safe to access from multiple goroutines.

func FindActivatedStorageContainer

func FindActivatedStorageContainer(ctx context.Context, path string) (StorageContainer, error)

FindActivatedStorageContainer returns a StorageContainer associated with the supplied path to some storage that is backed by a source storage container, probing each of the registered backend to obtain an appropriate instance. The path may or may not be a path to a block device, depending on the backends that are registered, because not all backends that may exist in the future will make use of block devices for a storage container.

This will always return the same StorageContainer instance for any path that points to the same activated storage container, and will return the same StorageContainer that FindStorageContainer returns when it is supplied with a path to the source container.

If no StorageContainer is found, a ErrNoStorageContainer error is returned.

This is safe to call from multiple goroutines.

func FindStorageContainer

func FindStorageContainer(ctx context.Context, path string) (StorageContainer, error)

FindStorageContainer returns a StorageContainer associated with the specified path to a storage container source, probing each of the registered backends to obtain an appropriate instance. The path may or may not be a path to a block device, depending on the backends that are registered, because not all backends that may exist in the future will make use of block devices for a storage container.

This will always return the same StorageContainer instance for any path that points to the same storage container source, and will return the same StorageContainer that FindActivatedStorageContainer returns when it is supplied with the path of any container that is backed by this one.

If no StorageContainer is found, a ErrNoStorageContainer error is returned.

This is safe to call from multiple goroutines.

type StorageContainerBackend

type StorageContainerBackend interface {
	// Probe returns a StorageContainer instance for the supplied
	// path to a storage container source if it can be handled by this
	// backend, else it returns (nil, nil).
	//
	// Implementations should always return the same StorageContainer
	// instance for the same container referenced by the supplied path -
	// the implementation should at least handle the cases of symbolic
	// links. It should also be the same instance as the one returned
	// via the ProbeActivated method with a path to the corresponding
	// activate storage container.
	//
	// Implementations of this must be safe to call from any goroutine.
	//
	// The supplied path may or may not be a path to a block device,
	// depending on how the backend works - there may be backends in the
	// future that don't use block devices for storage containers.
	Probe(ctx context.Context, path string) (StorageContainer, error)

	// ProbeActivated returns a StorageContainer instance for the
	// supplied path to an activated storage container if it can be
	// handled by this backend, else it returns (nil, nil). An activated
	// storage container is one that is backed by some source that can
	// be returned via the Probe method using the path to the source
	// instead.
	//
	// Implementations should always return the same StorageContainer
	// instance for the same container referenced by the supplied path -
	// the implementation should at least handle the cases of symbolic
	// links. It should also be the same instance as the one returned
	// via the Probe method with the corresponding source path.
	//
	// Implementations of this must be safe to call from any goroutine.
	//
	// The supplied path may or may not be a path to a block device,
	// depending on how the backend works - there may be backends in the
	// future that don't use block devices for storage containers.
	ProbeActivated(ctx context.Context, path string) (StorageContainer, error)
}

StorageContainerBackend is an interface used by secboot to communicate with a backend that has support for a specific type of encrypted storage container.

type StorageContainerReader

type StorageContainerReader interface {
	// Container returns the StorageContainer that this reader
	// was opened from. It can return nil once Close is called.
	Container() StorageContainer

	// io.Closer is used to close this reader.
	io.Closer

	// ListKeyslotNames returns a sorted list of keyslot names.
	ListKeyslotNames(ctx context.Context) ([]string, error)

	// ReadKeyslot returns information about the keyslot with
	// the specified name.
	ReadKeyslot(ctx context.Context, name string) (Keyslot, error)
}

StorageContainerReader provides a mechanism to perform read-only operations on keyslots on a storage container.

The implementation does not need to be threadsafe - it should be used from a single goroutine. If access is needed on another goroutine, use the associated StorageContainer to open a new one.

The backend should permit as many of these to be opened as required, but should never permit one to be opened at the same time as a [StorageContainerReadWriter].

type SystemdAuthRequestorStringFn

type SystemdAuthRequestorStringFn func(name, path string, authTypes UserAuthType) (string, error)

SystemdAuthRequestorStringFn is a callback used to supply translated messages to the systemd implementation of AuthRequestor.RequestUserCredential. The name is a string supplied via the WithAuthRequestorUserVisibleName option, and the path is the storage container path.

type UserAuthResult

type UserAuthResult int

UserAuthResult indicates the result of a user auth attempt.

const (
	// UserAuthResultSuccess indicates that an authentication attempt
	// was successful.
	UserAuthResultSuccess UserAuthResult = iota

	// UserAuthResultFailed indicates that an authentication attempt failed.
	UserAuthResultFailed

	// UserAuthResultInvalidFormat indicates that authentication
	// could not be attempted because the supplied credential was formatted
	// incorrectly for the type.
	UserAuthResultInvalidFormat
)

type UserAuthType

type UserAuthType int

UserAuthType describes a user authentication type that can be requested via AuthRequestor.

const (
	// UserAuthTypePassphrase indicates that a passphase is
	// being requested.
	UserAuthTypePassphrase UserAuthType = 1 << iota

	// UserAuthTypePIN indicates that a PIN is being requested.
	UserAuthTypePIN

	// UserAuthTypeRecoveryKey indicates that a recovery key
	// is being requesteed.
	UserAuthTypeRecoveryKey
)

type UserAuthUnavailableError

type UserAuthUnavailableError struct {
	// contains filtered or unexported fields
}

UserAuthUnavailableError is returned from KeyData methods that require knowledge of a PIN or passphrase but the platform indicates that user authorization is currently unavailable.

func (*UserAuthUnavailableError) Error

func (e *UserAuthUnavailableError) Error() string

func (*UserAuthUnavailableError) Unwrap

func (e *UserAuthUnavailableError) Unwrap() error

Directories

Path Synopsis
Package bootscope provides a way to bind keys to certain system properties for platforms that don't support measured boot.
Package bootscope provides a way to bind keys to certain system properties for platforms that don't support measured boot.
cmd
run_argon2 command
* Copyright (C) 2024-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.
* Copyright (C) 2024-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.
efi
Package hooks provides a way to protect keys using hooks supplied via a gadget and kernel snap for a device.
Package hooks provides a way to protect keys using hooks supplied via a gadget and kernel snap for a device.
internal
efi
keyring
Package keyring provides a way to work with the kernel keyring.
Package keyring provides a way to work with the kernel keyring.
keyring/forcesessioninit
Package forcesessioninit should be imported by applications that want to unconditionally join a new anonymous session keyring before the go runtime starts.
Package forcesessioninit should be imported by applications that want to unconditionally join a new anonymous session keyring before the go runtime starts.
keyring/keyringtest
Package keyringtest provides some helpers to use in unit tests of packages that make use of the keyring package.
Package keyringtest provides some helpers to use in unit tests of packages that make use of the keyring package.
keyring/processinit
Package processinit should be imported by applications that want a process keyring created before the go runtime starts.
Package processinit should be imported by applications that want a process keyring created before the go runtime starts.
pe1.14
Package pe implements access to PE (Microsoft Windows Portable Executable) files.
Package pe implements access to PE (Microsoft Windows Portable Executable) files.
tcg
Package plainkey is a platform for recovering keys that are protected by a key that is protected by some other mechanism.
Package plainkey is a platform for recovering keys that are protected by a key that is protected by some other mechanism.
tools

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL