Documentation
¶
Overview ¶
Package gpg provides GPG operations by shelling out to the gpg binary.
Index ¶
- Constants
- func LatestSubkeyIDs(keys []SubKey) []string
- func UsageLabel(usage string) string
- func ValidateFingerprint(fp string) error
- func ValidateKeyID(id string) error
- func ValidateSerial(serial string) error
- func ValidateServerAlias(alias string) error
- func WriteAgentConfig(homeDir string) error
- func YkmanAvailable() bool
- type CardInfo
- type CardMode
- type Client
- func (c *Client) AddUID(ctx context.Context, masterFP string, uid string) error
- func (c *Client) AutoDiscoverConfig(ctx context.Context) (*Config, error)
- func (c *Client) CardStatus(ctx context.Context) (*CardInfo, error)
- func (c *Client) DiscoverCard(ctx context.Context) (*YubiKeyEntry, error)
- func (c *Client) ExportPubKeyToLocal(ctx context.Context, masterFP string) error
- func (c *Client) ExportSSHPubKey(ctx context.Context, masterFP string) (string, error)
- func (c *Client) GenerateMasterKey(ctx context.Context, opts MasterKeyOpts) (string, error)
- func (c *Client) GenerateSubkeys(ctx context.Context, opts SubkeyOpts) error
- func (c *Client) HasPassphrase() bool
- func (c *Client) HomeDir() string
- func (c *Client) ListKeys(ctx context.Context) ([]SubKey, error)
- func (c *Client) ListSecretKeys(ctx context.Context) ([]SubKey, error)
- func (c *Client) ListUIDs(ctx context.Context, masterFP string) ([]UID, error)
- func (c *Client) LoadConfig() (*Config, error)
- func (c *Client) LoadInventory() (*Inventory, error)
- func (c *Client) LoadServerRegistry() (*ServerRegistry, error)
- func (c *Client) LookupGitHub(ctx context.Context, masterFP string) KeyserverLookupResult
- func (c *Client) LookupKeyservers(ctx context.Context, masterFP string, servers []string) []KeyserverLookupResult
- func (c *Client) MoveToCard(ctx context.Context, masterFP string, keyIDs []string) error
- func (c *Client) Publish(ctx context.Context, masterFP string, targets []PublishTarget) []PublishResult
- func (c *Client) Revoke(ctx context.Context, masterFP string, keyID string) error
- func (c *Client) RevokeUID(ctx context.Context, masterFP string, uid string) error
- func (c *Client) SaveConfig(cfg *Config) error
- func (c *Client) SaveInventory(inv *Inventory) error
- func (c *Client) SaveServerRegistry(reg *ServerRegistry) error
- func (c *Client) SetPrimaryUID(ctx context.Context, masterFP string, uid string) error
- func (c *Client) YkmanInfo(ctx context.Context) (*YkmanDeviceInfo, error)
- type Config
- type Inventory
- type KeyserverLookupResult
- type MasterKeyOpts
- type Options
- type PublishResult
- type PublishTarget
- type ServerEntry
- type ServerRegistry
- type SubKey
- type SubKeyRef
- type SubkeyOpts
- type UID
- type YkmanDeviceInfo
- type YubiKeyEntry
Constants ¶
const ( // TargetTypeKeyserver is the publish target type for keyservers. TargetTypeKeyserver = "keyserver" // TargetTypeGitHub is the publish target type for GitHub. TargetTypeGitHub = "github" )
Variables ¶
This section is empty.
Functions ¶
func LatestSubkeyIDs ¶
LatestSubkeyIDs returns the key IDs of the most recently created non-revoked S, E, A subkeys. This is used to determine which subkeys to move to a card.
func UsageLabel ¶
UsageLabel converts a usage code to a human-readable label.
func ValidateFingerprint ¶
ValidateFingerprint checks that fp looks like a valid GPG fingerprint (40 hex chars).
func ValidateKeyID ¶
ValidateKeyID checks that id looks like a valid GPG key ID (16 hex chars).
func ValidateSerial ¶
ValidateSerial checks that serial looks like a valid card serial number (numeric).
func ValidateServerAlias ¶ added in v0.1.0
ValidateServerAlias checks that an alias is non-empty and contains only lowercase letters, digits, and hyphens.
func WriteAgentConfig ¶ added in v0.3.0
WriteAgentConfig writes gpg.conf and gpg-agent.conf into homeDir to enable loopback pinentry mode. This bypasses pinentry entirely so the application can supply passphrases via --passphrase-fd, which works in any environment (TTY, non-TTY, container, CI). It also tunes gpg-agent's passphrase cache for typical interactive session lengths.
Existing files are overwritten. Permissions are set to 0600.
func YkmanAvailable ¶
func YkmanAvailable() bool
YkmanAvailable returns true if the ykman CLI is installed.
Types ¶
type CardInfo ¶
type CardInfo struct {
Serial string
Model string
ReaderName string // raw Reader field from card-status
KeyIDs []string // key grip or key IDs on the card
}
CardInfo holds information from gpg --card-status.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client wraps the gpg binary for key operations.
func (*Client) AddUID ¶ added in v0.3.0
AddUID attaches a new user ID to the master key. The uid argument must be in the form "Name <email>" or "Name (comment) <email>".
func (*Client) AutoDiscoverConfig ¶
AutoDiscoverConfig detects the master key fingerprint and populates a default config.
func (*Client) CardStatus ¶
CardStatus queries the connected smart card and returns its info.
On systems without pcscd (where scdaemon uses internal CCID via libusb), only one scdaemon at a time can claim a YubiKey. If the user has a long-running gpg-agent for ~/.gnupg (typical for desktop Linux with enable-ssh-support), its scdaemon will hold the card and a fresh scdaemon spawned in the gpgsmith session's GNUPGHOME cannot acquire it.
To handle this, we detect the "No such device" failure mode, kill all conflicting scdaemons system-wide via `gpgconf --kill scdaemon` (which affects every gpg-agent on this user account), and retry once. The killed scdaemons will respawn on the next gpg call from any homedir, so this is a transient interruption — no permanent state change.
func (*Client) DiscoverCard ¶
func (c *Client) DiscoverCard(ctx context.Context) (*YubiKeyEntry, error)
DiscoverCard detects a connected YubiKey and returns an inventory entry. The entry is not automatically added to the inventory.
func (*Client) ExportPubKeyToLocal ¶ added in v0.1.0
ExportPubKeyToLocal exports the public key from the current GNUPGHOME and imports it into the user's default ~/.gnupg keyring. It also copies private key stubs for card-bound subkeys so the local keyring can use the card for signing outside the vault session.
func (*Client) ExportSSHPubKey ¶
ExportSSHPubKey exports the authentication subkey as an SSH public key to ~/.ssh/gpgsmith-<keyid>.pub.
func (*Client) GenerateMasterKey ¶ added in v0.2.0
GenerateMasterKey creates a new master key (certify-only) using --quick-gen-key. It returns the fingerprint of the newly created key.
func (*Client) GenerateSubkeys ¶
func (c *Client) GenerateSubkeys(ctx context.Context, opts SubkeyOpts) error
GenerateSubkeys creates Sign, Encrypt, and Auth subkeys under the master key.
func (*Client) HasPassphrase ¶ added in v0.3.0
HasPassphrase reports whether a passphrase is configured for this client.
func (*Client) ListSecretKeys ¶
ListSecretKeys returns all secret keys and subkeys in the keyring.
func (*Client) ListUIDs ¶ added in v0.3.0
ListUIDs returns all user IDs on the master key identified by masterFP, in the order gpg reports them. Revoked UIDs are included.
Uses --list-sigs (not --list-keys) so that revoked UIDs still have an associated creation date: gpg's colon output strips field 5 from a revoked uid record, but the original self-signature line that follows it still carries the date the UID was added. The companion rev: line (if present) carries the revocation date.
func (*Client) LoadConfig ¶
LoadConfig reads the GPG config from GNUPGHOME/gpgsmith.yaml.
func (*Client) LoadInventory ¶
LoadInventory reads the YubiKey inventory from GNUPGHOME/gpgsmith-inventory.yaml.
func (*Client) LoadServerRegistry ¶ added in v0.1.0
func (c *Client) LoadServerRegistry() (*ServerRegistry, error)
LoadServerRegistry reads the server registry from GNUPGHOME/gpgsmith-servers.yaml. If the file does not exist, it migrates from publish_targets in the config or initializes with defaults.
func (*Client) LookupGitHub ¶
func (c *Client) LookupGitHub(ctx context.Context, masterFP string) KeyserverLookupResult
LookupGitHub checks if the GPG key is registered on GitHub via `gh gpg-key list`.
func (*Client) LookupKeyservers ¶
func (c *Client) LookupKeyservers(ctx context.Context, masterFP string, servers []string) []KeyserverLookupResult
LookupKeyservers queries multiple keyservers to check if a key is published. Each keyserver query has a 15-second timeout to avoid hanging on unresponsive servers.
func (*Client) MoveToCard ¶
MoveToCard transfers subkeys to the connected smart card using a single --edit-key session. keyIDs specifies which subkeys to move (by long key ID). The correct gpg subkey index and card slot are determined automatically from the keyring. All subkeys are moved in one gpg process so the master key passphrase is requested only once.
func (*Client) Publish ¶
func (c *Client) Publish(ctx context.Context, masterFP string, targets []PublishTarget) []PublishResult
Publish sends the public key to all configured publish targets. It continues on failure, collecting results for each target.
func (*Client) RevokeUID ¶ added in v0.3.0
RevokeUID revokes a user ID on the master key. The uid argument must match the existing UID exactly (use ListUIDs to look it up).
func (*Client) SaveConfig ¶
SaveConfig writes the GPG config to GNUPGHOME/gpgsmith.yaml.
func (*Client) SaveInventory ¶
SaveInventory writes the YubiKey inventory to GNUPGHOME/gpgsmith-inventory.yaml.
func (*Client) SaveServerRegistry ¶ added in v0.1.0
func (c *Client) SaveServerRegistry(reg *ServerRegistry) error
SaveServerRegistry writes the server registry to GNUPGHOME/gpgsmith-servers.yaml.
func (*Client) SetPrimaryUID ¶ added in v0.3.0
SetPrimaryUID promotes a user ID to primary on the master key. The uid argument must match the existing UID exactly.
type Config ¶
type Config struct {
MasterFP string `yaml:"master_fp"`
SubkeyAlgo string `yaml:"subkey_algo"`
SubkeyExpiry string `yaml:"subkey_expiry"`
PublishTargets []PublishTarget `yaml:"publish_targets,omitempty"`
}
Config holds GPG-specific configuration stored inside GNUPGHOME/gpgsmith.yaml.
type Inventory ¶
type Inventory struct {
YubiKeys []YubiKeyEntry `yaml:"yubikeys"`
}
Inventory holds all known YubiKeys.
func (*Inventory) FindByLabel ¶
func (inv *Inventory) FindByLabel(labelOrSerial string) *YubiKeyEntry
FindByLabel returns the YubiKey entry matching the given label or serial.
type KeyserverLookupResult ¶
KeyserverLookupResult holds the result of looking up a key on a keyserver.
type MasterKeyOpts ¶ added in v0.2.0
type MasterKeyOpts struct {
NameReal string // e.g. "Oleg Tsarev"
NameEmail string // e.g. "oleg@example.com"
Algo string // e.g. "rsa4096", "ed25519" (default: "rsa4096")
Expiry string // e.g. "0" (no expiry), "2y" (default: "0")
}
MasterKeyOpts configures master key generation.
type Options ¶
type Options struct {
Binary string // gpg binary path (default: "gpg")
HomeDir string // GNUPGHOME directory
Logger *slog.Logger
Passphrase string // optional master-key passphrase, used with --pinentry-mode loopback
}
Options configures a new Client.
type PublishResult ¶
type PublishResult struct {
Target PublishTarget
Err error
}
PublishResult holds the outcome of publishing to a single target.
type PublishTarget ¶
type PublishTarget struct {
Type string `yaml:"type"` // "keyserver" or "github"
URL string `yaml:"url,omitempty"`
}
PublishTarget describes where to publish public keys.
func ToPublishTargets ¶ added in v0.1.0
func ToPublishTargets(entries []ServerEntry) []PublishTarget
ToPublishTargets converts server entries to PublishTarget slice for use with Publish().
type ServerEntry ¶ added in v0.1.0
type ServerEntry struct {
Alias string `yaml:"alias"`
Type string `yaml:"type"` // "keyserver" or "github"
URL string `yaml:"url,omitempty"`
Enabled bool `yaml:"enabled"`
}
ServerEntry represents a publish target (keyserver or GitHub) in the registry.
func DefaultServers ¶ added in v0.1.0
func DefaultServers() []ServerEntry
DefaultServers returns the built-in server list.
type ServerRegistry ¶ added in v0.1.0
type ServerRegistry struct {
Servers []ServerEntry `yaml:"servers"`
}
ServerRegistry holds all known publish targets.
func (*ServerRegistry) AllServerURLs ¶ added in v0.1.0
func (reg *ServerRegistry) AllServerURLs() []string
AllServerURLs returns all unique keyserver URLs from the registry.
func (*ServerRegistry) EnabledServers ¶ added in v0.1.0
func (reg *ServerRegistry) EnabledServers() []ServerEntry
EnabledServers returns all servers with Enabled == true.
func (*ServerRegistry) FindByAlias ¶ added in v0.1.0
func (reg *ServerRegistry) FindByAlias(alias string) *ServerEntry
FindByAlias returns a pointer to the server entry with the given alias, or nil.
type SubKey ¶
type SubKey struct {
KeyID string
Fingerprint string
Algorithm string
Usage string // S, E, A, C (may be combined like "SC")
Created time.Time
Expires time.Time
CardSerial string
Validity string // validity field from colons output: "r" = revoked, "e" = expired, etc.
}
SubKey represents a GPG key or subkey parsed from --with-colons output.
type SubKeyRef ¶
type SubKeyRef struct {
KeyID string `yaml:"keyid"`
Usage string `yaml:"usage"` // "sign", "encrypt", "auth"
Created time.Time `yaml:"created"`
Expires time.Time `yaml:"expires,omitempty"`
}
SubKeyRef is a reference to a subkey stored on a YubiKey.
type SubkeyOpts ¶
type SubkeyOpts struct {
MasterFP string // master key fingerprint
Algo string // e.g. "rsa4096", "ed25519"
Expiry string // e.g. "2y", "1y"
}
SubkeyOpts configures subkey generation.
type UID ¶ added in v0.3.0
type UID struct {
Index int // 1-based index in the order returned by gpg
Validity string // validity field: "u" = ultimate, "r" = revoked, "e" = expired
Created time.Time
Revoked time.Time // zero unless the UID has been revoked
Hash string // 40-char hex hash of the UID (gpg internal identifier)
UID string // "Name (comment) <email>"
}
UID represents a user ID attached to a master key.
type YkmanDeviceInfo ¶
type YkmanDeviceInfo struct {
DeviceType string // e.g. "YubiKey 5 NFC"
Serial string
FirmwareVersion string
FormFactor string
}
YkmanDeviceInfo holds info from `ykman info`.
type YubiKeyEntry ¶
type YubiKeyEntry struct {
Serial string `yaml:"serial"`
Label string `yaml:"label"`
Model string `yaml:"model"`
Description string `yaml:"description,omitempty"`
Provisioning string `yaml:"provisioning"` // "same-keys" or "unique-keys"
Subkeys []SubKeyRef `yaml:"subkeys,omitempty"`
ProvisionedAt time.Time `yaml:"provisioned_at"`
Status string `yaml:"status"` // "active" or "revoked"
}
YubiKeyEntry represents a provisioned YubiKey in the inventory.