crypto

package
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Aug 12, 2026 License: AGPL-3.0 Imports: 25 Imported by: 0

Documentation

Overview

Package crypto provides cryptographic primitives for authserver.

Index

Constants

View Source
const (
	// PKCEMinVerifierLength is the minimum code_verifier length per RFC 7636 §4.1.
	PKCEMinVerifierLength = 43
	// PKCEMaxVerifierLength is the maximum code_verifier length per RFC 7636 §4.1.
	PKCEMaxVerifierLength = 128
)
View Source
const DefaultBcryptCost = 12

DefaultBcryptCost is the bcrypt cost factor for hashing client secrets.

Variables

View Source
var ErrClientSecretMismatch = errors.New("client secret mismatch")

ErrClientSecretMismatch is returned when a client secret does not match its stored HMAC hash.

Functions

func AssertionAlgorithms

func AssertionAlgorithms() []jose.SignatureAlgorithm

AssertionAlgorithms returns the list of algorithms accepted for ID-JAG assertions.

func BuildJWKS

func BuildJWKS(keys ...*KeyPair) jose.JSONWebKeySet

BuildJWKS constructs a jose.JSONWebKeySet from one or more key pairs.

func CompareBcrypt

func CompareBcrypt(hash, plaintext string) error

CompareBcrypt compares a bcrypt hash with a plaintext string. Returns nil on match, error otherwise.

func CompareClientSecret

func CompareClientSecret(hash, plaintext string) error

CompareClientSecret verifies a client secret against its stored hash, auto-detecting the scheme (HMAC-SHA256 vs legacy bcrypt). Returns nil on a match. The comparison is constant-time.

func CompareHash

func CompareHash(hash, plain string) bool

CompareHash performs a constant-time comparison of a hex-encoded SHA-256 hash against the hash of plain. Returns true if they match.

func ComputeATH

func ComputeATH(accessToken string) string

ComputeATH computes the access token hash for DPoP ath claim. Returns base64url(SHA-256(access_token)).

func ComputeJKT

func ComputeJKT(jwk jose.JSONWebKey) (string, error)

ComputeJKT computes the JWK Thumbprint per RFC 7638 using SHA-256. Returns the base64url-encoded (no padding) SHA-256 hash of the JWK's canonical form (sorted, minimal members as per the key type).

func ComputeS256Challenge

func ComputeS256Challenge(verifier string) string

ComputeS256Challenge computes the S256 code_challenge for the given verifier. challenge = BASE64URL(SHA256(verifier)) per RFC 7636 §4.2.

func CreateDPoPProof

func CreateDPoPProof(signer jose.Signer, jti, htm, htu string, iat time.Time, nonce, ath string) (string, error)

CreateDPoPProof creates a DPoP proof JWT. Used in tests and as a helper.

func GenerateAuthCode

func GenerateAuthCode() string

GenerateAuthCode returns a random authorization code (43 chars, 32 bytes entropy).

func GenerateClientID

func GenerateClientID() string

GenerateClientID returns a random client identifier (22 chars, 16 bytes entropy).

func GenerateClientSecret

func GenerateClientSecret() string

GenerateClientSecret returns a random client secret (43 chars, 32 bytes entropy).

func GenerateNonce

func GenerateNonce() string

GenerateNonce creates a cryptographically random nonce for DPoP. Returns a 32-byte base64url-encoded string (43 chars).

func GenerateRandomString

func GenerateRandomString(n int) string

GenerateRandomString returns a URL-safe base64-encoded random string of n random bytes (the encoded string will be longer than n).

func GenerateVerifier

func GenerateVerifier() string

GenerateVerifier returns a cryptographically random PKCE code_verifier (43 chars from 32 bytes of entropy, URL-safe base64).

func HashBcrypt

func HashBcrypt(plaintext string) (string, error)

HashBcrypt returns the bcrypt hash of the given plaintext.

func HashClientSecret

func HashClientSecret(plaintext string) (string, error)

HashClientSecret hashes a client secret for storage. With a pepper configured it uses HMAC-SHA256 (fast); otherwise it falls back to bcrypt.

func HashSHA256

func HashSHA256(s string) string

HashSHA256 returns the hex-encoded SHA-256 hash of s. Used for hashing auth codes and refresh tokens before storage.

func IsDPoPBound

func IsDPoPBound(claims *AccessTokenClaims) bool

IsDPoPBound checks if an access token has a cnf.jkt claim indicating DPoP binding. This is used to determine if a resource request requires a DPoP proof.

func NewDPoPSigner

func NewDPoPSigner(privateKey interface{}, alg jose.SignatureAlgorithm) (jose.Signer, error)

NewDPoPSigner creates a jose.Signer for DPoP proofs with the correct headers. Sets typ: dpop+jwt and embeds the public key in the jwk header.

func SetClientSecretPepper

func SetClientSecretPepper(pepper string)

SetClientSecretPepper configures the HMAC key used to hash and verify client secrets. With a non-empty pepper, HashClientSecret produces HMAC-SHA256 hashes; with an empty pepper it falls back to bcrypt. Existing hashes of either scheme continue to verify regardless. Call once at startup, before serving requests.

func SignAccessToken

func SignAccessToken(kp *KeyPair, claims AccessTokenClaims) (string, error)

SignAccessToken signs an RFC 9068 JWT access token with typ: at+jwt. Returns an error if required claims are missing.

For concrete key types (*ecdsa.PrivateKey, *rsa.PrivateKey) the key is passed directly to go-jose. For opaque crypto.Signer implementations (e.g. Vault Transit, KMS) the key is wrapped as a jose.OpaqueSigner so go-jose delegates signing without needing access to raw key material.

func ValidateAccessTokenClaims

func ValidateAccessTokenClaims(c AccessTokenClaims) error

ValidateAccessTokenClaims checks that required JWT claims are non-empty before signing.

func ValidateChallengeMethod

func ValidateChallengeMethod(method string) error

ValidateChallengeMethod rejects anything other than S256. plain is never accepted per security invariant.

func ValidateIDJAG

func ValidateIDJAG(raw string, trustedKeys *jose.JSONWebKeySet, expectedAudience string, maxAge time.Duration) (*token.IdentityAssertion, error)

ValidateIDJAG parses and validates an ID-JAG (Identity Assertion Authorization Grant) JWT per RFC 7523 and the MCP Enterprise-Managed Authorization extension.

Validation steps:

  1. Parse as signed JWT — reject alg:none and HS* algorithms.
  2. Verify typ header == "oauth-id-jag+jwt".
  3. Verify signature against provided JWKS.
  4. Validate exp (not expired, 30s clock skew).
  5. Validate iat (not in future, not too old per maxAge).
  6. Validate aud matches expectedAudience.
  7. Validate iss, sub, client_id, jti are all non-empty.

func VerifyS256

func VerifyS256(verifier, challenge string) error

VerifyS256 verifies a PKCE code_verifier against a stored code_challenge. Returns nil on success.

Types

type AccessTokenClaims

type AccessTokenClaims struct {
	Issuer     string                 `json:"iss"`
	Subject    string                 `json:"sub"`
	Audience   []string               `json:"aud"`
	ClientID   string                 `json:"client_id"`
	Scope      string                 `json:"scope,omitempty"`
	JTI        string                 `json:"jti"`
	IssuedAt   int64                  `json:"iat"`
	Expiry     int64                  `json:"exp"`
	NotBefore  int64                  `json:"nbf"`
	Cnf        map[string]interface{} `json:"cnf,omitempty"`         // DPoP confirmation claim (RFC 9449 §6): {"jkt": "<thumbprint>"}
	Act        map[string]interface{} `json:"act,omitempty"`         // RFC 8693 §4.1: delegation chain {"sub": "...", "act": {...}}
	MayAct     map[string]interface{} `json:"may_act,omitempty"`     // RFC 8693 §5: authorized actors {"sub": "..."}
	AgentID    string                 `json:"agent_id,omitempty"`    // Authplane extension: client_id of the acting agent
	AgentChain []string               `json:"agent_chain,omitempty"` // Authplane extension: ordered delegation chain [root, ..., acting_agent]
}

AccessTokenClaims are the claims in an RFC 9068 JWT access token. Audience is []string for JSON marshal flexibility. Per RFC 8707 we bind each token to a single resource, so Audience will have exactly one element. JSON serializes as ["https://..."] (array), which is valid per RFC 7519 §4.1.3.

func VerifyAccessToken

func VerifyAccessToken(token string, jwks *jose.JSONWebKeySet) (*AccessTokenClaims, error)

VerifyAccessToken parses and verifies a JWT access token against the given JWKS. It checks the signature, typ header, and expiry.

func VerifyAccessTokenWithIssuer

func VerifyAccessTokenWithIssuer(token string, jwks *jose.JSONWebKeySet, expectedIssuer string) (*AccessTokenClaims, error)

VerifyAccessTokenWithIssuer is like VerifyAccessToken but also validates the issuer claim. CODE FIX: Matrix 1.5.16 — issuer MUST be verified to prevent cross-issuer token injection.

func (*AccessTokenClaims) HasAudience

func (c *AccessTokenClaims) HasAudience(aud string) bool

HasAudience returns true if the given value is present in the Audience slice.

type DPoPResult

type DPoPResult struct {
	JKT   string // JWK thumbprint (base64url-encoded SHA-256)
	JTI   string // unique identifier from the proof, for replay detection
	Nonce string // nonce from the proof, if present
}

DPoPResult holds the validated output from a DPoP proof.

func ValidateProof

func ValidateProof(proof, method, reqURL, serverNonce, accessTokenHash string, proofLifetime time.Duration) (*DPoPResult, error)

ValidateProof validates a DPoP proof JWT per RFC 9449 §4.3.

Parameters:

  • proof: the raw DPoP proof JWT string from the DPoP header
  • method: the HTTP method of the request (e.g. "POST")
  • reqURL: the HTTP URL of the request (scheme + host + path; query is stripped)
  • serverNonce: the expected server nonce (empty string if nonce is not required)
  • accessTokenHash: base64url(SHA-256(access_token)) for ath validation (empty if not applicable)
  • proofLifetime: maximum age of the proof (|now - iat| must be within this)

Returns:

  • DPoPResult with JKT, JTI, and Nonce on success
  • domain.ErrDPoPInvalidProof on structural/cryptographic errors
  • domain.ErrDPoPNonceRequired if serverNonce is non-empty but proof has no nonce
  • domain.ErrDPoPNonceMismatch if proof nonce doesn't match serverNonce

type KeyPair

type KeyPair struct {
	PrivateKey crypto.Signer
	PublicKey  crypto.PublicKey
	Algorithm  jose.SignatureAlgorithm
	KeyID      string
}

KeyPair holds a signing key and its metadata.

func GenerateKeyPair

func GenerateKeyPair(alg, kid string) (*KeyPair, error)

GenerateKeyPair generates an ECDSA or RSA key pair for the given algorithm. Supported: ES256 (P-256), RS256 (RSA 2048).

Jump to

Keyboard shortcuts

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