...

Package jws

import "github.com/lestrrat-go/jwx/jws"
Overview
Index

Overview ▾

Package jws implements the digital signature on JSON based data structures as described in https://tools.ietf.org/html/rfc7515

If you do not care about the details, the only things that you would need to use are the following functions:

jws.Sign(payload, algorithm, key)
jws.Verify(encodedjws, algorithm, key)

To sign, simply use `jws.Sign`. `payload` is a []byte buffer that contains whatever data you want to sign. `alg` is one of the jwa.SignatureAlgorithm constants from package jwa. For RSA and ECDSA family of algorithms, you will need to prepare a private key. For HMAC family, you just need a []byte value. The `jws.Sign` function will return the encoded JWS message on success.

To verify, use `jws.Verify`. It will parse the `encodedjws` buffer and verify the result using `algorithm` and `key`. Upon successful verification, the original payload is returned, so you can work on it.

Index ▾

Constants
func AlgorithmsForKey(key interface{}) ([]jwa.SignatureAlgorithm, error)
func RegisterCustomField(name string, object interface{})
func RegisterSigner(alg jwa.SignatureAlgorithm, f SignerFactory)
func RegisterVerifier(alg jwa.SignatureAlgorithm, f VerifierFactory)
func Sign(payload []byte, alg jwa.SignatureAlgorithm, key interface{}, options ...SignOption) ([]byte, error)
func SignMulti(payload []byte, options ...Option) ([]byte, error)
func SplitCompact(src []byte) ([]byte, []byte, []byte, error)
func SplitCompactReader(rdr io.Reader) ([]byte, []byte, []byte, error)
func SplitCompactString(src string) ([]byte, []byte, []byte, error)
func Verify(buf []byte, alg jwa.SignatureAlgorithm, key interface{}, options ...VerifyOption) ([]byte, error)
func VerifyAuto(buf []byte, options ...VerifyOption) ([]byte, error)
func VerifySet(buf []byte, set jwk.Set) ([]byte, error)
type DecodeCtx
type HMACSigner
    func (s HMACSigner) Algorithm() jwa.SignatureAlgorithm
    func (s HMACSigner) Sign(payload []byte, key interface{}) ([]byte, error)
type HMACVerifier
    func (v HMACVerifier) Verify(payload, signature []byte, key interface{}) (err error)
type HeaderPair
type Headers
    func NewHeaders() Headers
type Iterator
type JWKSetFetchFunc
    func (f JWKSetFetchFunc) Fetch(u string) (jwk.Set, error)
type JWKSetFetcher
type Message
    func NewMessage() *Message
    func Parse(src []byte) (*Message, error)
    func ParseReader(src io.Reader) (*Message, error)
    func ParseString(src string) (*Message, error)
    func ReadFile(path string, _ ...ReadFileOption) (*Message, error)
    func (m *Message) AppendSignature(v *Signature) *Message
    func (m *Message) ClearSignatures() *Message
    func (m *Message) DecodeCtx() DecodeCtx
    func (m Message) LookupSignature(kid string) []*Signature
    func (m Message) MarshalJSON() ([]byte, error)
    func (m Message) Payload() []byte
    func (m *Message) SetDecodeCtx(dc DecodeCtx)
    func (m *Message) SetPayload(v []byte) *Message
    func (m Message) Signatures() []*Signature
    func (m *Message) UnmarshalJSON(buf []byte) error
type Option
    func WithSigner(signer Signer, key interface{}, public, protected Headers) Option
type ReadFileOption
type SignOption
    func WithHeaders(h Headers) SignOption
type SignVerifyOption
    func WithDetachedPayload(v []byte) SignVerifyOption
type Signature
    func NewSignature() *Signature
    func (s *Signature) DecodeCtx() DecodeCtx
    func (s Signature) ProtectedHeaders() Headers
    func (s Signature) PublicHeaders() Headers
    func (s *Signature) SetDecodeCtx(dc DecodeCtx)
    func (s *Signature) SetProtectedHeaders(v Headers) *Signature
    func (s *Signature) SetPublicHeaders(v Headers) *Signature
    func (s *Signature) SetSignature(v []byte) *Signature
    func (s *Signature) Sign(payload []byte, signer Signer, key interface{}) ([]byte, []byte, error)
    func (s Signature) Signature() []byte
    func (s *Signature) UnmarshalJSON(data []byte) error
type Signer
    func NewSigner(alg jwa.SignatureAlgorithm) (Signer, error)
type SignerFactory
type SignerFactoryFn
    func (fn SignerFactoryFn) Create() (Signer, error)
type SimpleJWKSetFetcher
    func NewJWKSetFetcher(options ...jwk.FetchOption) *SimpleJWKSetFetcher
    func (f *SimpleJWKSetFetcher) Fetch(u string) (jwk.Set, error)
type Verifier
    func NewVerifier(alg jwa.SignatureAlgorithm) (Verifier, error)
type VerifierFactory
type VerifierFactoryFn
    func (fn VerifierFactoryFn) Create() (Verifier, error)
type VerifyOption
    func WithFetchBackoff(b backoff.Policy) VerifyOption
    func WithFetchWhitelist(wl jwk.Whitelist) VerifyOption
    func WithHTTPClient(httpcl *http.Client) VerifyOption
    func WithJWKSetFetcher(f JWKSetFetcher) VerifyOption
    func WithMessage(m *Message) VerifyOption
type Visitor
type VisitorFunc

Package files

ecdsa.go eddsa.go headers.go headers_gen.go hmac.go interface.go io.go jws.go message.go option.go rsa.go signer.go verifier.go

Constants

const (
    AlgorithmKey              = "alg"
    ContentTypeKey            = "cty"
    CriticalKey               = "crit"
    JWKKey                    = "jwk"
    JWKSetURLKey              = "jku"
    KeyIDKey                  = "kid"
    TypeKey                   = "typ"
    X509CertChainKey          = "x5c"
    X509CertThumbprintKey     = "x5t"
    X509CertThumbprintS256Key = "x5t#S256"
    X509URLKey                = "x5u"
)

func AlgorithmsForKey

func AlgorithmsForKey(key interface{}) ([]jwa.SignatureAlgorithm, error)

AlgorithmsForKey returns the possible signature algorithms that can be used for a given key. It only takes in consideration keys/algorithms for verification purposes, as this is the only usage where one may need dynamically figure out which method to use.

func RegisterCustomField

func RegisterCustomField(name string, object interface{})

RegisterCustomField allows users to specify that a private field be decoded as an instance of the specified type. This option has a global effect.

For example, suppose you have a custom field `x-birthday`, which you want to represent as a string formatted in RFC3339 in JSON, but want it back as `time.Time`.

In that case you would register a custom field as follows

jwe.RegisterCustomField(`x-birthday`, timeT)

Then `hdr.Get("x-birthday")` will still return an `interface{}`, but you can convert its type to `time.Time`

bdayif, _ := hdr.Get(`x-birthday`)
bday := bdayif.(time.Time)

func RegisterSigner

func RegisterSigner(alg jwa.SignatureAlgorithm, f SignerFactory)

RegisterSigner is used to register a factory object that creates Signer objects based on the given algorithm.

For example, if you would like to provide a custom signer for jwa.EdDSA, use this function to register a `SignerFactory` (probably in your `init()`)

func RegisterVerifier

func RegisterVerifier(alg jwa.SignatureAlgorithm, f VerifierFactory)

RegisterVerifier is used to register a factory object that creates Verifier objects based on the given algorithm.

For example, if you would like to provide a custom verifier for jwa.EdDSA, use this function to register a `VerifierFactory` (probably in your `init()`)

func Sign

func Sign(payload []byte, alg jwa.SignatureAlgorithm, key interface{}, options ...SignOption) ([]byte, error)

Sign generates a signature for the given payload, and serializes it in compact serialization format. In this format you may NOT use multiple signers.

The `alg` parameter is the identifier for the signature algorithm that should be used.

For the `key` parameter, any of the following is accepted: * A "raw" key (e.g. rsa.PrivateKey, ecdsa.PrivateKey, etc) * A crypto.Signer * A jwk.Key

A `crypto.Signer` is used when the private part of a key is kept in an inaccessible location, such as hardware. `crypto.Signer` is currently supported for RSA, ECDSA, and EdDSA family of algorithms.

If the key is a jwk.Key and the key contains a key ID (`kid` field), then it is added to the protected header generated by the signature

The algorithm specified in the `alg` parameter must be able to support the type of key you provided, otherwise an error is returned.

If you would like to pass custom headers, use the WithHeaders option.

If the headers contain "b64" field, then the boolean value for the field is respected when creating the compact serialization form. That is, if you specify a header with `{"b64": false}`, then the payload is not base64 encoded.

If you want to use a detached payload, use `jws.WithDetachedPayload()` as one of the options. When you use this option, you must always set the first parameter (`payload`) to `nil`, or the function will return an error

func SignMulti

func SignMulti(payload []byte, options ...Option) ([]byte, error)

SignMulti accepts multiple signers via the options parameter, and creates a JWS in JSON serialization format that contains signatures from applying aforementioned signers.

Use `jws.WithSigner(...)` to specify values how to generate each signature in the `"signatures": [ ... ]` field.

func SplitCompact

func SplitCompact(src []byte) ([]byte, []byte, []byte, error)

SplitCompact splits a JWT and returns its three parts separately: protected headers, payload and signature.

func SplitCompactReader

func SplitCompactReader(rdr io.Reader) ([]byte, []byte, []byte, error)

SplitCompactReader splits a JWT and returns its three parts separately: protected headers, payload and signature.

func SplitCompactString

func SplitCompactString(src string) ([]byte, []byte, []byte, error)

SplitCompactString splits a JWT and returns its three parts separately: protected headers, payload and signature.

func Verify

func Verify(buf []byte, alg jwa.SignatureAlgorithm, key interface{}, options ...VerifyOption) ([]byte, error)

Verify checks if the given JWS message is verifiable using `alg` and `key`. `key` may be a "raw" key (e.g. rsa.PublicKey) or a jwk.Key

If the verification is successful, `err` is nil, and the content of the payload that was signed is returned. If you need more fine-grained control of the verification process, manually generate a `Verifier` in `verify` subpackage, and call `Verify` method on it. If you need to access signatures and JOSE headers in a JWS message, use `Parse` function to get `Message` object.

func VerifyAuto

func VerifyAuto(buf []byte, options ...VerifyOption) ([]byte, error)

VerifyAuto is a special case of Verify(), where verification is done using verifications parameters that can be obtained using the information that is carried within the JWS message itself.

Currently it only supports verification via `jku` which will be fetched using the object specified in `jws.JWKSetFetcher`. Note that URLs in `jku` can only have https scheme.

Using this function will result in your program accessing remote resources via https, and therefore extreme caution should be taken which urls can be accessed.

Without specifying extra arguments, the default `jws.JWKSetFetcher` will be configured with a whitelist that rejects *ALL URLSs*. This is to protect users from unintentionally allowing their projects to make unwanted requests. Therefore you must explicitly provide an instance of `jwk.Whitelist` that does what you want.

If you want open access to any URLs in the `jku`, you can do this by using `jwk.InsecureWhitelist` as the whitelist, but this should be avoided in most cases, especially if the payload comes from outside of a controlled environment.

It is also advised that you consider using some sort of backoff via `jws.WithFetchBackoff`

Alternatively, you can provide your own `jws.JWKSetFetcher`. In this case there is no way for the framework to force you to set a whitelist, so the default behavior is to allow any URLs. You are responsible for providing your own safety measures.

func VerifySet

func VerifySet(buf []byte, set jwk.Set) ([]byte, error)

VerifySet uses keys store in a jwk.Set to verify the payload in `buf`.

In order for `VerifySet()` to use a key in the given set, the `jwk.Key` object must have a valid "alg" field, and it also must have either an empty value or the value "sig" in the "use" field.

Furthermore if the JWS signature asks for a spefici "kid", the `jwk.Key` must have the same "kid" as the signature.

type DecodeCtx

type DecodeCtx interface {
    CollectRaw() bool
}

type HMACSigner

HMACSigner uses crypto/hmac to sign the payloads.

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

func (HMACSigner) Algorithm

func (s HMACSigner) Algorithm() jwa.SignatureAlgorithm

func (HMACSigner) Sign

func (s HMACSigner) Sign(payload []byte, key interface{}) ([]byte, error)

type HMACVerifier

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

func (HMACVerifier) Verify

func (v HMACVerifier) Verify(payload, signature []byte, key interface{}) (err error)

type HeaderPair

type HeaderPair = mapiter.Pair

type Headers

Headers describe a standard Header set.

type Headers interface {
    json.Marshaler
    json.Unmarshaler
    Algorithm() jwa.SignatureAlgorithm
    ContentType() string
    Critical() []string
    JWK() jwk.Key
    JWKSetURL() string
    KeyID() string
    Type() string
    X509CertChain() []string
    X509CertThumbprint() string
    X509CertThumbprintS256() string
    X509URL() string
    Iterate(ctx context.Context) Iterator
    Walk(context.Context, Visitor) error
    AsMap(context.Context) (map[string]interface{}, error)
    Copy(context.Context, Headers) error
    Merge(context.Context, Headers) (Headers, error)
    Get(string) (interface{}, bool)
    Set(string, interface{}) error
    Remove(string) error

    // PrivateParams returns the non-standard elements in the source structure
    // WARNING: DO NOT USE PrivateParams() IF YOU HAVE CONCURRENT CODE ACCESSING THEM.
    // Use AsMap() to get a copy of the entire header instead
    PrivateParams() map[string]interface{}
}

func NewHeaders

func NewHeaders() Headers

type Iterator

type Iterator = mapiter.Iterator

type JWKSetFetchFunc

type JWKSetFetchFunc func(string) (jwk.Set, error)

func (JWKSetFetchFunc) Fetch

func (f JWKSetFetchFunc) Fetch(u string) (jwk.Set, error)

type JWKSetFetcher

JWKSetFetcher is used to fetch JWK Set spcified in the `jku` field.

type JWKSetFetcher interface {
    Fetch(string) (jwk.Set, error)
}

type Message

Message represents a full JWS encoded message. Flattened serialization is not supported as a struct, but rather it's represented as a Message struct with only one `signature` element.

Do not expect to use the Message object to verify or construct a signed payload with. You should only use this when you want to actually programmatically view the contents of the full JWS payload.

As of this version, there is one big incompatibility when using Message objects to convert between compact and JSON representations. The protected header is sometimes encoded differently from the original message and the JSON serialization that we use in Go.

For example, the protected header `eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9` decodes to

{"typ":"JWT",
  "alg":"HS256"}

However, when we parse this into a message, we create a jws.Header object, which, when we marshal into a JSON object again, becomes

{"typ":"JWT","alg":"HS256"}

Notice that serialization lacks a line break and a space between `"JWT",` and `"alg"`. This causes a problem when verifying the signatures AFTER a compact JWS message has been unmarshaled into a jws.Message.

jws.Verify() doesn't go through this step, and therefore this does not manifest itself. However, you may see this discrepancy when you manually go through these conversions, and/or use the `jwx` tool like so:

jwx jws parse message.jws | jwx jws verify --key somekey.jwk --stdin

In this scenario, the first `jwx jws parse` outputs a parsed jws.Message which is marshaled into JSON. At this point the message's protected headers and the signatures don't match.

To sign and verify, use the appropriate `Sign()` and `Verify()` functions.

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

func NewMessage

func NewMessage() *Message

func Parse

func Parse(src []byte) (*Message, error)

Parse parses contents from the given source and creates a jws.Message struct. The input can be in either compact or full JSON serialization.

func ParseReader

func ParseReader(src io.Reader) (*Message, error)

Parse parses contents from the given source and creates a jws.Message struct. The input can be in either compact or full JSON serialization.

func ParseString

func ParseString(src string) (*Message, error)

Parse parses contents from the given source and creates a jws.Message struct. The input can be in either compact or full JSON serialization.

func ReadFile

func ReadFile(path string, _ ...ReadFileOption) (*Message, error)

func (*Message) AppendSignature

func (m *Message) AppendSignature(v *Signature) *Message

func (*Message) ClearSignatures

func (m *Message) ClearSignatures() *Message

func (*Message) DecodeCtx

func (m *Message) DecodeCtx() DecodeCtx

func (Message) LookupSignature

func (m Message) LookupSignature(kid string) []*Signature

LookupSignature looks up a particular signature entry using the `kid` value

func (Message) MarshalJSON

func (m Message) MarshalJSON() ([]byte, error)

func (Message) Payload

func (m Message) Payload() []byte

Payload returns the decoded payload

func (*Message) SetDecodeCtx

func (m *Message) SetDecodeCtx(dc DecodeCtx)

func (*Message) SetPayload

func (m *Message) SetPayload(v []byte) *Message

func (Message) Signatures

func (m Message) Signatures() []*Signature

func (*Message) UnmarshalJSON

func (m *Message) UnmarshalJSON(buf []byte) error

type Option

type Option = option.Interface

func WithSigner

func WithSigner(signer Signer, key interface{}, public, protected Headers) Option

type ReadFileOption

ReadFileOption describes options that can be passed to ReadFile. Currently there are no options available that can be passed to ReadFile, but it is provided here for anticipated future additions

type ReadFileOption interface {
    Option
    // contains filtered or unexported methods
}

type SignOption

type SignOption interface {
    Option
    // contains filtered or unexported methods
}

func WithHeaders

func WithHeaders(h Headers) SignOption

WithHeaders allows you to specify extra header values to include in the final JWS message

type SignVerifyOption

type SignVerifyOption interface {
    SignOption
    VerifyOption
}

func WithDetachedPayload

func WithDetachedPayload(v []byte) SignVerifyOption

WithDetachedPayload can be used to both sign or verify a JWS message with a detached payload.

When this option is used for `jws.Sign()`, the first parameter (normally the payload) must be set to `nil`.

If you have to verify using this option, you should know exactly how and why this works.

type Signature

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

func NewSignature

func NewSignature() *Signature

func (*Signature) DecodeCtx

func (s *Signature) DecodeCtx() DecodeCtx

func (Signature) ProtectedHeaders

func (s Signature) ProtectedHeaders() Headers

func (Signature) PublicHeaders

func (s Signature) PublicHeaders() Headers

func (*Signature) SetDecodeCtx

func (s *Signature) SetDecodeCtx(dc DecodeCtx)

func (*Signature) SetProtectedHeaders

func (s *Signature) SetProtectedHeaders(v Headers) *Signature

func (*Signature) SetPublicHeaders

func (s *Signature) SetPublicHeaders(v Headers) *Signature

func (*Signature) SetSignature

func (s *Signature) SetSignature(v []byte) *Signature

func (*Signature) Sign

func (s *Signature) Sign(payload []byte, signer Signer, key interface{}) ([]byte, []byte, error)

Sign populates the signature field, with a signature generated by given the signer object and payload.

The first return value is the raw signature in binary format. The second return value s the full three-segment signature (e.g. "eyXXXX.XXXXX.XXXX")

func (Signature) Signature

func (s Signature) Signature() []byte

func (*Signature) UnmarshalJSON

func (s *Signature) UnmarshalJSON(data []byte) error

type Signer

Signer generates the signature for a given payload.

type Signer interface {
    // Sign creates a signature for the given payload.
    // The scond argument is the key used for signing the payload, and is usually
    // the private key type associated with the signature method. For example,
    // for `jwa.RSXXX` and `jwa.PSXXX` types, you need to pass the
    // `*"crypto/rsa".PrivateKey` type.
    // Check the documentation for each signer for details
    Sign([]byte, interface{}) ([]byte, error)

    Algorithm() jwa.SignatureAlgorithm
}

func NewSigner

func NewSigner(alg jwa.SignatureAlgorithm) (Signer, error)

NewSigner creates a signer that signs payloads using the given signature algorithm.

type SignerFactory

type SignerFactory interface {
    Create() (Signer, error)
}

type SignerFactoryFn

type SignerFactoryFn func() (Signer, error)

func (SignerFactoryFn) Create

func (fn SignerFactoryFn) Create() (Signer, error)

type SimpleJWKSetFetcher

SimpleJWKSetFetcher is the default object used to fetch JWK Sets specified in `jku`, which uses `jwk.Fetch()`

For more complicated cases, such as using `jwk.AutoRefetch`, you will have to create your custom instance of `jws.JWKSetFetcher`

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

func NewJWKSetFetcher

func NewJWKSetFetcher(options ...jwk.FetchOption) *SimpleJWKSetFetcher

func (*SimpleJWKSetFetcher) Fetch

func (f *SimpleJWKSetFetcher) Fetch(u string) (jwk.Set, error)

type Verifier

type Verifier interface {
    // Verify checks whether the payload and signature are valid for
    // the given key.
    // `key` is the key used for verifying the payload, and is usually
    // the public key associated with the signature method. For example,
    // for `jwa.RSXXX` and `jwa.PSXXX` types, you need to pass the
    // `*"crypto/rsa".PublicKey` type.
    // Check the documentation for each verifier for details
    Verify(payload []byte, signature []byte, key interface{}) error
}

func NewVerifier

func NewVerifier(alg jwa.SignatureAlgorithm) (Verifier, error)

NewVerifier creates a verifier that signs payloads using the given signature algorithm.

type VerifierFactory

type VerifierFactory interface {
    Create() (Verifier, error)
}

type VerifierFactoryFn

type VerifierFactoryFn func() (Verifier, error)

func (VerifierFactoryFn) Create

func (fn VerifierFactoryFn) Create() (Verifier, error)

type VerifyOption

VerifyOption describes an option that can be passed to the jws.Verify function

type VerifyOption interface {
    Option
    // contains filtered or unexported methods
}

func WithFetchBackoff

func WithFetchBackoff(b backoff.Policy) VerifyOption

WithFetchBackoff specifies the backoff.Policy object to be passed to `jwk.Fetch()` when `jws.VerifyAuto()` is used.

This option is ignored if WithJWKSetFetcher is specified.

func WithFetchWhitelist

func WithFetchWhitelist(wl jwk.Whitelist) VerifyOption

WithFetchWhitelist specifies the whitelist object to be passed to `jwk.Fetch()` when `jws.VerifyAuto()` is used. If you do not specify a whitelist, `jws.VerifyAuto()` will ALWAYS fail.

This option is ignored if WithJWKSetFetcher is specified.

func WithHTTPClient

func WithHTTPClient(httpcl *http.Client) VerifyOption

WithHTTPClient specifies the *http.Client object to be passed to `jwk.Fetch()` when `jws.VerifyAuto()` is used.

This option is ignored if WithJWKSetFetcher is specified.

func WithJWKSetFetcher

func WithJWKSetFetcher(f JWKSetFetcher) VerifyOption

WithJWKSetFetcher specifies the JWKSetFetcher object to be used when `jws.VerifyAuto()`, for example, to use `jwk.AutoRefetch` instead of the default `jwk.Fetch()`

func WithMessage

func WithMessage(m *Message) VerifyOption

WithMessage can be passed to Verify() to obtain the jws.Message upon a successful verification.

type Visitor

type Visitor = iter.MapVisitor

type VisitorFunc

type VisitorFunc = iter.MapVisitorFunc