Compare commits

...
50 Commits
Author SHA1 Message Date
Sebastiaan van Stijn 5457199aa5 Merge pull request #7470 from thaJeztah/29.x_backport_bump_compress
[29.x backport] vendor: github.com/klauspost/compress v1.20.2
2026-11-03 22:35:02 +01:00
Sebastiaan van Stijn cac50c5e62 vendor: github.com/klauspost/compress v1.20.2
includes a fix for CVE-2026-116591 / [GHSA-fpmh-frq8-7rj8]

full diff: https://github.com/klauspost/compress/compare/v1.20.1...v1.20.2

[GHSA-fpmh-frq8-7rj8]: https://github.com/klauspost/compress/security/advisories/GHSA-fpmh-frq8-7rj8

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit b9456fd725)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-11-03 22:28:18 +01:00
Sebastiaan van Stijn 00d843b496 Merge pull request #7467 from thaJeztah/29.x_backport_bump_swarmkit
[29.x backport] vendor: github.com/moby/swarmkit/v2 v2.1.3
2026-11-03 21:22:28 +01:00
Sebastiaan van Stijn 64fe50bbea vendor: github.com/moby/swarmkit/v2 v2.1.3
full diff: https://github.com/moby/swarmkit/compare/v2.1.2...v2.1.3

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 77ebef3df8)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-11-03 21:12:39 +01:00
Paweł Gronowski 999ab16f09 Merge pull request #7464 from thaJeztah/29.x_backport_bump_jose2
[29.x backport] vendor: github.com/go-jose/go-jose/v4 v4.1.7
2026-11-03 14:41:51 +01:00
Sebastiaan van Stijn bb485bc900 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>
(cherry picked from commit 81e4a109a3)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-11-03 14:25:22 +01:00
Sebastiaan van Stijn 86e51b44de Merge pull request #7461 from thaJeztah/29.x_backport_bump_yaml
[29.x backport] vendor: go.yaml.in/yaml/v3 v3.0.6 (security)
2026-11-03 14:23:29 +01:00
Paweł Gronowski d9bbcfcb4d Merge pull request #7457 from thaJeztah/29.x_backport_bump_jose
[29.x backport] vendor: github.com/go-jose/go-jose/v4 v4.1.6 (security)
2026-11-03 14:23:03 +01:00
Paweł Gronowski 2e886262b1 Merge pull request #7458 from thaJeztah/29.x_bump_version
[29.x] bump version to v29.9.3
2026-11-03 14:19:45 +01:00
Sebastiaan van Stijn a4971d1f60 vendor: go.yaml.in/yaml/v3 v3.0.6
resolve: hint-class literal merge-key string "<<" so it's quoted on encode

full diff: https://github.com/yaml/go-yaml/compare/v3.0.5...v3.0.6

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 796f9633b4)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-11-03 11:57:17 +01:00
Sebastiaan van Stijn bfb5814dd5 bump version to v29.9.3
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-11-03 11:39:48 +01:00
Sebastiaan van Stijn 68e452624a vendor: github.com/go-jose/go-jose/v4 v4.1.6
- contains a fix for CVE-2026-116587 / [GHSA-mgcc-cww5-fp2q]

full diff: https://github.com/go-jose/go-jose/compare/v4.1.5...v4.1.6

[GHSA-mgcc-cww5-fp2q]: https://github.com/go-jose/go-jose/security/advisories/GHSA-mgcc-cww5-fp2q

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit ccccec73b0)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-11-03 11:31:54 +01:00
Sebastiaan van Stijn 160531c55d vendor: github.com/fvbommel/sortorder v1.2.1
full diff: https://github.com/fvbommel/sortorder/compare/v1.2.0...v1.2.1

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 1600418944)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-11-03 11:31:51 +01:00
Sebastiaan van Stijn a82e528901 Merge pull request #7418 from vvoland/7417-29.x
[29.x] Update to go1.26.10
2026-10-20 13:24:07 +02:00
Paweł Gronowski e35bc1b6ae Update to go1.26.10
These releases include 1 security fix following the security policy:

- crypto/x509: mitigation for security concerns with a specific Certificate Authority

  We're blocking trust in a small set of intermediate certificates due to specific security concerns around their operation.

  Verify will now filter out chains which contain these intermediates, preventing them from being returned to the caller.

  We highly recommend immediately upgrading to this release.

  This is CVE-2026-111943 and Go issue https://go.dev/issue/82345.

release notes: https://go.dev/doc/devel/release#go1.26.10

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2026-10-20 12:42:59 +02:00
Paweł Gronowski baf6c13889 Bump version
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2026-10-20 12:40:09 +02:00
Paweł Gronowski 4051f75f69 Merge tag 'v29.9.1' into 7417-29.x
v29.9.1

# -----BEGIN PGP SIGNATURE-----
#
# iK0EABYKAFUWIQQX90wwlHYgZQhz61ZuYvmhLGnMZgUCas/KIxsUgAAAAAAEAA5t
# YW51MiwyLjUrMS4xMiwwLDMbHHBhd2VsLmdyb25vd3NraUBkb2NrZXIuY29tAAoJ
# EG5i+aEsacxmKWgBAKZGzyE7LzPW1Xy2ETngj+i8n96ZxkRPuzU7b2Rd+XLlAQCc
# YddGBSzdhrlh6EQtYdYMx7ArXfx7g8T10tGORAKqBw==
# =7Syv
# -----END PGP SIGNATURE-----
# gpg: Signature made Wed Oct 14 20:29:55 2026 CEST
# gpg:                using EDDSA key 17F74C30947620650873EB566E62F9A12C69CC66
# gpg:                issuer "pawel.gronowski@docker.com"
# gpg: Good signature from "Paweł Gronowski <pawel.gronowski@docker.com>" [ultimate]
2026-10-20 12:39:56 +02:00
Paweł Gronowski 76321a699d Merge tag 'v29.9.0' into 7417-29.x
v29.9.0

# -----BEGIN PGP SIGNATURE-----
#
# iK0EABYKAFUWIQQX90wwlHYgZQhz61ZuYvmhLGnMZgUCasf+dhsUgAAAAAAEAA5t
# YW51MiwyLjUrMS4xMiwwLDMbHHBhd2VsLmdyb25vd3NraUBkb2NrZXIuY29tAAoJ
# EG5i+aEsacxm3EYBAKRhamCCxqMBniTJ9GtLRVn7G3gbweSztHdAzhCo70C6AP41
# K+a4eqECp+bjqTK1ldegnmdyAPZ8g8AoPMpJgSQ2CA==
# =N5Qp
# -----END PGP SIGNATURE-----
# gpg: Signature made Thu Oct  8 22:35:02 2026 CEST
# gpg:                using EDDSA key 17F74C30947620650873EB566E62F9A12C69CC66
# gpg:                issuer "pawel.gronowski@docker.com"
# gpg: Good signature from "Paweł Gronowski <pawel.gronowski@docker.com>" [ultimate]
2026-10-20 12:39:56 +02:00
Paweł Gronowski b82456c62f Merge tag 'v29.8.2' into 7417-29.x
v29.8.2

# -----BEGIN PGP SIGNATURE-----
#
# iK0EABYKAFUWIQQX90wwlHYgZQhz61ZuYvmhLGnMZgUCar1jPxsUgAAAAAAEAA5t
# YW51MiwyLjUrMS4xMiwwLDMbHHBhd2VsLmdyb25vd3NraUBkb2NrZXIuY29tAAoJ
# EG5i+aEsacxmaQABAKG/rnQXNds4jV6qfRvaOS+tGa3Gy2hTY6o2aOgX3g3LAP4n
# OF3/gfVEcaQAK2dgxYTQnQvZi+/p69M1Bjsmy8ytBg==
# =x2Qn
# -----END PGP SIGNATURE-----
# gpg: Signature made Wed Sep 30 21:30:07 2026 CEST
# gpg:                using EDDSA key 17F74C30947620650873EB566E62F9A12C69CC66
# gpg:                issuer "pawel.gronowski@docker.com"
# gpg: Good signature from "Paweł Gronowski <pawel.gronowski@docker.com>" [ultimate]
2026-10-20 12:39:55 +02:00
Paweł Gronowski a98becc3e3 Bump version
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2026-10-20 12:36:49 +02:00
Paweł Gronowski eabc65846b Merge tag 'v29.8.1' into 29.x
v29.8.1
2026-09-29 14:09:44 +02:00
Paweł Gronowski b873f57cd0 Merge tag 'v29.8.0' into 29.x
v29.8.0
2026-09-29 14:09:44 +02:00
Paweł Gronowski c8a849c2f9 Merge tag 'v29.8.0-rc.1' into 29.x
v29.8.0-rc.1
2026-09-29 14:09:44 +02:00
Paweł Gronowski f4efc1b596 Merge tag 'v29.7.2' into 29.x
v29.7.2
2026-08-11 13:21:01 +02:00
Paweł Gronowski 2747e2e3bf Merge tag 'v29.7.1' into 29.x
v29.7.1
2026-08-11 13:21:01 +02:00
Paweł Gronowski 329cdf1a9d Merge tag 'v29.7.0' into 29.x
v29.7.0
2026-08-11 13:21:01 +02:00
Paweł Gronowski 0c7e2e7203 Merge tag 'v29.7.0-rc.1' into 29.x
v29.7.0-rc.1
2026-08-11 13:21:00 +02:00
Paweł Gronowski dfc4efb1e2 Merge pull request #7109 from vvoland/update-docker
[29.x] Bump to 29.6.2
2026-07-16 18:09:24 +02:00
Paweł Gronowski dba867594c Bump to 29.6.2
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2026-07-16 12:51:30 +02:00
Paweł Gronowski d9aefe565a Merge tag 'v29.6.1' into 29.x
v29.6.1
2026-07-15 17:35:42 +02:00
Paweł Gronowski 9182b351c1 Merge tag 'v29.6.0' into 29.x
v29.6.0
2026-07-15 17:35:42 +02:00
Paweł Gronowski 0ae55a3e6c Merge tag 'v29.5.3' into 29.x
v29.5.3
2026-07-15 17:35:42 +02:00
Paweł Gronowski 029a4b21b3 Merge tag 'v29.5.2' into 29.x
v29.5.2
2026-07-15 17:35:41 +02:00
Paweł Gronowski e596fea454 Merge tag 'v29.5.1' into 29.x
v29.5.1
2026-07-15 17:35:41 +02:00
Paweł Gronowski 0c72f456aa Merge tag 'v29.5.0' into 29.x
v29.5.0
2026-07-15 17:35:41 +02:00
Paweł Gronowski 26f2736a2b Merge tag 'v29.4.1' into 29.x
v29.4.1
2026-07-15 17:35:41 +02:00
Paweł Gronowski ac4c4dfabd Merge tag 'v29.4.0' into 29.x
v29.4.0
2026-07-15 17:35:40 +02:00
Sebastiaan van Stijn 1245054535 Merge pull request #7099 from vvoland/7098-29.x
[29.x backport] scripts/sync-branch: Fix non-interactive merge
2026-07-10 08:34:26 +02:00
Paweł Gronowski f72fb0caf0 scripts/sync-branch: Fix non-interactive merge
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit f57e528457)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2026-07-09 16:52:02 +02:00
Sebastiaan van Stijn e4af2bf0d3 Merge pull request #7097 from vvoland/7091-29.x
[29.x backport] gha: Add release branch sync workflow
2026-07-09 16:35:45 +02:00
Paweł Gronowski 49a1af6aaa gha: Add release branch sync workflow
Add a manually dispatched workflow for maintainers to sync a Docker
release branch to a selected release tag.

The sync-release-branch job checks out the release branch, computes
the list of unmerged tags up to the requested tag via
scripts/unmerged-tags, merges them in order via scripts/sync-branch
using git merge --no-ff (resolving conflicts by taking the tag's
content), then pushes the result to a temporary branch.

The push-release-branch job runs after manual approval via the
docker-releases environment. It verifies that neither the release
branch nor the temporary branch moved since the sync job ran before
force-advancing the release branch and deleting the temporary branch.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
(cherry picked from commit 182f56fe8c)
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2026-07-09 14:45:32 +02:00
Paweł Gronowski c2be9ccfc3 Merge pull request #6887 from thaJeztah/29.x_backport_pin_actions
[29.x backport] ci: pin actions to digests
2026-03-25 15:22:32 +01:00
Sebastiaan van Stijn 0da6a5121f ci: pin actions to digests
As a follow-up, we should use the full version (major.minor.patch).

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 97b9e04a94)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-03-25 15:06:23 +01:00
Sebastiaan van Stijn 6b3ca8fc04 Merge pull request #6884 from thaJeztah/29.x_backport_missing_buildtags
[29.x backport] cli/command: add missing "go:build" comments
2026-03-25 15:04:52 +01:00
Paweł Gronowski f47603c290 Merge pull request #6885 from thaJeztah/29.x_backport_update_actions
[29.x backport] update actions
2026-03-25 14:23:37 +01:00
dependabot[bot] 9709c8fe08 build(deps): bump docker/metadata-action from 5 to 6
Bumps [docker/metadata-action](https://github.com/docker/metadata-action) from 5 to 6.
- [Release notes](https://github.com/docker/metadata-action/releases)
- [Commits](https://github.com/docker/metadata-action/compare/v5...v6)

---
updated-dependencies:
- dependency-name: docker/metadata-action
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
(cherry picked from commit 39d676c72d)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-03-25 14:16:00 +01:00
dependabot[bot] af45a23fa9 build(deps): bump docker/bake-action from 6 to 7
Bumps [docker/bake-action](https://github.com/docker/bake-action) from 6 to 7.
- [Release notes](https://github.com/docker/bake-action/releases)
- [Commits](https://github.com/docker/bake-action/compare/v6...v7)

---
updated-dependencies:
- dependency-name: docker/bake-action
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
(cherry picked from commit 6453c4c3a7)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-03-25 14:15:48 +01:00
Paweł Gronowski bc97f5ac19 Merge pull request #6883 from thaJeztah/29.x_backport_update_go1.25.8
[29.x backport] update to go1.25.8
2026-03-25 14:14:46 +01:00
Sebastiaan van Stijn 6d71967120 cli/command: add missing "go:build" comments
- commit e8dc2fce32 modernized loops to
  range over int, which requires go1.22 or later.
- commit 85ebca52fd modernized code to
  use stdlib min/max, which requires go1.21 or later.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 9a471180cb)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-03-25 14:11:15 +01:00
Sebastiaan van Stijn 9b51892b80 update to go1.25.8
go1.25.8 (released 2026-03-05) includes security fixes to the html/template,
net/url, and os packages, as well as bug fixes to the go command, the compiler,
and the os package. See the Go 1.25.8 milestone on our issue tracker for details.

- 1.25.8 https://github.com/golang/go/issues?q=milestone%3AGo1.25.8+label%3ACherryPickApproved
- diff: https://github.com/golang/go/compare/go1.25.7...go1.25.8
- 1.26.1 https://github.com/golang/go/issues?q=milestone%3AGo1.26.1+label%3ACherryPickApproved
- diff: https://github.com/golang/go/compare/go1.26.0...go1.26.1

---

We have just released Go versions 1.26.1 and 1.25.8, minor point releases.

These releases include 5 security fixes following the security policy:

crypto/x509: incorrect enforcement of email constraints

- When verifying a certificate chain which contains a certificate containing
  multiple email address constraints (composed of the full email address) which
  share common local portions (the portion of the address before the '@'
  character) but different domain portions (the portion of the address after the
  '@' character), these constraints will not be properly applied, and only the
  last constraint will be considered.

  This can allow certificates in the chain containing email addresses which are
  either not permitted or excluded by the relevant constraints to be returned by
  calls to Certificate.Verify. Since the name constraint checks happen after chain
  building is complete, this only applies to certificate chains which chain to
  trusted roots (root certificates either in VerifyOptions.Roots or in the system
  root certificate pool), requiring a trusted CA to issue certificates containing
  either not permitted or excluded email addresses.

  This issue only affects Go 1.26.

  Thanks to Jakub Ciolek for reporting this issue.

  This is CVE-2026-27137 and Go issue https://go.dev/issue/77952.

- crypto/x509: panic in name constraint checking for malformed certificates

  Certificate verification can panic when a certificate in the chain has an empty
  DNS name and another certificate in the chain has excluded name constraints.
  This can crash programs that are either directly verifying X.509 certificate
  chains, or those that use TLS.

  Since the name constraint checks happen after chain building is complete, this
  only applies to certificate chains which chain to trusted roots (root
  certificates either in VerifyOptions.Roots or in the system root certificate
  pool), requiring a trusted CA to issue certificates containing malformed DNS
  names.

  This issue only affects Go 1.26.

  Thanks to Jakub Ciolek for reporting this issue.

  This is CVE-2026-27138 and Go issue https://go.dev/issue/77953.

- html/template: URLs in meta content attribute actions are not escaped

  Actions which insert URLs into the content attribute of HTML meta tags are not
  escaped. This can allow XSS if the meta tag also has an http-equiv attribute
  with the value "refresh".

  A new GODEBUG setting has been added, htmlmetacontenturlescape, which can be
  used to disable escaping URLs in actions in the meta content attribute which
  follow "url=" by setting htmlmetacontenturlescape=0.

  This is CVE-2026-27142 and Go issue https://go.dev/issue/77954.

- net/url: reject IPv6 literal not at start of host

  The Go standard library function net/url.Parse insufficiently
  validated the host/authority component and accepted some invalid URLs
  by effectively treating garbage before an IP-literal as ignorable.
  The function should have rejected this as invalid.

  To prevent this behavior, net/url.Parse now rejects IPv6 literals
  that do not appear at the start of the host subcomponent of a URL.

  Thanks to Masaki Hara (https://github.com/qnighy) of Wantedly.

  This is CVE-2026-25679 and Go issue https://go.dev/issue/77578.

- os: FileInfo can escape from a Root

  On Unix platforms, when listing the contents of a directory using
  File.ReadDir or File.Readdir the returned FileInfo could reference
  a file outside of the Root in which the File was opened.

  The contents of the FileInfo were populated using the lstat system
  call, which takes the path to the file as a parameter. If a component
  of the full path of the file described by the FileInfo is replaced with
  a symbolic link, the target of the lstat can be directed to another
  location on the filesystem.

  The impact of this escape is limited to reading metadata provided by
  lstat from arbitrary locations on the filesystem. This could be used
  to probe for the presence or absence of files as well as gleaning
  metadata like file sizes, but does not permit reading or writing files
  outside the root.

  The FileInfo is now populated using fstatat.

  Thank you to Miloslav Trmač of Red Hat for reporting this issue.

  This is CVE-2026-27139 and Go issue https://go.dev/issue/77827.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit f7d83cbae8)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-03-25 14:08:46 +01:00
35 changed files with 498 additions and 218 deletions
+1 -1
View File
@@ -64,7 +64,7 @@ jobs:
name: Update Go
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: "1.27.1"
go-version: "1.26.10"
cache: false
-
name: Initialize CodeQL
+1 -1
View File
@@ -68,7 +68,7 @@ jobs:
name: Set up Go
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: "1.27.1"
go-version: "1.26.10"
cache: false
-
name: Test
+1 -1
View File
@@ -101,7 +101,7 @@ jobs:
name: Set up Go
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: "1.27.1"
go-version: "1.26.10"
cache: false
-
name: Run gocompat check
+1 -1
View File
@@ -5,7 +5,7 @@ run:
# which causes it to fallback to go1.17 semantics.
#
# TODO(thaJeztah): update "usetesting" settings to enable go1.24 features once our minimum version is go1.24
go: "1.26.9"
go: "1.26.10"
timeout: 5m
+1 -1
View File
@@ -8,7 +8,7 @@ ARG BASE_VARIANT=alpine
ARG ALPINE_VERSION=3.23
ARG BASE_DEBIAN_DISTRO=bookworm
ARG GO_VERSION=1.26.9
ARG GO_VERSION=1.26.10
# XX_VERSION specifies the version of the xx utility to use.
# It must be a valid tag in the docker.io/tonistiigi/xx image repository.
+1 -1
View File
@@ -1 +1 @@
29.9.1
29.9.3
+1 -1
View File
@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:1
ARG GO_VERSION=1.26.9
ARG GO_VERSION=1.26.10
# ALPINE_VERSION sets the version of the alpine base image to use, including for the golang image.
# It must be a supported tag in the docker.io/library/alpine image repository
+1 -1
View File
@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:1
ARG GO_VERSION=1.26.9
ARG GO_VERSION=1.26.10
# ALPINE_VERSION sets the version of the alpine base image to use, including for the golang image.
# It must be a supported tag in the docker.io/library/alpine image repository
+1 -1
View File
@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:1
ARG GO_VERSION=1.26.9
ARG GO_VERSION=1.26.10
# ALPINE_VERSION sets the version of the alpine base image to use, including for the golang image.
# It must be a supported tag in the docker.io/library/alpine image repository
+5 -5
View File
@@ -24,8 +24,8 @@ require (
github.com/docker/docker-credential-helpers v0.9.9
github.com/docker/go-connections v0.8.2
github.com/docker/go-units v0.5.0
github.com/fvbommel/sortorder v1.2.0
github.com/go-jose/go-jose/v4 v4.1.5
github.com/fvbommel/sortorder v1.2.1
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
@@ -36,7 +36,7 @@ require (
github.com/moby/moby/api v1.56.1
github.com/moby/moby/client v0.6.2
github.com/moby/patternmatcher v0.6.1
github.com/moby/swarmkit/v2 v2.1.2
github.com/moby/swarmkit/v2 v2.1.3
github.com/moby/sys/atomicwriter v0.1.0
github.com/moby/sys/capability v0.4.0
github.com/moby/sys/sequential v0.7.0
@@ -60,7 +60,7 @@ require (
go.opentelemetry.io/otel/sdk v1.46.0
go.opentelemetry.io/otel/sdk/metric v1.46.0
go.opentelemetry.io/otel/trace v1.46.0
go.yaml.in/yaml/v3 v3.0.5
go.yaml.in/yaml/v3 v3.0.6
golang.org/x/sync v0.23.0
golang.org/x/sys v0.48.0
golang.org/x/term v0.46.0
@@ -87,7 +87,7 @@ require (
github.com/gorilla/mux v1.8.1 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.30.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/klauspost/compress v1.20.1 // indirect
github.com/klauspost/compress v1.20.2 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/sys/user v0.4.1 // indirect
github.com/moby/sys/userns v0.2.1 // indirect
+10 -10
View File
@@ -49,10 +49,10 @@ github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
github.com/felixge/httpsnoop v1.1.0 h1:3YtUj32ZZkqZtt3sZZsClsymw/QDuVfpNhoA31zeORc=
github.com/felixge/httpsnoop v1.1.0/go.mod h1:Zqxgdd+1Rkcz8euOqdr7lqgCRJztwr5hp9vDSi5UZCE=
github.com/fvbommel/sortorder v1.2.0 h1:TRIiRiGX+djh3Yf4FVxmWmAcYfIr5dH0NbzJWOSAWZk=
github.com/fvbommel/sortorder v1.2.0/go.mod h1:LbhO04ijZIeUuvz9B9BkI/qYrpZZEn1gWhxv4QjUKVs=
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/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.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=
@@ -78,8 +78,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.20.1 h1:T7kKElXUMXrUJ2E9QhQhxFtcK5rPyLdsGZvdbLMPdiQ=
github.com/klauspost/compress v1.20.1/go.mod h1:LUdAzn7YLVvxLpc7y3V1m40wESHTgc1422pwwBSKYuI=
github.com/klauspost/compress v1.20.2 h1:v5tiZvm1KGLyg5d5oXdXe3lsSPrbEUiKoXGia//I7Qo=
github.com/klauspost/compress v1.20.2/go.mod h1:LUdAzn7YLVvxLpc7y3V1m40wESHTgc1422pwwBSKYuI=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/mattn/go-runewidth v0.0.31 h1:1oCV4ReTlosDBc6rYRw5cL8S/4y8iv5oRl4SJ5IBgwo=
@@ -94,8 +94,8 @@ github.com/moby/moby/client v0.6.2 h1:ekSPlMccrZGcw6Scb8T9D39qE0mB+XupU/yS0zNw9N
github.com/moby/moby/client v0.6.2/go.mod h1:DGcnO7qmPJrqobx/ggQgQ/AUk+2wgVdQv7uxB0/mEsc=
github.com/moby/patternmatcher v0.6.1 h1:qlhtafmr6kgMIJjKJMDmMWq7WLkKIo23hsrpR3x084U=
github.com/moby/patternmatcher v0.6.1/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
github.com/moby/swarmkit/v2 v2.1.2 h1:1WDZAI6HVYNKdCG4zlXnTAPyLsLwuhRGWlHoOUf5Z6I=
github.com/moby/swarmkit/v2 v2.1.2/go.mod h1:GQ6T0ij2oBbWX10OHwpvK449xfXkQMZ8J+B+eQ4mgp4=
github.com/moby/swarmkit/v2 v2.1.3 h1:UcwtwkIRjr75qSgUWCTIuzKUzAXlidxsiqVMnyxSF1w=
github.com/moby/swarmkit/v2 v2.1.3/go.mod h1:KhkxT93Hm4wHoNUPJ4JRD384pS7OODFGzJWoDRj9bLE=
github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs=
github.com/moby/sys/capability v0.4.0 h1:4D4mI6KlNtWMCM1Z/K0i7RV1FkX+DBDHKVJpCndZoHk=
@@ -180,8 +180,8 @@ go.opentelemetry.io/proto/otlp v1.11.0/go.mod h1:SmVizdCOAm3XBtG1g1NnOdhW6jtddT7
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw=
go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg=
go.yaml.in/yaml/v3 v3.0.6 h1:zcDfvjXEqTQmpjniUBLc91xYJMB2c4QOFxEF/LCEckM=
go.yaml.in/yaml/v3 v3.0.6/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+33 -3
View File
@@ -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)
+6 -32
View File
@@ -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
View File
@@ -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
View File
@@ -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")
+59 -25
View File
@@ -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)
}
+74 -24
View File
@@ -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")
}
+79 -32
View File
@@ -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)
}
+1 -1
View File
@@ -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)")
+12 -17
View File
@@ -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,
+43 -37
View File
@@ -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
}
+4 -1
View File
@@ -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
View File
@@ -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")
}
+13
View File
@@ -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", "./..."]
+25
View File
@@ -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.
+2 -1
View File
@@ -659,7 +659,8 @@ func (s *Scratch) validateNorm() (err error) {
if v >= 0 {
total += int(v)
} else {
total -= int(v)
// -1 takes one cell. Adding -v would let a wrapped -32768 pass.
total++
}
}
defer func() {
+6
View File
@@ -3,6 +3,7 @@ package fse
import (
"errors"
"fmt"
"math"
)
const (
@@ -123,6 +124,11 @@ func (s *Scratch) readNCount() error {
remaining -= count
gotTotal += count
}
if count > math.MaxInt16 {
// Only one symbol filling a tableLog 15 table, which cannot be decoded.
// Truncated, it would leave the decoding table unwritten.
return fmt.Errorf("corruption detected (count %d > %d)", count, math.MaxInt16)
}
s.norm[charnum&0xff] = int16(count)
charnum++
previous0 = count == 0
+4
View File
@@ -54,6 +54,10 @@ func ReadTable(in []byte, s *Scratch) (s2 *Scratch, remain []byte, err error) {
if len(in) < int(iSize) {
return s, nil, fmt.Errorf("input too small for table, want %d bytes, have %d", iSize, len(in))
}
// The low nibble is the weights' FSE tableLog - 5, which the format limits to 6.
if in[0]&15+5 > 6 {
return s, nil, errors.New("corrupt input: weights tableLog too big")
}
// FSE compressed weights
s.fse.DecompressLimit = 255
hw := s.huffWeight[:]
+3
View File
@@ -219,6 +219,9 @@ func BuildDict(o BuildDictOptions) ([]byte, error) {
if len(contents) == 0 {
return nil, errors.New("no content provided")
}
if o.Level < speedNotSet || o.Level >= speedLast {
return nil, fmt.Errorf("unknown encoder level %d", o.Level)
}
d := dict{
id: o.ID,
litEnc: nil,
+12
View File
@@ -69,6 +69,10 @@ var (
// No CRC value is being generated and not all CRC values of the Snappy stream are checked.
// However, it provides really fast recompression of Snappy streams.
// The converter can be reused to avoid allocations, even after errors.
//
// Deprecated: Decode the stream with s2.NewReader, which reads Snappy streams,
// and compress the output with an Encoder. This validates the input and
// compresses much better.
type SnappyConverter struct {
r io.Reader
err error
@@ -373,6 +377,14 @@ func decodeSnappy(blk *blockEnc, src []byte) error {
offset = uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24
}
// A zstd match is at least zstdMinMatch bytes. A shorter copy
// cannot be represented as a sequence and would underflow the
// matchLen computation below, producing an out-of-range match
// length code.
if length < zstdMinMatch {
return ErrSnappyCorrupt
}
if offset <= 0 || blk.size+lits < int(offset) /*|| length > len(blk)-d */ {
println("offset <= 0 || blk.size+lits < int(offset)", offset, blk.size+lits, int(offset), blk.size, lits)
+60 -9
View File
@@ -22,7 +22,7 @@ file {
java_package: "com.google.protobuf"
java_outer_classname: "TimestampProto"
java_multiple_files: true
go_package: "github.com/golang/protobuf/ptypes/timestamp"
go_package: "google.golang.org/protobuf/types/known/timestamppb"
cc_enable_arenas: true
objc_class_prefix: "GPB"
csharp_namespace: "Google.Protobuf.WellKnownTypes"
@@ -53,7 +53,7 @@ file {
java_package: "com.google.protobuf"
java_outer_classname: "DurationProto"
java_multiple_files: true
go_package: "github.com/golang/protobuf/ptypes/duration"
go_package: "google.golang.org/protobuf/types/known/durationpb"
cc_enable_arenas: true
objc_class_prefix: "GPB"
csharp_namespace: "Google.Protobuf.WellKnownTypes"
@@ -157,7 +157,7 @@ file {
java_package: "com.google.protobuf"
java_outer_classname: "WrappersProto"
java_multiple_files: true
go_package: "github.com/golang/protobuf/ptypes/wrappers"
go_package: "google.golang.org/protobuf/types/known/wrapperspb"
cc_enable_arenas: true
objc_class_prefix: "GPB"
csharp_namespace: "Google.Protobuf.WellKnownTypes"
@@ -484,6 +484,13 @@ file {
type_name: ".google.protobuf.FieldOptions"
json_name: "options"
}
field {
name: "proto3_optional"
number: 17
label: LABEL_OPTIONAL
type: TYPE_BOOL
json_name: "proto3Optional"
}
enum_type {
name: "Type"
value {
@@ -853,7 +860,7 @@ file {
number: 31
label: LABEL_OPTIONAL
type: TYPE_BOOL
default_value: "false"
default_value: "true"
json_name: "ccEnableArenas"
}
field {
@@ -1405,7 +1412,7 @@ file {
java_package: "com.google.protobuf"
java_outer_classname: "DescriptorProtos"
optimize_for: SPEED
go_package: "github.com/golang/protobuf/protoc-gen-go/descriptor;descriptor"
go_package: "google.golang.org/protobuf/types/descriptorpb"
cc_enable_arenas: true
objc_class_prefix: "GPB"
csharp_namespace: "Google.Protobuf.Reflection"
@@ -5208,7 +5215,7 @@ file {
java_package: "com.google.protobuf"
java_outer_classname: "AnyProto"
java_multiple_files: true
go_package: "github.com/golang/protobuf/ptypes/any"
go_package: "google.golang.org/protobuf/types/known/anypb"
objc_class_prefix: "GPB"
csharp_namespace: "Google.Protobuf.WellKnownTypes"
}
@@ -10590,7 +10597,7 @@ file {
syntax: "proto3"
}
file {
name: "go.etcd.io/etcd/raft/v3/raftpb/raft.proto"
name: "go.etcd.io/raft/v3/raftpb/raft.proto"
package: "raftpb"
dependency: "gogoproto/gogo.proto"
message_type {
@@ -10773,6 +10780,16 @@ file {
}
json_name: "commit"
}
field {
name: "vote"
number: 13
label: LABEL_OPTIONAL
type: TYPE_UINT64
options {
65001: 0
}
json_name: "vote"
}
field {
name: "snapshot"
number: 9
@@ -10780,7 +10797,7 @@ file {
type: TYPE_MESSAGE
type_name: ".raftpb.Snapshot"
options {
65001: 0
65001: 1
}
json_name: "snapshot"
}
@@ -10809,8 +10826,22 @@ file {
number: 12
label: LABEL_OPTIONAL
type: TYPE_BYTES
options {
65001: 1
}
json_name: "context"
}
field {
name: "responses"
number: 14
label: LABEL_REPEATED
type: TYPE_MESSAGE
type_name: ".raftpb.Message"
options {
65001: 0
}
json_name: "responses"
}
}
message_type {
name: "HardState"
@@ -11079,6 +11110,26 @@ file {
name: "MsgPreVoteResp"
number: 18
}
value {
name: "MsgStorageAppend"
number: 19
}
value {
name: "MsgStorageAppendResp"
number: 20
}
value {
name: "MsgStorageApply"
number: 21
}
value {
name: "MsgStorageApplyResp"
number: 22
}
value {
name: "MsgForgetLeader"
number: 23
}
}
enum_type {
name: "ConfChangeTransition"
@@ -11130,7 +11181,7 @@ file {
package: "docker.swarmkit.v1"
dependency: "github.com/docker/swarmkit/api/objects.proto"
dependency: "github.com/docker/swarmkit/api/types.proto"
dependency: "go.etcd.io/etcd/raft/v3/raftpb/raft.proto"
dependency: "go.etcd.io/raft/v3/raftpb/raft.proto"
dependency: "gogoproto/gogo.proto"
dependency: "github.com/docker/swarmkit/protobuf/plugin/plugin.proto"
message_type {
+2 -2
View File
@@ -12,7 +12,7 @@ type CopierFrom interface {
// Copy takes the fields from src and copies them into the target object.
//
// Calling this method with a nil receiver or a nil src may panic.
CopyFrom(src interface{})
CopyFrom(src any)
}
// Copy copies src into dst. dst and src must have the same type.
@@ -24,7 +24,7 @@ type CopierFrom interface {
//
// If the copy cannot be performed, this function will panic. Make sure to test
// types that use this function.
func Copy(dst, src interface{}) {
func Copy(dst, src any) {
switch dst := dst.(type) {
case *types.Any:
src := src.(*types.Any)
+2 -2
View File
@@ -73,7 +73,7 @@ func customIndexer(kind string, annotations *Annotations) (bool, [][]byte, error
return len(converted) != 0, converted, nil
}
func fromArgs(args ...interface{}) ([]byte, error) {
func fromArgs(args ...any) ([]byte, error) {
if len(args) != 1 {
return nil, fmt.Errorf("must provide only a single argument")
}
@@ -86,7 +86,7 @@ func fromArgs(args ...interface{}) ([]byte, error) {
return []byte(arg), nil
}
func prefixFromArgs(args ...interface{}) ([]byte, error) {
func prefixFromArgs(args ...any) ([]byte, error) {
val, err := fromArgs(args...)
if err != nil {
return nil, err
+1
View File
@@ -42,6 +42,7 @@ func init() {
for _, c := range "yYnNtTfFoO~" {
t[int(c)] = 'M' // In map
}
t[int('<')] = 'M' // In map (merge key "<<")
t[int('.')] = '.' // Float (potentially in map)
var resolveMapList = []struct {
+6 -6
View File
@@ -90,10 +90,10 @@ github.com/docker/go-units
# github.com/felixge/httpsnoop v1.1.0
## explicit; go 1.25
github.com/felixge/httpsnoop
# github.com/fvbommel/sortorder v1.2.0
# github.com/fvbommel/sortorder v1.2.1
## explicit; go 1.21
github.com/fvbommel/sortorder
# 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
@@ -145,7 +145,7 @@ github.com/grpc-ecosystem/grpc-gateway/v2/utilities
# github.com/inconshreveable/mousetrap v1.1.0
## explicit; go 1.18
github.com/inconshreveable/mousetrap
# github.com/klauspost/compress v1.20.1
# github.com/klauspost/compress v1.20.2
## explicit; go 1.25
github.com/klauspost/compress
github.com/klauspost/compress/fse
@@ -205,8 +205,8 @@ github.com/moby/moby/client/pkg/versions
## explicit; go 1.19
github.com/moby/patternmatcher
github.com/moby/patternmatcher/ignorefile
# github.com/moby/swarmkit/v2 v2.1.2
## explicit; go 1.24.0
# github.com/moby/swarmkit/v2 v2.1.3
## explicit; go 1.25.0
github.com/moby/swarmkit/v2/api
github.com/moby/swarmkit/v2/api/deepcopy
github.com/moby/swarmkit/v2/api/defaults
@@ -388,7 +388,7 @@ go.opentelemetry.io/proto/otlp/common/v1
go.opentelemetry.io/proto/otlp/metrics/v1
go.opentelemetry.io/proto/otlp/resource/v1
go.opentelemetry.io/proto/otlp/trace/v1
# go.yaml.in/yaml/v3 v3.0.5
# go.yaml.in/yaml/v3 v3.0.6
## explicit; go 1.16
go.yaml.in/yaml/v3
# golang.org/x/mod v0.41.0