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
- Variables
- func DecodeJWKPublicKey(jwk *JWK) (ed25519.PublicKey, error)
- func DecodeMultibaseKey(multibase string) (ed25519.PublicKey, error)
- func GenerateNonce(size int) (string, error)
- func SignNonce(nonce string, privateKey ed25519.PrivateKey, keyID string) (string, error)
- func VerifyMCPPoPResponse(request *MCPPoPRequest, response *MCPPoPResponse, publicKey ed25519.PublicKey, ...) error
- func VerifyResponse(challenge *Challenge, response *Response, publicKey ed25519.PublicKey) error
- func VerifySignature(signatureJWS string, expectedNonce string, publicKey ed25519.PublicKey) error
- type CacheConfig
- type CacheEntry
- type Challenge
- type JWK
- type MCPPoPRequest
- type MCPPoPResponse
- type Response
- type SessionCache
- func (c *SessionCache) Clear()
- func (c *SessionCache) Delete(key string)
- func (c *SessionCache) Get(key string) *CacheEntry
- func (c *SessionCache) InvalidateBySession(sessionID string)
- func (c *SessionCache) InvalidateByTrustLevel(minLevelStr string)
- func (c *SessionCache) Size() int
- func (c *SessionCache) Store(key string, entry *CacheEntry)
Constants ¶
const DefaultNonceSize = 32
DefaultNonceSize is 32 bytes (256 bits of entropy)
Variables ¶
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 ¶
DecodeJWKPublicKey decodes an Ed25519 public key from JWK format
func DecodeMultibaseKey ¶
DecodeMultibaseKey decodes a multibase-encoded public key Supports 'z' (base58btc) prefix for Ed25519VerificationKey2020
func GenerateNonce ¶
GenerateNonce creates a cryptographically secure random nonce Returns base64url-encoded string (no padding per RFC-003 §6.2)
func SignNonce ¶
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 ¶
VerifyResponse verifies a PoP response against a challenge
func VerifySignature ¶
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 ¶
NewChallenge creates a PoP challenge with the given TTL
func (*Challenge) MarshalJSON ¶
MarshalJSON implements json.Marshaler
func (*Challenge) UnmarshalJSON ¶
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)
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) 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