From b81418cfc0c93ab1cd166fba43946933769df35d Mon Sep 17 00:00:00 2001 From: 0xkatana Date: Sat, 31 Oct 2026 17:50:10 +0100 Subject: [PATCH] Bump go-jose to v4.1.7 for CVE-2026-116587 v4.1.5 is vulnerable to a denial of service when parsing crafted JWKs. v4.1.7 also fixes GHSA-r39w-98wm-9pp6, GHSA-27pc-rm86-68pq, GHSA-p9j4-2j95-j4rv, GHSA-v6h2-qj3f-2h6v and GHSA-c67m-wr4h-2ccg. Generated with hack/pin-dependency.sh and hack/update-vendor.sh. Signed-off-by: 0xkatana --- go.mod | 2 +- go.sum | 4 +- .../src/k8s.io/apiextensions-apiserver/go.sum | 2 +- staging/src/k8s.io/apiserver/go.mod | 2 +- staging/src/k8s.io/apiserver/go.sum | 4 +- staging/src/k8s.io/cloud-provider/go.sum | 2 +- staging/src/k8s.io/cluster-bootstrap/go.mod | 2 +- staging/src/k8s.io/cluster-bootstrap/go.sum | 4 +- staging/src/k8s.io/controller-manager/go.sum | 2 +- .../k8s.io/dynamic-resource-allocation/go.sum | 2 +- staging/src/k8s.io/kube-aggregator/go.sum | 2 +- .../src/k8s.io/pod-security-admission/go.sum | 2 +- staging/src/k8s.io/sample-apiserver/go.sum | 2 +- .../github.com/go-jose/go-jose/v4/crypter.go | 36 +++++- .../github.com/go-jose/go-jose/v4/encoding.go | 38 +----- .../go-jose/go-jose/v4/json/decode.go | 13 ++ .../go-jose/go-jose/v4/json/encode.go | 14 ++- vendor/github.com/go-jose/go-jose/v4/jwe.go | 84 +++++++++---- vendor/github.com/go-jose/go-jose/v4/jwk.go | 98 ++++++++++++---- vendor/github.com/go-jose/go-jose/v4/jws.go | 111 +++++++++++++----- .../go-jose/go-jose/v4/jwt/errors.go | 2 +- .../github.com/go-jose/go-jose/v4/jwt/jwt.go | 29 ++--- .../github.com/go-jose/go-jose/v4/shared.go | 80 +++++++------ .../github.com/go-jose/go-jose/v4/signing.go | 5 +- .../go-jose/go-jose/v4/symmetric.go | 2 +- .../go-jose/go-jose/v4/tests.Containerfile | 13 ++ .../go-jose/go-jose/v4/threat_model.md | 25 ++++ vendor/modules.txt | 2 +- 28 files changed, 393 insertions(+), 191 deletions(-) create mode 100644 vendor/github.com/go-jose/go-jose/v4/tests.Containerfile create mode 100644 vendor/github.com/go-jose/go-jose/v4/threat_model.md diff --git a/go.mod b/go.mod index 34f200a8183..a97ff5f8228 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( github.com/docker/go-units v0.5.0 github.com/emicklei/go-restful/v3 v3.14.0 github.com/fsnotify/fsnotify v1.9.0 - github.com/go-jose/go-jose/v4 v4.1.5 + github.com/go-jose/go-jose/v4 v4.1.7 github.com/go-logr/logr v1.4.4 github.com/go-openapi/jsonreference v1.0.2 github.com/godbus/dbus/v5 v5.2.4 diff --git a/go.sum b/go.sum index 25c70f19d78..9b668fcc482 100644 --- a/go.sum +++ b/go.sum @@ -109,8 +109,8 @@ github.com/gkampitakis/go-snaps v0.5.15 h1:amyJrvM1D33cPHwVrjo9jQxX8g/7E2wYdZ+01 github.com/gkampitakis/go-snaps v0.5.15/go.mod h1:HNpx/9GoKisdhw9AFOBT1N7DBs9DiHo/hGheFGBZ+mc= github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk= github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= -github.com/go-jose/go-jose/v4 v4.1.5 h1:RjgjO2LOtWOJKUC5wpwY9LR3B3vwVAz6JS2YHfYU6eA= -github.com/go-jose/go-jose/v4 v4.1.5/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/staging/src/k8s.io/apiextensions-apiserver/go.sum b/staging/src/k8s.io/apiextensions-apiserver/go.sum index 78ad093e6fb..b4952887142 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/go.sum +++ b/staging/src/k8s.io/apiextensions-apiserver/go.sum @@ -51,7 +51,7 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.9.4 h1:xwjVlxEMR3S605oUlgBjKLTTeGFciYPGYCtF/35LKGo= github.com/fxamacker/cbor/v2 v2.9.4/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= -github.com/go-jose/go-jose/v4 v4.1.5/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= +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/staging/src/k8s.io/apiserver/go.mod b/staging/src/k8s.io/apiserver/go.mod index 8d7885bf367..c51700e11a1 100644 --- a/staging/src/k8s.io/apiserver/go.mod +++ b/staging/src/k8s.io/apiserver/go.mod @@ -13,7 +13,7 @@ require ( github.com/coreos/go-systemd/v22 v22.7.0 github.com/emicklei/go-restful/v3 v3.14.0 github.com/fsnotify/fsnotify v1.9.0 - github.com/go-jose/go-jose/v4 v4.1.5 + github.com/go-jose/go-jose/v4 v4.1.7 github.com/go-logr/logr v1.4.4 github.com/go-openapi/jsonreference v1.0.2 github.com/google/gnostic-models v0.7.1 diff --git a/staging/src/k8s.io/apiserver/go.sum b/staging/src/k8s.io/apiserver/go.sum index f094d9dfdc5..477148520e5 100644 --- a/staging/src/k8s.io/apiserver/go.sum +++ b/staging/src/k8s.io/apiserver/go.sum @@ -52,8 +52,8 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.9.4 h1:xwjVlxEMR3S605oUlgBjKLTTeGFciYPGYCtF/35LKGo= github.com/fxamacker/cbor/v2 v2.9.4/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= -github.com/go-jose/go-jose/v4 v4.1.5 h1:RjgjO2LOtWOJKUC5wpwY9LR3B3vwVAz6JS2YHfYU6eA= -github.com/go-jose/go-jose/v4 v4.1.5/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/staging/src/k8s.io/cloud-provider/go.sum b/staging/src/k8s.io/cloud-provider/go.sum index 42bd78fc2aa..4a7b63a41ee 100644 --- a/staging/src/k8s.io/cloud-provider/go.sum +++ b/staging/src/k8s.io/cloud-provider/go.sum @@ -47,7 +47,7 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.9.4 h1:xwjVlxEMR3S605oUlgBjKLTTeGFciYPGYCtF/35LKGo= github.com/fxamacker/cbor/v2 v2.9.4/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= -github.com/go-jose/go-jose/v4 v4.1.5/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= +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/staging/src/k8s.io/cluster-bootstrap/go.mod b/staging/src/k8s.io/cluster-bootstrap/go.mod index 1161da81a97..cb11b4364bf 100644 --- a/staging/src/k8s.io/cluster-bootstrap/go.mod +++ b/staging/src/k8s.io/cluster-bootstrap/go.mod @@ -7,7 +7,7 @@ go 1.27.0 godebug default=go1.27 require ( - github.com/go-jose/go-jose/v4 v4.1.5 + github.com/go-jose/go-jose/v4 v4.1.7 github.com/stretchr/testify v1.12.1 k8s.io/api v0.0.0 k8s.io/apimachinery v0.0.0 diff --git a/staging/src/k8s.io/cluster-bootstrap/go.sum b/staging/src/k8s.io/cluster-bootstrap/go.sum index 8a49f1c0c65..29456705ef6 100644 --- a/staging/src/k8s.io/cluster-bootstrap/go.sum +++ b/staging/src/k8s.io/cluster-bootstrap/go.sum @@ -2,8 +2,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fxamacker/cbor/v2 v2.9.4 h1:xwjVlxEMR3S605oUlgBjKLTTeGFciYPGYCtF/35LKGo= github.com/fxamacker/cbor/v2 v2.9.4/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= -github.com/go-jose/go-jose/v4 v4.1.5 h1:RjgjO2LOtWOJKUC5wpwY9LR3B3vwVAz6JS2YHfYU6eA= -github.com/go-jose/go-jose/v4 v4.1.5/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.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8= github.com/go-logr/logr v1.4.4/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-openapi/jsonpointer v1.0.2/go.mod h1:N0rI4MbNKD7xAFTiHtB+5Nhrg2j/wwYg7m7Fmb4/jk8= diff --git a/staging/src/k8s.io/controller-manager/go.sum b/staging/src/k8s.io/controller-manager/go.sum index 28b50943adb..024090ef16c 100644 --- a/staging/src/k8s.io/controller-manager/go.sum +++ b/staging/src/k8s.io/controller-manager/go.sum @@ -44,7 +44,7 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.9.4 h1:xwjVlxEMR3S605oUlgBjKLTTeGFciYPGYCtF/35LKGo= github.com/fxamacker/cbor/v2 v2.9.4/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= -github.com/go-jose/go-jose/v4 v4.1.5/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= +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/staging/src/k8s.io/dynamic-resource-allocation/go.sum b/staging/src/k8s.io/dynamic-resource-allocation/go.sum index 97d85c5a226..93555910afe 100644 --- a/staging/src/k8s.io/dynamic-resource-allocation/go.sum +++ b/staging/src/k8s.io/dynamic-resource-allocation/go.sum @@ -33,7 +33,7 @@ github.com/felixge/httpsnoop v1.1.0/go.mod h1:Zqxgdd+1Rkcz8euOqdr7lqgCRJztwr5hp9 github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.9.4 h1:xwjVlxEMR3S605oUlgBjKLTTeGFciYPGYCtF/35LKGo= github.com/fxamacker/cbor/v2 v2.9.4/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= -github.com/go-jose/go-jose/v4 v4.1.5/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= +github.com/go-jose/go-jose/v4 v4.1.7/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= 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= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= diff --git a/staging/src/k8s.io/kube-aggregator/go.sum b/staging/src/k8s.io/kube-aggregator/go.sum index ac0a940e210..8278874c5de 100644 --- a/staging/src/k8s.io/kube-aggregator/go.sum +++ b/staging/src/k8s.io/kube-aggregator/go.sum @@ -45,7 +45,7 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.9.4 h1:xwjVlxEMR3S605oUlgBjKLTTeGFciYPGYCtF/35LKGo= github.com/fxamacker/cbor/v2 v2.9.4/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= -github.com/go-jose/go-jose/v4 v4.1.5/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= +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/staging/src/k8s.io/pod-security-admission/go.sum b/staging/src/k8s.io/pod-security-admission/go.sum index 28b50943adb..024090ef16c 100644 --- a/staging/src/k8s.io/pod-security-admission/go.sum +++ b/staging/src/k8s.io/pod-security-admission/go.sum @@ -44,7 +44,7 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.9.4 h1:xwjVlxEMR3S605oUlgBjKLTTeGFciYPGYCtF/35LKGo= github.com/fxamacker/cbor/v2 v2.9.4/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= -github.com/go-jose/go-jose/v4 v4.1.5/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= +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/staging/src/k8s.io/sample-apiserver/go.sum b/staging/src/k8s.io/sample-apiserver/go.sum index 033003d7ef0..56023ccbd04 100644 --- a/staging/src/k8s.io/sample-apiserver/go.sum +++ b/staging/src/k8s.io/sample-apiserver/go.sum @@ -44,7 +44,7 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.9.4 h1:xwjVlxEMR3S605oUlgBjKLTTeGFciYPGYCtF/35LKGo= github.com/fxamacker/cbor/v2 v2.9.4/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= -github.com/go-jose/go-jose/v4 v4.1.5/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= +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 e3df79c2dc5..c766539115d 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 @@ -428,6 +431,13 @@ func (ctx *genericEncrypter) Options() EncrypterOptions { } } +func validateContentEncryptionKeySize(cek []byte, cipher contentCipher) error { + if len(cek) != cipher.keySize() { + return ErrInvalidKeySize + } + return nil +} + // Decrypt and validate the object and return the plaintext. This // function does not support multi-recipient. If you desire multi-recipient // decryption use DecryptMulti instead. @@ -485,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] @@ -495,6 +508,10 @@ func (obj JSONWebEncryption) Decrypt(decryptionKey interface{}) ([]byte, error) if err != nil { return nil, ErrCryptoFailure } + err = validateContentEncryptionKeySize(cek, cipher) + if err != nil { + return nil, ErrCryptoFailure + } // Found a valid CEK -- let's try to decrypt. plaintext, err = cipher.decrypt(cek, authData, parts) @@ -520,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) @@ -553,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 @@ -572,6 +598,10 @@ func (obj JSONWebEncryption) DecryptMulti(decryptionKey interface{}) (int, Heade if err != nil { continue } + err = validateContentEncryptionKeySize(cek, cipher) + if err != nil { + continue + } // Found a valid CEK -- let's try to decrypt. plaintext, err = cipher.decrypt(cek, authData, parts) 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 4f6e0d4a5cf..34f5501a748 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 50634dd8478..6c5e7404200 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 98de68ce1e9..fd77790cd3f 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 ae173461b70..9b034569504 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,21 +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()) - } - } - - // Note: this must be called _after_ we parse the protected header, - // otherwise fields from the protected header will not get picked up. - var err error - mergedHeaders := obj.mergedHeaders(nil) - obj.Header, err = mergedHeaders.sanitized() + protected, err := parseProtectedHeader(parsed.Protected) if err != nil { - return nil, fmt.Errorf("go-jose/go-jose: cannot sanitize merged headers: %v (%v)", err, mergedHeaders) + return nil, err } + obj.protected = protected if len(parsed.Recipients) == 0 { obj.recipients = []recipientInfo{ @@ -264,6 +270,14 @@ 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) + obj.Header, err = mergedHeaders.sanitized() + if err != nil { + return nil, fmt.Errorf("go-jose/go-jose: cannot sanitize merged headers: %w", err) + } + obj.iv = parsed.Iv.bytes() obj.ciphertext = parsed.Ciphertext.bytes() obj.tag = parsed.Tag.bytes() @@ -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 f712ec7ec8f..87acb2c5e1b 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" @@ -177,13 +178,29 @@ func (k JSONWebKey) MarshalJSON() ([]byte, error) { // UnmarshalJSON reads a key from its JSON representation. // // Returns ErrUnsupportedKeyType for unrecognized or unsupported "kty" header values. -func (k *JSONWebKey) UnmarshalJSON(data []byte) (err error) { +// +// Directly unmarshaling a JWK is not safe for untrusted input. +func (k *JSONWebKey) UnmarshalJSON(data []byte) error { + return k.unmarshalJSON(data, true) +} + +// unmarshalJSON reads a key from its JSON representation. +// +// If allowPrivate is false, a JWK with private key material is rejected and the +// function is safe for use against untrusted input. +func (k *JSONWebKey) unmarshalJSON(data []byte, allowPrivate bool) (err error) { var raw rawJSONWebKey err = json.Unmarshal(data, &raw) if err != nil { return err } + if !allowPrivate && + (raw.K != nil || raw.D != nil || raw.P != nil || raw.Q != nil || + raw.Dp != nil || raw.Dq != nil || raw.Qi != nil) { + return errors.New("go-jose/go-jose: JWK contains private parameters") + } + certs, err := parseCertificateChain(raw.X5c) if err != nil { return fmt.Errorf("go-jose/go-jose: failed to unmarshal x5c field: %s", err) @@ -233,7 +250,7 @@ func (k *JSONWebKey) UnmarshalJSON(data []byte) (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() @@ -272,10 +289,8 @@ func (k *JSONWebKey) UnmarshalJSON(data []byte) (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} @@ -392,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 @@ -505,14 +523,41 @@ func (k *JSONWebKey) Valid() bool { return true } +// MaxRSAModulusBits is the largest RSA modulus size, in bits, that will be +// 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 := 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: key.N.bigInt(), - E: key.E.toInt(), + N: n, + E: int(eInt64), }, nil } @@ -556,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") } @@ -673,16 +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, ", ")) } + 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: key.N.bigInt(), - E: key.E.toInt(), - }, - D: key.D.bigInt(), - Primes: []*big.Int{ - key.P.bigInt(), - key.Q.bigInt(), - }, + PublicKey: *pubKey, + D: key.D.bigInt(), + Primes: []*big.Int{p, q}, } if key.Dp != nil { @@ -695,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 } @@ -769,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 0444a5da05c..451817a7f77 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 @@ -275,17 +302,17 @@ func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgo Signature: parsed.Signature, } - var err error - signature.Header, err = signature.mergedHeaders().sanitized() - if err != nil { - return nil, err - } - - alg := SignatureAlgorithm(signature.Header.Algorithm) + mergedHeaders := signature.mergedHeaders() + alg := mergedHeaders.getSignatureAlgorithm() if !containsSignatureAlgorithm(signatureAlgorithms, alg) { return nil, newErrUnexpectedSignatureAlgorithm(alg, signatureAlgorithms) } + signature.Header, err = mergedHeaders.sanitized() + if err != nil { + return nil, err + } + if signature.header != nil { signature.Unprotected, err = signature.header.sanitized() if err != nil { @@ -310,30 +337,31 @@ 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 } - var err error - obj.Signatures[i].Header, err = obj.Signatures[i].mergedHeaders().sanitized() - if err != nil { - return nil, err - } + obj.Signatures[i].header = sig.Header - alg := SignatureAlgorithm(obj.Signatures[i].Header.Algorithm) + mergedHeaders := obj.Signatures[i].mergedHeaders() + alg := mergedHeaders.getSignatureAlgorithm() if !containsSignatureAlgorithm(signatureAlgorithms, alg) { return nil, newErrUnexpectedSignatureAlgorithm(alg, signatureAlgorithms) } + obj.Signatures[i].Header, err = mergedHeaders.sanitized() + if err != nil { + return nil, err + } + if obj.Signatures[i].header != nil { obj.Signatures[i].Unprotected, err = obj.Signatures[i].header.sanitized() if err != nil { @@ -359,7 +387,6 @@ func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgo // Copy value of sig original := sig - obj.Signatures[i].header = sig.Header obj.Signatures[i].original = &original } @@ -424,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 { @@ -449,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 @@ -470,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/errors.go b/vendor/github.com/go-jose/go-jose/v4/jwt/errors.go index 27388e5449a..b7e1e4bfbb1 100644 --- a/vendor/github.com/go-jose/go-jose/v4/jwt/errors.go +++ b/vendor/github.com/go-jose/go-jose/v4/jwt/errors.go @@ -47,7 +47,7 @@ var ErrNotValidYet = errors.New("go-jose/go-jose/jwt: validation failed, token n var ErrExpired = errors.New("go-jose/go-jose/jwt: validation failed, token is expired (exp)") // ErrIssuedInTheFuture indicates that the iat field is in the future. -var ErrIssuedInTheFuture = errors.New("go-jose/go-jose/jwt: validation field, token issued in the future (iat)") +var ErrIssuedInTheFuture = errors.New("go-jose/go-jose/jwt: validation failed, token issued in the future (iat)") // ErrInvalidContentType indicates that token requires JWT cty header. var ErrInvalidContentType = errors.New("go-jose/go-jose/jwt: expected content type to be JWT (cty header)") 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 c4998d7875d..30251e6f75e 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 3df242ca6a4..7303615a9f0 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() @@ -297,9 +305,10 @@ func (parsed rawHeader) getEPK() (*JSONWebKey, error) { if v == nil { return nil, nil } - var epk *JSONWebKey - err := json.Unmarshal(*v, &epk) - if err != nil { + // RFC 7518 Section 4.6.1.1: the "epk" header is the ephemeral public key + // of the originator. Reject private key material before parsing it. + epk := new(JSONWebKey) + if err := epk.unmarshalJSON(*v, false); err != nil { return nil, err } return epk, nil @@ -325,20 +334,6 @@ func (parsed rawHeader) getTag() (*byteBuffer, error) { return parsed.getByteBuffer(headerTag) } -// getJWK extracts parsed "jwk" from the raw JSON. -func (parsed rawHeader) getJWK() (*JSONWebKey, error) { - v := parsed[headerJWK] - if v == nil { - return nil, nil - } - var jwk *JSONWebKey - err := json.Unmarshal(*v, &jwk) - if err != nil { - return nil, err - } - return jwk, nil -} - // getCritical extracts parsed "crit" from the raw JSON. If omitted, it // returns an empty slice. func (parsed rawHeader) getCritical() ([]string, error) { @@ -424,10 +419,14 @@ func (parsed rawHeader) sanitized() (h Header, err error) { } switch k { case headerJWK: - var jwk *JSONWebKey - err = json.Unmarshal(*v, &jwk) + // RFC 7515 Section 4.1.3 and RFC 7516 Section 4.1.5: the "jwk" + // header is the public key that corresponds to the key used to + // sign the JWS or encrypt the JWE. Reject private key material + // before parsing it. + jwk := new(JSONWebKey) + err = jwk.unmarshalJSON(*v, false) if err != nil { - err = fmt.Errorf("failed to unmarshal JWK: %v: %#v", err, string(*v)) + err = fmt.Errorf("failed to unmarshal JWK: %w", err) return } h.JSONWebKey = jwk @@ -499,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. @@ -564,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 5baf75cb2e8..008cd4a2709 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 ca597d6a127..3f2a4fdf851 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/github.com/go-jose/go-jose/v4/tests.Containerfile b/vendor/github.com/go-jose/go-jose/v4/tests.Containerfile new file mode 100644 index 00000000000..b45da99bd2a --- /dev/null +++ b/vendor/github.com/go-jose/go-jose/v4/tests.Containerfile @@ -0,0 +1,13 @@ +# This containerfile can be used to run the go-jose tests and cli + +FROM golang:1.27-trixie +ENV GOTOOLCHAIN=local + +COPY . /src +WORKDIR /src + +# Install the jose-util cli, which will also build the library +RUN go build -o /usr/local/bin/jose-util ./jose-util + +# By default, run the tests +CMD ["go", "test", "./..."] diff --git a/vendor/github.com/go-jose/go-jose/v4/threat_model.md b/vendor/github.com/go-jose/go-jose/v4/threat_model.md new file mode 100644 index 00000000000..c9e66d4c205 --- /dev/null +++ b/vendor/github.com/go-jose/go-jose/v4/threat_model.md @@ -0,0 +1,25 @@ +# Threat model + +## What this project does and where untrusted input enters +go-jose is a Go implementation of JOSE family of algorithms. + +It is a library which will parse attacker-controlled data in network-reachable +services. + +## Components that matter most / least +The primary attack surface of interest is parsing and validating JWS, JWE, JWK, +etc when this library is used to implement authentication and authorization. + +## How to exercise it +Testing is primarily done by Golang unit tests, which can be run with the +tests.Container file's default CMD. + +## How you rate severity +Any authentication bypass enabled by a go-jose issue is a high+ severity. + +Denial-of-service attacks are of interest when the functions may be used in a protocol like OIDC, ACME, etc +which could have a server processing attacker-controlled data. + +## Anything to leave alone +Any bug which only affects the jose-util CLI tool, but it can be used to exercise the library. + diff --git a/vendor/modules.txt b/vendor/modules.txt index 47156b4a430..df2c1fcbfa4 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -182,7 +182,7 @@ github.com/fxamacker/cbor/v2 # github.com/go-errors/errors v1.5.1 ## explicit; go 1.14 github.com/go-errors/errors -# github.com/go-jose/go-jose/v4 v4.1.5 +# 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