pop

package
v2.4.0 Latest Latest
Warning

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

Go to latest
Published: Jan 19, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package pop provides shared Proof of Possession cryptographic primitives.

These primitives are used by: - RFC-003: Badge issuance PoP (agent proves key to CA) - RFC-007: MCP server identity PoP (server proves key to client)

The package extracts common operations to avoid duplication: - Nonce generation - JWS proof signing - Proof verification - DID document key extraction

Package pop provides shared Proof of Possession cryptographic primitives. This file implements session caching for verified PoP results.

Session caching avoids re-verifying on every request within a session. Per team guidance, session definitions: - HTTP: per connection or per TTL window (configurable) - MCP stdio: per process lifetime or per initialize session

Cache invalidation occurs on: - Badge expiry - TTL expiry (configurable, default: sync with badge TTL) - Explicit invalidation (key rotation, trust level change)

Index

Constants

View Source
const DefaultNonceSize = 32

DefaultNonceSize is 32 bytes (256 bits of entropy)

Variables

View Source
var (
	ErrNonceGeneration    = errors.New("failed to generate nonce")
	ErrNonceMismatch      = errors.New("nonce does not match")
	ErrSignatureInvalid   = errors.New("signature verification failed")
	ErrChallengeExpired   = errors.New("challenge has expired")
	ErrInvalidPrivateKey  = errors.New("invalid private key")
	ErrUnsupportedKeyType = errors.New("unsupported key type")
)

Functions

func DecodeJWKPublicKey

func DecodeJWKPublicKey(jwk *JWK) (ed25519.PublicKey, error)

DecodeJWKPublicKey decodes an Ed25519 public key from JWK format

func DecodeMultibaseKey

func DecodeMultibaseKey(multibase string) (ed25519.PublicKey, error)

DecodeMultibaseKey decodes a multibase-encoded public key Supports 'z' (base58btc) prefix for Ed25519VerificationKey2020

func GenerateNonce

func GenerateNonce(size int) (string, error)

GenerateNonce creates a cryptographically secure random nonce Returns base64url-encoded string (no padding per RFC-003 §6.2)

func SignNonce

func SignNonce(nonce string, privateKey ed25519.PrivateKey, keyID string) (string, error)

SignNonce signs a nonce with an Ed25519 private key Returns JWS compact serialization

This is used by: - RFC-003: Agent signing PoP proof for CA - RFC-007: MCP server signing nonce for client verification

func VerifyMCPPoPResponse

func VerifyMCPPoPResponse(request *MCPPoPRequest, response *MCPPoPResponse, publicKey ed25519.PublicKey, maxAge time.Duration) error

VerifyMCPPoPResponse verifies MCP server's PoP response Used by clients to verify server identity within handshake

func VerifyResponse

func VerifyResponse(challenge *Challenge, response *Response, publicKey ed25519.PublicKey) error

VerifyResponse verifies a PoP response against a challenge

func VerifySignature

func VerifySignature(signatureJWS string, expectedNonce string, publicKey ed25519.PublicKey) error

VerifySignature verifies a JWS signature over a nonce using an Ed25519 public key

This is used by: - RFC-003: CA verifying agent PoP proof - RFC-007: Client verifying MCP server PoP response

Types

type CacheConfig

type CacheConfig struct {
	// DefaultTTL is the default cache entry lifetime
	// Should generally match badge TTL (default: 5 minutes)
	DefaultTTL time.Duration

	// MaxEntries limits cache size (0 = unlimited)
	MaxEntries int

	// CleanupInterval is how often to purge expired entries (0 = no background cleanup)
	CleanupInterval time.Duration
}

CacheConfig configures session cache behavior

func DefaultCacheConfig

func DefaultCacheConfig() *CacheConfig

DefaultCacheConfig returns sensible defaults

type CacheEntry

type CacheEntry struct {
	// SubjectDID is the verified DID
	SubjectDID string

	// TrustLevelStr from verified badge (string per RFC-002 §5)
	TrustLevelStr string

	// BadgeJTI for correlation
	BadgeJTI string

	// BadgeExpiresAt is when the badge expires
	BadgeExpiresAt time.Time

	// VerifiedAt is when PoP was verified
	VerifiedAt time.Time

	// ExpiresAt is when this cache entry expires
	ExpiresAt time.Time

	// SessionID for MCP session correlation (optional)
	SessionID string
}

CacheEntry represents a cached verification result

type Challenge

type Challenge struct {
	// Nonce is the random challenge value (base64url encoded, no padding)
	Nonce string `json:"nonce"`

	// CreatedAt is when the challenge was created
	CreatedAt time.Time `json:"created_at"`

	// ExpiresAt is when the challenge expires
	ExpiresAt time.Time `json:"expires_at"`

	// SubjectDID is the DID being challenged to prove key ownership
	SubjectDID string `json:"subject_did"`
}

Challenge represents a PoP challenge (nonce + metadata) Used by both RFC-003 and RFC-007

func NewChallenge

func NewChallenge(subjectDID string, ttl time.Duration) (*Challenge, error)

NewChallenge creates a PoP challenge with the given TTL

func (*Challenge) IsExpired

func (c *Challenge) IsExpired() bool

IsExpired checks if the challenge has expired

func (*Challenge) MarshalJSON

func (c *Challenge) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler

func (*Challenge) UnmarshalJSON

func (c *Challenge) UnmarshalJSON(data []byte) error

UnmarshalJSON implements json.Unmarshaler

type JWK

type JWK struct {
	Kty string `json:"kty"`
	Crv string `json:"crv"`
	X   string `json:"x"`
	Kid string `json:"kid,omitempty"`
}

JWK represents a JSON Web Key (minimal for Ed25519)

func EncodeJWKPublicKey

func EncodeJWKPublicKey(publicKey ed25519.PublicKey, keyID string) *JWK

EncodeJWKPublicKey encodes an Ed25519 public key to JWK format

type MCPPoPRequest

type MCPPoPRequest struct {
	// ClientNonce is the challenge nonce for server to sign
	ClientNonce string `json:"client_nonce"`

	// CreatedAt is when the nonce was generated
	CreatedAt time.Time `json:"created_at"`
}

MCPPoPRequest represents PoP data sent by client in initialize request _meta RFC-007: Embedded in MCP handshake, not separate endpoint

func NewMCPPoPRequest

func NewMCPPoPRequest() (*MCPPoPRequest, error)

NewMCPPoPRequest creates a PoP request for MCP initialize

func ParseMCPPoPRequestFromMeta

func ParseMCPPoPRequestFromMeta(meta map[string]interface{}) *MCPPoPRequest

ParseMCPPoPRequestFromMeta extracts PoP request from MCP _meta

func (*MCPPoPRequest) ToMeta

func (r *MCPPoPRequest) ToMeta() map[string]interface{}

ToMeta serializes PoP request for MCP _meta

type MCPPoPResponse

type MCPPoPResponse struct {
	// NonceSignature is JWS over client_nonce, signed with server's DID key
	NonceSignature string `json:"nonce_signature"`

	// SignedAt is when the signature was created
	SignedAt time.Time `json:"signed_at"`
}

MCPPoPResponse represents PoP data returned by server in initialize response _meta RFC-007: Server proves key ownership within handshake

func CreateMCPPoPResponse

func CreateMCPPoPResponse(clientNonce string, privateKey ed25519.PrivateKey, keyID string) (*MCPPoPResponse, error)

CreateMCPPoPResponse creates a PoP response for MCP initialize Used by MCP servers to prove key ownership

func ParseMCPPoPResponseFromMeta

func ParseMCPPoPResponseFromMeta(meta map[string]interface{}) *MCPPoPResponse

ParseMCPPoPResponseFromMeta extracts PoP response from MCP _meta

func (*MCPPoPResponse) ToMeta

func (r *MCPPoPResponse) ToMeta() map[string]interface{}

ToMeta serializes PoP response for MCP _meta

type Response

type Response struct {
	// Nonce echoed from challenge
	Nonce string `json:"nonce"`

	// Signature is JWS compact serialization over nonce
	Signature string `json:"signature"`

	// SubjectDID is the responder's DID
	SubjectDID string `json:"subject_did"`
}

Response represents a PoP response (signature over nonce)

func CreateResponse

func CreateResponse(challenge *Challenge, privateKey ed25519.PrivateKey, keyID string) (*Response, error)

CreateResponse creates a complete PoP response by signing the challenge nonce

type SessionCache

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

SessionCache provides thread-safe caching of PoP verification results

func NewSessionCache

func NewSessionCache(config *CacheConfig) *SessionCache

NewSessionCache creates a new session cache

func (*SessionCache) Clear

func (c *SessionCache) Clear()

Clear removes all entries

func (*SessionCache) Delete

func (c *SessionCache) Delete(key string)

Delete removes a cached entry

func (*SessionCache) Get

func (c *SessionCache) Get(key string) *CacheEntry

Get retrieves a cached entry if valid Returns nil if not found or expired

func (*SessionCache) InvalidateBySession

func (c *SessionCache) InvalidateBySession(sessionID string)

InvalidateBySession removes all entries for a session

func (*SessionCache) InvalidateByTrustLevel

func (c *SessionCache) InvalidateByTrustLevel(minLevelStr string)

InvalidateByTrustLevel removes entries below a trust level Use when trust requirements increase mid-session minLevelStr should be "0", "1", "2", "3", or "4"

func (*SessionCache) Size

func (c *SessionCache) Size() int

Size returns the number of cached entries

func (*SessionCache) Store

func (c *SessionCache) Store(key string, entry *CacheEntry)

Store caches a verification result Key is typically the server DID

Jump to

Keyboard shortcuts

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