Documentation ¶
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, jws.WithKey(algorithm, key)) jws.Verify(serialized, jws.WithKey(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 Compact(msg *Message, options ...CompactOption) ([]byte, error)
- func ParseError() 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, options ...SignOption) ([]byte, error)
- func SignError() 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 UnregisterSigner(alg jwa.SignatureAlgorithm)
- func UnregisterVerifier(alg jwa.SignatureAlgorithm)
- func VerificationError() error
- func Verify(buf []byte, options ...VerifyOption) ([]byte, error)
- func VerifyError() error
- type CompactOption
- type CustomDecodeFunc
- type CustomDecoder
- type DecodeCtx
- type HMACSigner
- type HMACVerifier
- type Headers
- type KeyProvider
- type KeyProviderFunc
- type KeySink
- type Message
- 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
- type ParseOption
- type ReadFileOption
- type SignOption
- type SignVerifyOption
- type SignVerifyParseOption
- type 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
- type SignerFactory
- type SignerFactoryFn
- type Verifier
- type VerifierFactory
- type VerifierFactoryFn
- type VerifyOption
- func WithContext(v context.Context) VerifyOption
- func WithKeyProvider(v KeyProvider) VerifyOption
- func WithKeySet(set jwk.Set, options ...WithKeySetSuboption) VerifyOption
- func WithKeyUsed(v interface{}) VerifyOption
- func WithMessage(v *Message) VerifyOption
- func WithVerifyAuto(f jwk.Fetcher, options ...jwk.FetchOption) VerifyOption
- type WithJSONSuboption
- type WithKeySetSuboption
- type WithKeySuboption
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" )
Variables ¶
This section is empty.
Functions ¶
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 Compact ¶
func Compact(msg *Message, options ...CompactOption) ([]byte, error)
Compact generates a JWS message in compact serialization format from `*jws.Message` object. The object contain exactly one signature, or an error is returned.
If using a detached payload, the payload must already be stored in the `*jws.Message` object, and the `jws.WithDetached()` option must be passed to the function.
func ParseError ¶
func ParseError() error
ParseError returns an error that can be passed to `errors.Is` to check if the error is a parse error.
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 such case you would register a custom field as follows
jws.RegisterCustomField(`x-birthday`, time.Time{})
Then you can use a `time.Time` variable to extract the value of `x-birthday` field, instead of having to use `interface{}` and later convert it to `time.Time`
var bday time.Time _ = hdr.Get(`x-birthday`, &bday)
If you need a more fine-tuned control over the decoding process, you can register a `CustomDecoder`. For example, below shows how to register a decoder that can parse RFC1123 format string:
jws.RegisterCustomField(`x-birthday`, jws.CustomDecodeFunc(func(data []byte) (interface{}, error) { return time.Parse(time.RFC1123, string(data)) }))
Please note that use of custom fields can be problematic if you are using a library that does not implement MarshalJSON/UnmarshalJSON and you try to roundtrip from an object to JSON, and then back to an object. For example, in the above example, you can _parse_ time values formatted in the format specified in RFC822, but when you convert an object into JSON, it will be formatted in RFC3339, because that's what `time.Time` likes to do. To avoid this, it's always better to use a custom type that wraps your desired type (in this case `time.Time`) and implement MarshalJSON and UnmashalJSON.
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. Previous object instantiated by the factory is discarded.
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()`)
Unlike the `UnregisterSigner` function, this function automatically calls `jwa.RegisterSignatureAlgorithm` to register the algorithm in this module's algorithm database.
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()`)
Unlike the `UnregisterVerifier` function, this function automatically calls `jwa.RegisterSignatureAlgorithm` to register the algorithm in this module's algorithm database.
func Sign ¶
func Sign(payload []byte, options ...SignOption) ([]byte, error)
Sign generates a JWS message for the given payload and returns it in serialized form, which can be in either compact or JSON format. Default is compact.
You must pass at least one key to `jws.Sign()` by using `jws.WithKey()` option.
jws.Sign(payload, jws.WithKey(alg, key)) jws.Sign(payload, jws.WithJSON(), jws.WithKey(alg1, key1), jws.WithKey(alg2, key2))
Note that in the second example the `jws.WithJSON()` option is specified as well. This is because the compact serialization format does not support multiple signatures, and users must specifically ask for the JSON serialization format.
Read the documentation for `jws.WithKey()` to learn more about the possible values that can be used for `alg` and `key`.
You may create JWS messages with the "none" (jwa.NoSignature) algorithm if you use the `jws.WithInsecureNoSignature()` option. This option can be combined with one or more signature keys, as well as the `jws.WithJSON()` option to generate multiple signatures (though the usefulness of such constructs is highly debatable)
Note that this library does not allow you to successfully call `jws.Verify()` on signatures with the "none" algorithm. To parse these, use `jws.Parse()` instead.
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
You may also want to look at how to pass protected headers to the signing process, as you will likely be required to set the `b64` field when using detached payload.
Look for options that return `jws.SignOption` or `jws.SignVerifyOption` for a complete list of options that can be passed to this function.
You can use `errors.Is` with `jws.SignError()` to check if an error is from this function.
func SignError ¶
func SignError() error
SignError returns an error that can be passed to `errors.Is` to check if the error is a sign error.
func SplitCompact ¶
SplitCompact splits a JWT and returns its three parts separately: protected headers, payload and signature.
On error, returns a jws.ParseError.
func SplitCompactReader ¶
SplitCompactReader splits a JWT and returns its three parts separately: protected headers, payload and signature.
On error, returns a jws.ParseError.
func SplitCompactString ¶
SplitCompactString splits a JWT and returns its three parts separately: protected headers, payload and signature.
On error, returns a jws.ParseError.
func UnregisterSigner ¶
func UnregisterSigner(alg jwa.SignatureAlgorithm)
UnregisterSigner removes the signer factory associated with the given algorithm, as well as the signer instance created by the factory.
Note that when you call this function, the algorithm itself is not automatically unregistered from this module's algorithm database. This is because the algorithm may still be required for verification or some other operation (however unlikely, it is still possible). Therefore, in order to completely remove the algorithm, you must call `jwa.UnregisterSignatureAlgorithm` yourself.
func UnregisterVerifier ¶
func UnregisterVerifier(alg jwa.SignatureAlgorithm)
UnregisterVerifier removes the signer factory associated with the given algorithm.
Note that when you call this function, the algorithm itself is not automatically unregistered from this module's algorithm database. This is because the algorithm may still be required for signing or some other operation (however unlikely, it is still possible). Therefore, in order to completely remove the algorithm, you must call `jwa.UnregisterSignatureAlgorithm` yourself.
func VerificationError ¶
func VerificationError() error
VerificationError returns an error that can be passed to `errors.Is` to check if the error is a verification error.
func Verify ¶
func Verify(buf []byte, 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.
Because the use of "none" (jwa.NoSignature) algorithm is strongly discouraged, this function DOES NOT consider it a success when `{"alg":"none"}` is encountered in the message (it would also be counterintuitive when the code says it _verified_ something when in fact it did no such thing). If you want to accept messages with "none" signature algorithm, use `jws.Parse` to get the raw JWS message.
The error returned by this function is of type can be checked against `jws.VerifyError()` and `jws.VerificationError()`. The latter is returned when the verification process itself fails (e.g. invalid signature, wrong key), while the former is returned when any other part of the `jws.Verify()` function fails.
func VerifyError ¶
func VerifyError() error
VerifyError returns an error that can be passed to `errors.Is` to check if the error is a verify error.
Types ¶
type CompactOption ¶
type CompactOption interface { Option // contains filtered or unexported methods }
CompactOption describes options that can be passed to `jws.Compact`
func WithDetached ¶
func WithDetached(v bool) CompactOption
WithDetached specifies that the `jws.Message` should be serialized in JWS compact serialization with detached payload. The resulting octet sequence will not contain the payload section.
type CustomDecodeFunc ¶
type CustomDecodeFunc = json.CustomDecodeFunc
type CustomDecoder ¶
type CustomDecoder = json.CustomDecoder
type HMACSigner ¶
type HMACSigner struct {
// contains filtered or unexported fields
}
HMACSigner uses crypto/hmac to sign the payloads.
func (HMACSigner) Algorithm ¶
func (s HMACSigner) Algorithm() jwa.SignatureAlgorithm
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 Headers ¶
type Headers interface { Algorithm() (jwa.SignatureAlgorithm, bool) ContentType() (string, bool) Critical() ([]string, bool) JWK() (jwk.Key, bool) JWKSetURL() (string, bool) KeyID() (string, bool) Type() (string, bool) X509CertChain() (*cert.Chain, bool) X509CertThumbprint() (string, bool) X509CertThumbprintS256() (string, bool) X509URL() (string, bool) Copy(Headers) error Merge(Headers) (Headers, error) // Get is used to extract the value of any field, including non-standard fields, out of the header. // // The first argument is the name of the field. The second argument is a pointer // to a variable that will receive the value of the field. The method returns // an error if the field does not exist, or if the value cannot be assigned to // the destination variable. Note that a field is considered to "exist" even if // the value is empty-ish (e.g. 0, false, ""), as long as it is explicitly set. Get(string, interface{}) error Set(string, interface{}) error Remove(string) error // Has returns true if the specified header has a value, even if // the value is empty-ish (e.g. 0, false, "") as long as it has been // explicitly set. Has(string) bool Keys() []string }
Headers describe a standard JWS Header set. It is part of the JWS message and is used to represet both Public or Protected headers, which in turn can be found in each Signature object. If you are not sure how this works, it is strongly recommended that you read RFC7515, especially the section that describes the full JSON serialization format of JWS messages.
In most cases, you likely want to use the protected headers, as this is part of the signed content.
func NewHeaders ¶
func NewHeaders() Headers
type KeyProvider ¶
KeyProvider is responsible for providing key(s) to sign or verify a payload. Multiple `jws.KeyProvider`s can be passed to `jws.Verify()` or `jws.Sign()`
`jws.Sign()` can only accept static key providers via `jws.WithKey()`, while `jws.Verify()` can accept `jws.WithKey()`, `jws.WithKeySet()`, `jws.WithVerifyAuto()`, and `jws.WithKeyProvider()`.
Understanding how this works is crucial to learn how this package works.
`jws.Sign()` is straightforward: signatures are created for each provided key.
`jws.Verify()` is a bit more involved, because there are cases you will want to compute/deduce/guess the keys that you would like to use for verification.
The first thing that `jws.Verify()` does is to collect the KeyProviders from the option list that the user provided (presented in pseudocode):
keyProviders := filterKeyProviders(options)
Then, remember that a JWS message may contain multiple signatures in the message. For each signature, we call on the KeyProviders to give us the key(s) to use on this signature:
for sig in msg.Signatures { for kp in keyProviders { kp.FetchKeys(ctx, sink, sig, msg) ... } }
The `sink` argument passed to the KeyProvider is a temporary storage for the keys (either a jwk.Key or a "raw" key). The `KeyProvider` is responsible for sending keys into the `sink`.
When called, the `KeyProvider` created by `jws.WithKey()` sends the same key, `jws.WithKeySet()` sends keys that matches a particular `kid` and `alg`, `jws.WithVerifyAuto()` fetches a JWK from the `jku` URL, and finally `jws.WithKeyProvider()` allows you to execute arbitrary logic to provide keys. If you are providing a custom `KeyProvider`, you should execute the necessary checks or retrieval of keys, and then send the key(s) to the sink:
sink.Key(alg, key)
These keys are then retrieved and tried for each signature, until a match is found:
keys := sink.Keys() for key in keys { if givenSignature == makeSignature(key, payload, ...)) { return OK } }
type KeyProviderFunc ¶
KeyProviderFunc is a type of KeyProvider that is implemented by a single function. You can use this to create ad-hoc `KeyProvider` instances.
type KeySink ¶
type KeySink interface {
Key(jwa.SignatureAlgorithm, interface{})
}
KeySink is a data storage where `jws.KeyProvider` objects should send their keys to.
type Message ¶
type Message struct {
// contains filtered or unexported fields
}
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.
func NewMessage ¶
func NewMessage() *Message
func Parse ¶
func Parse(src []byte, options ...ParseOption) (*Message, error)
Parse parses contents from the given source and creates a jws.Message struct. By default the input can be in either compact or full JSON serialization.
You may pass `jws.WithJSON()` and/or `jws.WithCompact()` to specify explicitly which format to use. If neither or both is specified, the function will attempt to autodetect the format. If one or the other is specified, only the specified format will be attempted.
On error, returns a jws.ParseError.
func ParseReader ¶
ParseReader parses contents from the given source and creates a jws.Message struct. The input can be in either compact or full JSON serialization.
On error, returns a jws.ParseError.
func ParseString ¶
ParseString parses contents from the given source and creates a jws.Message struct. The input can be in either compact or full JSON serialization.
On error, returns a jws.ParseError.
func (*Message) AppendSignature ¶
func (*Message) ClearSignatures ¶
func (Message) LookupSignature ¶
LookupSignature looks up a particular signature entry using the `kid` value
func (Message) MarshalJSON ¶
func (*Message) SetDecodeCtx ¶
func (*Message) SetPayload ¶
func (Message) Signatures ¶
func (*Message) UnmarshalJSON ¶
type ParseOption ¶
type ParseOption interface { Option // contains filtered or unexported methods }
ReadFileOption is a type of `Option` that can be passed to `jwe.Parse`
type ReadFileOption ¶
type ReadFileOption interface { Option // contains filtered or unexported methods }
ReadFileOption is a type of `Option` that can be passed to `jws.ReadFile`
func WithFS ¶
func WithFS(v fs.FS) ReadFileOption
WithFS specifies the source `fs.FS` object to read the file from.
type SignOption ¶
type SignOption interface { Option // contains filtered or unexported methods }
SignOption describes options that can be passed to `jws.Sign`
func WithInsecureNoSignature ¶
func WithInsecureNoSignature(options ...WithKeySuboption) SignOption
WithInsecureNoSignature creates an option that allows the user to use the "none" signature algorithm.
Please note that this is insecure, and should never be used in production (this is exactly why specifying "none"/jwa.NoSignature to `jws.WithKey()` results in an error when `jws.Sign()` is called -- we do not allow using "none" by accident)
TODO: create specific suboption set for this option
type SignVerifyOption ¶
type SignVerifyOption interface { Option // contains filtered or unexported methods }
SignVerifyOption describes options that can be passed to either `jws.Verify` or `jws.Sign`
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.
func WithKey ¶
func WithKey(alg jwa.KeyAlgorithm, key interface{}, options ...WithKeySuboption) SignVerifyOption
WithKey is used to pass a static algorithm/key pair to either `jws.Sign()` or `jws.Verify()`.
The `alg` parameter is the identifier for the signature algorithm that should be used. It is of type `jwa.KeyAlgorithm` but in reality you can only pass `jwa.SignatureAlgorithm` types. It is this way so that the value in `(jwk.Key).Algorithm()` can be directly passed to the option. If you specify other algorithm types such as `jwa.KeyEncryptionAlgorithm`, then you will get an error when `jws.Sign()` or `jws.Verify()` is executed.
The `alg` parameter cannot be "none" (jwa.NoSignature) for security reasons. You will have to use a separate, more explicit option to allow the use of "none" algorithm (WithInsecureNoSignature).
The algorithm specified in the `alg` parameter MUST be able to support the type of key you provided, otherwise an error is returned.
Any of the following is accepted for the `key` parameter: * A "raw" key (e.g. rsa.PrivateKey, ecdsa.PrivateKey, etc) * A crypto.Signer * A jwk.Key
Note that due to technical reasons, this library is NOT able to differentiate between a valid/invalid key for given algorithm if the key implements crypto.Signer and the key is from an external library. For example, while we can tell that it is invalid to use `jwk.WithKey(jwa.RSA256, ecdsaPrivateKey)` because the key is presumably from `crypto/ecdsa` or this library, if you use a KMS wrapper that implements crypto.Signer that is outside of the go standard library or this library, we will not be able to properly catch the misuse of such keys -- the output will happily generate an ECDSA signature even in the presence of `jwa.RSA256`
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. You may consider using `github.com/jwx-go/crypto-signer` if you would like to use keys stored in GCP/AWS KMS services.
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.
`jws.WithKey()` can further accept suboptions to change signing behavior when used with `jws.Sign()`. `jws.WithProtected()` and `jws.WithPublic()` can be passed to specify JWS headers that should be used whe signing.
If the protected headers contain "b64" field, then the boolean value for the field is respected when serializing. That is, if you specify a header with `{"b64": false}`, then the payload is not base64 encoded.
These suboptions are ignored when the `jws.WithKey()` option is used with `jws.Verify()`.
func WithValidateKey ¶
func WithValidateKey(v bool) SignVerifyOption
WithValidateKey specifies whether the key used for signing or verification should be validated before using. Note that this means calling `key.Validate()` on the key, which in turn means that your key must be a `jwk.Key` instance, or a key that can be converted to a `jwk.Key` by calling `jwk.Import()`. This means that your custom hardware-backed keys will probably not work.
You can directly call `key.Validate()` yourself if you need to mix keys that cannot be converted to `jwk.Key`.
Please also note that use of this option will also result in one extra conversion of raw keys to a `jwk.Key` instance. If you care about shaving off as much as possible, consider using a pre-validated key instead of using this option to validate the key on-demand each time.
By default, the key is not validated.
type SignVerifyParseOption ¶
type SignVerifyParseOption interface { Option // contains filtered or unexported methods }
func WithCompact ¶
func WithCompact() SignVerifyParseOption
WithCompact specifies that the result of `jws.Sign()` is serialized in compact format.
By default `jws.Sign()` will opt to use compact format, so you usually do not need to specify this option other than to be explicit about it
func WithJSON ¶
func WithJSON(options ...WithJSONSuboption) SignVerifyParseOption
WithJSON specifies that the result of `jws.Sign()` is serialized in JSON format.
If you pass multiple keys to `jws.Sign()`, it will fail unless you also pass this option.
type Signature ¶
type Signature struct {
// contains filtered or unexported fields
}
func NewSignature ¶
func NewSignature() *Signature
func (Signature) ProtectedHeaders ¶
func (Signature) PublicHeaders ¶
func (*Signature) SetDecodeCtx ¶
func (*Signature) SetProtectedHeaders ¶
func (*Signature) SetPublicHeaders ¶
func (*Signature) SetSignature ¶
func (*Signature) Sign ¶
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) UnmarshalJSON ¶
type Signer ¶
type Signer interface { // Sign creates a signature for the given payload. // The second 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 }
Signer generates the signature for a given payload.
type SignerFactory ¶
type SignerFactoryFn ¶
func (SignerFactoryFn) Create ¶
func (fn SignerFactoryFn) Create() (Signer, 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 VerifierFactoryFn ¶
func (VerifierFactoryFn) Create ¶
func (fn VerifierFactoryFn) Create() (Verifier, error)
type VerifyOption ¶
type VerifyOption interface { Option // contains filtered or unexported methods }
VerifyOption describes options that can be passed to `jws.Verify`
func WithContext ¶
func WithContext(v context.Context) VerifyOption
func WithKeyProvider ¶
func WithKeyProvider(v KeyProvider) VerifyOption
func WithKeySet ¶
func WithKeySet(set jwk.Set, options ...WithKeySetSuboption) VerifyOption
WithKeySet specifies a JWKS (jwk.Set) to use for verification.
Because a JWKS can contain multiple keys and this library cannot tell which one of the keys should be used for verification, we by default require that both `alg` and `kid` fields in the JWS _and_ the key match before a key is considered to be used.
There are ways to override this behavior, but they must be explicitly specified by the caller.
To work with keys/JWS messages not having a `kid` field, you may specify the suboption `WithKeySetRequired` via `jws.WithKey(key, jws.WithRequireKid(false))`. This will allow the library to proceed without having to match the `kid` field.
However, it will still check if the `alg` fields in the JWS message and the key(s) match. If you must work with JWS messages that do not have an `alg` field, you will need to use `jws.WithKeySet(key, jws.WithInferAlgorithm(true))`.
See the documentation for `WithInferAlgorithm()` for more details.
func WithKeyUsed ¶
func WithKeyUsed(v interface{}) VerifyOption
WithKeyUsed allows you to specify the `jws.Verify()` function to return the key used for verification. This may be useful when you specify multiple key sources or if you pass a `jwk.Set` and you want to know which key was successful at verifying the signature.
`v` must be a pointer to an empty `interface{}`. Do not use `jwk.Key` here unless you are 100% sure that all keys that you have provided are instances of `jwk.Key` (remember that the jwx API allows users to specify a raw key such as *rsa.PublicKey)
func WithMessage ¶
func WithMessage(v *Message) VerifyOption
WithMessage can be passed to Verify() to obtain the jws.Message upon a successful verification.
func WithVerifyAuto ¶
func WithVerifyAuto(f jwk.Fetcher, options ...jwk.FetchOption) VerifyOption
WithVerifyAuto enables automatic verification of the signature using the JWKS specified in the `jku` header. Note that by default this option will _reject_ any jku provided by the JWS message. Read on for details.
The JWKS is retrieved by the `jwk.Fetcher` specified in the first argument. If the fetcher object is nil, the default fetcher, which is the `jwk.Fetch()` function (wrapped in the `jwk.FetchFunc` type) is used.
The remaining arguments are passed to the `(jwk.Fetcher).Fetch` method when the JWKS is retrieved.
jws.WithVerifyAuto(nil) // uses jwk.Fetch jws.WithVerifyAuto(jwk.NewCachedFetcher(...)) // uses cached fetcher jws.WithVerifyAuto(myFetcher) // use your custom fetcher
By default a whitelist that disallows all URLs is added to the options passed to the fetcher. You must explicitly specify a whitelist that allows the URLs you trust. This default behavior is provided because by design of the JWS specification it is the/ caller's responsibility to verify if the URL specified in the `jku` header can be trusted -- thus by default we trust nothing.
Users are free to specify an open whitelist if they so choose, but this must be explicitly done:
jws.WithVerifyAuto(nil, jwk.WithFetchWhitelist(jwk.InsecureWhitelist()))
You can also use `jwk.CachedFetcher` to use cached JWKS objects, but do note that this object is not really designed to accommodate a large set of arbitrary URLs. Use `jwk.CachedFetcher` as the first argument if you only have a small set of URLs that you trust. For anything more complex, you should implement your own `jwk.Fetcher` object.
type WithJSONSuboption ¶
type WithJSONSuboption interface { Option // contains filtered or unexported methods }
JSONSuboption describes suboptions that can be passed to the `jws.WithJSON()` option.
func WithPretty ¶
func WithPretty(v bool) WithJSONSuboption
WithPretty specifies whether the JSON output should be formatted and indented
type WithKeySetSuboption ¶
type WithKeySetSuboption interface { Option // contains filtered or unexported methods }
WithKeySetSuboption is a suboption passed to the `jws.WithKeySet()` option
func WithInferAlgorithmFromKey ¶
func WithInferAlgorithmFromKey(v bool) WithKeySetSuboption
WithInferAlgorithmFromKey specifies whether the JWS signing algorithm name should be inferred by looking at the provided key, in case the JWS message or the key does not have a proper `alg` header.
When this option is set to true, a list of algorithm(s) that is compatible with the key type will be enumerated, and _ALL_ of them will be tried against the key/message pair. If any of them succeeds, the verification will be considered successful.
Compared to providing explicit `alg` from the key this is slower, and verification may fail to verify if somehow our heuristics are wrong or outdated.
Also, automatic detection of signature verification methods are always more vulnerable for potential attack vectors.
It is highly recommended that you fix your key to contain a proper `alg` header field instead of resorting to using this option, but sometimes it just needs to happen.
func WithMultipleKeysPerKeyID ¶
func WithMultipleKeysPerKeyID(v bool) WithKeySetSuboption
WithMultipleKeysPerKeyID specifies if we should expect multiple keys to match against a key ID. By default it is assumed that key IDs are unique, i.e. for a given key ID, the key set only contains a single key that has the matching ID. When this option is set to true, multiple keys that match the same key ID in the set can be tried.
func WithRequireKid ¶
func WithRequireKid(v bool) WithKeySetSuboption
WithRequiredKid specifies whether the keys in the jwk.Set should only be matched if the target JWS message's Key ID and the Key ID in the given key matches.
func WithUseDefault ¶
func WithUseDefault(v bool) WithKeySetSuboption
WithUseDefault specifies that if and only if a jwk.Key contains exactly one jwk.Key, that key should be used.
type WithKeySuboption ¶
type WithKeySuboption interface { Option // contains filtered or unexported methods }
WithKeySuboption describes option types that can be passed to the `jws.WithKey()` option.
func WithProtectedHeaders ¶
func WithProtectedHeaders(v Headers) WithKeySuboption
WithProtected is used with `jws.WithKey()` option when used with `jws.Sign()` to specify a protected header to be attached to the JWS signature.
It has no effect if used when `jws.WithKey()` is passed to `jws.Verify()`
func WithPublicHeaders ¶
func WithPublicHeaders(v Headers) WithKeySuboption
WithPublic is used with `jws.WithKey()` option when used with `jws.Sign()` to specify a public header to be attached to the JWS signature.
It has no effect if used when `jws.WithKey()` is passed to `jws.Verify()`
`jws.Sign()` will result in an error if `jws.WithPublic()` is used and the serialization format is compact serialization.