diff --git a/vendor.mod b/vendor.mod index 4f0c4a591e..9e66de5331 100644 --- a/vendor.mod +++ b/vendor.mod @@ -25,7 +25,7 @@ require ( github.com/docker/go-connections v0.8.2 github.com/docker/go-units v0.5.0 github.com/fvbommel/sortorder v1.2.1 - github.com/go-jose/go-jose/v4 v4.1.6 + github.com/go-jose/go-jose/v4 v4.1.7 github.com/go-viper/mapstructure/v2 v2.5.0 github.com/gogo/protobuf v1.3.2 github.com/google/go-cmp v0.7.0 diff --git a/vendor.sum b/vendor.sum index c7b926adbe..11995f98bb 100644 --- a/vendor.sum +++ b/vendor.sum @@ -51,8 +51,8 @@ github.com/felixge/httpsnoop v1.1.0 h1:3YtUj32ZZkqZtt3sZZsClsymw/QDuVfpNhoA31zeO github.com/felixge/httpsnoop v1.1.0/go.mod h1:Zqxgdd+1Rkcz8euOqdr7lqgCRJztwr5hp9vDSi5UZCE= github.com/fvbommel/sortorder v1.2.1 h1:ASc85RbthwLEqzuiCk7WQQiopfyGWQiEYZVJ3Qa4A+U= github.com/fvbommel/sortorder v1.2.1/go.mod h1:LbhO04ijZIeUuvz9B9BkI/qYrpZZEn1gWhxv4QjUKVs= -github.com/go-jose/go-jose/v4 v4.1.6 h1:sNRkftxFJxwsILiQukqp5z83QBSmntVwmgRY7AqBDO4= -github.com/go-jose/go-jose/v4 v4.1.6/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= +github.com/go-jose/go-jose/v4 v4.1.7 h1:Nac/98uT5LPkfbiFuYa8ktf62a2VxwQ4xbq1GK8pV5E= +github.com/go-jose/go-jose/v4 v4.1.7/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8= github.com/go-logr/logr v1.4.4/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= diff --git a/vendor/github.com/go-jose/go-jose/v4/crypter.go b/vendor/github.com/go-jose/go-jose/v4/crypter.go index 53636c57b3..c766539115 100644 --- a/vendor/github.com/go-jose/go-jose/v4/crypter.go +++ b/vendor/github.com/go-jose/go-jose/v4/crypter.go @@ -408,7 +408,10 @@ func (ctx *genericEncrypter) EncryptWithAuthData(plaintext, aad []byte) (*JSONWe (*obj.protected)[k] = makeRawMessage(b) } - authData := obj.computeAuthData() + authData, err := obj.computeAuthData() + if err != nil { + return nil, err + } parts, err := ctx.cipher.encrypt(cek, authData, plaintext) if err != nil { return nil, err @@ -492,7 +495,10 @@ func (obj JSONWebEncryption) Decrypt(decryptionKey interface{}) ([]byte, error) tag: obj.tag, } - authData := obj.computeAuthData() + authData, err := obj.computeAuthData() + if err != nil { + return nil, err + } var plaintext []byte recipient := obj.recipients[0] @@ -531,6 +537,12 @@ func (obj JSONWebEncryption) Decrypt(decryptionKey interface{}) ([]byte, error) // // Automatically decompresses plaintext, but returns an error if the decompressed // data would be >250kB or >3x the size of the compressed data, whichever is larger. +// +// Calling DecryptMulti() with PBES2 enabled can result in excessive CPU work. +// The PBES2 key unwrapping algorithms are intentionally expensive, and have to +// be run for each recipient. To be safe: don't allow PBES2 algorithms in calls +// to ParseEncrypted / ParseEncryptedJSON. If your application requires PBES2, +// prefer Decrypt(), which will only process single-recipient messages. func (obj JSONWebEncryption) DecryptMulti(decryptionKey interface{}) (int, Header, []byte, error) { globalHeaders := obj.mergedHeaders(nil) @@ -564,7 +576,10 @@ func (obj JSONWebEncryption) DecryptMulti(decryptionKey interface{}) (int, Heade tag: obj.tag, } - authData := obj.computeAuthData() + authData, err := obj.computeAuthData() + if err != nil { + return -1, Header{}, nil, err + } index := -1 var plaintext []byte diff --git a/vendor/github.com/go-jose/go-jose/v4/encoding.go b/vendor/github.com/go-jose/go-jose/v4/encoding.go index 4f6e0d4a5c..34f5501a74 100644 --- a/vendor/github.com/go-jose/go-jose/v4/encoding.go +++ b/vendor/github.com/go-jose/go-jose/v4/encoding.go @@ -30,30 +30,6 @@ import ( "github.com/go-jose/go-jose/v4/json" ) -// Helper function to serialize known-good objects. -// Precondition: value is not a nil pointer. -func mustSerializeJSON(value interface{}) []byte { - out, err := json.Marshal(value) - if err != nil { - panic(err) - } - // We never want to serialize the top-level value "null," since it's not a - // valid JOSE message. But if a caller passes in a nil pointer to this method, - // MarshalJSON will happily serialize it as the top-level value "null". If - // that value is then embedded in another operation, for instance by being - // base64-encoded and fed as input to a signing algorithm - // (https://github.com/go-jose/go-jose/issues/22), the result will be - // incorrect. Because this method is intended for known-good objects, and a nil - // pointer is not a known-good object, we are free to panic in this case. - // Note: It's not possible to directly check whether the data pointed at by an - // interface is a nil pointer, so we do this hacky workaround. - // https://groups.google.com/forum/#!topic/golang-nuts/wnH302gBa4I - if string(out) == "null" { - panic("Tried to serialize a nil pointer.") - } - return out -} - // Strip all newlines and whitespace func stripWhitespace(data string) string { buf := strings.Builder{} @@ -122,6 +98,8 @@ func inflate(input []byte) ([]byte, error) { } // byteBuffer represents a slice of bytes that can be serialized to url-safe base64. +// +// A nil byteBuffer represents an empty slice of bytes. type byteBuffer struct { data []byte } @@ -169,13 +147,13 @@ func (b *byteBuffer) UnmarshalJSON(data []byte) error { return err } - *b = *newBuffer(decoded) + b.data = decoded return nil } func (b *byteBuffer) base64() string { - return base64.RawURLEncoding.EncodeToString(b.data) + return base64.RawURLEncoding.EncodeToString(b.bytes()) } func (b *byteBuffer) bytes() []byte { @@ -186,12 +164,8 @@ func (b *byteBuffer) bytes() []byte { return b.data } -func (b byteBuffer) bigInt() *big.Int { - return new(big.Int).SetBytes(b.data) -} - -func (b byteBuffer) toInt() int { - return int(b.bigInt().Int64()) +func (b *byteBuffer) bigInt() *big.Int { + return new(big.Int).SetBytes(b.bytes()) } func base64EncodeLen(sl []byte) int { diff --git a/vendor/github.com/go-jose/go-jose/v4/json/decode.go b/vendor/github.com/go-jose/go-jose/v4/json/decode.go index 50634dd847..6c5e740420 100644 --- a/vendor/github.com/go-jose/go-jose/v4/json/decode.go +++ b/vendor/github.com/go-jose/go-jose/v4/json/decode.go @@ -671,6 +671,19 @@ func (d *decodeState) object(v reflect.Value) { for _, i := range f.index { if subv.Kind() == reflect.Ptr { if subv.IsNil() { + // If a struct embeds a pointer to an unexported type, + // it is not possible to set a newly allocated value + // since the field is unexported. + // + // See https://golang.org/issue/21357 + if !subv.CanSet() { + d.saveError(fmt.Errorf("json: cannot set embedded pointer to unexported struct: %v", subv.Type().Elem())) + // Invalidate subv to ensure d.value(subv) skips over + // the JSON value without assigning it to subv. + subv = reflect.Value{} + destring = false + break + } subv.Set(reflect.New(subv.Type().Elem())) } subv = subv.Elem() diff --git a/vendor/github.com/go-jose/go-jose/v4/json/encode.go b/vendor/github.com/go-jose/go-jose/v4/json/encode.go index 98de68ce1e..fd77790cd3 100644 --- a/vendor/github.com/go-jose/go-jose/v4/json/encode.go +++ b/vendor/github.com/go-jose/go-jose/v4/json/encode.go @@ -1025,7 +1025,19 @@ func typeFields(t reflect.Type) []field { // Scan f.typ for fields to include. for i := 0; i < f.typ.NumField(); i++ { sf := f.typ.Field(i) - if sf.PkgPath != "" && !sf.Anonymous { // unexported + if sf.Anonymous { + t := sf.Type + if t.Kind() == reflect.Pointer { + t = t.Elem() + } + if !sf.IsExported() && t.Kind() != reflect.Struct { + // Ignore embedded fields of unexported non-struct types. + continue + } + // Do not ignore embedded fields of unexported struct types + // since they may have exported fields. + } else if !sf.IsExported() { + // Ignore unexported non-embedded fields. continue } tag := sf.Tag.Get("json") diff --git a/vendor/github.com/go-jose/go-jose/v4/jwe.go b/vendor/github.com/go-jose/go-jose/v4/jwe.go index a516901078..9b03456950 100644 --- a/vendor/github.com/go-jose/go-jose/v4/jwe.go +++ b/vendor/github.com/go-jose/go-jose/v4/jwe.go @@ -25,6 +25,12 @@ import ( "github.com/go-jose/go-jose/v4/json" ) +// MaxRecipients is the maximum number of recipients of a JWE at parse time. +// Higher values mean more potential work done across untrusted input. +// +// If modifying MaxRecipients, do it before any parsing occurs. +var MaxRecipients = 32 + // rawJSONWebEncryption represents a raw JWE JSON object. Used for parsing/serializing. type rawJSONWebEncryption struct { Protected *byteBuffer `json:"protected,omitempty"` @@ -84,14 +90,18 @@ func (obj JSONWebEncryption) mergedHeaders(recipient *recipientInfo) rawHeader { } // Get the additional authenticated data from a JWE object. -func (obj JSONWebEncryption) computeAuthData() []byte { +func (obj JSONWebEncryption) computeAuthData() ([]byte, error) { var protected string switch { case obj.original != nil && obj.original.Protected != nil: protected = obj.original.Protected.base64() case obj.protected != nil: - protected = base64.RawURLEncoding.EncodeToString(mustSerializeJSON((obj.protected))) + serializedProtected, err := json.Marshal(obj.protected) + if err != nil { + return nil, err + } + protected = base64.RawURLEncoding.EncodeToString(serializedProtected) default: protected = "" } @@ -102,7 +112,7 @@ func (obj JSONWebEncryption) computeAuthData() []byte { output = append(output, []byte(base64.RawURLEncoding.EncodeToString(obj.aad))...) } - return output + return output, nil } func containsKeyAlgorithm(haystack []KeyAlgorithm, needle KeyAlgorithm) bool { @@ -128,11 +138,10 @@ func containsContentEncryption(haystack []ContentEncryption, needle ContentEncry // https://datatracker.ietf.org/doc/html/rfc7516#section-3.1 // https://datatracker.ietf.org/doc/html/rfc7516#section-3.2 // -// The keyAlgorithms and contentEncryption parameters are used to validate the "alg" and "enc" -// header parameters respectively. They must be nonempty, and each "alg" or "enc" header in -// parsed data must contain a value that is present in the corresponding parameter. That -// includes the protected and unprotected headers as well as all recipients. To accept -// multiple algorithms, pass a slice of all the algorithms you want to accept. +// The keyAlgorithms and contentEncryption parameters contain the allowable algorithms in the "alg" and "enc" +// header parameters respectively. They must be non-empty. Non-matching algorithms cause a parse error. +// +// Deprecated: use ParseEncryptedJSON or ParseEncryptedCompact depending on which serialization you expect. func ParseEncrypted(input string, keyEncryptionAlgorithms []KeyAlgorithm, contentEncryption []ContentEncryption, @@ -145,9 +154,13 @@ func ParseEncrypted(input string, return ParseEncryptedCompact(input, keyEncryptionAlgorithms, contentEncryption) } -// ParseEncryptedJSON parses a message in JWE JSON Serialization. +// ParseEncryptedJSON parses a message in JWE JSON Serialization. Messages with +// more than [MaxRecipients] recipients are rejected. // // https://datatracker.ietf.org/doc/html/rfc7516#section-3.2 +// +// The keyAlgorithms and contentEncryption parameters contain the allowable algorithms in the "alg" and "enc" +// header parameters respectively. They must be non-empty. Any non-allowed algorithms will cause parsing to fail. func ParseEncryptedJSON( input string, keyEncryptionAlgorithms []KeyAlgorithm, @@ -177,6 +190,9 @@ func (parsed *rawJSONWebEncryption) sanitized( if len(contentEncryption) == 0 { return nil, errors.New("go-jose/go-jose: no content encryption algorithms provided") } + if len(parsed.Recipients) > MaxRecipients { + return nil, fmt.Errorf("go-jose/go-jose: too many recipients in JWE; maximum is %d", MaxRecipients) + } obj := &JSONWebEncryption{ original: parsed, @@ -195,12 +211,11 @@ func (parsed *rawJSONWebEncryption) sanitized( } } - if parsed.Protected != nil && len(parsed.Protected.bytes()) > 0 { - err := json.Unmarshal(parsed.Protected.bytes(), &obj.protected) - if err != nil { - return nil, fmt.Errorf("go-jose/go-jose: invalid protected header: %s, %s", err, parsed.Protected.base64()) - } + protected, err := parseProtectedHeader(parsed.Protected) + if err != nil { + return nil, err } + obj.protected = protected if len(parsed.Recipients) == 0 { obj.recipients = []recipientInfo{ @@ -258,7 +273,6 @@ func (parsed *rawJSONWebEncryption) sanitized( // Note: this must be called _after_ we parse the protected header, // otherwise fields from the protected header will not get picked up. mergedHeaders := obj.mergedHeaders(nil) - var err error obj.Header, err = mergedHeaders.sanitized() if err != nil { return nil, fmt.Errorf("go-jose/go-jose: cannot sanitize merged headers: %w", err) @@ -287,6 +301,9 @@ func validateAlgEnc(headers rawHeader, keyAlgorithms []KeyAlgorithm, contentEncr // ParseEncryptedCompact parses a message in JWE Compact Serialization. // // https://datatracker.ietf.org/doc/html/rfc7516#section-3.1 +// +// The keyAlgorithms and contentEncryption parameters contain the allowable algorithms in the "alg" and "enc" +// header parameters respectively. They must be non-empty. Any non-allowed algorithms will cause parsing to fail. func ParseEncryptedCompact( input string, keyAlgorithms []KeyAlgorithm, @@ -354,7 +371,10 @@ func (obj JSONWebEncryption) CompactSerialize() (string, error) { return "", ErrNotSupported } - serializedProtected := mustSerializeJSON(obj.protected) + serializedProtected, err := json.Marshal(obj.protected) + if err != nil { + return "", err + } return base64JoinWithDots( serializedProtected, @@ -366,7 +386,13 @@ func (obj JSONWebEncryption) CompactSerialize() (string, error) { } // FullSerialize serializes an object using the full JSON serialization format. +// +// It returns "" if obj cannot be serialized, for example if it has no recipients. func (obj JSONWebEncryption) FullSerialize() string { + if len(obj.recipients) == 0 { + return "" + } + raw := rawJSONWebEncryption{ Unprotected: obj.unprotected, Iv: newBuffer(obj.iv), @@ -392,8 +418,16 @@ func (obj JSONWebEncryption) FullSerialize() string { } if obj.protected != nil { - raw.Protected = newBuffer(mustSerializeJSON(obj.protected)) + serializedProtected, err := json.Marshal(obj.protected) + if err != nil { + return "" + } + raw.Protected = newBuffer(serializedProtected) } - return string(mustSerializeJSON(raw)) + out, err := json.Marshal(raw) + if err != nil { + return "" + } + return string(out) } diff --git a/vendor/github.com/go-jose/go-jose/v4/jwk.go b/vendor/github.com/go-jose/go-jose/v4/jwk.go index 8b7aa05ec2..87acb2c5e1 100644 --- a/vendor/github.com/go-jose/go-jose/v4/jwk.go +++ b/vendor/github.com/go-jose/go-jose/v4/jwk.go @@ -30,6 +30,7 @@ import ( "encoding/hex" "errors" "fmt" + "math" "math/big" "net/url" "reflect" @@ -249,7 +250,7 @@ func (k *JSONWebKey) unmarshalJSON(data []byte, allowPrivate bool) (err error) { keyPub = key } case "oct": - if certPub != nil { + if len(certs) > 0 { return errors.New("go-jose/go-jose: invalid JWK, found 'oct' (symmetric) key with cert chain") } key, err = raw.symmetricKey() @@ -288,10 +289,8 @@ func (k *JSONWebKey) unmarshalJSON(data []byte, allowPrivate bool) (err error) { return ErrUnsupportedKeyType } - if certPub != nil && keyPub != nil { - if !reflect.DeepEqual(certPub, keyPub) { - return errors.New("go-jose/go-jose: invalid JWK, public keys in key and x5c fields do not match") - } + if len(certs) > 0 && (certPub == nil || !reflect.DeepEqual(certPub, keyPub)) { + return errors.New("go-jose/go-jose: invalid JWK, public keys in key and x5c fields do not match") } *k = JSONWebKey{Key: key, KeyID: raw.Kid, Algorithm: raw.Alg, Use: raw.Use, Certificates: certs} @@ -408,6 +407,9 @@ func ecThumbprintInput(curve elliptic.Curve, x, y *big.Int) (string, error) { } func rsaThumbprintInput(n *big.Int, e int) (string, error) { + if n == nil || e <= 0 { + return "", errors.New("go-jose/go-jose: invalid RSA key") + } return fmt.Sprintf(rsaThumbprintTemplate, newBufferFromInt(uint64(e)).base64(), newBuffer(n.Bytes()).base64()), nil @@ -522,25 +524,40 @@ func (k *JSONWebKey) Valid() bool { } // MaxRSAModulusBits is the largest RSA modulus size, in bits, that will be -// accepted when parsing a JWK. Applications that need larger keys can raise -// this limit. +// accepted when parsing a JWK or verifying an x5c certificate chain with +// [Header.Certificates]. Applications that need larger keys can raise this +// limit. // // If modifying MaxRSAModulusBits, do it before any parsing occurs. var MaxRSAModulusBits = 4096 func (key rawJSONWebKey) rsaPublicKey() (*rsa.PublicKey, error) { - if key.N == nil || key.E == nil { + return rsaPublicKey(key.N, key.E) +} + +func rsaPublicKey(N, E *byteBuffer) (*rsa.PublicKey, error) { + if N == nil || E == nil { return nil, fmt.Errorf("go-jose/go-jose: invalid RSA key, missing n/e values") } - n := key.N.bigInt() + n := N.bigInt() if n.BitLen() > MaxRSAModulusBits { return nil, fmt.Errorf("go-jose/go-jose: invalid RSA key, modulus too large") } + e := new(big.Int).SetBytes(E.bytes()) + if !e.IsInt64() { + return nil, fmt.Errorf("go-jose/go-jose: invalid RSA key, bad e value") + } + + eInt64 := e.Int64() + if eInt64 < 2 || eInt64 > math.MaxInt { + return nil, fmt.Errorf("go-jose/go-jose: invalid RSA key, bad e value") + } + return &rsa.PublicKey{ N: n, - E: key.E.toInt(), + E: int(eInt64), }, nil } @@ -584,11 +601,11 @@ func (key rawJSONWebKey) ecPublicKey() (*ecdsa.PublicKey, error) { // The length of this octet string MUST be the full size of a coordinate for // 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) { + if curveSize(curve) != len(key.X.bytes()) { return nil, fmt.Errorf("go-jose/go-jose: invalid EC public key, wrong length for x") } - if curveSize(curve) != len(key.Y.data) { + if curveSize(curve) != len(key.Y.bytes()) { return nil, fmt.Errorf("go-jose/go-jose: invalid EC public key, wrong length for y") } @@ -701,23 +718,21 @@ func (key rawJSONWebKey) rsaPrivateKey() (*rsa.PrivateKey, error) { return nil, fmt.Errorf("go-jose/go-jose: invalid RSA private key, missing %s value(s)", strings.Join(missing, ", ")) } - n := key.N.bigInt() - if n.BitLen() > MaxRSAModulusBits { - return nil, fmt.Errorf("go-jose/go-jose: invalid RSA key, modulus too large") + pubKey, err := rsaPublicKey(key.N, key.E) + if err != nil { + return nil, err } + n := pubKey.N p, q := key.P.bigInt(), key.Q.bigInt() if p.BitLen()+q.BitLen() > n.BitLen()+1 || new(big.Int).Mul(p, q).Cmp(n) != 0 { return nil, errors.New("go-jose/go-jose: invalid RSA private key, p * q != n") } rv := &rsa.PrivateKey{ - PublicKey: rsa.PublicKey{ - N: n, - E: key.E.toInt(), - }, - D: key.D.bigInt(), - Primes: []*big.Int{p, q}, + PublicKey: *pubKey, + D: key.D.bigInt(), + Primes: []*big.Int{p, q}, } if key.Dp != nil { @@ -730,7 +745,7 @@ func (key rawJSONWebKey) rsaPrivateKey() (*rsa.PrivateKey, error) { rv.Precomputed.Qinv = key.Qi.bigInt() } - err := rv.Validate() + err = rv.Validate() return rv, err } @@ -804,16 +819,16 @@ func (key rawJSONWebKey) ecPrivateKey() (*ecdsa.PrivateKey, error) { // The length of this octet string MUST be the full size of a coordinate for // 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) { + if curveSize(curve) != len(key.X.bytes()) { return nil, fmt.Errorf("go-jose/go-jose: invalid EC private key, wrong length for x") } - if curveSize(curve) != len(key.Y.data) { + if curveSize(curve) != len(key.Y.bytes()) { return nil, fmt.Errorf("go-jose/go-jose: invalid EC private key, wrong length for y") } // https://tools.ietf.org/html/rfc7518#section-6.2.2.1 - if dSize(curve) != len(key.D.data) { + if dSize(curve) != len(key.D.bytes()) { return nil, fmt.Errorf("go-jose/go-jose: invalid EC private key, wrong length for d") } diff --git a/vendor/github.com/go-jose/go-jose/v4/jws.go b/vendor/github.com/go-jose/go-jose/v4/jws.go index 18224df7d9..451817a7f7 100644 --- a/vendor/github.com/go-jose/go-jose/v4/jws.go +++ b/vendor/github.com/go-jose/go-jose/v4/jws.go @@ -27,6 +27,12 @@ import ( "github.com/go-jose/go-jose/v4/json" ) +// MaxSignatures is the maximum number of signatures in a JWS at parse time. +// Higher values mean more potential work done across untrusted input. +// +// If modifying MaxSignatures, do it before any parsing occurs. +var MaxSignatures = 32 + // rawJSONWebSignature represents a raw JWS JSON object. Used for parsing/serializing. type rawJSONWebSignature struct { Payload *byteBuffer `json:"payload,omitempty"` @@ -86,6 +92,11 @@ type Signature struct { // Verify() after parsing to validate the signature and obtain the payload. // // https://datatracker.ietf.org/doc/html/rfc7515#section-7 +// +// The signatureAlgorithms parameter contains the allowable algorithms in the "alg" header parameter. +// It must be non-empty. Non-matching algorithms cause a parse error. +// +// Deprecated: call ParseSignedJSON or ParseSignedCompact depending on which serialization you expect. func ParseSigned( signature string, signatureAlgorithms []SignatureAlgorithm, @@ -108,6 +119,9 @@ func ParseSigned( // Verify() after parsing to validate the signature and obtain the payload. // // https://datatracker.ietf.org/doc/html/rfc7515#section-7.1 +// +// The signatureAlgorithms parameter contains the allowable algorithms in the "alg" header parameter. +// It must be non-empty. Non-matching algorithms cause a parse error. func ParseSignedCompact( signature string, signatureAlgorithms []SignatureAlgorithm, @@ -125,6 +139,9 @@ func ParseSignedCompact( // parsing. Call Verify() after parsing to validate the signature and obtain the payload. // // https://datatracker.ietf.org/doc/html/rfc7515#appendix-F +// +// The signatureAlgorithms parameter contains the allowable algorithms in the "alg" header parameter. +// It must be non-empty. Any non-allowed algorithms will cause parsing to fail. func ParseDetached( signature string, payload []byte, @@ -157,7 +174,11 @@ func (obj JSONWebSignature) computeAuthData(payload []byte, signature *Signature authData.WriteString(signature.original.Protected.base64()) } else if signature.protected != nil { protectedHeader = signature.protected - authData.WriteString(base64.RawURLEncoding.EncodeToString(mustSerializeJSON(protectedHeader))) + serializedProtected, err := json.Marshal(protectedHeader) + if err != nil { + return nil, err + } + authData.WriteString(base64.RawURLEncoding.EncodeToString(serializedProtected)) } needsBase64 := true @@ -180,9 +201,13 @@ func (obj JSONWebSignature) computeAuthData(payload []byte, signature *Signature return authData.Bytes(), nil } -// ParseSignedJSON parses a message in JWS JSON Serialization. +// ParseSignedJSON parses a message in JWS JSON Serialization. Messages with +// more than [MaxSignatures] signatures are rejected. // // https://datatracker.ietf.org/doc/html/rfc7515#section-7.2 +// +// The signatureAlgorithms parameter contains the allowable algorithms in the "alg" header parameter. +// It must be non-empty. Non-matching algorithms cause a parse error. func ParseSignedJSON( input string, signatureAlgorithms []SignatureAlgorithm, @@ -236,6 +261,9 @@ func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgo if parsed.Payload == nil { return nil, fmt.Errorf("go-jose/go-jose: missing payload in JWS message") } + if len(parsed.Signatures) > MaxSignatures { + return nil, fmt.Errorf("go-jose/go-jose: too many signatures in JWS; maximum is %d", MaxSignatures) + } obj := &JSONWebSignature{ payload: parsed.Payload.bytes(), @@ -245,14 +273,13 @@ func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgo if len(parsed.Signatures) == 0 { // No signatures array, must be flattened serialization signature := Signature{} - if parsed.Protected != nil && len(parsed.Protected.bytes()) > 0 { - signature.protected = &rawHeader{} - err := json.Unmarshal(parsed.Protected.bytes(), signature.protected) - if err != nil { - return nil, err - } + prot, err := parseProtectedHeader(parsed.Protected) + if err != nil { + return nil, err } + signature.protected = prot + // Check that there is not a nonce in the unprotected header if parsed.Header != nil && parsed.Header.getNonce() != "" { return nil, ErrUnprotectedNonce @@ -281,7 +308,6 @@ func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgo return nil, newErrUnexpectedSignatureAlgorithm(alg, signatureAlgorithms) } - var err error signature.Header, err = mergedHeaders.sanitized() if err != nil { return nil, err @@ -311,14 +337,13 @@ func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgo } for i, sig := range parsed.Signatures { - if sig.Protected != nil && len(sig.Protected.bytes()) > 0 { - obj.Signatures[i].protected = &rawHeader{} - err := json.Unmarshal(sig.Protected.bytes(), obj.Signatures[i].protected) - if err != nil { - return nil, err - } + prot, err := parseProtectedHeader(sig.Protected) + if err != nil { + return nil, err } + obj.Signatures[i].protected = prot + // Check that there is not a nonce in the unprotected header if sig.Header != nil && sig.Header.getNonce() != "" { return nil, ErrUnprotectedNonce @@ -332,7 +357,6 @@ func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgo return nil, newErrUnexpectedSignatureAlgorithm(alg, signatureAlgorithms) } - var err error obj.Signatures[i].Header, err = mergedHeaders.sanitized() if err != nil { return nil, err @@ -427,7 +451,10 @@ func (obj JSONWebSignature) compactSerialize(detached bool) (string, error) { return "", ErrNotSupported } - serializedProtected := mustSerializeJSON(obj.Signatures[0].protected) + serializedProtected, err := json.Marshal(obj.Signatures[0].protected) + if err != nil { + return "", err + } var payload []byte if !detached { @@ -452,14 +479,23 @@ func (obj JSONWebSignature) DetachedCompactSerialize() (string, error) { } // FullSerialize serializes an object using the full JSON serialization format. +// +// It returns "" if obj cannot be serialized. func (obj JSONWebSignature) FullSerialize() string { raw := rawJSONWebSignature{ Payload: newBuffer(obj.payload), } + if len(obj.Signatures) == 0 { + return "" + } + if len(obj.Signatures) == 1 { if obj.Signatures[0].protected != nil { - serializedProtected := mustSerializeJSON(obj.Signatures[0].protected) + serializedProtected, err := json.Marshal(obj.Signatures[0].protected) + if err != nil { + return "" + } raw.Protected = newBuffer(serializedProtected) } raw.Header = obj.Signatures[0].header @@ -473,10 +509,18 @@ func (obj JSONWebSignature) FullSerialize() string { } if signature.protected != nil { - raw.Signatures[i].Protected = newBuffer(mustSerializeJSON(signature.protected)) + serializedProtected, err := json.Marshal(signature.protected) + if err != nil { + return "" + } + raw.Signatures[i].Protected = newBuffer(serializedProtected) } } } - return string(mustSerializeJSON(raw)) + out, err := json.Marshal(raw) + if err != nil { + return "" + } + return string(out) } diff --git a/vendor/github.com/go-jose/go-jose/v4/jwt/jwt.go b/vendor/github.com/go-jose/go-jose/v4/jwt/jwt.go index c4998d7875..30251e6f75 100644 --- a/vendor/github.com/go-jose/go-jose/v4/jwt/jwt.go +++ b/vendor/github.com/go-jose/go-jose/v4/jwt/jwt.go @@ -85,7 +85,12 @@ func (t *NestedJSONWebToken) Decrypt(decryptionKey interface{}) (*JSONWebToken, return sig, nil } -// ParseSigned parses token from JWS form. +// ParseSigned parses a JWT in the JWS Compact Serialization. +// +// https://datatracker.ietf.org/doc/html/rfc7515#section-3.1 +// +// The signatureAlgorithms parameter contains the allowable algorithms in the "alg" header parameter. +// It must be non-empty. Non-matching algorithms cause a parse error. func ParseSigned(s string, signatureAlgorithms []jose.SignatureAlgorithm) (*JSONWebToken, error) { sig, err := jose.ParseSignedCompact(s, signatureAlgorithms) if err != nil { @@ -142,13 +147,10 @@ func parseEncryptedCompact( return enc, nil } -// ParseEncrypted parses token from JWE form. +// ParseEncrypted parses a JWT in the JWE Compact Serialization. // -// The keyAlgorithms and contentEncryption parameters are used to validate the "alg" and "enc" -// header parameters respectively. They must be nonempty, and each "alg" or "enc" header in -// parsed data must contain a value that is present in the corresponding parameter. That -// includes the protected and unprotected headers as well as all recipients. To accept -// multiple algorithms, pass a slice of all the algorithms you want to accept. +// The keyAlgorithms and contentEncryption parameters contain the allowable algorithms in the "alg" and "enc" +// header parameters respectively. They must be non-empty. Non-matching algorithms cause a parse error. func ParseEncrypted(s string, keyAlgorithms []jose.KeyAlgorithm, contentEncryption []jose.ContentEncryption, @@ -164,17 +166,10 @@ func ParseEncrypted(s string, }, nil } -// ParseSignedAndEncrypted parses signed-then-encrypted token from JWE form. +// ParseSignedAndEncrypted parses a signed-then-encrypted token in the JWE Compact Serialization. // -// The encryptionKeyAlgorithms and contentEncryption parameters are used to validate the "alg" and "enc" -// header parameters, respectively, of the outer JWE. They must be nonempty, and each "alg" or "enc" -// header in parsed data must contain a value that is present in the corresponding parameter. That -// includes the protected and unprotected headers as well as all recipients. To accept -// multiple algorithms, pass a slice of all the algorithms you want to accept. -// -// The signatureAlgorithms parameter is used to validate the "alg" header parameter of the -// inner JWS. It must be nonempty, and the "alg" header in the inner JWS must contain a value -// that is present in the parameter. +// The encryptionKeyAlgorithms, contentEncryption, and signatureAlgorithms parameters contain the allowable +// algorithms. They must be non-empty. Non-matching algorithms cause a parse error. func ParseSignedAndEncrypted(s string, encryptionKeyAlgorithms []jose.KeyAlgorithm, contentEncryption []jose.ContentEncryption, diff --git a/vendor/github.com/go-jose/go-jose/v4/shared.go b/vendor/github.com/go-jose/go-jose/v4/shared.go index 1e8bf88210..7303615a9f 100644 --- a/vendor/github.com/go-jose/go-jose/v4/shared.go +++ b/vendor/github.com/go-jose/go-jose/v4/shared.go @@ -18,6 +18,7 @@ package jose import ( "crypto/elliptic" + "crypto/rsa" "crypto/x509" "encoding/base64" "errors" @@ -210,13 +211,20 @@ type Header struct { // Certificates verifies & returns the certificate chain present // in the x5c header field of a message, if one was present. Returns -// an error if there was no x5c header present or the chain could +// an error if there was no x5c header present, any certificate in the +// chain has an RSA key larger than [MaxRSAModulusBits], or the chain could // not be validated with the given verify options. func (h Header) Certificates(opts x509.VerifyOptions) ([][]*x509.Certificate, error) { if len(h.certificates) == 0 { return nil, ErrMissingX5cHeader } + for _, cert := range h.certificates { + if pub, ok := cert.PublicKey.(*rsa.PublicKey); ok && pub.N.BitLen() > MaxRSAModulusBits { + return nil, fmt.Errorf("go-jose/go-jose: invalid RSA key in x5c certificate, modulus too large") + } + } + leaf := h.certificates[0] if opts.Intermediates == nil { opts.Intermediates = x509.NewCertPool() @@ -490,22 +498,8 @@ func parseCertificateChain(chain []string) ([]*x509.Certificate, error) { } func (parsed rawHeader) isSet(k HeaderKey) bool { - dvr := parsed[k] - if dvr == nil { - return false - } - - var dv interface{} - err := json.Unmarshal(*dvr, &dv) - if err != nil { - return true - } - - if dvStr, ok := dv.(string); ok { - return dvStr != "" - } - - return true + _, ok := parsed[k] + return ok } // Merge headers from src into dst, giving precedence to headers from l. @@ -555,3 +549,24 @@ func makeRawMessage(b []byte) *json.RawMessage { rm := json.RawMessage(b) return &rm } + +// parseProtectedHeader parses a `byteBuffer` into a `*rawHeader`. +// +// The byteBuffer represents a base64-decoded "protected" header, which +// is specified to contain a JSON object. +// +// If the input is nil or empty, returns `nil, nil`. +// +// `rawHeader` is a map type and so can be nil. When this function +// returns a non-nil `*rawHeader`, the map is guaranteed to be non-nil. +func parseProtectedHeader(in *byteBuffer) (*rawHeader, error) { + if in == nil || len(in.bytes()) == 0 { + return nil, nil + } + var header rawHeader + err := json.Unmarshal(in.bytes(), &header) + if err != nil || header == nil { + return nil, errors.New("go-jose/go-jose: invalid protected header") + } + return &header, nil +} diff --git a/vendor/github.com/go-jose/go-jose/v4/signing.go b/vendor/github.com/go-jose/go-jose/v4/signing.go index 5baf75cb2e..008cd4a270 100644 --- a/vendor/github.com/go-jose/go-jose/v4/signing.go +++ b/vendor/github.com/go-jose/go-jose/v4/signing.go @@ -321,7 +321,10 @@ func (ctx *genericSigner) Sign(payload []byte) (*JSONWebSignature, error) { protected[k] = v } - serializedProtected := mustSerializeJSON(protected) + serializedProtected, err := json.Marshal(protected) + if err != nil { + return nil, fmt.Errorf("go-jose/go-jose: Error marshaling JSON: %s", err) + } needsBase64 := true if b64, ok := protected[headerB64]; ok { diff --git a/vendor/github.com/go-jose/go-jose/v4/symmetric.go b/vendor/github.com/go-jose/go-jose/v4/symmetric.go index ca597d6a12..3f2a4fdf85 100644 --- a/vendor/github.com/go-jose/go-jose/v4/symmetric.go +++ b/vendor/github.com/go-jose/go-jose/v4/symmetric.go @@ -421,7 +421,7 @@ func (ctx *symmetricKeyCipher) decryptKey(headers rawHeader, recipient *recipien if err != nil { return nil, fmt.Errorf("go-jose/go-jose: invalid P2S: %v", err) } - if p2s == nil || len(p2s.data) == 0 { + if p2s == nil || len(p2s.bytes()) == 0 { return nil, fmt.Errorf("go-jose/go-jose: invalid P2S: must be present") } diff --git a/vendor/modules.txt b/vendor/modules.txt index 6cb7cb1874..cd04537f37 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -93,7 +93,7 @@ github.com/felixge/httpsnoop # github.com/fvbommel/sortorder v1.2.1 ## explicit; go 1.21 github.com/fvbommel/sortorder -# github.com/go-jose/go-jose/v4 v4.1.6 +# github.com/go-jose/go-jose/v4 v4.1.7 ## explicit; go 1.24.0 github.com/go-jose/go-jose/v4 github.com/go-jose/go-jose/v4/cipher