ssh

package
v2.303.7 Latest Latest
Warning

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

Go to latest
Published: Mar 16, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package ssh provides an SSH-style token format for go-service.

This package implements a simple signed token scheme using SSH public key cryptography. It is intentionally different from claim-based tokens (JWT/PASETO): it does not encode audiences, issuers, expiration, or other claims. Instead, it provides a compact token that binds a key name to a signature.

Token format

Tokens are ASCII strings of the form:

<name>-<base64(signature)>

Where:

  • <name> is the logical name of the signing key (for example "primary").
  • signature is produced by signing the bytes of <name> with the configured SSH private key.
  • base64(signature) is the standard base64 encoding of the raw signature bytes.

The separator is the first "-" in the token string. Anything after the first "-" is treated as the base64-encoded signature.

Signing keys and verification keys

Configuration is provided via Config:

  • Config.Key is the single signing key used for Generate.
  • Config.Keys is a set of named public keys used for Verify.

Verification is “name-based”: Verify extracts <name> from the token and then looks up a matching public key configuration in Config.Keys (via Keys.Get(name)). If no key with that name exists, verification fails.

This design supports key rotation and multi-key verification: you can mint tokens with the active signing key name while allowing verification against multiple historical/active public keys by including them in Config.Keys.

Key material loading and “source strings”

The Token constructor accepts an *os.FS and uses go-service crypto/ssh helpers to load key material based on the embedded crypto/ssh.Config in Key.

Those configs commonly support go-service “source strings” for key sources (for example env:/file:/literal). Resolution and filesystem behavior depend on the go-service os.FS and crypto/ssh packages used by your wiring.

Error handling expectations

Verify returns the key name on success (the <name> prefix from the token). On failure, it returns an error. Common failure modes include:

  • token does not contain the "-" separator,
  • no verification key exists for the extracted name,
  • base64 decoding fails,
  • signature verification fails,
  • key material cannot be loaded.

Some invalid-token cases are intentionally collapsed into a generic “invalid match” class so callers do not learn whether a name exists or which specific check failed. Callers that need fine-grained diagnostics should add logging/metrics at the call site rather than relying on error text.

Security notes

This scheme authenticates possession of a key (via signature verification) and binds that to a logical name. It does not provide expiration or replay protection by itself. If your use case requires time-bounded validity, nonce/jti semantics, or audience restrictions, prefer JWT or PASETO token kinds or layer additional checks at a higher level.

Relationship to the top-level token facade

Services often use the top-level token.Token facade (package token), which delegates to this implementation when Config.Kind == "ssh".

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	// Key is the signing key configuration used to mint SSH-style tokens.
	//
	// This should include the private key material (via the embedded crypto/ssh.Config
	// fields) and a logical Name that will be embedded in minted tokens.
	//
	// If Key is nil, Token.Generate will not be usable.
	Key *Key `yaml:"key,omitempty" json:"key,omitempty" toml:"key,omitempty"`

	// Keys is the set of verification keys that may be used to validate SSH-style tokens.
	//
	// Verification uses the token's embedded name to select a key from this set. If Keys
	// is empty or does not contain the token's name, verification fails.
	//
	// If Keys is nil/empty, Token.Verify will not be usable.
	Keys Keys `yaml:"keys,omitempty" json:"keys,omitempty" toml:"keys,omitempty"`
}

Config configures the SSH-style token implementation.

This token kind uses a simple signed token format (see package ssh docs) and requires SSH key material for:

  • signing (minting tokens), and
  • verification (validating tokens).

Config separates those concerns:

  • Key is the single signing key used by Token.Generate.
  • Keys is the set of verification keys that Token.Verify may use.

Key rotation and multi-key verification

Verification is name-based: the token embeds a key name prefix, and verification selects a matching public key config from Keys (via Keys.Get(name)). This design supports key rotation by allowing you to:

  • mint new tokens with the active signing key name, and
  • continue verifying older tokens by keeping historical public keys in Keys.

Note: This package does not enforce that Key.Name exists in Keys. If you want tokens minted by Key to be verifiable by this same Config, include the corresponding public key entry in Keys under the same name.

Enablement

Enablement is modeled by presence and content: a nil *Config is disabled, and a config with neither Key nor Keys is disabled (see IsEnabled).

func (*Config) IsEnabled added in v2.115.0

func (c *Config) IsEnabled() bool

IsEnabled reports whether SSH token configuration is enabled.

It returns true when the receiver is non-nil and at least one of Key or Keys is present.

type Key

type Key struct {
	// Config contains the SSH key material configuration (public/private key sources).
	*ssh.Config `yaml:",inline" json:",inline" toml:",inline"`

	// Name is the logical key name used to select a key (for example via Keys.Get).
	//
	// For signing, this name is embedded into minted tokens as the "<name>-" prefix.
	// For verification, this name is used as the lookup key into Keys.
	Name string `yaml:"name,omitempty" json:"name,omitempty" toml:"name,omitempty"`
}

Key describes SSH key material configuration along with its logical name.

The embedded crypto/ssh.Config provides the public/private key source configuration used by go-service crypto/ssh helpers (typically via an os.FS).

The Name identifies the key logically and is used to select keys during verification.

type Keys

type Keys []*Key

Keys is a list of named SSH keys.

This is used for verification key selection. Names are expected (but not required) to be unique; Get returns the first match.

func (Keys) Get

func (c Keys) Get(name string) *Key

Get returns the key with the given name, or nil if no matching key exists.

If multiple keys share the same Name, Get returns the first match.

type Signer added in v2.9.0

type Signer = ssh.Signer

Signer is an alias for crypto/ssh.Signer.

It represents an object capable of producing signatures using SSH key material.

type Token

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

Token generates and verifies SSH-style tokens.

This token kind is intentionally simple and does not carry claims (audience, issuer, expiration, etc.). Instead, it binds a logical key name to a signature.

Note: Token assumes cfg and fs are non-nil and that cfg contains the appropriate key material for the operation (signing key for Generate, verification keys for Verify). If those dependencies are missing, methods may panic.

func NewToken

func NewToken(cfg *Config, fs *os.FS) *Token

NewToken constructs a Token using cfg and fs.

The returned Token loads key material using fs when generating and verifying tokens.

Enablement is modeled by configuration: if cfg is disabled (see Config.IsEnabled), NewToken returns nil.

func (*Token) Generate

func (t *Token) Generate() (string, error)

Generate creates an SSH-style token.

Token format:

<name>-<base64(signature)>

Where <name> is t.cfg.Key.Name and signature is produced by signing the bytes of <name> using the configured signing key material.

High-level algorithm:

  1. Load an SSH signer from the configured signing key (t.cfg.Key) using fs.
  2. Compute signature = Sign(<name>).
  3. Return "<name>-<base64(signature)>".

Errors are returned when key material cannot be loaded or signature generation fails.

func (*Token) Verify

func (t *Token) Verify(token string) (string, error)

Verify validates token and returns the embedded key name if it is valid.

Token format:

<name>-<base64(signature)>

Verification is name-based: Verify extracts <name> and then selects the matching verification key configuration from t.cfg.Keys using Keys.Get(name). It verifies the signature over the bytes of <name> with that key.

High-level algorithm:

  1. Split token into (name, encodedSignature) on the first "-".
  2. Look up a verification key config for name in t.cfg.Keys.
  3. Load an SSH verifier from the selected key material using fs.
  4. Decode the signature from base64.
  5. Verify(signature, <name>).

Security-oriented error behavior:

  • If the token cannot be split or no key exists for the name, Verify returns errors.ErrInvalidMatch. This intentionally collapses multiple invalid-token cases into a single class to avoid leaking whether a given key name exists.
  • Base64 decode errors and verifier loading errors are returned as-is.

On success, Verify returns the extracted name.

type Verifier added in v2.9.0

type Verifier = ssh.Verifier

Verifier is an alias for crypto/ssh.Verifier.

It represents an object capable of verifying signatures produced by an SSH signer.

Jump to

Keyboard shortcuts

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