keyfile

package
v0.10.1 Latest Latest
Warning

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

Go to latest
Published: Oct 24, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package keyfile loads a long-lived key from disk, creating it on first use or storing one it was handed.

Seven products in the suite did this seven ways, and the disagreements were not stylistic. kynotes-server continued past a key file it could not decode and left the secret an empty string, so the server ran with no pairing secret and no error. kypassword-server's audit store regenerated on an empty file, which silently orphans every record written under the old key. Five of the seven read and then wrote with no exclusion, so two starting processes each minted a key and one won after the other had already sealed data. Only one fsynced, so a crash just after first boot left a zero-length file for the next boot to misread.

This package refuses rather than guesses: an existing file that does not decode to exactly the expected size is an error, never something to replace.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrUnreadable reports an existing key file that does not decode to the expected
	// size. The file is left exactly as it was found.
	ErrUnreadable = errors.New("keyfile: existing key file is unreadable and will not be replaced")
	// ErrPermissive reports a key file that some account other than its owner can read.
	ErrPermissive = errors.New("keyfile: key file is readable beyond its owner")
	// ErrUnsafe reports a key path that is not a regular file owned by this process's user.
	ErrUnsafe = errors.New("keyfile: key path is not a regular file owned by the current user")
)

Functions

func FromEnv

func FromEnv(name string, size int) ([]byte, bool, error)

FromEnv reads a key from an environment variable, accepting hex or base64.

It returns false when the variable is unset or blank. A variable that is set to something else but does not decode to exactly size bytes is an error, never a miss: falling through to the file there would start the process under a key the operator did not choose and believes they overrode.

This exists because four products in the suite check an environment variable before the file, and doing that outside this package means the env-supplied key skips every check the file-supplied one gets.

func Load

func Load(path string, size int) ([]byte, error)

Load returns the size-byte secret stored at path as lowercase hex, and never creates one. See LoadEncoded for other spellings.

A process that reads a key another process minted must not be able to mint its own. When both can, a restart in the wrong order leaves half the data under a key that no longer exists, and nothing reports it — every write succeeds, and every old read fails as though the data were corrupt.

func LoadEncoded

func LoadEncoded(path string, size int, enc Encoding) ([]byte, error)

LoadEncoded is Load for a key written in another spelling.

func LoadOrCreate

func LoadOrCreate(path string, size int) ([]byte, error)

LoadOrCreate returns the size-byte secret stored at path as lowercase hex, creating it if the file does not exist. See LoadOrCreateEncoded for other spellings.

func LoadOrCreateEncoded

func LoadOrCreateEncoded(path string, size int, enc Encoding) ([]byte, error)

LoadOrCreateEncoded returns the size-byte secret stored at path in the given encoding, creating it if the file does not exist.

Hex is this package's default and the suite's preference: an operator can read it, copy it and diff it, with no ambiguity about whether the bytes are raw, hex or base64 — which three of the seven original implementations disagreed about. Raw and Base64 exist because other products already wrote their key files that way.

func ReadPrivate

func ReadPrivate(path string, limit int64) ([]byte, error)

ReadPrivate reads a bounded opaque secret or setup bundle from an existing private regular file. It uses the same verified descriptor as key loading and never creates or repairs a file. Content is returned only after ownership and mode checks pass.

func RequireOwnerOnly

func RequireOwnerOnly(path string) error

RequireOwnerOnly reports whether path is readable by anyone but its owner. Nothing in the suite checked this, so a key file relaxed to 0644 by a stray chmod or a restore kept being used as though it were secret.

func RequirePrivateDirectory

func RequirePrivateDirectory(path string) error

RequirePrivateDirectory validates a container-local control directory without changing ownership or permissions. It refuses a symlink or a foreign/permissive path.

func RequireTrustedAncestry

func RequireTrustedAncestry(path string) error

RequireTrustedAncestry refuses a path whose existing ancestors another user could rename or replace: each must be a real directory owned by root or the current user, writable by others only when root-owned and sticky. Missing components are allowed; they can only be created beneath a verified ancestor.

func Store

func Store(path string, key []byte, enc Encoding) error

Store persists a key the caller already holds — a public key received at pairing — with the durability and permissions of LoadOrCreate, and refuses to replace a file that exists.

The refusal is the point. Replacing a product's recovery public key is how every later backup gets sealed to whoever wrote the replacement; os.Link failing on an existing name is what makes that attack fail rather than succeed silently. Rotation, when it comes, gets a deliberate path, not an overwrite. The error satisfies errors.Is(err, fs.ErrExist).

Types

type Encoding

type Encoding int

Encoding is how a key is spelled on disk.

Hex is this package's default and the suite's preference: an operator can read it, copy it and diff it without a tool. Raw and Base64 exist because four products already wrote their key files that way, and a package that cannot read them is a package they cannot adopt.

const (
	// Hex is lowercase hex, optionally with surrounding whitespace.
	Hex Encoding = iota
	// Raw is the key bytes themselves, with nothing around them.
	Raw
	// Base64 is standard base64, optionally with surrounding whitespace.
	Base64
)

Jump to

Keyboard shortcuts

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