99 lines
3.5 KiB
Go
99 lines
3.5 KiB
Go
package jws
|
|
|
|
import (
|
|
"github.com/lestrrat-go/iter/mapiter"
|
|
"github.com/lestrrat-go/jwx/internal/iter"
|
|
"github.com/lestrrat-go/jwx/jwa"
|
|
)
|
|
|
|
// 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 {
|
|
payload []byte
|
|
signatures []*Signature
|
|
b64 bool // true if payload should be base64 encoded
|
|
}
|
|
|
|
type Signature struct {
|
|
headers Headers // Unprotected Headers
|
|
protected Headers // Protected Headers
|
|
signature []byte // Signature
|
|
}
|
|
|
|
type Visitor = iter.MapVisitor
|
|
type VisitorFunc = iter.MapVisitorFunc
|
|
type HeaderPair = mapiter.Pair
|
|
type Iterator = mapiter.Iterator
|
|
|
|
// 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
|
|
}
|
|
|
|
type hmacSignFunc func([]byte, []byte) ([]byte, error)
|
|
|
|
// HMACSigner uses crypto/hmac to sign the payloads.
|
|
type HMACSigner struct {
|
|
alg jwa.SignatureAlgorithm
|
|
sign hmacSignFunc
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
type HMACVerifier struct {
|
|
signer Signer
|
|
}
|