mirror of
https://github.com/docker/cli.git
synced 2026-11-06 13:10:41 -04:00
vendor: github.com/go-jose/go-jose/v4 v4.1.7
Fixed Security Issues - Thumbprint: reject invalid RSA key [GHSA-r39w-98wm-9pp6] - json: backport stdlib fix for embedded unexported field [GHSA-27pc-rm86-68pq] - Detect if headers are set by presence in the map [GHSA-p9j4-2j95-j4rv] - limit RSA size in certificate verify [GHSA-v6h2-qj3f-2h6v] - Limit recipients and signatures in JWE/JWS [GHSA-c67m-wr4h-2ccg] Fixed - jwk: fix bug in x5c parsing - reject base64-encoded "null" in protected headers Deprecated - deprecate ParseEncrypted / ParseSigned full diff: https://github.com/go-jose/go-jose/compare/v4.1.6...v4.1.7 [GHSA-r39w-98wm-9pp6]: https://github.com/go-jose/go-jose/security/advisories/GHSA-r39w-98wm-9pp6 [GHSA-27pc-rm86-68pq]: https://github.com/go-jose/go-jose/security/advisories/GHSA-27pc-rm86-68pq [GHSA-p9j4-2j95-j4rv]: https://github.com/go-jose/go-jose/security/advisories/GHSA-p9j4-2j95-j4rv [GHSA-v6h2-qj3f-2h6v]: https://github.com/go-jose/go-jose/security/advisories/GHSA-v6h2-qj3f-2h6v [GHSA-c67m-wr4h-2ccg]: https://github.com/go-jose/go-jose/security/advisories/GHSA-c67m-wr4h-2ccg Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
+1
-1
@@ -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
|
||||
|
||||
+2
-2
@@ -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=
|
||||
|
||||
+18
-3
@@ -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
|
||||
|
||||
+6
-32
@@ -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 {
|
||||
|
||||
+13
@@ -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()
|
||||
|
||||
+13
-1
@@ -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")
|
||||
|
||||
+52
-18
@@ -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)
|
||||
}
|
||||
|
||||
+40
-25
@@ -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")
|
||||
}
|
||||
|
||||
|
||||
+64
-20
@@ -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)
|
||||
}
|
||||
|
||||
+12
-17
@@ -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,
|
||||
|
||||
+32
-17
@@ -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
|
||||
}
|
||||
|
||||
+4
-1
@@ -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 {
|
||||
|
||||
+1
-1
@@ -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")
|
||||
}
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user