pvx

package module
v0.0.0-...-ac00bc3 Latest Latest
Warning

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

Go to latest
Published: Sep 12, 2021 License: MIT Imports: 19 Imported by: 11

README

PVX

PVX is a (work in progress) PASETO implementation for Go programming language. Currently, library supports version 2 and version 4, and partially version 3 local purpose (if you need NIST-approved algorithms), but it is under active development, does not have unnecessary dependencies and has greater than 86% of test coverage.

You can use https://github.com/o1egl/paseto if you are looking for version 1.

Why this library exists:

  1. https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-bad-standard-that-everyone-should-avoid
  2. https://www.howmanydayssinceajwtalgnonevuln.com

Check "Intended Use-Cases for PASETO" before using this library. https://paseto.io/rfc/draft-00

Go Reference

Go version

A minimal version is 1.14

Installation

go get -u github.com/vk-rv/pvx

General usage

Version 4 (local)

Recommended

Encrypt / Decrypt

k, err := hex.DecodeString("707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f")
if err != nil {
    return err 
}
symK := pvx.NewSymmetricKey(k, pvx.Version4)
pv4 := pvx.NewPV4Local()
token, err := pv4.Encrypt(symK, claims, pvx.WithAssert([]byte("test")))
if err != nil {
	return err
}
cc := MyClaims{}
err = pv4.
    Decrypt(token, symK, pvx.WithAssert([]byte("test"))).
    ScanClaims(&cc)
if err != nil {
    return err 
}
// work with cc claims ...

// or without assert
token, err := pv4.Encrypt(symK, claims)
if err != nil {
	return err
}
err = pv4.Decrypt(token, symK).ScanClaims(&cc)

// more info about implicit asserts is here
// https://github.com/paseto-standard/paseto-spec/blob/master/docs/Rationale-V3-V4.md#implicit-assertions-feature

Version 4 (public)

Recommended

Sign / Verify

publicKey, privateKey, _ := ed25519.GenerateKey(nil)
sk := pvx.NewAsymmetricSecretKey(privateKey, pvx.Version4)
pk := pvx.NewAsymmetricPublicKey(publicKey, pvx.Version4)

pv4 := pvx.NewPV4Public()

token, err := pv4.Sign(sk, claims, pvx.WithAssert([]byte("test")))
if err != nil {//...}

var claims MyClaims 
if err := pv4.Verify(token, pk, pvx.WithAssert([]byte("test")).ScanClaims(&claims); err != nil {//...}

// more info about implicit asserts is here
// https://github.com/paseto-standard/paseto-spec/blob/master/docs/Rationale-V3-V4.md#implicit-assertions-feature

Version 3 (local)

If you need NIST-approved algorithms

k, err := hex.DecodeString("707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f")
if err != nil {
    return err 
}
symK := pvx.NewSymmetricKey(k, pvx.Version3)
pv3 := pvx.NewPV3Local()
token, err := pv3.Encrypt(symK, claims, pvx.WithAssert([]byte("test")))
if err != nil {
	return err
}
cc := MyClaims{}
err = pv3.
    Decrypt(token, symK, pvx.WithAssert([]byte("test"))).
    ScanClaims(&cc)
if err != nil {
    return err 
}
// work with cc claims ...

// or without assert
token, err := pv3.Encrypt(symK, claims)
if err != nil {
	return err
}
err = pv3.Decrypt(token, symK).ScanClaims(&cc)

// more info about implicit asserts is here
// https://github.com/paseto-standard/paseto-spec/blob/master/docs/Rationale-V3-V4.md#implicit-assertions-feature

Claims validation

PVX adds extra layer of security by adding validation of time-based registered claims during a scan by default. During validation multiple errors can occur, and you can check every of them by calling sugar routines on special type.

 // For additional layer of safety, 
 // ScanClaims verifies exp, iss and nbf claims automatically under the hood and you can check whether validation error occurred or not 
 if err := decrypted.ScanClaims(&myClaimsScanned); err != nil {
    var validationErr *pvx.ValidationError
    if errors.As(err, &validationErr) {
        if validationErr.HasExpiredErr() { 
                // handle 
		}
		if validationErr.HasNotBeforeErr() { 
                // handle 
		}
	}
}

You can also use extend validation rules implementing Claims interface on your custom type

type MyClaims struct {
	pvx.RegisteredClaims
	AdditionalData string
	OtherData string 
} 

func (c *MyClaims) Valid() error {

	validationErr := &pvx.ValidationError{}
	
	// first, check the validity of registered claims
	if err := c.RegisteredClaims.Valid(); err != nil {
		errors.As(err, &validationErr)
	}
	
	//  then, perform custom validation
	
	
	return nil 
	
}

To disable validation of registered claims you should implement Claims interface explicitly returning nil in your checks. This is from design.

PASETO V3 and V4

A library has a work in progress status because currently is the next iteration of the PASETO specification. https://paragonie.com/blog/2021/08/paseto-is-even-more-secure-alternative-jose-standards-jwt-etc

Documentation

Index

Constants

View Source
const (
	ValidationErrorIssuer uint32 = 1 << iota
	ValidationErrorSubject
	ValidationErrorAudience
	ValidationErrorExpired
	ValidationErrorNotValidYet
	ValidationErrorIssuedAt
	ValidationErrorTokenID
	ValidationErrorKeyID
	ValidationErrorClaimsInvalid // generic validation error
)

Variables

View Source
var ErrInvalidSignature = errors.New("invalid token signature")

ErrInvalidSignature is returned when signature in invalid for provided message.

View Source
var ErrMalformedToken = errors.New("token is malformed")

ErrMalformedToken indicates that obtained token was not properly formed

View Source
var ErrWrongKey = errors.New("the given key is not intended for this version of PASETO")

ErrWrongKey is occurred when given key is not intended for specified version of PASETO.

View Source
var PV2Local = NewPV2Local()

PV2Local can be used as a global reference for protocol version 2 with local purpose.

View Source
var PV2Public = NewPV2Public()

PV2Public can be used as a global reference for protocol version 2 with public purpose.

View Source
var PV3Local = NewPV3Local()

PV3Local can be used as a global reference for protocol version 3 with local purpose.

View Source
var PV4Local = NewPV4Local()

PV4Local can be used as a global reference for protocol version 4 with local purpose.

View Source
var PV4Public = NewPV4Public()

PV4Public can be used as a global reference for protocol version 4 with public purpose.

Functions

func TimePtr

func TimePtr(t time.Time) *time.Time

TimePtr converts time structure to time pointer for optional json marshalling.

Types

type AsymPublicKey

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

AsymPublicKey is an asymmetric key abstraction for usage inside PASETO on verify.

func NewAsymmetricPublicKey

func NewAsymmetricPublicKey(keyMaterial []byte, version Version) *AsymPublicKey

NewAsymmetricPublicKey is a constructor-like function for AsymPublicKey which is a wrapper for raw key material used inside PASETO.

type AsymSecretKey

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

AsymSecretKey is an asymmetric key abstraction for usage inside PASETO on sign.

func NewAsymmetricSecretKey

func NewAsymmetricSecretKey(keyMaterial []byte, version Version) *AsymSecretKey

NewAsymmetricSecretKey is a constructor-like function for AsymSecretKey which is a wrapper for raw key material used inside PASETO.

type Claims

type Claims interface {
	Valid() error
}

Claims is everything that can be checked for validity.

type ProtoV2Local

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

ProtoV2Local is a protocol version 2 with local purpose.

func NewPV2Local

func NewPV2Local() *ProtoV2Local

NewPV2Local is a constructor-like sugar for protocol 2 version local purpose.

func (*ProtoV2Local) Decrypt

func (pv2 *ProtoV2Local) Decrypt(token string, key SymmetricKey) *Token

Decrypt implements PASETO v2.Decrypt returning Token struct ready for subsequent scan in case of success.

func (*ProtoV2Local) Encrypt

func (pv2 *ProtoV2Local) Encrypt(key SymmetricKey, claims Claims, footer interface{}) (string, error)

Encrypt encrypts claims with provided symmetric key and authenticates footer, protecting it from tampering but preserving it in base64 encoded plaintext.

func (*ProtoV2Local) EncryptFooterNil

func (pv2 *ProtoV2Local) EncryptFooterNil(key SymmetricKey, claims Claims) (string, error)

EncryptFooterNil is a sugar function which eliminates optional footer from function parameter list Equivalent to Encrypt (key, claims, nil).

type ProtoV2Public

type ProtoV2Public struct{}

ProtoV2Public is a public purpose of PASETO which supports token signing and verification.

func NewPV2Public

func NewPV2Public() *ProtoV2Public

NewPV2Public is a constructor-like sugar for ProtoV2Public.

func (*ProtoV2Public) Sign

func (pv2 *ProtoV2Public) Sign(privateKey ed25519.PrivateKey, claims Claims, footer interface{}) (string, error)

Sign signs claims with private key, authenticating its content but still preserving in plaintext.

func (*ProtoV2Public) SignFooterNil

func (pv2 *ProtoV2Public) SignFooterNil(privateKey ed25519.PrivateKey, claims Claims) (string, error)

SignFooterNil signs claims with private key, authenticating its content but still preserving in plaintext. Does not accept footer, internally calls Sign method with footer equal to nil.

func (*ProtoV2Public) Verify

func (pv2 *ProtoV2Public) Verify(token string, publicKey ed25519.PublicKey) *Token

type ProtoV3Local

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

ProtoV3Local is a protocol version 3 with local purpose.

func NewPV3Local

func NewPV3Local() *ProtoV3Local

NewPV3Local is a constructor-like sugar for protocol 3 version local purpose.

func (*ProtoV3Local) Decrypt

func (pv3 *ProtoV3Local) Decrypt(token string, key *SymKey, ops ...ProvidedOption) *Token

Decrypt implements PASETO v3.Decrypt returning Token struct ready for subsequent scan in case of success.

func (*ProtoV3Local) Encrypt

func (pv3 *ProtoV3Local) Encrypt(key *SymKey, claims Claims, ops ...ProvidedOption) (string, error)

Encrypt encrypts claims with provided symmetric key and authenticates footer, protecting it from tampering but preserving it in base64 encoded plaintext.

type ProtoV4Local

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

ProtoV4Local is a protocol version 4 with local purpose.

func NewPV4Local

func NewPV4Local() *ProtoV4Local

NewPV4Local is a constructor-like sugar for protocol 4 version local purpose.

func (*ProtoV4Local) Decrypt

func (pv4 *ProtoV4Local) Decrypt(token string, key *SymKey, ops ...ProvidedOption) *Token

Decrypt implements PASETO v4.Decrypt returning Token struct ready for subsequent scan in case of success.

func (*ProtoV4Local) Encrypt

func (pv4 *ProtoV4Local) Encrypt(key *SymKey, claims Claims, ops ...ProvidedOption) (string, error)

Encrypt encrypts claims with provided symmetric key and authenticates footer, protecting it from tampering but preserving it in base64 encoded plaintext.

type ProtoV4Public

type ProtoV4Public struct{}

ProtoV4Public is a public purpose of PASETO which supports token signing and verification.

func NewPV4Public

func NewPV4Public() *ProtoV4Public

NewPV4Public is a constructor-like sugar for ProtoV4Public.

func (*ProtoV4Public) Sign

func (pv4 *ProtoV4Public) Sign(sk *AsymSecretKey, claims Claims, ops ...ProvidedOption) (string, error)

Sign signs claims with private key, authenticating its content but still preserving in plaintext.

func (*ProtoV4Public) Verify

func (pv4 *ProtoV4Public) Verify(token string, asymmetricPublicKey *AsymPublicKey, ops ...ProvidedOption) *Token

Verify just verifies token returning its structure for subsequent mapping.

type ProvidedOption

type ProvidedOption func(*optional) error

ProvidedOption is the type of constructor options.

func WithAssert

func WithAssert(assertion []byte) ProvidedOption

WithAssert adds implicit assertion to PASETO token Implicit assertion is an unencrypted but authenticated data (like the optional footer), but is NOT stored in the PASETO token (thus, implicit) and MUST be asserted when verifying a token.

func WithFooter

func WithFooter(footer interface{}) ProvidedOption

WithFooter adds PASETO footer to the token.

type RegisteredClaims

type RegisteredClaims struct {
	Issuer     string     `json:"iss,omitempty"`
	Subject    string     `json:"sub,omitempty"`
	Audience   string     `json:"aud,omitempty"`
	Expiration *time.Time `json:"exp,omitempty"`
	NotBefore  *time.Time `json:"nbf,omitempty"`
	IssuedAt   *time.Time `json:"iat,omitempty"`
	TokenID    string     `json:"jti,omitempty"`
	KeyID      string     `json:"kid,omitempty"`
}

RegisteredClaims are claims indicated in RFC.

func (*RegisteredClaims) Valid

func (c *RegisteredClaims) Valid() error

Validates time-based claims "exp, iat, nbf". If any of the above claims are not in the token, it will still be considered a valid claim.

type SymKey

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

SymKey is a symmetric key abstraction for usage inside PASETO.

func NewSymmetricKey

func NewSymmetricKey(keyMaterial []byte, version Version) *SymKey

NewSymmetricKey is a constructor-like function for SymKey which is a wrapper for raw key material used inside PASETO

type SymmetricKey

type SymmetricKey []byte

SymmetricKey is used in encryption and decryption routines.

type Token

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

Token is a structure which encapsulates raw claims and optionally raw footer or error which occurred in case of decryption/verification.

func (*Token) Err

func (t *Token) Err() error

Err is a getter which helps to separate decryption error from scanning or validation problem.

func (*Token) HasFooter

func (t *Token) HasFooter() bool

HasFooter reports whether footer was not empty after token decryption.

func (*Token) Scan

func (t *Token) Scan(claims Claims, footer interface{}) error

Scan deserialize claims to claims object and footer to footer object Performs claims validation (or user-provided in case of wrapping) under the hood for safer defaults.

func (*Token) ScanClaims

func (t *Token) ScanClaims(claims Claims) error

ScanClaims deserialize claims to object Performs claims validation (or user-provided in case of wrapping) under the hood for safer defaults.

type ValidationError

type ValidationError struct {
	Inner  error
	Errors uint32
}

ValidationError is a struct that encapsulates multiple validation errors which can occur during claims validation.

func (ValidationError) Error

func (e ValidationError) Error() string

func (*ValidationError) HasAudienceErr

func (e *ValidationError) HasAudienceErr() bool

HasAudienceErr checks the existence of aud validation problem.

func (*ValidationError) HasExpiredErr

func (e *ValidationError) HasExpiredErr() bool

HasExpiredErr checks the existence of exp validation problem.

func (*ValidationError) HasGenericValidationErr

func (e *ValidationError) HasGenericValidationErr() bool

HasGenericValidationErr checks the existence of generic validation problem.

func (*ValidationError) HasIssuedAtErr

func (e *ValidationError) HasIssuedAtErr() bool

HasIssuedAtErr checks the existence of iat validation problem.

func (*ValidationError) HasIssuerErr

func (e *ValidationError) HasIssuerErr() bool

HasIssuerErr checks the existence of iss validation problem.

func (*ValidationError) HasKeyIDErr

func (e *ValidationError) HasKeyIDErr() bool

HasKeyIDErr checks the existence of kid validation problem.

func (*ValidationError) HasNotBeforeErr

func (e *ValidationError) HasNotBeforeErr() bool

HasNotBeforeErr checks the existence of nbf validation problem.

func (*ValidationError) HasSubjectErr

func (e *ValidationError) HasSubjectErr() bool

HasSubjectErr checks the existence of sub validation problem.

func (*ValidationError) HasTokenIDErr

func (e *ValidationError) HasTokenIDErr() bool

HasTokenIDErr checks the existence of jti validation problem.

type Version

type Version int32

Version denotes PASETO version which will be used.

const (
	Version2 Version = 2
	Version3 Version = 3
	Version4 Version = 4
)

Jump to

Keyboard shortcuts

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