mirror of
https://github.com/docker/cli.git
synced 2026-11-12 15:53:52 -04:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5457199aa5 | ||
|
|
cac50c5e62 | ||
|
|
00d843b496 | ||
|
|
64fe50bbea | ||
|
|
999ab16f09 | ||
|
|
bb485bc900 | ||
|
|
86e51b44de | ||
|
|
d9bbcfcb4d | ||
|
|
2e886262b1 | ||
|
|
a4971d1f60 | ||
|
|
bfb5814dd5 | ||
|
|
68e452624a | ||
|
|
160531c55d | ||
|
|
a82e528901 | ||
|
|
e35bc1b6ae | ||
|
|
baf6c13889 | ||
|
|
4051f75f69 | ||
|
|
76321a699d | ||
|
|
b82456c62f | ||
|
|
a98becc3e3 | ||
|
|
eabc65846b | ||
|
|
b873f57cd0 | ||
|
|
c8a849c2f9 | ||
|
|
f4efc1b596 | ||
|
|
2747e2e3bf | ||
|
|
329cdf1a9d | ||
|
|
0c7e2e7203 | ||
|
|
dfc4efb1e2 | ||
|
|
dba867594c | ||
|
|
d9aefe565a | ||
|
|
9182b351c1 | ||
|
|
0ae55a3e6c | ||
|
|
029a4b21b3 | ||
|
|
e596fea454 | ||
|
|
0c72f456aa | ||
|
|
26f2736a2b | ||
|
|
ac4c4dfabd | ||
|
|
1245054535 | ||
|
|
f72fb0caf0 | ||
|
|
e4af2bf0d3 | ||
|
|
49a1af6aaa | ||
|
|
c2be9ccfc3 | ||
|
|
0da6a5121f | ||
|
|
6b3ca8fc04 | ||
|
|
f47603c290 | ||
|
|
9709c8fe08 | ||
|
|
af45a23fa9 | ||
|
|
bc97f5ac19 | ||
|
|
6d71967120 | ||
|
|
9b51892b80 |
@@ -64,7 +64,7 @@ jobs:
|
|||||||
name: Update Go
|
name: Update Go
|
||||||
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
||||||
with:
|
with:
|
||||||
go-version: "1.27.1"
|
go-version: "1.26.10"
|
||||||
cache: false
|
cache: false
|
||||||
-
|
-
|
||||||
name: Initialize CodeQL
|
name: Initialize CodeQL
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ jobs:
|
|||||||
name: Set up Go
|
name: Set up Go
|
||||||
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
||||||
with:
|
with:
|
||||||
go-version: "1.27.1"
|
go-version: "1.26.10"
|
||||||
cache: false
|
cache: false
|
||||||
-
|
-
|
||||||
name: Test
|
name: Test
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ jobs:
|
|||||||
name: Set up Go
|
name: Set up Go
|
||||||
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
||||||
with:
|
with:
|
||||||
go-version: "1.27.1"
|
go-version: "1.26.10"
|
||||||
cache: false
|
cache: false
|
||||||
-
|
-
|
||||||
name: Run gocompat check
|
name: Run gocompat check
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ run:
|
|||||||
# which causes it to fallback to go1.17 semantics.
|
# 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
|
# 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
|
timeout: 5m
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -8,7 +8,7 @@ ARG BASE_VARIANT=alpine
|
|||||||
ARG ALPINE_VERSION=3.23
|
ARG ALPINE_VERSION=3.23
|
||||||
ARG BASE_DEBIAN_DISTRO=bookworm
|
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.
|
# 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.
|
# It must be a valid tag in the docker.io/tonistiigi/xx image repository.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# syntax=docker/dockerfile:1
|
# 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.
|
# 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
|
# It must be a supported tag in the docker.io/library/alpine image repository
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# syntax=docker/dockerfile:1
|
# 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.
|
# 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
|
# It must be a supported tag in the docker.io/library/alpine image repository
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# syntax=docker/dockerfile:1
|
# 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.
|
# 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
|
# It must be a supported tag in the docker.io/library/alpine image repository
|
||||||
|
|||||||
+5
-5
@@ -24,8 +24,8 @@ require (
|
|||||||
github.com/docker/docker-credential-helpers v0.9.9
|
github.com/docker/docker-credential-helpers v0.9.9
|
||||||
github.com/docker/go-connections v0.8.2
|
github.com/docker/go-connections v0.8.2
|
||||||
github.com/docker/go-units v0.5.0
|
github.com/docker/go-units v0.5.0
|
||||||
github.com/fvbommel/sortorder v1.2.0
|
github.com/fvbommel/sortorder v1.2.1
|
||||||
github.com/go-jose/go-jose/v4 v4.1.5
|
github.com/go-jose/go-jose/v4 v4.1.7
|
||||||
github.com/go-viper/mapstructure/v2 v2.5.0
|
github.com/go-viper/mapstructure/v2 v2.5.0
|
||||||
github.com/gogo/protobuf v1.3.2
|
github.com/gogo/protobuf v1.3.2
|
||||||
github.com/google/go-cmp v0.7.0
|
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/api v1.56.1
|
||||||
github.com/moby/moby/client v0.6.2
|
github.com/moby/moby/client v0.6.2
|
||||||
github.com/moby/patternmatcher v0.6.1
|
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/atomicwriter v0.1.0
|
||||||
github.com/moby/sys/capability v0.4.0
|
github.com/moby/sys/capability v0.4.0
|
||||||
github.com/moby/sys/sequential v0.7.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 v1.46.0
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.46.0
|
go.opentelemetry.io/otel/sdk/metric v1.46.0
|
||||||
go.opentelemetry.io/otel/trace 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/sync v0.23.0
|
||||||
golang.org/x/sys v0.48.0
|
golang.org/x/sys v0.48.0
|
||||||
golang.org/x/term v0.46.0
|
golang.org/x/term v0.46.0
|
||||||
@@ -87,7 +87,7 @@ require (
|
|||||||
github.com/gorilla/mux v1.8.1 // indirect
|
github.com/gorilla/mux v1.8.1 // indirect
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.30.0 // indirect
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.30.0 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.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/docker-image-spec v1.3.1 // indirect
|
||||||
github.com/moby/sys/user v0.4.1 // indirect
|
github.com/moby/sys/user v0.4.1 // indirect
|
||||||
github.com/moby/sys/userns v0.2.1 // indirect
|
github.com/moby/sys/userns v0.2.1 // indirect
|
||||||
|
|||||||
+10
-10
@@ -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/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 h1:3YtUj32ZZkqZtt3sZZsClsymw/QDuVfpNhoA31zeORc=
|
||||||
github.com/felixge/httpsnoop v1.1.0/go.mod h1:Zqxgdd+1Rkcz8euOqdr7lqgCRJztwr5hp9vDSi5UZCE=
|
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.1 h1:ASc85RbthwLEqzuiCk7WQQiopfyGWQiEYZVJ3Qa4A+U=
|
||||||
github.com/fvbommel/sortorder v1.2.0/go.mod h1:LbhO04ijZIeUuvz9B9BkI/qYrpZZEn1gWhxv4QjUKVs=
|
github.com/fvbommel/sortorder v1.2.1/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.7 h1:Nac/98uT5LPkfbiFuYa8ktf62a2VxwQ4xbq1GK8pV5E=
|
||||||
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.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 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8=
|
||||||
github.com/go-logr/logr v1.4.4/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
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/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
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/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.2 h1:v5tiZvm1KGLyg5d5oXdXe3lsSPrbEUiKoXGia//I7Qo=
|
||||||
github.com/klauspost/compress v1.20.1/go.mod h1:LUdAzn7YLVvxLpc7y3V1m40wESHTgc1422pwwBSKYuI=
|
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 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
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=
|
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/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 h1:qlhtafmr6kgMIJjKJMDmMWq7WLkKIo23hsrpR3x084U=
|
||||||
github.com/moby/patternmatcher v0.6.1/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
|
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.3 h1:UcwtwkIRjr75qSgUWCTIuzKUzAXlidxsiqVMnyxSF1w=
|
||||||
github.com/moby/swarmkit/v2 v2.1.2/go.mod h1:GQ6T0ij2oBbWX10OHwpvK449xfXkQMZ8J+B+eQ4mgp4=
|
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 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
|
||||||
github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs=
|
github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs=
|
||||||
github.com/moby/sys/capability v0.4.0 h1:4D4mI6KlNtWMCM1Z/K0i7RV1FkX+DBDHKVJpCndZoHk=
|
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 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
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.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.6 h1:zcDfvjXEqTQmpjniUBLc91xYJMB2c4QOFxEF/LCEckM=
|
||||||
go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg=
|
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-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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
|||||||
+33
-3
@@ -408,7 +408,10 @@ func (ctx *genericEncrypter) EncryptWithAuthData(plaintext, aad []byte) (*JSONWe
|
|||||||
(*obj.protected)[k] = makeRawMessage(b)
|
(*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)
|
parts, err := ctx.cipher.encrypt(cek, authData, plaintext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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
|
// Decrypt and validate the object and return the plaintext. This
|
||||||
// function does not support multi-recipient. If you desire multi-recipient
|
// function does not support multi-recipient. If you desire multi-recipient
|
||||||
// decryption use DecryptMulti instead.
|
// decryption use DecryptMulti instead.
|
||||||
@@ -485,7 +495,10 @@ func (obj JSONWebEncryption) Decrypt(decryptionKey interface{}) ([]byte, error)
|
|||||||
tag: obj.tag,
|
tag: obj.tag,
|
||||||
}
|
}
|
||||||
|
|
||||||
authData := obj.computeAuthData()
|
authData, err := obj.computeAuthData()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
var plaintext []byte
|
var plaintext []byte
|
||||||
recipient := obj.recipients[0]
|
recipient := obj.recipients[0]
|
||||||
@@ -495,6 +508,10 @@ func (obj JSONWebEncryption) Decrypt(decryptionKey interface{}) ([]byte, error)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ErrCryptoFailure
|
return nil, ErrCryptoFailure
|
||||||
}
|
}
|
||||||
|
err = validateContentEncryptionKeySize(cek, cipher)
|
||||||
|
if err != nil {
|
||||||
|
return nil, ErrCryptoFailure
|
||||||
|
}
|
||||||
|
|
||||||
// Found a valid CEK -- let's try to decrypt.
|
// Found a valid CEK -- let's try to decrypt.
|
||||||
plaintext, err = cipher.decrypt(cek, authData, parts)
|
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
|
// 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.
|
// 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) {
|
func (obj JSONWebEncryption) DecryptMulti(decryptionKey interface{}) (int, Header, []byte, error) {
|
||||||
globalHeaders := obj.mergedHeaders(nil)
|
globalHeaders := obj.mergedHeaders(nil)
|
||||||
|
|
||||||
@@ -553,7 +576,10 @@ func (obj JSONWebEncryption) DecryptMulti(decryptionKey interface{}) (int, Heade
|
|||||||
tag: obj.tag,
|
tag: obj.tag,
|
||||||
}
|
}
|
||||||
|
|
||||||
authData := obj.computeAuthData()
|
authData, err := obj.computeAuthData()
|
||||||
|
if err != nil {
|
||||||
|
return -1, Header{}, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
index := -1
|
index := -1
|
||||||
var plaintext []byte
|
var plaintext []byte
|
||||||
@@ -572,6 +598,10 @@ func (obj JSONWebEncryption) DecryptMulti(decryptionKey interface{}) (int, Heade
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
err = validateContentEncryptionKeySize(cek, cipher)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// Found a valid CEK -- let's try to decrypt.
|
// Found a valid CEK -- let's try to decrypt.
|
||||||
plaintext, err = cipher.decrypt(cek, authData, parts)
|
plaintext, err = cipher.decrypt(cek, authData, parts)
|
||||||
|
|||||||
+6
-32
@@ -30,30 +30,6 @@ import (
|
|||||||
"github.com/go-jose/go-jose/v4/json"
|
"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
|
// Strip all newlines and whitespace
|
||||||
func stripWhitespace(data string) string {
|
func stripWhitespace(data string) string {
|
||||||
buf := strings.Builder{}
|
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.
|
// 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 {
|
type byteBuffer struct {
|
||||||
data []byte
|
data []byte
|
||||||
}
|
}
|
||||||
@@ -169,13 +147,13 @@ func (b *byteBuffer) UnmarshalJSON(data []byte) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
*b = *newBuffer(decoded)
|
b.data = decoded
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *byteBuffer) base64() string {
|
func (b *byteBuffer) base64() string {
|
||||||
return base64.RawURLEncoding.EncodeToString(b.data)
|
return base64.RawURLEncoding.EncodeToString(b.bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *byteBuffer) bytes() []byte {
|
func (b *byteBuffer) bytes() []byte {
|
||||||
@@ -186,12 +164,8 @@ func (b *byteBuffer) bytes() []byte {
|
|||||||
return b.data
|
return b.data
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b byteBuffer) bigInt() *big.Int {
|
func (b *byteBuffer) bigInt() *big.Int {
|
||||||
return new(big.Int).SetBytes(b.data)
|
return new(big.Int).SetBytes(b.bytes())
|
||||||
}
|
|
||||||
|
|
||||||
func (b byteBuffer) toInt() int {
|
|
||||||
return int(b.bigInt().Int64())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func base64EncodeLen(sl []byte) int {
|
func base64EncodeLen(sl []byte) int {
|
||||||
|
|||||||
+13
@@ -671,6 +671,19 @@ func (d *decodeState) object(v reflect.Value) {
|
|||||||
for _, i := range f.index {
|
for _, i := range f.index {
|
||||||
if subv.Kind() == reflect.Ptr {
|
if subv.Kind() == reflect.Ptr {
|
||||||
if subv.IsNil() {
|
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.Set(reflect.New(subv.Type().Elem()))
|
||||||
}
|
}
|
||||||
subv = subv.Elem()
|
subv = subv.Elem()
|
||||||
|
|||||||
+13
-1
@@ -1025,7 +1025,19 @@ func typeFields(t reflect.Type) []field {
|
|||||||
// Scan f.typ for fields to include.
|
// Scan f.typ for fields to include.
|
||||||
for i := 0; i < f.typ.NumField(); i++ {
|
for i := 0; i < f.typ.NumField(); i++ {
|
||||||
sf := f.typ.Field(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
|
continue
|
||||||
}
|
}
|
||||||
tag := sf.Tag.Get("json")
|
tag := sf.Tag.Get("json")
|
||||||
|
|||||||
+59
-25
@@ -25,6 +25,12 @@ import (
|
|||||||
"github.com/go-jose/go-jose/v4/json"
|
"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.
|
// rawJSONWebEncryption represents a raw JWE JSON object. Used for parsing/serializing.
|
||||||
type rawJSONWebEncryption struct {
|
type rawJSONWebEncryption struct {
|
||||||
Protected *byteBuffer `json:"protected,omitempty"`
|
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.
|
// Get the additional authenticated data from a JWE object.
|
||||||
func (obj JSONWebEncryption) computeAuthData() []byte {
|
func (obj JSONWebEncryption) computeAuthData() ([]byte, error) {
|
||||||
var protected string
|
var protected string
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case obj.original != nil && obj.original.Protected != nil:
|
case obj.original != nil && obj.original.Protected != nil:
|
||||||
protected = obj.original.Protected.base64()
|
protected = obj.original.Protected.base64()
|
||||||
case obj.protected != nil:
|
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:
|
default:
|
||||||
protected = ""
|
protected = ""
|
||||||
}
|
}
|
||||||
@@ -102,7 +112,7 @@ func (obj JSONWebEncryption) computeAuthData() []byte {
|
|||||||
output = append(output, []byte(base64.RawURLEncoding.EncodeToString(obj.aad))...)
|
output = append(output, []byte(base64.RawURLEncoding.EncodeToString(obj.aad))...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return output
|
return output, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func containsKeyAlgorithm(haystack []KeyAlgorithm, needle KeyAlgorithm) bool {
|
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.1
|
||||||
// https://datatracker.ietf.org/doc/html/rfc7516#section-3.2
|
// https://datatracker.ietf.org/doc/html/rfc7516#section-3.2
|
||||||
//
|
//
|
||||||
// The keyAlgorithms and contentEncryption parameters are used to validate the "alg" and "enc"
|
// The keyAlgorithms and contentEncryption parameters contain the allowable algorithms in the "alg" and "enc"
|
||||||
// header parameters respectively. They must be nonempty, and each "alg" or "enc" header in
|
// header parameters respectively. They must be non-empty. Non-matching algorithms cause a parse error.
|
||||||
// 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
|
// Deprecated: use ParseEncryptedJSON or ParseEncryptedCompact depending on which serialization you expect.
|
||||||
// multiple algorithms, pass a slice of all the algorithms you want to accept.
|
|
||||||
func ParseEncrypted(input string,
|
func ParseEncrypted(input string,
|
||||||
keyEncryptionAlgorithms []KeyAlgorithm,
|
keyEncryptionAlgorithms []KeyAlgorithm,
|
||||||
contentEncryption []ContentEncryption,
|
contentEncryption []ContentEncryption,
|
||||||
@@ -145,9 +154,13 @@ func ParseEncrypted(input string,
|
|||||||
return ParseEncryptedCompact(input, keyEncryptionAlgorithms, contentEncryption)
|
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
|
// 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(
|
func ParseEncryptedJSON(
|
||||||
input string,
|
input string,
|
||||||
keyEncryptionAlgorithms []KeyAlgorithm,
|
keyEncryptionAlgorithms []KeyAlgorithm,
|
||||||
@@ -177,6 +190,9 @@ func (parsed *rawJSONWebEncryption) sanitized(
|
|||||||
if len(contentEncryption) == 0 {
|
if len(contentEncryption) == 0 {
|
||||||
return nil, errors.New("go-jose/go-jose: no content encryption algorithms provided")
|
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{
|
obj := &JSONWebEncryption{
|
||||||
original: parsed,
|
original: parsed,
|
||||||
@@ -195,21 +211,11 @@ func (parsed *rawJSONWebEncryption) sanitized(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if parsed.Protected != nil && len(parsed.Protected.bytes()) > 0 {
|
protected, err := parseProtectedHeader(parsed.Protected)
|
||||||
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()
|
|
||||||
if err != nil {
|
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 {
|
if len(parsed.Recipients) == 0 {
|
||||||
obj.recipients = []recipientInfo{
|
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.iv = parsed.Iv.bytes()
|
||||||
obj.ciphertext = parsed.Ciphertext.bytes()
|
obj.ciphertext = parsed.Ciphertext.bytes()
|
||||||
obj.tag = parsed.Tag.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.
|
// ParseEncryptedCompact parses a message in JWE Compact Serialization.
|
||||||
//
|
//
|
||||||
// https://datatracker.ietf.org/doc/html/rfc7516#section-3.1
|
// 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(
|
func ParseEncryptedCompact(
|
||||||
input string,
|
input string,
|
||||||
keyAlgorithms []KeyAlgorithm,
|
keyAlgorithms []KeyAlgorithm,
|
||||||
@@ -354,7 +371,10 @@ func (obj JSONWebEncryption) CompactSerialize() (string, error) {
|
|||||||
return "", ErrNotSupported
|
return "", ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
serializedProtected := mustSerializeJSON(obj.protected)
|
serializedProtected, err := json.Marshal(obj.protected)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
return base64JoinWithDots(
|
return base64JoinWithDots(
|
||||||
serializedProtected,
|
serializedProtected,
|
||||||
@@ -366,7 +386,13 @@ func (obj JSONWebEncryption) CompactSerialize() (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FullSerialize serializes an object using the full JSON serialization format.
|
// 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 {
|
func (obj JSONWebEncryption) FullSerialize() string {
|
||||||
|
if len(obj.recipients) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
raw := rawJSONWebEncryption{
|
raw := rawJSONWebEncryption{
|
||||||
Unprotected: obj.unprotected,
|
Unprotected: obj.unprotected,
|
||||||
Iv: newBuffer(obj.iv),
|
Iv: newBuffer(obj.iv),
|
||||||
@@ -392,8 +418,16 @@ func (obj JSONWebEncryption) FullSerialize() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if obj.protected != nil {
|
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
@@ -30,6 +30,7 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
"net/url"
|
"net/url"
|
||||||
"reflect"
|
"reflect"
|
||||||
@@ -177,13 +178,29 @@ func (k JSONWebKey) MarshalJSON() ([]byte, error) {
|
|||||||
// UnmarshalJSON reads a key from its JSON representation.
|
// UnmarshalJSON reads a key from its JSON representation.
|
||||||
//
|
//
|
||||||
// Returns ErrUnsupportedKeyType for unrecognized or unsupported "kty" header values.
|
// 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
|
var raw rawJSONWebKey
|
||||||
err = json.Unmarshal(data, &raw)
|
err = json.Unmarshal(data, &raw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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)
|
certs, err := parseCertificateChain(raw.X5c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("go-jose/go-jose: failed to unmarshal x5c field: %s", err)
|
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
|
keyPub = key
|
||||||
}
|
}
|
||||||
case "oct":
|
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")
|
return errors.New("go-jose/go-jose: invalid JWK, found 'oct' (symmetric) key with cert chain")
|
||||||
}
|
}
|
||||||
key, err = raw.symmetricKey()
|
key, err = raw.symmetricKey()
|
||||||
@@ -272,10 +289,8 @@ func (k *JSONWebKey) UnmarshalJSON(data []byte) (err error) {
|
|||||||
return ErrUnsupportedKeyType
|
return ErrUnsupportedKeyType
|
||||||
}
|
}
|
||||||
|
|
||||||
if certPub != nil && keyPub != nil {
|
if len(certs) > 0 && (certPub == nil || !reflect.DeepEqual(certPub, keyPub)) {
|
||||||
if !reflect.DeepEqual(certPub, keyPub) {
|
return errors.New("go-jose/go-jose: invalid JWK, public keys in key and x5c fields do not match")
|
||||||
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}
|
*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) {
|
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,
|
return fmt.Sprintf(rsaThumbprintTemplate,
|
||||||
newBufferFromInt(uint64(e)).base64(),
|
newBufferFromInt(uint64(e)).base64(),
|
||||||
newBuffer(n.Bytes()).base64()), nil
|
newBuffer(n.Bytes()).base64()), nil
|
||||||
@@ -505,14 +523,41 @@ func (k *JSONWebKey) Valid() bool {
|
|||||||
return true
|
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) {
|
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")
|
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{
|
return &rsa.PublicKey{
|
||||||
N: key.N.bigInt(),
|
N: n,
|
||||||
E: key.E.toInt(),
|
E: int(eInt64),
|
||||||
}, nil
|
}, 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 length of this octet string MUST be the full size of a coordinate for
|
||||||
// the curve specified in the "crv" parameter.
|
// the curve specified in the "crv" parameter.
|
||||||
// https://tools.ietf.org/html/rfc7518#section-6.2.1.2
|
// 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")
|
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")
|
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, ", "))
|
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{
|
rv := &rsa.PrivateKey{
|
||||||
PublicKey: rsa.PublicKey{
|
PublicKey: *pubKey,
|
||||||
N: key.N.bigInt(),
|
D: key.D.bigInt(),
|
||||||
E: key.E.toInt(),
|
Primes: []*big.Int{p, q},
|
||||||
},
|
|
||||||
D: key.D.bigInt(),
|
|
||||||
Primes: []*big.Int{
|
|
||||||
key.P.bigInt(),
|
|
||||||
key.Q.bigInt(),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if key.Dp != nil {
|
if key.Dp != nil {
|
||||||
@@ -695,7 +745,7 @@ func (key rawJSONWebKey) rsaPrivateKey() (*rsa.PrivateKey, error) {
|
|||||||
rv.Precomputed.Qinv = key.Qi.bigInt()
|
rv.Precomputed.Qinv = key.Qi.bigInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
err := rv.Validate()
|
err = rv.Validate()
|
||||||
return rv, err
|
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 length of this octet string MUST be the full size of a coordinate for
|
||||||
// the curve specified in the "crv" parameter.
|
// the curve specified in the "crv" parameter.
|
||||||
// https://tools.ietf.org/html/rfc7518#section-6.2.1.2
|
// 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")
|
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")
|
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
|
// 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")
|
return nil, fmt.Errorf("go-jose/go-jose: invalid EC private key, wrong length for d")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+79
-32
@@ -27,6 +27,12 @@ import (
|
|||||||
"github.com/go-jose/go-jose/v4/json"
|
"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.
|
// rawJSONWebSignature represents a raw JWS JSON object. Used for parsing/serializing.
|
||||||
type rawJSONWebSignature struct {
|
type rawJSONWebSignature struct {
|
||||||
Payload *byteBuffer `json:"payload,omitempty"`
|
Payload *byteBuffer `json:"payload,omitempty"`
|
||||||
@@ -86,6 +92,11 @@ type Signature struct {
|
|||||||
// Verify() after parsing to validate the signature and obtain the payload.
|
// Verify() after parsing to validate the signature and obtain the payload.
|
||||||
//
|
//
|
||||||
// https://datatracker.ietf.org/doc/html/rfc7515#section-7
|
// 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(
|
func ParseSigned(
|
||||||
signature string,
|
signature string,
|
||||||
signatureAlgorithms []SignatureAlgorithm,
|
signatureAlgorithms []SignatureAlgorithm,
|
||||||
@@ -108,6 +119,9 @@ func ParseSigned(
|
|||||||
// Verify() after parsing to validate the signature and obtain the payload.
|
// Verify() after parsing to validate the signature and obtain the payload.
|
||||||
//
|
//
|
||||||
// https://datatracker.ietf.org/doc/html/rfc7515#section-7.1
|
// 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(
|
func ParseSignedCompact(
|
||||||
signature string,
|
signature string,
|
||||||
signatureAlgorithms []SignatureAlgorithm,
|
signatureAlgorithms []SignatureAlgorithm,
|
||||||
@@ -125,6 +139,9 @@ func ParseSignedCompact(
|
|||||||
// parsing. Call Verify() after parsing to validate the signature and obtain the payload.
|
// parsing. Call Verify() after parsing to validate the signature and obtain the payload.
|
||||||
//
|
//
|
||||||
// https://datatracker.ietf.org/doc/html/rfc7515#appendix-F
|
// 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(
|
func ParseDetached(
|
||||||
signature string,
|
signature string,
|
||||||
payload []byte,
|
payload []byte,
|
||||||
@@ -157,7 +174,11 @@ func (obj JSONWebSignature) computeAuthData(payload []byte, signature *Signature
|
|||||||
authData.WriteString(signature.original.Protected.base64())
|
authData.WriteString(signature.original.Protected.base64())
|
||||||
} else if signature.protected != nil {
|
} else if signature.protected != nil {
|
||||||
protectedHeader = signature.protected
|
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
|
needsBase64 := true
|
||||||
@@ -180,9 +201,13 @@ func (obj JSONWebSignature) computeAuthData(payload []byte, signature *Signature
|
|||||||
return authData.Bytes(), nil
|
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
|
// 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(
|
func ParseSignedJSON(
|
||||||
input string,
|
input string,
|
||||||
signatureAlgorithms []SignatureAlgorithm,
|
signatureAlgorithms []SignatureAlgorithm,
|
||||||
@@ -236,6 +261,9 @@ func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgo
|
|||||||
if parsed.Payload == nil {
|
if parsed.Payload == nil {
|
||||||
return nil, fmt.Errorf("go-jose/go-jose: missing payload in JWS message")
|
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{
|
obj := &JSONWebSignature{
|
||||||
payload: parsed.Payload.bytes(),
|
payload: parsed.Payload.bytes(),
|
||||||
@@ -245,14 +273,13 @@ func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgo
|
|||||||
if len(parsed.Signatures) == 0 {
|
if len(parsed.Signatures) == 0 {
|
||||||
// No signatures array, must be flattened serialization
|
// No signatures array, must be flattened serialization
|
||||||
signature := Signature{}
|
signature := Signature{}
|
||||||
if parsed.Protected != nil && len(parsed.Protected.bytes()) > 0 {
|
prot, err := parseProtectedHeader(parsed.Protected)
|
||||||
signature.protected = &rawHeader{}
|
if err != nil {
|
||||||
err := json.Unmarshal(parsed.Protected.bytes(), signature.protected)
|
return nil, err
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signature.protected = prot
|
||||||
|
|
||||||
// Check that there is not a nonce in the unprotected header
|
// Check that there is not a nonce in the unprotected header
|
||||||
if parsed.Header != nil && parsed.Header.getNonce() != "" {
|
if parsed.Header != nil && parsed.Header.getNonce() != "" {
|
||||||
return nil, ErrUnprotectedNonce
|
return nil, ErrUnprotectedNonce
|
||||||
@@ -275,17 +302,17 @@ func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgo
|
|||||||
Signature: parsed.Signature,
|
Signature: parsed.Signature,
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
mergedHeaders := signature.mergedHeaders()
|
||||||
signature.Header, err = signature.mergedHeaders().sanitized()
|
alg := mergedHeaders.getSignatureAlgorithm()
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
alg := SignatureAlgorithm(signature.Header.Algorithm)
|
|
||||||
if !containsSignatureAlgorithm(signatureAlgorithms, alg) {
|
if !containsSignatureAlgorithm(signatureAlgorithms, alg) {
|
||||||
return nil, newErrUnexpectedSignatureAlgorithm(alg, signatureAlgorithms)
|
return nil, newErrUnexpectedSignatureAlgorithm(alg, signatureAlgorithms)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signature.Header, err = mergedHeaders.sanitized()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
if signature.header != nil {
|
if signature.header != nil {
|
||||||
signature.Unprotected, err = signature.header.sanitized()
|
signature.Unprotected, err = signature.header.sanitized()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -310,30 +337,31 @@ func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgo
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i, sig := range parsed.Signatures {
|
for i, sig := range parsed.Signatures {
|
||||||
if sig.Protected != nil && len(sig.Protected.bytes()) > 0 {
|
prot, err := parseProtectedHeader(sig.Protected)
|
||||||
obj.Signatures[i].protected = &rawHeader{}
|
if err != nil {
|
||||||
err := json.Unmarshal(sig.Protected.bytes(), obj.Signatures[i].protected)
|
return nil, err
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
obj.Signatures[i].protected = prot
|
||||||
|
|
||||||
// Check that there is not a nonce in the unprotected header
|
// Check that there is not a nonce in the unprotected header
|
||||||
if sig.Header != nil && sig.Header.getNonce() != "" {
|
if sig.Header != nil && sig.Header.getNonce() != "" {
|
||||||
return nil, ErrUnprotectedNonce
|
return nil, ErrUnprotectedNonce
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
obj.Signatures[i].header = sig.Header
|
||||||
obj.Signatures[i].Header, err = obj.Signatures[i].mergedHeaders().sanitized()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
alg := SignatureAlgorithm(obj.Signatures[i].Header.Algorithm)
|
mergedHeaders := obj.Signatures[i].mergedHeaders()
|
||||||
|
alg := mergedHeaders.getSignatureAlgorithm()
|
||||||
if !containsSignatureAlgorithm(signatureAlgorithms, alg) {
|
if !containsSignatureAlgorithm(signatureAlgorithms, alg) {
|
||||||
return nil, newErrUnexpectedSignatureAlgorithm(alg, signatureAlgorithms)
|
return nil, newErrUnexpectedSignatureAlgorithm(alg, signatureAlgorithms)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
obj.Signatures[i].Header, err = mergedHeaders.sanitized()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
if obj.Signatures[i].header != nil {
|
if obj.Signatures[i].header != nil {
|
||||||
obj.Signatures[i].Unprotected, err = obj.Signatures[i].header.sanitized()
|
obj.Signatures[i].Unprotected, err = obj.Signatures[i].header.sanitized()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -359,7 +387,6 @@ func (parsed *rawJSONWebSignature) sanitized(signatureAlgorithms []SignatureAlgo
|
|||||||
// Copy value of sig
|
// Copy value of sig
|
||||||
original := sig
|
original := sig
|
||||||
|
|
||||||
obj.Signatures[i].header = sig.Header
|
|
||||||
obj.Signatures[i].original = &original
|
obj.Signatures[i].original = &original
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -424,7 +451,10 @@ func (obj JSONWebSignature) compactSerialize(detached bool) (string, error) {
|
|||||||
return "", ErrNotSupported
|
return "", ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
serializedProtected := mustSerializeJSON(obj.Signatures[0].protected)
|
serializedProtected, err := json.Marshal(obj.Signatures[0].protected)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
var payload []byte
|
var payload []byte
|
||||||
if !detached {
|
if !detached {
|
||||||
@@ -449,14 +479,23 @@ func (obj JSONWebSignature) DetachedCompactSerialize() (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FullSerialize serializes an object using the full JSON serialization format.
|
// FullSerialize serializes an object using the full JSON serialization format.
|
||||||
|
//
|
||||||
|
// It returns "" if obj cannot be serialized.
|
||||||
func (obj JSONWebSignature) FullSerialize() string {
|
func (obj JSONWebSignature) FullSerialize() string {
|
||||||
raw := rawJSONWebSignature{
|
raw := rawJSONWebSignature{
|
||||||
Payload: newBuffer(obj.payload),
|
Payload: newBuffer(obj.payload),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(obj.Signatures) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
if len(obj.Signatures) == 1 {
|
if len(obj.Signatures) == 1 {
|
||||||
if obj.Signatures[0].protected != nil {
|
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.Protected = newBuffer(serializedProtected)
|
||||||
}
|
}
|
||||||
raw.Header = obj.Signatures[0].header
|
raw.Header = obj.Signatures[0].header
|
||||||
@@ -470,10 +509,18 @@ func (obj JSONWebSignature) FullSerialize() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if signature.protected != nil {
|
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
@@ -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)")
|
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.
|
// 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.
|
// 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)")
|
var ErrInvalidContentType = errors.New("go-jose/go-jose/jwt: expected content type to be JWT (cty header)")
|
||||||
|
|||||||
+12
-17
@@ -85,7 +85,12 @@ func (t *NestedJSONWebToken) Decrypt(decryptionKey interface{}) (*JSONWebToken,
|
|||||||
return sig, nil
|
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) {
|
func ParseSigned(s string, signatureAlgorithms []jose.SignatureAlgorithm) (*JSONWebToken, error) {
|
||||||
sig, err := jose.ParseSignedCompact(s, signatureAlgorithms)
|
sig, err := jose.ParseSignedCompact(s, signatureAlgorithms)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -142,13 +147,10 @@ func parseEncryptedCompact(
|
|||||||
return enc, nil
|
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"
|
// The keyAlgorithms and contentEncryption parameters contain the allowable algorithms in the "alg" and "enc"
|
||||||
// header parameters respectively. They must be nonempty, and each "alg" or "enc" header in
|
// header parameters respectively. They must be non-empty. Non-matching algorithms cause a parse error.
|
||||||
// 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.
|
|
||||||
func ParseEncrypted(s string,
|
func ParseEncrypted(s string,
|
||||||
keyAlgorithms []jose.KeyAlgorithm,
|
keyAlgorithms []jose.KeyAlgorithm,
|
||||||
contentEncryption []jose.ContentEncryption,
|
contentEncryption []jose.ContentEncryption,
|
||||||
@@ -164,17 +166,10 @@ func ParseEncrypted(s string,
|
|||||||
}, nil
|
}, 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"
|
// The encryptionKeyAlgorithms, contentEncryption, and signatureAlgorithms parameters contain the allowable
|
||||||
// header parameters, respectively, of the outer JWE. They must be nonempty, and each "alg" or "enc"
|
// algorithms. They must be non-empty. Non-matching algorithms cause a parse error.
|
||||||
// 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.
|
|
||||||
func ParseSignedAndEncrypted(s string,
|
func ParseSignedAndEncrypted(s string,
|
||||||
encryptionKeyAlgorithms []jose.KeyAlgorithm,
|
encryptionKeyAlgorithms []jose.KeyAlgorithm,
|
||||||
contentEncryption []jose.ContentEncryption,
|
contentEncryption []jose.ContentEncryption,
|
||||||
|
|||||||
+43
-37
@@ -18,6 +18,7 @@ package jose
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
|
"crypto/rsa"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
@@ -210,13 +211,20 @@ type Header struct {
|
|||||||
|
|
||||||
// Certificates verifies & returns the certificate chain present
|
// Certificates verifies & returns the certificate chain present
|
||||||
// in the x5c header field of a message, if one was present. Returns
|
// 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.
|
// not be validated with the given verify options.
|
||||||
func (h Header) Certificates(opts x509.VerifyOptions) ([][]*x509.Certificate, error) {
|
func (h Header) Certificates(opts x509.VerifyOptions) ([][]*x509.Certificate, error) {
|
||||||
if len(h.certificates) == 0 {
|
if len(h.certificates) == 0 {
|
||||||
return nil, ErrMissingX5cHeader
|
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]
|
leaf := h.certificates[0]
|
||||||
if opts.Intermediates == nil {
|
if opts.Intermediates == nil {
|
||||||
opts.Intermediates = x509.NewCertPool()
|
opts.Intermediates = x509.NewCertPool()
|
||||||
@@ -297,9 +305,10 @@ func (parsed rawHeader) getEPK() (*JSONWebKey, error) {
|
|||||||
if v == nil {
|
if v == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
var epk *JSONWebKey
|
// RFC 7518 Section 4.6.1.1: the "epk" header is the ephemeral public key
|
||||||
err := json.Unmarshal(*v, &epk)
|
// of the originator. Reject private key material before parsing it.
|
||||||
if err != nil {
|
epk := new(JSONWebKey)
|
||||||
|
if err := epk.unmarshalJSON(*v, false); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return epk, nil
|
return epk, nil
|
||||||
@@ -325,20 +334,6 @@ func (parsed rawHeader) getTag() (*byteBuffer, error) {
|
|||||||
return parsed.getByteBuffer(headerTag)
|
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
|
// getCritical extracts parsed "crit" from the raw JSON. If omitted, it
|
||||||
// returns an empty slice.
|
// returns an empty slice.
|
||||||
func (parsed rawHeader) getCritical() ([]string, error) {
|
func (parsed rawHeader) getCritical() ([]string, error) {
|
||||||
@@ -424,10 +419,14 @@ func (parsed rawHeader) sanitized() (h Header, err error) {
|
|||||||
}
|
}
|
||||||
switch k {
|
switch k {
|
||||||
case headerJWK:
|
case headerJWK:
|
||||||
var jwk *JSONWebKey
|
// RFC 7515 Section 4.1.3 and RFC 7516 Section 4.1.5: the "jwk"
|
||||||
err = json.Unmarshal(*v, &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 {
|
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
|
return
|
||||||
}
|
}
|
||||||
h.JSONWebKey = jwk
|
h.JSONWebKey = jwk
|
||||||
@@ -499,22 +498,8 @@ func parseCertificateChain(chain []string) ([]*x509.Certificate, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (parsed rawHeader) isSet(k HeaderKey) bool {
|
func (parsed rawHeader) isSet(k HeaderKey) bool {
|
||||||
dvr := parsed[k]
|
_, ok := parsed[k]
|
||||||
if dvr == nil {
|
return ok
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge headers from src into dst, giving precedence to headers from l.
|
// 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)
|
rm := json.RawMessage(b)
|
||||||
return &rm
|
return &rm
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parseProtectedHeader parses a `byteBuffer` into a `*rawHeader`.
|
||||||
|
//
|
||||||
|
// The byteBuffer represents a base64-decoded "protected" header, which
|
||||||
|
// is specified to contain a JSON object.
|
||||||
|
//
|
||||||
|
// If the input is nil or empty, returns `nil, nil`.
|
||||||
|
//
|
||||||
|
// `rawHeader` is a map type and so can be nil. When this function
|
||||||
|
// returns a non-nil `*rawHeader`, the map is guaranteed to be non-nil.
|
||||||
|
func parseProtectedHeader(in *byteBuffer) (*rawHeader, error) {
|
||||||
|
if in == nil || len(in.bytes()) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
var header rawHeader
|
||||||
|
err := json.Unmarshal(in.bytes(), &header)
|
||||||
|
if err != nil || header == nil {
|
||||||
|
return nil, errors.New("go-jose/go-jose: invalid protected header")
|
||||||
|
}
|
||||||
|
return &header, nil
|
||||||
|
}
|
||||||
|
|||||||
+4
-1
@@ -321,7 +321,10 @@ func (ctx *genericSigner) Sign(payload []byte) (*JSONWebSignature, error) {
|
|||||||
protected[k] = v
|
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
|
needsBase64 := true
|
||||||
|
|
||||||
if b64, ok := protected[headerB64]; ok {
|
if b64, ok := protected[headerB64]; ok {
|
||||||
|
|||||||
+1
-1
@@ -421,7 +421,7 @@ func (ctx *symmetricKeyCipher) decryptKey(headers rawHeader, recipient *recipien
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("go-jose/go-jose: invalid P2S: %v", err)
|
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")
|
return nil, fmt.Errorf("go-jose/go-jose: invalid P2S: must be present")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
@@ -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
@@ -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
@@ -659,7 +659,8 @@ func (s *Scratch) validateNorm() (err error) {
|
|||||||
if v >= 0 {
|
if v >= 0 {
|
||||||
total += int(v)
|
total += int(v)
|
||||||
} else {
|
} else {
|
||||||
total -= int(v)
|
// -1 takes one cell. Adding -v would let a wrapped -32768 pass.
|
||||||
|
total++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
|
|||||||
+6
@@ -3,6 +3,7 @@ package fse
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -123,6 +124,11 @@ func (s *Scratch) readNCount() error {
|
|||||||
remaining -= count
|
remaining -= count
|
||||||
gotTotal += 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)
|
s.norm[charnum&0xff] = int16(count)
|
||||||
charnum++
|
charnum++
|
||||||
previous0 = count == 0
|
previous0 = count == 0
|
||||||
|
|||||||
+4
@@ -54,6 +54,10 @@ func ReadTable(in []byte, s *Scratch) (s2 *Scratch, remain []byte, err error) {
|
|||||||
if len(in) < int(iSize) {
|
if len(in) < int(iSize) {
|
||||||
return s, nil, fmt.Errorf("input too small for table, want %d bytes, have %d", iSize, len(in))
|
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
|
// FSE compressed weights
|
||||||
s.fse.DecompressLimit = 255
|
s.fse.DecompressLimit = 255
|
||||||
hw := s.huffWeight[:]
|
hw := s.huffWeight[:]
|
||||||
|
|||||||
+3
@@ -219,6 +219,9 @@ func BuildDict(o BuildDictOptions) ([]byte, error) {
|
|||||||
if len(contents) == 0 {
|
if len(contents) == 0 {
|
||||||
return nil, errors.New("no content provided")
|
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{
|
d := dict{
|
||||||
id: o.ID,
|
id: o.ID,
|
||||||
litEnc: nil,
|
litEnc: nil,
|
||||||
|
|||||||
+12
@@ -69,6 +69,10 @@ var (
|
|||||||
// No CRC value is being generated and not all CRC values of the Snappy stream are checked.
|
// 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.
|
// However, it provides really fast recompression of Snappy streams.
|
||||||
// The converter can be reused to avoid allocations, even after errors.
|
// 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 {
|
type SnappyConverter struct {
|
||||||
r io.Reader
|
r io.Reader
|
||||||
err error
|
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
|
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 */ {
|
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)
|
println("offset <= 0 || blk.size+lits < int(offset)", offset, blk.size+lits, int(offset), blk.size, lits)
|
||||||
|
|
||||||
|
|||||||
+60
-9
@@ -22,7 +22,7 @@ file {
|
|||||||
java_package: "com.google.protobuf"
|
java_package: "com.google.protobuf"
|
||||||
java_outer_classname: "TimestampProto"
|
java_outer_classname: "TimestampProto"
|
||||||
java_multiple_files: true
|
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
|
cc_enable_arenas: true
|
||||||
objc_class_prefix: "GPB"
|
objc_class_prefix: "GPB"
|
||||||
csharp_namespace: "Google.Protobuf.WellKnownTypes"
|
csharp_namespace: "Google.Protobuf.WellKnownTypes"
|
||||||
@@ -53,7 +53,7 @@ file {
|
|||||||
java_package: "com.google.protobuf"
|
java_package: "com.google.protobuf"
|
||||||
java_outer_classname: "DurationProto"
|
java_outer_classname: "DurationProto"
|
||||||
java_multiple_files: true
|
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
|
cc_enable_arenas: true
|
||||||
objc_class_prefix: "GPB"
|
objc_class_prefix: "GPB"
|
||||||
csharp_namespace: "Google.Protobuf.WellKnownTypes"
|
csharp_namespace: "Google.Protobuf.WellKnownTypes"
|
||||||
@@ -157,7 +157,7 @@ file {
|
|||||||
java_package: "com.google.protobuf"
|
java_package: "com.google.protobuf"
|
||||||
java_outer_classname: "WrappersProto"
|
java_outer_classname: "WrappersProto"
|
||||||
java_multiple_files: true
|
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
|
cc_enable_arenas: true
|
||||||
objc_class_prefix: "GPB"
|
objc_class_prefix: "GPB"
|
||||||
csharp_namespace: "Google.Protobuf.WellKnownTypes"
|
csharp_namespace: "Google.Protobuf.WellKnownTypes"
|
||||||
@@ -484,6 +484,13 @@ file {
|
|||||||
type_name: ".google.protobuf.FieldOptions"
|
type_name: ".google.protobuf.FieldOptions"
|
||||||
json_name: "options"
|
json_name: "options"
|
||||||
}
|
}
|
||||||
|
field {
|
||||||
|
name: "proto3_optional"
|
||||||
|
number: 17
|
||||||
|
label: LABEL_OPTIONAL
|
||||||
|
type: TYPE_BOOL
|
||||||
|
json_name: "proto3Optional"
|
||||||
|
}
|
||||||
enum_type {
|
enum_type {
|
||||||
name: "Type"
|
name: "Type"
|
||||||
value {
|
value {
|
||||||
@@ -853,7 +860,7 @@ file {
|
|||||||
number: 31
|
number: 31
|
||||||
label: LABEL_OPTIONAL
|
label: LABEL_OPTIONAL
|
||||||
type: TYPE_BOOL
|
type: TYPE_BOOL
|
||||||
default_value: "false"
|
default_value: "true"
|
||||||
json_name: "ccEnableArenas"
|
json_name: "ccEnableArenas"
|
||||||
}
|
}
|
||||||
field {
|
field {
|
||||||
@@ -1405,7 +1412,7 @@ file {
|
|||||||
java_package: "com.google.protobuf"
|
java_package: "com.google.protobuf"
|
||||||
java_outer_classname: "DescriptorProtos"
|
java_outer_classname: "DescriptorProtos"
|
||||||
optimize_for: SPEED
|
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
|
cc_enable_arenas: true
|
||||||
objc_class_prefix: "GPB"
|
objc_class_prefix: "GPB"
|
||||||
csharp_namespace: "Google.Protobuf.Reflection"
|
csharp_namespace: "Google.Protobuf.Reflection"
|
||||||
@@ -5208,7 +5215,7 @@ file {
|
|||||||
java_package: "com.google.protobuf"
|
java_package: "com.google.protobuf"
|
||||||
java_outer_classname: "AnyProto"
|
java_outer_classname: "AnyProto"
|
||||||
java_multiple_files: true
|
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"
|
objc_class_prefix: "GPB"
|
||||||
csharp_namespace: "Google.Protobuf.WellKnownTypes"
|
csharp_namespace: "Google.Protobuf.WellKnownTypes"
|
||||||
}
|
}
|
||||||
@@ -10590,7 +10597,7 @@ file {
|
|||||||
syntax: "proto3"
|
syntax: "proto3"
|
||||||
}
|
}
|
||||||
file {
|
file {
|
||||||
name: "go.etcd.io/etcd/raft/v3/raftpb/raft.proto"
|
name: "go.etcd.io/raft/v3/raftpb/raft.proto"
|
||||||
package: "raftpb"
|
package: "raftpb"
|
||||||
dependency: "gogoproto/gogo.proto"
|
dependency: "gogoproto/gogo.proto"
|
||||||
message_type {
|
message_type {
|
||||||
@@ -10773,6 +10780,16 @@ file {
|
|||||||
}
|
}
|
||||||
json_name: "commit"
|
json_name: "commit"
|
||||||
}
|
}
|
||||||
|
field {
|
||||||
|
name: "vote"
|
||||||
|
number: 13
|
||||||
|
label: LABEL_OPTIONAL
|
||||||
|
type: TYPE_UINT64
|
||||||
|
options {
|
||||||
|
65001: 0
|
||||||
|
}
|
||||||
|
json_name: "vote"
|
||||||
|
}
|
||||||
field {
|
field {
|
||||||
name: "snapshot"
|
name: "snapshot"
|
||||||
number: 9
|
number: 9
|
||||||
@@ -10780,7 +10797,7 @@ file {
|
|||||||
type: TYPE_MESSAGE
|
type: TYPE_MESSAGE
|
||||||
type_name: ".raftpb.Snapshot"
|
type_name: ".raftpb.Snapshot"
|
||||||
options {
|
options {
|
||||||
65001: 0
|
65001: 1
|
||||||
}
|
}
|
||||||
json_name: "snapshot"
|
json_name: "snapshot"
|
||||||
}
|
}
|
||||||
@@ -10809,8 +10826,22 @@ file {
|
|||||||
number: 12
|
number: 12
|
||||||
label: LABEL_OPTIONAL
|
label: LABEL_OPTIONAL
|
||||||
type: TYPE_BYTES
|
type: TYPE_BYTES
|
||||||
|
options {
|
||||||
|
65001: 1
|
||||||
|
}
|
||||||
json_name: "context"
|
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 {
|
message_type {
|
||||||
name: "HardState"
|
name: "HardState"
|
||||||
@@ -11079,6 +11110,26 @@ file {
|
|||||||
name: "MsgPreVoteResp"
|
name: "MsgPreVoteResp"
|
||||||
number: 18
|
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 {
|
enum_type {
|
||||||
name: "ConfChangeTransition"
|
name: "ConfChangeTransition"
|
||||||
@@ -11130,7 +11181,7 @@ file {
|
|||||||
package: "docker.swarmkit.v1"
|
package: "docker.swarmkit.v1"
|
||||||
dependency: "github.com/docker/swarmkit/api/objects.proto"
|
dependency: "github.com/docker/swarmkit/api/objects.proto"
|
||||||
dependency: "github.com/docker/swarmkit/api/types.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: "gogoproto/gogo.proto"
|
||||||
dependency: "github.com/docker/swarmkit/protobuf/plugin/plugin.proto"
|
dependency: "github.com/docker/swarmkit/protobuf/plugin/plugin.proto"
|
||||||
message_type {
|
message_type {
|
||||||
|
|||||||
+2
-2
@@ -12,7 +12,7 @@ type CopierFrom interface {
|
|||||||
// Copy takes the fields from src and copies them into the target object.
|
// 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.
|
// 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.
|
// 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
|
// If the copy cannot be performed, this function will panic. Make sure to test
|
||||||
// types that use this function.
|
// types that use this function.
|
||||||
func Copy(dst, src interface{}) {
|
func Copy(dst, src any) {
|
||||||
switch dst := dst.(type) {
|
switch dst := dst.(type) {
|
||||||
case *types.Any:
|
case *types.Any:
|
||||||
src := src.(*types.Any)
|
src := src.(*types.Any)
|
||||||
|
|||||||
+2
-2
@@ -73,7 +73,7 @@ func customIndexer(kind string, annotations *Annotations) (bool, [][]byte, error
|
|||||||
return len(converted) != 0, converted, nil
|
return len(converted) != 0, converted, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func fromArgs(args ...interface{}) ([]byte, error) {
|
func fromArgs(args ...any) ([]byte, error) {
|
||||||
if len(args) != 1 {
|
if len(args) != 1 {
|
||||||
return nil, fmt.Errorf("must provide only a single argument")
|
return nil, fmt.Errorf("must provide only a single argument")
|
||||||
}
|
}
|
||||||
@@ -86,7 +86,7 @@ func fromArgs(args ...interface{}) ([]byte, error) {
|
|||||||
return []byte(arg), nil
|
return []byte(arg), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func prefixFromArgs(args ...interface{}) ([]byte, error) {
|
func prefixFromArgs(args ...any) ([]byte, error) {
|
||||||
val, err := fromArgs(args...)
|
val, err := fromArgs(args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
+1
@@ -42,6 +42,7 @@ func init() {
|
|||||||
for _, c := range "yYnNtTfFoO~" {
|
for _, c := range "yYnNtTfFoO~" {
|
||||||
t[int(c)] = 'M' // In map
|
t[int(c)] = 'M' // In map
|
||||||
}
|
}
|
||||||
|
t[int('<')] = 'M' // In map (merge key "<<")
|
||||||
t[int('.')] = '.' // Float (potentially in map)
|
t[int('.')] = '.' // Float (potentially in map)
|
||||||
|
|
||||||
var resolveMapList = []struct {
|
var resolveMapList = []struct {
|
||||||
|
|||||||
Vendored
+6
-6
@@ -90,10 +90,10 @@ github.com/docker/go-units
|
|||||||
# github.com/felixge/httpsnoop v1.1.0
|
# github.com/felixge/httpsnoop v1.1.0
|
||||||
## explicit; go 1.25
|
## explicit; go 1.25
|
||||||
github.com/felixge/httpsnoop
|
github.com/felixge/httpsnoop
|
||||||
# github.com/fvbommel/sortorder v1.2.0
|
# github.com/fvbommel/sortorder v1.2.1
|
||||||
## explicit; go 1.21
|
## explicit; go 1.21
|
||||||
github.com/fvbommel/sortorder
|
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
|
## explicit; go 1.24.0
|
||||||
github.com/go-jose/go-jose/v4
|
github.com/go-jose/go-jose/v4
|
||||||
github.com/go-jose/go-jose/v4/cipher
|
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
|
# github.com/inconshreveable/mousetrap v1.1.0
|
||||||
## explicit; go 1.18
|
## explicit; go 1.18
|
||||||
github.com/inconshreveable/mousetrap
|
github.com/inconshreveable/mousetrap
|
||||||
# github.com/klauspost/compress v1.20.1
|
# github.com/klauspost/compress v1.20.2
|
||||||
## explicit; go 1.25
|
## explicit; go 1.25
|
||||||
github.com/klauspost/compress
|
github.com/klauspost/compress
|
||||||
github.com/klauspost/compress/fse
|
github.com/klauspost/compress/fse
|
||||||
@@ -205,8 +205,8 @@ github.com/moby/moby/client/pkg/versions
|
|||||||
## explicit; go 1.19
|
## explicit; go 1.19
|
||||||
github.com/moby/patternmatcher
|
github.com/moby/patternmatcher
|
||||||
github.com/moby/patternmatcher/ignorefile
|
github.com/moby/patternmatcher/ignorefile
|
||||||
# github.com/moby/swarmkit/v2 v2.1.2
|
# github.com/moby/swarmkit/v2 v2.1.3
|
||||||
## explicit; go 1.24.0
|
## explicit; go 1.25.0
|
||||||
github.com/moby/swarmkit/v2/api
|
github.com/moby/swarmkit/v2/api
|
||||||
github.com/moby/swarmkit/v2/api/deepcopy
|
github.com/moby/swarmkit/v2/api/deepcopy
|
||||||
github.com/moby/swarmkit/v2/api/defaults
|
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/metrics/v1
|
||||||
go.opentelemetry.io/proto/otlp/resource/v1
|
go.opentelemetry.io/proto/otlp/resource/v1
|
||||||
go.opentelemetry.io/proto/otlp/trace/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
|
## explicit; go 1.16
|
||||||
go.yaml.in/yaml/v3
|
go.yaml.in/yaml/v3
|
||||||
# golang.org/x/mod v0.41.0
|
# golang.org/x/mod v0.41.0
|
||||||
|
|||||||
Reference in New Issue
Block a user