summaryrefslogtreecommitdiff
path: root/vendor/gopkg.in/square/go-jose.v2
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gopkg.in/square/go-jose.v2')
-rw-r--r--vendor/gopkg.in/square/go-jose.v2/.gitignore1
-rw-r--r--vendor/gopkg.in/square/go-jose.v2/.travis.yml11
-rw-r--r--vendor/gopkg.in/square/go-jose.v2/asymmetric.go4
-rw-r--r--vendor/gopkg.in/square/go-jose.v2/cipher/ecdh_es.go28
-rw-r--r--vendor/gopkg.in/square/go-jose.v2/crypter.go14
-rw-r--r--vendor/gopkg.in/square/go-jose.v2/encoding.go14
-rw-r--r--vendor/gopkg.in/square/go-jose.v2/jwk.go174
-rw-r--r--vendor/gopkg.in/square/go-jose.v2/jws.go95
-rw-r--r--vendor/gopkg.in/square/go-jose.v2/opaque.go61
-rw-r--r--vendor/gopkg.in/square/go-jose.v2/shared.go21
-rw-r--r--vendor/gopkg.in/square/go-jose.v2/signing.go74
11 files changed, 432 insertions, 65 deletions
diff --git a/vendor/gopkg.in/square/go-jose.v2/.gitignore b/vendor/gopkg.in/square/go-jose.v2/.gitignore
index 5b4d73b68..95a851586 100644
--- a/vendor/gopkg.in/square/go-jose.v2/.gitignore
+++ b/vendor/gopkg.in/square/go-jose.v2/.gitignore
@@ -5,3 +5,4 @@
*.pem
*.cov
jose-util/jose-util
+jose-util.t.err \ No newline at end of file
diff --git a/vendor/gopkg.in/square/go-jose.v2/.travis.yml b/vendor/gopkg.in/square/go-jose.v2/.travis.yml
index fc501ca9b..ae69862df 100644
--- a/vendor/gopkg.in/square/go-jose.v2/.travis.yml
+++ b/vendor/gopkg.in/square/go-jose.v2/.travis.yml
@@ -8,11 +8,9 @@ matrix:
- go: tip
go:
-- '1.7.x'
-- '1.8.x'
-- '1.9.x'
-- '1.10.x'
- '1.11.x'
+- '1.12.x'
+- tip
go_import_path: gopkg.in/square/go-jose.v2
@@ -28,6 +26,8 @@ before_install:
- go get github.com/wadey/gocovmerge
- go get github.com/mattn/goveralls
- go get github.com/stretchr/testify/assert
+- go get github.com/stretchr/testify/require
+- go get github.com/google/go-cmp/cmp
- go get golang.org/x/tools/cmd/cover || true
- go get code.google.com/p/go.tools/cmd/cover || true
- pip install cram --user
@@ -37,10 +37,9 @@ script:
- go test ./cipher -v -covermode=count -coverprofile=cipher/profile.cov
- go test ./jwt -v -covermode=count -coverprofile=jwt/profile.cov
- go test ./json -v # no coverage for forked encoding/json package
-- cd jose-util && go build && PATH=$PWD:$PATH cram -v jose-util.t
+- cd jose-util && go build && PATH=$PWD:$PATH cram -v jose-util.t # cram tests jose-util
- cd ..
after_success:
- gocovmerge *.cov */*.cov > merged.coverprofile
- $HOME/gopath/bin/goveralls -coverprofile merged.coverprofile -service=travis-ci
-
diff --git a/vendor/gopkg.in/square/go-jose.v2/asymmetric.go b/vendor/gopkg.in/square/go-jose.v2/asymmetric.go
index 67935561b..b69aa0369 100644
--- a/vendor/gopkg.in/square/go-jose.v2/asymmetric.go
+++ b/vendor/gopkg.in/square/go-jose.v2/asymmetric.go
@@ -29,7 +29,7 @@ import (
"math/big"
"golang.org/x/crypto/ed25519"
- "gopkg.in/square/go-jose.v2/cipher"
+ josecipher "gopkg.in/square/go-jose.v2/cipher"
"gopkg.in/square/go-jose.v2/json"
)
@@ -288,7 +288,7 @@ func (ctx rsaDecrypterSigner) signPayload(payload []byte, alg SignatureAlgorithm
out, err = rsa.SignPKCS1v15(RandReader, ctx.privateKey, hash, hashed)
case PS256, PS384, PS512:
out, err = rsa.SignPSS(RandReader, ctx.privateKey, hash, hashed, &rsa.PSSOptions{
- SaltLength: rsa.PSSSaltLengthAuto,
+ SaltLength: rsa.PSSSaltLengthEqualsHash,
})
}
diff --git a/vendor/gopkg.in/square/go-jose.v2/cipher/ecdh_es.go b/vendor/gopkg.in/square/go-jose.v2/cipher/ecdh_es.go
index c128e327f..093c64674 100644
--- a/vendor/gopkg.in/square/go-jose.v2/cipher/ecdh_es.go
+++ b/vendor/gopkg.in/square/go-jose.v2/cipher/ecdh_es.go
@@ -17,8 +17,10 @@
package josecipher
import (
+ "bytes"
"crypto"
"crypto/ecdsa"
+ "crypto/elliptic"
"encoding/binary"
)
@@ -44,16 +46,38 @@ func DeriveECDHES(alg string, apuData, apvData []byte, priv *ecdsa.PrivateKey, p
panic("public key not on same curve as private key")
}
- z, _ := priv.PublicKey.Curve.ScalarMult(pub.X, pub.Y, priv.D.Bytes())
- reader := NewConcatKDF(crypto.SHA256, z.Bytes(), algID, ptyUInfo, ptyVInfo, supPubInfo, []byte{})
+ z, _ := priv.Curve.ScalarMult(pub.X, pub.Y, priv.D.Bytes())
+ zBytes := z.Bytes()
+ // Note that calling z.Bytes() on a big.Int may strip leading zero bytes from
+ // the returned byte array. This can lead to a problem where zBytes will be
+ // shorter than expected which breaks the key derivation. Therefore we must pad
+ // to the full length of the expected coordinate here before calling the KDF.
+ octSize := dSize(priv.Curve)
+ if len(zBytes) != octSize {
+ zBytes = append(bytes.Repeat([]byte{0}, octSize-len(zBytes)), zBytes...)
+ }
+
+ reader := NewConcatKDF(crypto.SHA256, zBytes, algID, ptyUInfo, ptyVInfo, supPubInfo, []byte{})
key := make([]byte, size)
// Read on the KDF will never fail
_, _ = reader.Read(key)
+
return key
}
+// dSize returns the size in octets for a coordinate on a elliptic curve.
+func dSize(curve elliptic.Curve) int {
+ order := curve.Params().P
+ bitLen := order.BitLen()
+ size := bitLen / 8
+ if bitLen%8 != 0 {
+ size++
+ }
+ return size
+}
+
func lengthPrefixed(data []byte) []byte {
out := make([]byte, len(data)+4)
binary.BigEndian.PutUint32(out, uint32(len(data)))
diff --git a/vendor/gopkg.in/square/go-jose.v2/crypter.go b/vendor/gopkg.in/square/go-jose.v2/crypter.go
index c45c71206..d24cabf6b 100644
--- a/vendor/gopkg.in/square/go-jose.v2/crypter.go
+++ b/vendor/gopkg.in/square/go-jose.v2/crypter.go
@@ -141,6 +141,8 @@ func NewEncrypter(enc ContentEncryption, rcpt Recipient, opts *EncrypterOptions)
keyID, rawKey = encryptionKey.KeyID, encryptionKey.Key
case *JSONWebKey:
keyID, rawKey = encryptionKey.KeyID, encryptionKey.Key
+ case OpaqueKeyEncrypter:
+ keyID, rawKey = encryptionKey.KeyID(), encryptionKey
default:
rawKey = encryptionKey
}
@@ -267,9 +269,11 @@ func makeJWERecipient(alg KeyAlgorithm, encryptionKey interface{}) (recipientKey
recipient, err := makeJWERecipient(alg, encryptionKey.Key)
recipient.keyID = encryptionKey.KeyID
return recipient, err
- default:
- return recipientKeyInfo{}, ErrUnsupportedKeyType
}
+ if encrypter, ok := encryptionKey.(OpaqueKeyEncrypter); ok {
+ return newOpaqueKeyEncrypter(alg, encrypter)
+ }
+ return recipientKeyInfo{}, ErrUnsupportedKeyType
}
// newDecrypter creates an appropriate decrypter based on the key type
@@ -295,9 +299,11 @@ func newDecrypter(decryptionKey interface{}) (keyDecrypter, error) {
return newDecrypter(decryptionKey.Key)
case *JSONWebKey:
return newDecrypter(decryptionKey.Key)
- default:
- return nil, ErrUnsupportedKeyType
}
+ if okd, ok := decryptionKey.(OpaqueKeyDecrypter); ok {
+ return &opaqueKeyDecrypter{decrypter: okd}, nil
+ }
+ return nil, ErrUnsupportedKeyType
}
// Implementation of encrypt method producing a JWE object.
diff --git a/vendor/gopkg.in/square/go-jose.v2/encoding.go b/vendor/gopkg.in/square/go-jose.v2/encoding.go
index b9687c647..70f7385c4 100644
--- a/vendor/gopkg.in/square/go-jose.v2/encoding.go
+++ b/vendor/gopkg.in/square/go-jose.v2/encoding.go
@@ -23,13 +23,12 @@ import (
"encoding/binary"
"io"
"math/big"
- "regexp"
+ "strings"
+ "unicode"
"gopkg.in/square/go-jose.v2/json"
)
-var stripWhitespaceRegex = regexp.MustCompile("\\s")
-
// Helper function to serialize known-good objects.
// Precondition: value is not a nil pointer.
func mustSerializeJSON(value interface{}) []byte {
@@ -56,7 +55,14 @@ func mustSerializeJSON(value interface{}) []byte {
// Strip all newlines and whitespace
func stripWhitespace(data string) string {
- return stripWhitespaceRegex.ReplaceAllString(data, "")
+ buf := strings.Builder{}
+ buf.Grow(len(data))
+ for _, r := range data {
+ if !unicode.IsSpace(r) {
+ buf.WriteRune(r)
+ }
+ }
+ return buf.String()
}
// Perform compression based on algorithm
diff --git a/vendor/gopkg.in/square/go-jose.v2/jwk.go b/vendor/gopkg.in/square/go-jose.v2/jwk.go
index 6cb8adb84..2dc6aec4b 100644
--- a/vendor/gopkg.in/square/go-jose.v2/jwk.go
+++ b/vendor/gopkg.in/square/go-jose.v2/jwk.go
@@ -17,15 +17,20 @@
package jose
import (
+ "bytes"
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rsa"
+ "crypto/sha1"
+ "crypto/sha256"
"crypto/x509"
"encoding/base64"
+ "encoding/hex"
"errors"
"fmt"
"math/big"
+ "net/url"
"reflect"
"strings"
@@ -57,16 +62,31 @@ type rawJSONWebKey struct {
Dq *byteBuffer `json:"dq,omitempty"`
Qi *byteBuffer `json:"qi,omitempty"`
// Certificates
- X5c []string `json:"x5c,omitempty"`
+ X5c []string `json:"x5c,omitempty"`
+ X5u *url.URL `json:"x5u,omitempty"`
+ X5tSHA1 string `json:"x5t,omitempty"`
+ X5tSHA256 string `json:"x5t#S256,omitempty"`
}
// JSONWebKey represents a public or private key in JWK format.
type JSONWebKey struct {
- Key interface{}
+ // Cryptographic key, can be a symmetric or asymmetric key.
+ Key interface{}
+ // Key identifier, parsed from `kid` header.
+ KeyID string
+ // Key algorithm, parsed from `alg` header.
+ Algorithm string
+ // Key use, parsed from `use` header.
+ Use string
+
+ // X.509 certificate chain, parsed from `x5c` header.
Certificates []*x509.Certificate
- KeyID string
- Algorithm string
- Use string
+ // X.509 certificate URL, parsed from `x5u` header.
+ CertificatesURL *url.URL
+ // X.509 certificate thumbprint (SHA-1), parsed from `x5t` header.
+ CertificateThumbprintSHA1 []byte
+ // X.509 certificate thumbprint (SHA-256), parsed from `x5t#S256` header.
+ CertificateThumbprintSHA256 []byte
}
// MarshalJSON serializes the given key to its JSON representation.
@@ -105,6 +125,39 @@ func (k JSONWebKey) MarshalJSON() ([]byte, error) {
raw.X5c = append(raw.X5c, base64.StdEncoding.EncodeToString(cert.Raw))
}
+ x5tSHA1Len := len(k.CertificateThumbprintSHA1)
+ x5tSHA256Len := len(k.CertificateThumbprintSHA256)
+ if x5tSHA1Len > 0 {
+ if x5tSHA1Len != sha1.Size {
+ return nil, fmt.Errorf("square/go-jose: invalid SHA-1 thumbprint (must be %d bytes, not %d)", sha1.Size, x5tSHA1Len)
+ }
+ raw.X5tSHA1 = base64.RawURLEncoding.EncodeToString(k.CertificateThumbprintSHA1)
+ }
+ if x5tSHA256Len > 0 {
+ if x5tSHA256Len != sha256.Size {
+ return nil, fmt.Errorf("square/go-jose: invalid SHA-256 thumbprint (must be %d bytes, not %d)", sha256.Size, x5tSHA256Len)
+ }
+ raw.X5tSHA256 = base64.RawURLEncoding.EncodeToString(k.CertificateThumbprintSHA256)
+ }
+
+ // If cert chain is attached (as opposed to being behind a URL), check the
+ // keys thumbprints to make sure they match what is expected. This is to
+ // ensure we don't accidentally produce a JWK with semantically inconsistent
+ // data in the headers.
+ if len(k.Certificates) > 0 {
+ expectedSHA1 := sha1.Sum(k.Certificates[0].Raw)
+ expectedSHA256 := sha256.Sum256(k.Certificates[0].Raw)
+
+ if len(k.CertificateThumbprintSHA1) > 0 && !bytes.Equal(k.CertificateThumbprintSHA1, expectedSHA1[:]) {
+ return nil, errors.New("square/go-jose: invalid SHA-1 thumbprint, does not match cert chain")
+ }
+ if len(k.CertificateThumbprintSHA256) > 0 && !bytes.Equal(k.CertificateThumbprintSHA256, expectedSHA256[:]) {
+ return nil, errors.New("square/go-jose: invalid or SHA-256 thumbprint, does not match cert chain")
+ }
+ }
+
+ raw.X5u = k.CertificatesURL
+
return json.Marshal(raw)
}
@@ -116,28 +169,61 @@ func (k *JSONWebKey) UnmarshalJSON(data []byte) (err error) {
return err
}
+ certs, err := parseCertificateChain(raw.X5c)
+ if err != nil {
+ return fmt.Errorf("square/go-jose: failed to unmarshal x5c field: %s", err)
+ }
+
var key interface{}
+ var certPub interface{}
+ var keyPub interface{}
+
+ if len(certs) > 0 {
+ // We need to check that leaf public key matches the key embedded in this
+ // JWK, as required by the standard (see RFC 7517, Section 4.7). Otherwise
+ // the JWK parsed could be semantically invalid. Technically, should also
+ // check key usage fields and other extensions on the cert here, but the
+ // standard doesn't exactly explain how they're supposed to map from the
+ // JWK representation to the X.509 extensions.
+ certPub = certs[0].PublicKey
+ }
+
switch raw.Kty {
case "EC":
if raw.D != nil {
key, err = raw.ecPrivateKey()
+ if err == nil {
+ keyPub = key.(*ecdsa.PrivateKey).Public()
+ }
} else {
key, err = raw.ecPublicKey()
+ keyPub = key
}
case "RSA":
if raw.D != nil {
key, err = raw.rsaPrivateKey()
+ if err == nil {
+ keyPub = key.(*rsa.PrivateKey).Public()
+ }
} else {
key, err = raw.rsaPublicKey()
+ keyPub = key
}
case "oct":
+ if certPub != nil {
+ return errors.New("square/go-jose: invalid JWK, found 'oct' (symmetric) key with cert chain")
+ }
key, err = raw.symmetricKey()
case "OKP":
if raw.Crv == "Ed25519" && raw.X != nil {
if raw.D != nil {
key, err = raw.edPrivateKey()
+ if err == nil {
+ keyPub = key.(ed25519.PrivateKey).Public()
+ }
} else {
key, err = raw.edPublicKey()
+ keyPub = key
}
} else {
err = fmt.Errorf("square/go-jose: unknown curve %s'", raw.Crv)
@@ -146,12 +232,78 @@ func (k *JSONWebKey) UnmarshalJSON(data []byte) (err error) {
err = fmt.Errorf("square/go-jose: unknown json web key type '%s'", raw.Kty)
}
- if err == nil {
- *k = JSONWebKey{Key: key, KeyID: raw.Kid, Algorithm: raw.Alg, Use: raw.Use}
+ if err != nil {
+ return
+ }
+
+ if certPub != nil && keyPub != nil {
+ if !reflect.DeepEqual(certPub, keyPub) {
+ return errors.New("square/go-jose: invalid JWK, public keys in key and x5c fields to not match")
+ }
+ }
+
+ *k = JSONWebKey{Key: key, KeyID: raw.Kid, Algorithm: raw.Alg, Use: raw.Use, Certificates: certs}
- k.Certificates, err = parseCertificateChain(raw.X5c)
+ k.CertificatesURL = raw.X5u
+
+ // x5t parameters are base64url-encoded SHA thumbprints
+ // See RFC 7517, Section 4.8, https://tools.ietf.org/html/rfc7517#section-4.8
+ x5tSHA1bytes, err := base64.RawURLEncoding.DecodeString(raw.X5tSHA1)
+ if err != nil {
+ return errors.New("square/go-jose: invalid JWK, x5t header has invalid encoding")
+ }
+
+ // RFC 7517, Section 4.8 is ambiguous as to whether the digest output should be byte or hex,
+ // for this reason, after base64 decoding, if the size is sha1.Size it's likely that the value is a byte encoded
+ // checksum so we skip this. Otherwise if the checksum was hex encoded we expect a 40 byte sized array so we'll
+ // try to hex decode it. When Marshalling this value we'll always use a base64 encoded version of byte format checksum.
+ if len(x5tSHA1bytes) == 2*sha1.Size {
+ hx, err := hex.DecodeString(string(x5tSHA1bytes))
+ if err != nil {
+ return fmt.Errorf("square/go-jose: invalid JWK, unable to hex decode x5t: %v", err)
+
+ }
+ x5tSHA1bytes = hx
+ }
+
+ k.CertificateThumbprintSHA1 = x5tSHA1bytes
+
+ x5tSHA256bytes, err := base64.RawURLEncoding.DecodeString(raw.X5tSHA256)
+ if err != nil {
+ return errors.New("square/go-jose: invalid JWK, x5t#S256 header has invalid encoding")
+ }
+
+ if len(x5tSHA256bytes) == 2*sha256.Size {
+ hx256, err := hex.DecodeString(string(x5tSHA256bytes))
if err != nil {
- return fmt.Errorf("failed to unmarshal x5c field: %s", err)
+ return fmt.Errorf("square/go-jose: invalid JWK, unable to hex decode x5t#S256: %v", err)
+ }
+ x5tSHA256bytes = hx256
+ }
+
+ k.CertificateThumbprintSHA256 = x5tSHA256bytes
+
+ x5tSHA1Len := len(k.CertificateThumbprintSHA1)
+ x5tSHA256Len := len(k.CertificateThumbprintSHA256)
+ if x5tSHA1Len > 0 && x5tSHA1Len != sha1.Size {
+ return errors.New("square/go-jose: invalid JWK, x5t header is of incorrect size")
+ }
+ if x5tSHA256Len > 0 && x5tSHA256Len != sha256.Size {
+ return errors.New("square/go-jose: invalid JWK, x5t#S256 header is of incorrect size")
+ }
+
+ // If certificate chain *and* thumbprints are set, verify correctness.
+ if len(k.Certificates) > 0 {
+ leaf := k.Certificates[0]
+ sha1sum := sha1.Sum(leaf.Raw)
+ sha256sum := sha256.Sum256(leaf.Raw)
+
+ if len(k.CertificateThumbprintSHA1) > 0 && !bytes.Equal(sha1sum[:], k.CertificateThumbprintSHA1) {
+ return errors.New("square/go-jose: invalid JWK, x5c thumbprint does not match x5t value")
+ }
+
+ if len(k.CertificateThumbprintSHA256) > 0 && !bytes.Equal(sha256sum[:], k.CertificateThumbprintSHA256) {
+ return errors.New("square/go-jose: invalid JWK, x5c thumbprint does not match x5t#S256 value")
}
}
@@ -357,11 +509,11 @@ func (key rawJSONWebKey) ecPublicKey() (*ecdsa.PublicKey, error) {
// the curve specified in the "crv" parameter.
// https://tools.ietf.org/html/rfc7518#section-6.2.1.2
if curveSize(curve) != len(key.X.data) {
- return nil, fmt.Errorf("square/go-jose: invalid EC private key, wrong length for x")
+ return nil, fmt.Errorf("square/go-jose: invalid EC public key, wrong length for x")
}
if curveSize(curve) != len(key.Y.data) {
- return nil, fmt.Errorf("square/go-jose: invalid EC private key, wrong length for y")
+ return nil, fmt.Errorf("square/go-jose: invalid EC public key, wrong length for y")
}
x := key.X.bigInt()
diff --git a/vendor/gopkg.in/square/go-jose.v2/jws.go b/vendor/gopkg.in/square/go-jose.v2/jws.go
index 8b59b6ab2..7e261f937 100644
--- a/vendor/gopkg.in/square/go-jose.v2/jws.go
+++ b/vendor/gopkg.in/square/go-jose.v2/jws.go
@@ -17,6 +17,7 @@
package jose
import (
+ "bytes"
"encoding/base64"
"errors"
"fmt"
@@ -75,13 +76,21 @@ type Signature struct {
}
// ParseSigned parses a signed message in compact or full serialization format.
-func ParseSigned(input string) (*JSONWebSignature, error) {
- input = stripWhitespace(input)
- if strings.HasPrefix(input, "{") {
- return parseSignedFull(input)
+func ParseSigned(signature string) (*JSONWebSignature, error) {
+ signature = stripWhitespace(signature)
+ if strings.HasPrefix(signature, "{") {
+ return parseSignedFull(signature)
}
- return parseSignedCompact(input)
+ return parseSignedCompact(signature, nil)
+}
+
+// ParseDetached parses a signed message in compact serialization format with detached payload.
+func ParseDetached(signature string, payload []byte) (*JSONWebSignature, error) {
+ if payload == nil {
+ return nil, errors.New("square/go-jose: nil payload")
+ }
+ return parseSignedCompact(stripWhitespace(signature), payload)
}
// Get a header value
@@ -93,20 +102,39 @@ func (sig Signature) mergedHeaders() rawHeader {
}
// Compute data to be signed
-func (obj JSONWebSignature) computeAuthData(payload []byte, signature *Signature) []byte {
- var serializedProtected string
+func (obj JSONWebSignature) computeAuthData(payload []byte, signature *Signature) ([]byte, error) {
+ var authData bytes.Buffer
+
+ protectedHeader := new(rawHeader)
if signature.original != nil && signature.original.Protected != nil {
- serializedProtected = signature.original.Protected.base64()
+ if err := json.Unmarshal(signature.original.Protected.bytes(), protectedHeader); err != nil {
+ return nil, err
+ }
+ authData.WriteString(signature.original.Protected.base64())
} else if signature.protected != nil {
- serializedProtected = base64.RawURLEncoding.EncodeToString(mustSerializeJSON(signature.protected))
+ protectedHeader = signature.protected
+ authData.WriteString(base64.RawURLEncoding.EncodeToString(mustSerializeJSON(protectedHeader)))
+ }
+
+ needsBase64 := true
+
+ if protectedHeader != nil {
+ var err error
+ if needsBase64, err = protectedHeader.getB64(); err != nil {
+ needsBase64 = true
+ }
+ }
+
+ authData.WriteByte('.')
+
+ if needsBase64 {
+ authData.WriteString(base64.RawURLEncoding.EncodeToString(payload))
} else {
- serializedProtected = ""
+ authData.Write(payload)
}
- return []byte(fmt.Sprintf("%s.%s",
- serializedProtected,
- base64.RawURLEncoding.EncodeToString(payload)))
+ return authData.Bytes(), nil
}
// parseSignedFull parses a message in full format.
@@ -246,20 +274,26 @@ func (parsed *rawJSONWebSignature) sanitized() (*JSONWebSignature, error) {
}
// parseSignedCompact parses a message in compact format.
-func parseSignedCompact(input string) (*JSONWebSignature, error) {
+func parseSignedCompact(input string, payload []byte) (*JSONWebSignature, error) {
parts := strings.Split(input, ".")
if len(parts) != 3 {
return nil, fmt.Errorf("square/go-jose: compact JWS format must have three parts")
}
+ if parts[1] != "" && payload != nil {
+ return nil, fmt.Errorf("square/go-jose: payload is not detached")
+ }
+
rawProtected, err := base64.RawURLEncoding.DecodeString(parts[0])
if err != nil {
return nil, err
}
- payload, err := base64.RawURLEncoding.DecodeString(parts[1])
- if err != nil {
- return nil, err
+ if payload == nil {
+ payload, err = base64.RawURLEncoding.DecodeString(parts[1])
+ if err != nil {
+ return nil, err
+ }
}
signature, err := base64.RawURLEncoding.DecodeString(parts[2])
@@ -275,19 +309,30 @@ func parseSignedCompact(input string) (*JSONWebSignature, error) {
return raw.sanitized()
}
-// CompactSerialize serializes an object using the compact serialization format.
-func (obj JSONWebSignature) CompactSerialize() (string, error) {
+func (obj JSONWebSignature) compactSerialize(detached bool) (string, error) {
if len(obj.Signatures) != 1 || obj.Signatures[0].header != nil || obj.Signatures[0].protected == nil {
return "", ErrNotSupported
}
- serializedProtected := mustSerializeJSON(obj.Signatures[0].protected)
+ serializedProtected := base64.RawURLEncoding.EncodeToString(mustSerializeJSON(obj.Signatures[0].protected))
+ payload := ""
+ signature := base64.RawURLEncoding.EncodeToString(obj.Signatures[0].Signature)
+
+ if !detached {
+ payload = base64.RawURLEncoding.EncodeToString(obj.payload)
+ }
+
+ return fmt.Sprintf("%s.%s.%s", serializedProtected, payload, signature), nil
+}
+
+// CompactSerialize serializes an object using the compact serialization format.
+func (obj JSONWebSignature) CompactSerialize() (string, error) {
+ return obj.compactSerialize(false)
+}
- return fmt.Sprintf(
- "%s.%s.%s",
- base64.RawURLEncoding.EncodeToString(serializedProtected),
- base64.RawURLEncoding.EncodeToString(obj.payload),
- base64.RawURLEncoding.EncodeToString(obj.Signatures[0].Signature)), nil
+// DetachedCompactSerialize serializes an object using the compact serialization format with detached payload.
+func (obj JSONWebSignature) DetachedCompactSerialize() (string, error) {
+ return obj.compactSerialize(true)
}
// FullSerialize serializes an object using the full JSON serialization format.
diff --git a/vendor/gopkg.in/square/go-jose.v2/opaque.go b/vendor/gopkg.in/square/go-jose.v2/opaque.go
index 4a8bd8f32..df747f992 100644
--- a/vendor/gopkg.in/square/go-jose.v2/opaque.go
+++ b/vendor/gopkg.in/square/go-jose.v2/opaque.go
@@ -81,3 +81,64 @@ type opaqueVerifier struct {
func (o *opaqueVerifier) verifyPayload(payload []byte, signature []byte, alg SignatureAlgorithm) error {
return o.verifier.VerifyPayload(payload, signature, alg)
}
+
+// OpaqueKeyEncrypter is an interface that supports encrypting keys with an opaque key.
+type OpaqueKeyEncrypter interface {
+ // KeyID returns the kid
+ KeyID() string
+ // Algs returns a list of supported key encryption algorithms.
+ Algs() []KeyAlgorithm
+ // encryptKey encrypts the CEK using the given algorithm.
+ encryptKey(cek []byte, alg KeyAlgorithm) (recipientInfo, error)
+}
+
+type opaqueKeyEncrypter struct {
+ encrypter OpaqueKeyEncrypter
+}
+
+func newOpaqueKeyEncrypter(alg KeyAlgorithm, encrypter OpaqueKeyEncrypter) (recipientKeyInfo, error) {
+ var algSupported bool
+ for _, salg := range encrypter.Algs() {
+ if alg == salg {
+ algSupported = true
+ break
+ }
+ }
+ if !algSupported {
+ return recipientKeyInfo{}, ErrUnsupportedAlgorithm
+ }
+
+ return recipientKeyInfo{
+ keyID: encrypter.KeyID(),
+ keyAlg: alg,
+ keyEncrypter: &opaqueKeyEncrypter{
+ encrypter: encrypter,
+ },
+ }, nil
+}
+
+func (oke *opaqueKeyEncrypter) encryptKey(cek []byte, alg KeyAlgorithm) (recipientInfo, error) {
+ return oke.encrypter.encryptKey(cek, alg)
+}
+
+//OpaqueKeyDecrypter is an interface that supports decrypting keys with an opaque key.
+type OpaqueKeyDecrypter interface {
+ DecryptKey(encryptedKey []byte, header Header) ([]byte, error)
+}
+
+type opaqueKeyDecrypter struct {
+ decrypter OpaqueKeyDecrypter
+}
+
+func (okd *opaqueKeyDecrypter) decryptKey(headers rawHeader, recipient *recipientInfo, generator keyGenerator) ([]byte, error) {
+ mergedHeaders := rawHeader{}
+ mergedHeaders.merge(&headers)
+ mergedHeaders.merge(recipient.header)
+
+ header, err := mergedHeaders.sanitized()
+ if err != nil {
+ return nil, err
+ }
+
+ return okd.decrypter.DecryptKey(recipient.encryptedKey, header)
+}
diff --git a/vendor/gopkg.in/square/go-jose.v2/shared.go b/vendor/gopkg.in/square/go-jose.v2/shared.go
index b0a6255ec..f8438641f 100644
--- a/vendor/gopkg.in/square/go-jose.v2/shared.go
+++ b/vendor/gopkg.in/square/go-jose.v2/shared.go
@@ -153,12 +153,18 @@ const (
headerJWK = "jwk" // *JSONWebKey
headerKeyID = "kid" // string
headerNonce = "nonce" // string
+ headerB64 = "b64" // bool
headerP2C = "p2c" // *byteBuffer (int)
headerP2S = "p2s" // *byteBuffer ([]byte)
)
+// supportedCritical is the set of supported extensions that are understood and processed.
+var supportedCritical = map[string]bool{
+ headerB64: true,
+}
+
// rawHeader represents the JOSE header for JWE/JWS objects (used for parsing).
//
// The decoding of the constituent items is deferred because we want to marshal
@@ -349,6 +355,21 @@ func (parsed rawHeader) getP2S() (*byteBuffer, error) {
return parsed.getByteBuffer(headerP2S)
}
+// getB64 extracts parsed "b64" from the raw JSON, defaulting to true.
+func (parsed rawHeader) getB64() (bool, error) {
+ v := parsed[headerB64]
+ if v == nil {
+ return true, nil
+ }
+
+ var b64 bool
+ err := json.Unmarshal(*v, &b64)
+ if err != nil {
+ return true, err
+ }
+ return b64, nil
+}
+
// sanitized produces a cleaned-up header object from the raw JSON.
func (parsed rawHeader) sanitized() (h Header, err error) {
for k, v := range parsed {
diff --git a/vendor/gopkg.in/square/go-jose.v2/signing.go b/vendor/gopkg.in/square/go-jose.v2/signing.go
index be6cf0481..bad820cea 100644
--- a/vendor/gopkg.in/square/go-jose.v2/signing.go
+++ b/vendor/gopkg.in/square/go-jose.v2/signing.go
@@ -17,6 +17,7 @@
package jose
import (
+ "bytes"
"crypto/ecdsa"
"crypto/rsa"
"encoding/base64"
@@ -77,6 +78,27 @@ func (so *SignerOptions) WithType(typ ContentType) *SignerOptions {
return so.WithHeader(HeaderType, typ)
}
+// WithCritical adds the given names to the critical ("crit") header and returns
+// the updated SignerOptions.
+func (so *SignerOptions) WithCritical(names ...string) *SignerOptions {
+ if so.ExtraHeaders[headerCritical] == nil {
+ so.WithHeader(headerCritical, make([]string, 0, len(names)))
+ }
+ crit := so.ExtraHeaders[headerCritical].([]string)
+ so.ExtraHeaders[headerCritical] = append(crit, names...)
+ return so
+}
+
+// WithBase64 adds a base64url-encode payload ("b64") header and returns the updated
+// SignerOptions. When the "b64" value is "false", the payload is not base64 encoded.
+func (so *SignerOptions) WithBase64(b64 bool) *SignerOptions {
+ if !b64 {
+ so.WithHeader(headerB64, b64)
+ so.WithCritical(headerB64)
+ }
+ return so
+}
+
type payloadSigner interface {
signPayload(payload []byte, alg SignatureAlgorithm) (Signature, error)
}
@@ -233,7 +255,10 @@ func (ctx *genericSigner) Sign(payload []byte) (*JSONWebSignature, error) {
if ctx.embedJWK {
protected[headerJWK] = recipient.publicKey()
} else {
- protected[headerKeyID] = recipient.publicKey().KeyID
+ keyID := recipient.publicKey().KeyID
+ if keyID != "" {
+ protected[headerKeyID] = keyID
+ }
}
}
@@ -250,12 +275,26 @@ func (ctx *genericSigner) Sign(payload []byte) (*JSONWebSignature, error) {
}
serializedProtected := mustSerializeJSON(protected)
+ needsBase64 := true
+
+ if b64, ok := protected[headerB64]; ok {
+ if needsBase64, ok = b64.(bool); !ok {
+ return nil, errors.New("square/go-jose: Invalid b64 header parameter")
+ }
+ }
+
+ var input bytes.Buffer
- input := []byte(fmt.Sprintf("%s.%s",
- base64.RawURLEncoding.EncodeToString(serializedProtected),
- base64.RawURLEncoding.EncodeToString(payload)))
+ input.WriteString(base64.RawURLEncoding.EncodeToString(serializedProtected))
+ input.WriteByte('.')
- signatureInfo, err := recipient.signer.signPayload(input, recipient.sigAlg)
+ if needsBase64 {
+ input.WriteString(base64.RawURLEncoding.EncodeToString(payload))
+ } else {
+ input.Write(payload)
+ }
+
+ signatureInfo, err := recipient.signer.signPayload(input.Bytes(), recipient.sigAlg)
if err != nil {
return nil, err
}
@@ -324,12 +363,18 @@ func (obj JSONWebSignature) DetachedVerify(payload []byte, verificationKey inter
if err != nil {
return err
}
- if len(critical) > 0 {
- // Unsupported crit header
+
+ for _, name := range critical {
+ if !supportedCritical[name] {
+ return ErrCryptoFailure
+ }
+ }
+
+ input, err := obj.computeAuthData(payload, &signature)
+ if err != nil {
return ErrCryptoFailure
}
- input := obj.computeAuthData(payload, &signature)
alg := headers.getSignatureAlgorithm()
err = verifier.verifyPayload(input, signature.Signature, alg)
if err == nil {
@@ -366,18 +411,25 @@ func (obj JSONWebSignature) DetachedVerifyMulti(payload []byte, verificationKey
return -1, Signature{}, err
}
+outer:
for i, signature := range obj.Signatures {
headers := signature.mergedHeaders()
critical, err := headers.getCritical()
if err != nil {
continue
}
- if len(critical) > 0 {
- // Unsupported crit header
+
+ for _, name := range critical {
+ if !supportedCritical[name] {
+ continue outer
+ }
+ }
+
+ input, err := obj.computeAuthData(payload, &signature)
+ if err != nil {
continue
}
- input := obj.computeAuthData(payload, &signature)
alg := headers.getSignatureAlgorithm()
err = verifier.verifyPayload(input, signature.Signature, alg)
if err == nil {